diff --git a/README.md b/README.md index f966123..91c8c52 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,9 @@ Not every app is available on both EL versions. The installer shows a small **EL | FogPanther | ✅ | ✅ | Via Flathub | | Gaffer | ✅ | ✅ | Guided portable binary install (works on EL9 and EL10) | | Natron | ✅ | ✅ | Via Flathub | +| Open 3D Engine | ❌ | ✅ | Via COPR (hellaenergy/o3de), BETA | +| Unreal Engine 5.8 | ✅ | ✅ | Guided vendor install (Epic account), preview build | +| Unigine | ✅ | ✅ | Guided vendor install (.run) | > This table reflects current EPEL availability and will be updated as packages land in EL10. @@ -243,6 +246,9 @@ post-production, and content creation environments: - Epic Asset Manager - Asset Manager Studio - Godots + - Open 3D Engine *(via COPR, EL10 only, BETA)* + - Unreal Engine 5.8 *(guided vendor install, preview build)* + - Unigine *(guided vendor install)* - **Audio** - Ardour diff --git a/UIDev/ansibleshed/01-creative_gnome_defaults b/UIDev/ansibleshed/01-creative_gnome_defaults new file mode 100644 index 0000000..fbd1a8f --- /dev/null +++ b/UIDev/ansibleshed/01-creative_gnome_defaults @@ -0,0 +1,96 @@ +########################### +### Window Management + +[org/gnome/desktop/wm/preferences] + +button-layout='appmenu:minimize,maximize,close' +resize-with-right-button=true + +########################### +### Interface + +[org/gnome/desktop/interface] + +gtk-theme='Adwaita-dark' +enable-hot-corners=false + +########################### +### File Browser (Nautilus) + +[org/gnome/nautilus/preferences] + +always-use-location-entry=true +default-folder-viewer='list-view' + +[org/gnome/nautilus/list-view] + +default-zoom-level='small' +use-tree-view=true +default-visible-columns=['name', 'size', 'date_modified', 'type', 'starred'] + +########################### +### Workspace + +[org/gnome/mutter] + +workspaces-only-on-primary=false + +########################## +### Favorite Apps +[org/gnome/shell] +favorite-apps=['google-chrome.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Terminal.desktop', 'com.slack.Slack.desktop', 'almalinux-creative-installer.desktop'] + +########################## +### Gnome Extensions +[org/gnome/shell] + +# Set default Enabled Extensions +enabled-extensions=['top-icons@gnome-shell-extensions.gcampax.github.com', 'background-logo@fedorahosted.org', 'dash-to-panel@jderose9.github.com', 'system-monitor@paradoxxx.zero.gmail.com', 'arcmenu@arcmenu.com', 'gnome-ui-tune@itstime.tech', 'blur-my-shell@aunetx'] + +# Dash to Panel +[org/gnome/shell/extensions/dash-to-panel] + +multi-monitors=true +isolate-monitors=false +isolate-workspaces=true +scroll-panel-action='NOTHING' +dot-style-focused='SEGMENTED' +dot-style-unfocused='DASHES' +dot-color-override=true +dot-color-1='#5294e2' +dot-color-2='#5294e2' +dot-color-3='#5294e2' +dot-color-4='#5294e2' +dot-color-unfocused-different=true +dot-color-unfocused-1='#c0bfbc' +dot-color-unfocused-2='#c0bfbc' +dot-color-unfocused-3='#c0bfbc' +dot-color-unfocused-4='#c0bfbc' +click-action='TOGGLE-SHOWPREVIEW' +hide-overview-on-startup=true +appicon-padding=4 +appicon-margin=1 +panel-sizes='{"0":40,"1":40}' +panel-element-positions='{"0":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}],"1":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}]}' + +# System Monitor +[org/gnome/shell/extensions/system-monitor] + +compact-display=true +center-display=true +net-display=false +swap-display=true +icon-display=false + +# Arc Menu +[org/gnome/shell/extensions/arcmenu] + +multi-monitor=true +menu-button-icon='Distro_Icon' +menu-layout='Redmond' +enable-horizontal-flip=true + +# Gnome 4x UI Improvement +[org/gnome/shell/extensions/gnome-ui-tune] + +hide-search=false diff --git a/UIDev/ansibleshed/Packages.zip b/UIDev/ansibleshed/Packages.zip new file mode 100644 index 0000000..1319c12 Binary files /dev/null and b/UIDev/ansibleshed/Packages.zip differ diff --git a/UIDev/ansibleshed/Packages/01-creative_gnome_defaults b/UIDev/ansibleshed/Packages/01-creative_gnome_defaults new file mode 100644 index 0000000..fbd1a8f --- /dev/null +++ b/UIDev/ansibleshed/Packages/01-creative_gnome_defaults @@ -0,0 +1,96 @@ +########################### +### Window Management + +[org/gnome/desktop/wm/preferences] + +button-layout='appmenu:minimize,maximize,close' +resize-with-right-button=true + +########################### +### Interface + +[org/gnome/desktop/interface] + +gtk-theme='Adwaita-dark' +enable-hot-corners=false + +########################### +### File Browser (Nautilus) + +[org/gnome/nautilus/preferences] + +always-use-location-entry=true +default-folder-viewer='list-view' + +[org/gnome/nautilus/list-view] + +default-zoom-level='small' +use-tree-view=true +default-visible-columns=['name', 'size', 'date_modified', 'type', 'starred'] + +########################### +### Workspace + +[org/gnome/mutter] + +workspaces-only-on-primary=false + +########################## +### Favorite Apps +[org/gnome/shell] +favorite-apps=['google-chrome.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Terminal.desktop', 'com.slack.Slack.desktop', 'almalinux-creative-installer.desktop'] + +########################## +### Gnome Extensions +[org/gnome/shell] + +# Set default Enabled Extensions +enabled-extensions=['top-icons@gnome-shell-extensions.gcampax.github.com', 'background-logo@fedorahosted.org', 'dash-to-panel@jderose9.github.com', 'system-monitor@paradoxxx.zero.gmail.com', 'arcmenu@arcmenu.com', 'gnome-ui-tune@itstime.tech', 'blur-my-shell@aunetx'] + +# Dash to Panel +[org/gnome/shell/extensions/dash-to-panel] + +multi-monitors=true +isolate-monitors=false +isolate-workspaces=true +scroll-panel-action='NOTHING' +dot-style-focused='SEGMENTED' +dot-style-unfocused='DASHES' +dot-color-override=true +dot-color-1='#5294e2' +dot-color-2='#5294e2' +dot-color-3='#5294e2' +dot-color-4='#5294e2' +dot-color-unfocused-different=true +dot-color-unfocused-1='#c0bfbc' +dot-color-unfocused-2='#c0bfbc' +dot-color-unfocused-3='#c0bfbc' +dot-color-unfocused-4='#c0bfbc' +click-action='TOGGLE-SHOWPREVIEW' +hide-overview-on-startup=true +appicon-padding=4 +appicon-margin=1 +panel-sizes='{"0":40,"1":40}' +panel-element-positions='{"0":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}],"1":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}]}' + +# System Monitor +[org/gnome/shell/extensions/system-monitor] + +compact-display=true +center-display=true +net-display=false +swap-display=true +icon-display=false + +# Arc Menu +[org/gnome/shell/extensions/arcmenu] + +multi-monitor=true +menu-button-icon='Distro_Icon' +menu-layout='Redmond' +enable-horizontal-flip=true + +# Gnome 4x UI Improvement +[org/gnome/shell/extensions/gnome-ui-tune] + +hide-search=false diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/COPYING b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/COPYING new file mode 100644 index 0000000..0cf672a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/README.md b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/README.md new file mode 100644 index 0000000..a81ec23 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/README.md @@ -0,0 +1,148 @@ +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_WideBanner.png) + +----- + +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_Banner.png) + +----- + +### Introduction + +ArcMenu is an application menu for GNOME Shell, designed to provide a more traditional user experience and workflow. This extension has many features, including multiple menu layout styles, GNOME search, quick access to system shorctus, and more! If you are a new user to GNOME and are looking for a Windows style start menu, this extension will be perfect for you! + +**For ArcMenu to work properly, you may need [these dependencies](https://gitlab.com/arcmenu/ArcMenu/-/wikis/ArcMenu-Dependencies).** + +----- + +### Support ArcMenu + +ArcMenu is provided free of charge. If you enjoy using ArcMenu and wish to help support the project, feel free to use the link below! + +[![Donate via Paypal](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/paypal_donate.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url) + + +----- + +### Installation + +#### To install the most recent official release: Visit ArcMenu on the [Official GNOME Extensions](https://extensions.gnome.org/extension/3628/arcmenu/) website. + +- **To install ArcMenu from source**: Please see the: [Install From Source wiki Guide](https://gitlab.com/arcmenu/ArcMenu/-/wikis/Install-From-Source-Guide). + +

+ + + + +----- + +### Bugs + +Bugs should be reported [here](https://gitlab.com/arcmenu/ArcMenu/issues) on the GitLab issues page. + +When reporting a bug, please provide as much information as you can about the issue and make sure to include your Linux distribution, GNOME Shell version, and ArcMenu version. + +----- + +### Credits: + +**@[AndrewZaech](https://gitlab.com/AndrewZaech) - Current Project Maintainer and Developer** + +**@[AndyC](https://gitlab.com/LinxGem33) - Founder of ArcMenu and former project maintainer** + +**@[lexruee](https://github.com/lexruee) - Former UI/UX Designer | @[Thomas Ingvarsson](https://gitlab.com/tingvarsson) - Former Developer** + +Additional credits: +* The 'ArcMenu' layout design is insipired by the Zorin OS menu extension. +* ArcMenu utilizes various code from GNOME Shell and the GNOME Shell extensions package. +* Borrowed code from Dash-to-Dock's extension 'location.js' file to implement a trash shortcut in ArcMenu. + +----- + +### Contributors: + +#### Thanks to the following people for contributing via pull requests: + +**@[fishears](https://github.com/fishears/Arc-Menu)** | **@[JasonLG1979](https://github.com/JasonLG1979)** | **@[itmitica](https://github.com/itmitica)** | **@[vikaig](https://gitlab.com/vikaig)** | **@[MagneFire](https://gitlab.com/MagneFire)** + +**@[tognee](https://gitlab.com/tognee)** | **@[hlechner](https://gitlab.com/hlechner)** | **@[vanillajonathan](https://gitlab.com/vanillajonathan)** | **@[epskampie](https://gitlab.com/epskampie)** | **@[GnomeBook](https://gitlab.com/GnomeBook)** + +**@[charlesg99](https://github.com/charlesg99)** | **@[harshadgavali](https://gitlab.com/harshadgavali)** | **@[O. Giesmann ](https://gitlab.com/Etamuk)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Bug Fixes: + +**@[JasonLG1979](https://github.com/JasonLG1979)** | **@[lexruee](https://github.com/lexruee/Arc-Menu)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Translators: + +**@[Nilvus](https://gitlab.com/Nilvus) - French** | **@[Etamuk](https://gitlab.com/Etamuk) - German** | **@[alex4401](https://gitlab.com/alex4401) - Polish** | **@[frnogueira](https://gitlab.com/frnogueira), @[Z Bed](https://gitlab.com/zbed) - Brazilian Portuguese** | **@[sigbjokj](https://gitlab.com/sigbjokj), @[sssandum](https://gitlab.com/sssandum) - Norwegian** + + **@[Ivan](https://gitlab.com/vantu5z), @[Ser82-png](https://gitlab.com/Ser82-png) - Russian** | **@[gkkulik](https://gitlab.com/gkkulik) - Silesian** | **@[vikaig](https://gitlab.com/vikaig) - Ukrainian** | **@[jordim](https://gitlab.com/jordim) - Catalan** | **@[aylinux](https://gitlab.com/aylinux) - Turkish** + + +**@[MorganAntonsson](https://gitlab.com/MorganAntonsson) - Swedish** | **@[jiri.doubravsky](https://gitlab.com/jiri.doubravsky), @[panmourovaty ](https://gitlab.com/panmourovaty) - Czech** | **@[juanlucer](https://gitlab.com/juanlucer) - Spanish** | **@[plesry](https://gitlab.com/plesry) - Chinese (Taiwan)** | **@[Vombato](https://gitlab.com/Vombato), @[matguidi](https://gitlab.com/matguidi) - Italian** + +**@[skygmin](https://gitlab.com/skygmin) - Simplified Chinese** | **@[Vistaus](https://gitlab.com/Vistaus), @[vinno97](https://gitlab.com/vinno97) - Dutch** | **@[artnay](https://gitlab.com/artnay) - Finnish** | **@[rimasx](https://gitlab.com/rimasx) - Estonian** | **@[stevendobay](https://gitlab.com/stevendobay) - Hungarian** + +**@[omeritzics](https://gitlab.com/omeritzics) - Hebrew** | **@[prescott66](https://gitlab.com/prescott66) - Slovak** | **@[Mejans](https://gitlab.com/Mejans) - Occitan** | **@[KuroeHanako](https://gitlab.com/KuroeHanako) - Korean** | **@[sayuri](https://gitlab.com/sayuri-) - Sinhalese** + +**@[Latgardi](https://gitlab.com/Latgardi) - Belarusian** + +----- + +### License & Terms + +ArcMenu is available under the terms of the GPL-2.0 license See [`COPYING`](https://gitlab.com/arcmenu/ArcMenu/blob/master/COPYING) for details. + +Most of ArcMenu's image assets including, but not limited to, custom menu button icons, wire frame svgs, and custom settings icons, are created by [LinxGem33](https://gitlab.com/LinxGem33) and licensed under; [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +**Legal disclaimer for brand icons and trademarks:** + +*" All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer. "* + +

+Read More... + +

+ +* **UBUNTU ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Ubuntu name and Ubuntu logo is a trademark of Canonical ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Ltd. + +* **FEDORA ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Fedora and the Infinity design logo are trademarks of Red Hat, Inc. + +* **DEBIAN ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project. + +* **MANJARO ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - (logo) and name is a trademark of Manjaro GmbH & Co. KG + +* **POP_OS! ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Name and (logo) is a trademark of system 76 ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Inc. + +* **ARCH LINUX ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - The stylized Arch Linux logo are recognised trademarks of Arch Linux, copyright 2002-2017 Judd Vinet and Aaron Griffin + +* **SOLUS** - name and logo is Copyright ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) 2014-2018 by Solus Project + +* **KALI LINUX** - logo and name is part of ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) OffSec Services Limited 2020 + +* **PUREOS** - name and logo is developed by members of the Purism community + +* **RASPBERRY PI** ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) - Logo and name is part of Raspberry Pi Foundation +UK Registered Charity 1129409 + +* **Gentoo Authors![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2001–2020 +Gentoo is a trademark of the Gentoo Foundation, Inc. + +* **Voyager ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Linux** +(name) and (logo) + +* **MXLinux![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2020 - +Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries. + +* **Red Hat, Inc.![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** Copyright 2020 +(name) and (logo) + +* **ZORIN OS** - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd + +

+
+ +----- diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/constants.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/constants.js new file mode 100644 index 0000000..082cb4b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/constants.js @@ -0,0 +1,460 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var SearchbarLocation = { + BOTTOM: 0, + TOP: 1 +} + +var MenuItemLocation = { + BOTTOM: 0, + TOP: 1 +} + +var DisplayType = { + LIST: 0, + GRID: 1, + BUTTON: 2, + SIMPLE_CATEGORY: 3, + SUBMENU_CATEGORY: 4, +} + +var CategoryType = { + FAVORITES: 0, + FREQUENT_APPS: 1, + ALL_PROGRAMS: 2, + PINNED_APPS: 3, + RECENT_FILES: 4, + HOME_SCREEN: 5, + SEARCH_RESULTS: 6, + CATEGORIES_LIST: 7, +}; + +var DefaultMenuView = { + PINNED_APPS: 0, + CATEGORIES_LIST: 1, + FREQUENT_APPS: 2, + ALL_PROGRAMS: 3 +} + +var PrefsVisiblePage = { + MAIN: 0, + MENU_LAYOUT: 1, + BUTTON_APPEARANCE: 2, + LAYOUT_TWEAKS: 3, + ABOUT: 4, + CUSTOMIZE_MENU: 5, + RUNNER_TWEAKS: 6 +} + +var DefaultMenuViewTognee = { + CATEGORIES_LIST: 0, + ALL_PROGRAMS: 1 +} + +var SoftwareManagerIDs = ['org.manjaro.pamac.manager.desktop', 'pamac-manager.desktop', 'io.elementary.appcenter.desktop', + 'snap-store_ubuntu-software.desktop', 'snap-store_snap-store.desktop', 'org.gnome.Software.desktop']; + +var Categories = [ + {CATEGORY: CategoryType.FAVORITES, NAME: _("Favorites"), ICON: 'emblem-favorite-symbolic', FULL_COLOR_ICON: 'emblem-favorite'}, + {CATEGORY: CategoryType.FREQUENT_APPS, NAME: _("Frequent Apps"), ICON: 'user-bookmarks-symbolic', FULL_COLOR_ICON: 'user-bookmarks'}, + {CATEGORY: CategoryType.ALL_PROGRAMS, NAME: _("All Apps"), ICON: 'view-grid-symbolic', FULL_COLOR_ICON: 'view-grid-symbolic'}, + {CATEGORY: CategoryType.PINNED_APPS, NAME: _("Pinned Apps"), ICON: 'view-pin-symbolic', FULL_COLOR_ICON: 'view-pin-symbolic'}, + {CATEGORY: CategoryType.RECENT_FILES, NAME: _("Recent Files"), ICON: 'document-open-recent-symbolic', FULL_COLOR_ICON: 'document-open-recent'} +] + +var ArcMenuPlacement = { + PANEL: 0, + DTP: 1, + DASH: 2 +}; + +var TooltipLocation = { + TOP_CENTERED: 0, + BOTTOM_CENTERED: 1, + BOTTOM: 2, +}; + +var SeparatorAlignment = { + VERTICAL: 0, + HORIZONTAL: 1 +}; + +var SeparatorStyle = { + SHORT: 0, + MEDIUM: 1, + LONG: 2, + MAX: 3, + HEADER_LABEL: 4, + NORMAL: 5, + ALWAYS_SHOW: 6, +}; + +var CaretPosition = { + END: -1, + START: 0, + MIDDLE: 2, +}; + +var CategoryIconType = { + FULL_COLOR: 0, + SYMBOLIC: 1, +} + +var ForcedMenuLocation = { + OFF: 0, + TOP_CENTERED: 1, + BOTTOM_CENTERED: 2, +} + +var IconSize = { + DEFAULT: 0, + EXTRA_SMALL: 1, + SMALL: 2, + MEDIUM: 3, + LARGE: 4, + EXTRA_LARGE: 5, +} + +var GridIconSize = { + DEFAULT: 0, + SMALL: 1, + MEDIUM: 2, + LARGE: 3, + SMALL_RECT: 4, + MEDIUM_RECT: 5, + LARGE_RECT: 6, +}; + +var GridIconInfo = [ + { NAME: 'SmallIconGrid', SIZE: 90, ICON_SIZE: 36, ENUM: GridIconSize.SMALL }, + { NAME: 'MediumIconGrid', SIZE: 97, ICON_SIZE: 42, ENUM: GridIconSize.MEDIUM }, + { NAME: "LargeIconGrid", SIZE: 105, ICON_SIZE: 52, ENUM: GridIconSize.LARGE }, + { NAME: 'SmallRectIconGrid', SIZE: 95, ICON_SIZE: 28, ENUM: GridIconSize.SMALL_RECT }, + { NAME: 'MediumRectIconGrid', SIZE: 102, ICON_SIZE: 34, ENUM: GridIconSize.MEDIUM_RECT }, + { NAME: 'LargeRectIconGrid', SIZE: 105, ICON_SIZE: 42, ENUM: GridIconSize.LARGE_RECT }, +] + +var EXTRA_SMALL_ICON_SIZE = 16; +var SMALL_ICON_SIZE = 20; +var MEDIUM_ICON_SIZE = 25; +var LARGE_ICON_SIZE = 30; +var EXTRA_LARGE_ICON_SIZE = 35; +var MISC_ICON_SIZE = 24; + +var SUPER_L = 'Super_L'; +var SUPER_R = 'Super_R'; +var EMPTY_STRING = ''; + +var HotKey = { + UNDEFINED: 0, + SUPER_L: 1, + CUSTOM: 2, + // Inverse mapping + 0: EMPTY_STRING, + 1: SUPER_L, +}; + +var RunnerHotKey = { + SUPER_L: 0, + CUSTOM: 1, + 0: SUPER_L, +}; + +var HotCornerAction = { + DEFAULT: 0, + DISABLED: 1, + TOGGLE_ARCMENU: 2, + CUSTOM: 3 +} + +var SECTIONS = [ + 'devices', + 'network', + 'bookmarks', +]; + +var MenuPosition = { + LEFT: 0, + CENTER: 1, + RIGHT: 2 +}; + +var RavenPosition = { + LEFT: 0, + RIGHT: 1 +}; + +var DiaglogType = { + DEFAULT: 0, + OTHER: 1, + APPLICATIONS: 2, + DIRECTORIES: 3 +}; + +var MenuButtonAppearance = { + ICON: 0, + TEXT: 1, + ICON_TEXT: 2, + TEXT_ICON: 3, + NONE: 4 +}; + +var MenuIcon = { + ARC_MENU: 0, + DISTRO_ICON: 1, + CUSTOM: 2 +}; + +var PowerType = { + LOGOUT: 0, + LOCK: 1, + RESTART: 2, + POWER_OFF: 3, + SUSPEND: 4, + HYBRID_SLEEP: 5, + HIBERNATE: 6, +}; + +var SleepIcon = { + PATH: '/media/icons/menu_icons/sleep-symbolic.svg' +}; + +var PowerOptions = [ + { TYPE: PowerType.LOGOUT, IMAGE: 'application-exit-symbolic', TITLE: _("Log Out") }, + { TYPE: PowerType.LOCK, IMAGE: 'changes-prevent-symbolic', TITLE: _("Lock") }, + { TYPE: PowerType.RESTART, IMAGE: 'system-reboot-symbolic', TITLE: _("Restart") }, + { TYPE: PowerType.POWER_OFF, IMAGE: 'system-shutdown-symbolic', TITLE: _("Power Off") }, + { TYPE: PowerType.SUSPEND, IMAGE: 'media-playback-pause-symbolic', TITLE: _("Suspend") }, + { TYPE: PowerType.HYBRID_SLEEP, IMAGE: Me.path + SleepIcon.PATH, TITLE: _("Hybrid Sleep") }, + { TYPE: PowerType.HIBERNATE, IMAGE: 'document-save-symbolic', TITLE: _("Hibernate") }, +]; + +var MenuIcons = [ + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/curved-a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/focus-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sums-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arrow-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/lins-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/search-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/transform-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3d-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/alien-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cloud-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/fly-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pacman-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peaks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pie-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pointer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/toxic-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/tree-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/zegon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/apps-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bug-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cita-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/eclipse-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/heddy-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/helmet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/palette-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peeks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/record-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/saucer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/step-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vancer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vibe-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/start-box-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dolphin-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dota-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/loveheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/rewind-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/snap-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/time-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3D-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bat-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dra-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/equal-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/gnacs-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/groove-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/kaaet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pac-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/robots-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sheild-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/somnia-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/utool-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/swirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/round-symbolic.svg'}, +] + +var DistroIcons = [ + { PATH: 'start-here-symbolic'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg'}, +] + +var MenuLayout = { + ARCMENU: 0, + BRISK: 1, + WHISKER: 2, + GNOME_MENU: 3, + MINT: 4, + ELEMENTARY: 5, + GNOME_OVERVIEW: 6, + SIMPLE: 7, + SIMPLE_2: 8, + REDMOND: 9, + UNITY: 10, + BUDGIE: 11, + INSIDER: 12, + RUNNER: 13, + CHROMEBOOK: 14, + RAVEN: 15, + TOGNEE: 16, + PLASMA: 17, + WINDOWS: 18, + LAUNCHER: 19, + ELEVEN: 20, + AZ: 21, +}; + +var TraditionalMenus = [ + { IMAGE: 'arcmenu-layout-symbolic', TITLE: _('ArcMenu'), LAYOUT: MenuLayout.ARCMENU}, + { IMAGE: 'brisk-layout-symbolic', TITLE: _('Brisk'), LAYOUT: MenuLayout.BRISK}, + { IMAGE: 'whisker-layout-symbolic', TITLE: _('Whisker'), LAYOUT: MenuLayout.WHISKER}, + { IMAGE: 'gnomemenu-layout-symbolic', TITLE: _('GNOME Menu'), LAYOUT: MenuLayout.GNOME_MENU}, + { IMAGE: 'mint-layout-symbolic', TITLE: _('Mint'), LAYOUT: MenuLayout.MINT}, + { IMAGE: 'budgie-layout-symbolic', TITLE: _('Budgie'), LAYOUT: MenuLayout.BUDGIE}]; + +var ModernMenus = [ + { IMAGE: 'unity-layout-symbolic', TITLE: _('Unity'), LAYOUT: MenuLayout.UNITY}, + { IMAGE: 'plasma-layout-symbolic', TITLE: _('Plasma'), LAYOUT: MenuLayout.PLASMA}, + { IMAGE: 'tognee-layout-symbolic', TITLE: _('tognee'), LAYOUT: MenuLayout.TOGNEE}, + { IMAGE: 'insider-layout-symbolic', TITLE: _('Insider'), LAYOUT: MenuLayout.INSIDER}, + { IMAGE: 'redmond-layout-symbolic', TITLE: _('Redmond'), LAYOUT: MenuLayout.REDMOND}, + { IMAGE: 'windows-layout-symbolic', TITLE: _('Windows'), LAYOUT: MenuLayout.WINDOWS}, + { IMAGE: 'eleven-layout-symbolic', TITLE: _('11'), LAYOUT: MenuLayout.ELEVEN}, + { IMAGE: 'az-layout-symbolic', TITLE: _('a.z.'), LAYOUT: MenuLayout.AZ}]; + +var TouchMenus = [ + { IMAGE: 'elementary-layout-symbolic', TITLE: _('Elementary'), LAYOUT: MenuLayout.ELEMENTARY}, + { IMAGE: 'chromebook-layout-symbolic', TITLE: _('Chromebook'), LAYOUT: MenuLayout.CHROMEBOOK}]; + +var LauncherMenus = [ + { IMAGE: 'launcher-layout-symbolic', TITLE: _('Launcher'), LAYOUT: MenuLayout.LAUNCHER}, + { IMAGE: 'runner-layout-symbolic', TITLE: _('Runner'), LAYOUT: MenuLayout.RUNNER}, + { IMAGE: 'gnomeoverview-layout-symbolic', TITLE: _('GNOME Overview'), LAYOUT: MenuLayout.GNOME_OVERVIEW}]; + +var SimpleMenus = [ + { IMAGE: 'simple-layout-symbolic', TITLE: _('Simple'), LAYOUT: MenuLayout.SIMPLE}, + { IMAGE: 'simple2-layout-symbolic', TITLE: _('Simple 2'), LAYOUT: MenuLayout.SIMPLE_2}]; + +var AlternativeMenus = [ + { IMAGE: 'raven-layout-symbolic', TITLE: _('Raven'), LAYOUT: MenuLayout.RAVEN}]; + +var MenuStyles = { + STYLES: [ + { IMAGE: 'traditional-category-symbolic', TITLE: _("Traditional"), MENU_TYPE: TraditionalMenus }, + { IMAGE: 'modern-category-symbolic', TITLE: _("Modern"), MENU_TYPE: ModernMenus }, + { IMAGE: 'touch-category-symbolic', TITLE: _("Touch"), MENU_TYPE: TouchMenus }, + { IMAGE: 'simple-category-symbolic', TITLE: _("Simple"), MENU_TYPE: SimpleMenus }, + { IMAGE: 'launcher-category-symbolic', TITLE: _("Launcher"), MENU_TYPE: LauncherMenus }, + { IMAGE: 'alternative-category-symbolic', TITLE: _("Alternative"), MENU_TYPE: AlternativeMenus } + ] +}; + +var ArcMenuSettingsCommand = 'gnome-extensions prefs arcmenu@arcmenu.com'; + +var HamburgerIcon = { + PATH: '/media/icons/menu_icons/hamburger-symbolic.svg' +}; + +var DistroIconsDisclaimer = '"All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer."'+ + '\n\n• Ubuntu® - Ubuntu name and Ubuntu logo are trademarks of Canonical© Ltd.'+ + '\n\n• Fedora® - Fedora and the Infinity design logo are trademarks of Red Hat, Inc.'+ + '\n\n• Debian® - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project.'+ + '\n\n• Manjaro® - logo and name are trademarks of Manjaro GmbH & Co. KG'+ + '\n\n• Pop_OS!® - logo and name are trademarks of system 76© Inc.'+ + '\n\n• Arch Linux™ - The stylized Arch Linux logo is a recognized trademark of Arch Linux, copyright 2002–2017 Judd Vinet and Aaron Griffin.'+ + '\n\n• openSUSE® - logo and name 2001–2020 SUSE LLC, © 2005–2020 openSUSE Contributors & others.'+ + '\n\n• Raspberry Pi® - logo and name are part of Raspberry Pi Foundation UK Registered Charity 1129409'+ + '\n\n• Kali Linux™ - logo and name are part of © OffSec Services Limited 2020'+ + '\n\n• PureOS - logo and name are developed by members of the Purism community'+ + '\n\n• Solus - logo and name are copyright © 2014–2018 by Solus Project'+ + '\n\n• Gentoo Authors© - 2001–2020 Gentoo is a trademark of the Gentoo Foundation, Inc.'+ + '\n\n• Voyager© Linux - name and logo'+ + '\n\n• MX Linux© - 2020 - Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries.'+ + '\n\n• Red Hat, Inc.© - Copyright 2020 name and logo' + + '\n\n• ZORIN OS - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd'; + +var DEVELOPERS = 'Andrew Zaech @AndrewZaech\nLead Project Developer and Maintainer\t' + + '\n\nLinxGem33 aka Andy C @LinxGem33 - (Inactive)\nArcMenu Founder - Former Maintainer - Former Digital Art Designer'; +var TRANSLATORS = 'Thank you to all translators!\n\n' + + 'For a list of all translators please visit ArcMenu on GitLab'; +var CONTRIBUTORS = 'Thank you to all who contributed to, and/or helped, the developement of ArcMenu!' + +'\n\nFor a list of all contributors please visit ArcMenu on GitLab'; +var ARTWORK = 'LinxGem33 aka Andy C\nWiki Screens, Icons, Wire-Frames, ArcMenu Assets' + + '\n\nAndrew Zaech\nIcons, Wire-Frames'; + +var GNU_SOFTWARE = '' + + 'This program comes with absolutely no warranty.\n' + + 'See the ' + + 'GNU General Public License, version 2 or later for details.' + + ''; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/controller.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/controller.js new file mode 100644 index 0000000..7c35a80 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/controller.js @@ -0,0 +1,749 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Gio, GLib, Gtk, St} = imports.gi; +const Constants = Me.imports.constants; +const Helper = Me.imports.helper; +const Main = imports.ui.main; +const MenuButton = Me.imports.menuButton; +const {StandaloneRunner} = Me.imports.standaloneRunner; +const Utils = Me.imports.utils; + +var MenuSettingsController = class { + constructor(settings, settingsControllers, panel, panelIndex, arcMenuPlacement) { + this._settings = settings; + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this.panel = panel; + this.arcMenuPlacement = arcMenuPlacement; + + global.toggleArcMenu = () => this.toggleMenus(); + + this.currentMonitorIndex = 0; + this._activitiesButton = Main.panel.statusArea.activities; + this.isPrimary = panelIndex === 0 ? true : false; + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel); + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel, panelIndex); + this.menuButtonAdjustedActor = this._menuButton.container; + } + + this._settingsControllers = settingsControllers + + if(this.isPrimary){ + this._menuHotKeybinder = new Helper.MenuHotKeybinder(); + this._keybindingManager = new Helper.KeybindingManager(this._settings); + this._hotCornerManager = new Helper.HotCornerManager(this._settings,() => this.toggleMenus()); + } + this._applySettings(); + } + + // Load and apply the settings from the arc-menu settings + _applySettings() { + if(this.isPrimary){ + this._updateHotCornerManager(); + this._updateHotKeyBinder(); + } + + this._setButtonAppearance(); + this._setButtonText(); + this._setButtonIcon(); + this._setButtonIconSize(); + this._setButtonIconPadding(); + this._configureActivitiesButton(); + } + // Bind the callbacks for handling the settings changes to the event signals + bindSettingsChanges() { + this.settingsChangeIds = [ + this._settings.connect('changed::hot-corners', this._updateHotCornerManager.bind(this)), + this._settings.connect('changed::menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::runner-menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::enable-standlone-runner-menu', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::position-in-panel', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-button-position-offset', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-position-alignment', this._setMenuPositionAlignment.bind(this)), + this._settings.connect('changed::menu-button-appearance', this._setButtonAppearance.bind(this)), + this._settings.connect('changed::custom-menu-button-text', this._setButtonText.bind(this)), + this._settings.connect('changed::menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::distro-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::arc-menu-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon-size', this._setButtonIconSize.bind(this)), + this._settings.connect('changed::button-padding', this._setButtonIconPadding.bind(this)), + this._settings.connect('changed::enable-menu-button-arrow', this._setMenuButtonArrow.bind(this)), + this._settings.connect('changed::enable-custom-arc-menu', this._updateStyle.bind(this)), + this._settings.connect('changed::remove-menu-arrow', this._updateStyle.bind(this)), + this._settings.connect('changed::disable-searchbox-border', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-color', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-text-color', this._updateStyle.bind(this)), + this._settings.connect('changed::directory-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::application-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::disable-recently-installed-apps', this._initiateRecentlyInstalledApps.bind(this)), + this._settings.connect('changed::extra-categories', this._reload.bind(this)), + this._settings.connect('changed::power-options', this._reload.bind(this)), + this._settings.connect('changed::show-external-devices', this._reload.bind(this)), + this._settings.connect('changed::show-bookmarks', this._reload.bind(this)), + this._settings.connect('changed::disable-user-avatar', this._reload.bind(this)), + this._settings.connect('changed::enable-activities-shortcut', this._reload.bind(this)), + this._settings.connect('changed::enable-horizontal-flip', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-bottom-location', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._plasmaMenuReloadTheme.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._reload.bind(this)), + this._settings.connect('changed::multi-lined-labels', this._reload.bind(this)), + this._settings.connect('changed::apps-show-extra-details', this._reload.bind(this)), + this._settings.connect('changed::show-search-result-details', this._reload.bind(this)), + this._settings.connect('changed::search-provider-open-windows', this._reload.bind(this)), + this._settings.connect('changed::search-provider-recent-files', this._reload.bind(this)), + this._settings.connect('changed::disable-scrollview-fade-effect', this._reload.bind(this)), + this._settings.connect('changed::menu-height', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::menu-width-adjustment', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::reload-theme', this._reloadTheme.bind(this)), + this._settings.connect('changed::pinned-app-list',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::brisk-shortcuts-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::windows-disable-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::windows-disable-pinned-apps', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view-tognee',this._reload.bind(this)), + this._settings.connect('changed::alphabetize-all-programs',this._reload.bind(this)), + this._settings.connect('changed::enable-unity-homescreen',this._setDefaultMenuView.bind(this)), + this._settings.connect('changed::menu-layout', this._updateMenuLayout.bind(this)), + this._settings.connect('changed::menu-item-grid-icon-size', this._reload.bind(this)), + this._settings.connect('changed::menu-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::button-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::quicklinks-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::misc-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::runner-position', this.updateLocation.bind(this)), + this._settings.connect('changed::runner-show-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::enable-sub-menus', this._reload.bind(this)), + this._settings.connect('changed::show-activities-button', this._configureActivitiesButton.bind(this)), + this._settings.connect('changed::force-menu-location', this._forceMenuLocation.bind(this)), + this._settings.connect('changed::category-icon-type', this._reload.bind(this)), + this._settings.connect('changed::shortcut-icon-type', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links-location', this._reload.bind(this)), + ]; + } + + _reload(){ + this._menuButton.reload(); + if(this.runnerMenu) + this.runnerMenu.reload(); + } + + _forceMenuLocation(){ + this._menuButton.forceMenuLocation(); + } + + _initiateRecentlyInstalledApps(){ + this._menuButton.initiateRecentlyInstalledApps(); + this._menuButton.reload(); + if(this.runnerMenu){ + this.runnerMenu.initiateRecentlyInstalledApps(); + this.runnerMenu.reload(); + } + } + + _plasmaMenuReloadTheme(){ + if(this._settings.get_enum('menu-layout') === Constants.MenuLayout.PLASMA){ + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this._settings.set_boolean('reload-theme', true); + } + } + + updateLocation(){ + this._menuButton.updateLocation(); + if(this.runnerMenu) + this.runnerMenu.updateLocation(); + } + + _updateMenuLayout(){ + this._menuButton.updateMenuLayout(); + } + + _setDefaultMenuView(){ + this._menuButton.setDefaultMenuView(); + } + + toggleStandaloneRunner(){ + this._closeAllArcMenus(); + if(this.runnerMenu) + this.runnerMenu.toggleMenu(); + } + + toggleMenus(){ + if(this.runnerMenu && this.runnerMenu.arcMenu.isOpen) + this.runnerMenu.toggleMenu(); + if(global.dashToPanel || this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + const MultipleArcMenus = this._settingsControllers.length > 1; + const ShowArcMenuOnPrimaryMonitor = this._settings.get_boolean('hotkey-open-primary-monitor'); + if(MultipleArcMenus && ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.primaryMonitor); + else if(MultipleArcMenus && !ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.currentMonitor); + else + this._menuButton.toggleMenu(); + } + else + this._menuButton.toggleMenu(); + } + + _toggleMenuOnMonitor(monitor){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + let monitorIndex = this._settingsControllers[i].monitorIndex; + if(monitor.index === monitorIndex) + this.currentMonitorIndex = i; + else{ + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + //open the current monitors menu + this._settingsControllers[this.currentMonitorIndex]._menuButton.toggleMenu(); + } + + _closeAllArcMenus(){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + + _reloadTheme(){ + if(this.isPrimary && this._settings.get_boolean('reload-theme')) { + this._settings.reset('reload-theme'); + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(this._settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + menuButton.updateStyle(); + } + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + } + + _updateStyle() { + this._menuButton.updateStyle(); + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + + _updateMenuHeight(){ + this._menuButton.updateHeight(); + } + + _updatePinnedApps(){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadPinnedApps(); + + //If the active category is Pinned Apps, redisplay the new Pinned Apps + const activeCategory = this._menuButton.MenuLayout?.activeCategoryType; + if(!activeCategory) + return; + if(activeCategory === Constants.CategoryType.PINNED_APPS || activeCategory === Constants.CategoryType.HOME_SCREEN) + this._menuButton.displayPinnedApps(); + } + + _updateExtraPinnedApps(){ + let layout = this._settings.get_enum('menu-layout'); + if(layout == Constants.MenuLayout.UNITY || layout == Constants.MenuLayout.MINT || layout == Constants.MenuLayout.BRISK){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadExtraPinnedApps(); + } + } + + _updateHotCornerManager() { + if (this.isPrimary) { + let hotCornerAction = this._settings.get_enum('hot-corners'); + if (hotCornerAction === Constants.HotCornerAction.DEFAULT) { + this._hotCornerManager.restoreDefaultHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.DISABLED) { + this._hotCornerManager.disableHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU) { + this._hotCornerManager.modifyHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.CUSTOM) { + this._hotCornerManager.modifyHotCorners(); + } + } + } + + _updateHotKeyBinder() { + if (this.isPrimary) { + const RunnerHotKey = this._settings.get_enum('runner-menu-hotkey'); + const HotKey = this._settings.get_enum('menu-hotkey'); + const EnableStandaloneRunnerMenu = this._settings.get_boolean('enable-standlone-runner-menu'); + + this._keybindingManager.unbind('ToggleArcMenu'); + this._keybindingManager.unbind('ToggleRunnerMenu'); + this._menuHotKeybinder.disableHotKey(); + this._menuKeyBindingKey = null; + this._runnerKeyBindingKey = null; + + if(EnableStandaloneRunnerMenu){ + if(!this.runnerMenu){ + this.runnerMenu = new StandaloneRunner(this._settings); + this.runnerMenu.initiate(); + } + + if(RunnerHotKey === Constants.RunnerHotKey.CUSTOM){ + this._keybindingManager.bind('ToggleRunnerMenu', 'toggle-runner-menu', () => this._onHotkey(() => this.toggleStandaloneRunner())); + this._runnerKeyBindingKey = this._settings.get_strv('toggle-runner-menu').toString(); + } + else if(RunnerHotKey === Constants.RunnerHotKey.SUPER_L){ + this._menuHotKeybinder.enableHotKey(() => this.toggleStandaloneRunner()); + } + } + else if(this.runnerMenu){ + this.runnerMenu.destroy(); + this.runnerMenu = null; + } + + if(HotKey === Constants.HotKey.CUSTOM){ + this._keybindingManager.bind('ToggleArcMenu', 'toggle-arcmenu', () => this._onHotkey(() => this.toggleMenus())); + this._menuKeyBindingKey = this._settings.get_strv('toggle-arcmenu').toString(); + } + else if(HotKey === Constants.HotKey.SUPER_L){ + this._menuHotKeybinder.disableHotKey(); + this._menuHotKeybinder.enableHotKey(() => this.toggleMenus()); + } + + if(this._menuKeyBindingKey){ + this._menuKeyBindingKey = Gtk.accelerator_parse(this._menuKeyBindingKey)[0]; + } + if(this._runnerKeyBindingKey){ + this._runnerKeyBindingKey = Gtk.accelerator_parse(this._runnerKeyBindingKey)[0]; + } + } + } + + _onHotkey(callback) { + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + callback(); + else + this._onHotkeyRelease(callback); + } + + _onHotkeyRelease(callback) { + let activeMenu = this._settingsControllers[this.currentMonitorIndex]._menuButton.getActiveMenu() || ((this.runnerMenu && this.runnerMenu.arcMenu.isOpen) ? this.runnerMenu.arcMenu : null); + let focusPanel; + + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL) + focusPanel = this.panel; + else + focusPanel = this.panel._allDocks[0].dash; + + let focusTarget = activeMenu ? + (activeMenu.actor || activeMenu) : focusPanel; + + this.disconnectKeyRelease(); + + this.keyInfo = { + pressId: focusTarget.connect('key-press-event', () => this.disconnectKeyRelease()), + releaseId: focusTarget.connect('key-release-event', (actor, event) => { + this.disconnectKeyRelease(); + + if (this._menuKeyBindingKey === event.get_key_symbol()) { + callback(); + } + + if (this._runnerKeyBindingKey === event.get_key_symbol()) { + callback(); + } + }), + target: focusTarget + }; + + focusTarget.grab_key_focus(); + } + + disconnectKeyRelease() { + if (this.keyInfo && this.keyInfo.target) { + this.keyInfo.target.disconnect(this.keyInfo.pressId); + this.keyInfo.target.disconnect(this.keyInfo.releaseId); + this.keyInfo = 0; + } + } + + // Place the menu button to main panel as specified in the settings + _setButtonPosition() { + if (this._isButtonEnabled()) { + this._removeMenuButtonFromMainPanel(); + this._addMenuButtonToMainPanel(); + this._setMenuPositionAlignment(); + } + } + + _setMenuPositionAlignment(){ + this._menuButton.setMenuPositionAlignment(); + } + + // Change the menu button appearance as specified in the settings + _setButtonAppearance() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + this._menuButton.container.set_width(-1); + this._menuButton.container.set_height(-1); + menuButtonWidget.actor.show(); + switch (this._settings.get_enum('menu-button-appearance')) { + case Constants.MenuButtonAppearance.TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.showPanelText(); + break; + case Constants.MenuButtonAppearance.ICON_TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-left: 5px;'); + break; + case Constants.MenuButtonAppearance.TEXT_ICON: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-right: 5px;'); + menuButtonWidget.showPanelIcon(); + break; + case Constants.MenuButtonAppearance.NONE: + menuButtonWidget.actor.hide(); + this._menuButton.container.set_width(0); + this._menuButton.container.set_height(0); + break; + case Constants.MenuButtonAppearance.ICON: /* falls through */ + default: + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + } + this._setMenuButtonArrow(); + } + } + _setMenuButtonArrow() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + if (this._settings.get_boolean('enable-menu-button-arrow')) { + menuButtonWidget.hideArrowIcon(); + menuButtonWidget.showArrowIcon(); + } else { + menuButtonWidget.hideArrowIcon(); + } + } + } + + // Update the text of the menu button as specified in the settings + _setButtonText() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + // Update the text of the menu button + let menuButtonWidget = this._menuButton.menuButtonWidget; + let label = menuButtonWidget.getPanelLabel(); + + let customTextLabel = this._settings.get_string('custom-menu-button-text'); + label.set_text(customTextLabel); + } + } + + // Update the icon of the menu button as specified in the settings + _setButtonIcon() { + let path = this._settings.get_string('custom-menu-button-icon'); + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + + let iconString = Utils.getMenuButtonIcon(this._settings, path); + stIcon.set_gicon(Gio.icon_new_for_string(iconString)); + } + + // Update the icon of the menu button as specified in the settings + _setButtonIconSize() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let size = iconSize; + stIcon.icon_size = size; + } + } + + _setButtonIconPadding() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let padding = this._settings.get_int('button-padding'); + if(padding > -1) + this._menuButton.style = "-natural-hpadding: " + (padding * 2 ) + "px; -minimum-hpadding: " + padding + "px;"; + else + this._menuButton.style = null; + + let parent = this._menuButton.get_parent(); + if(!parent) + return; + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(this._menuButton); + } + + parent.remove_child(this._menuButton); + parent.insert_child_at_index(this._menuButton, actorIndex); + } + } + + // Get the current position of the menu button and its associated position order + _getMenuPosition() { + let offset = this._settings.get_int('menu-button-position-offset'); + switch (this._settings.get_enum('position-in-panel')) { + case Constants.MenuPosition.CENTER: + return [offset, 'center']; + case Constants.MenuPosition.RIGHT: + // get number of childrens in rightBox (without arcmenu) + let n_children = Main.panel._rightBox.get_n_children(); + n_children -= Main.panel.statusArea.ArcMenu !== undefined; + // position where icon should go, + // offset = 0, icon should be last + // offset = 1, icon should be second last + const order = Math.clamp(n_children - offset, 0, n_children); + return [order, 'right']; + case Constants.MenuPosition.LEFT: + default: + return [offset, 'left']; + } + } + + _configureActivitiesButton(){ + let isActivitiesButtonPresent = Main.panel.statusArea.activities && Main.panel.statusArea.activities.container && Main.panel._leftBox.contains(Main.panel.statusArea.activities.container); + let showActivities = this._settings.get_boolean('show-activities-button'); + + let container = Main.panel.statusArea.activities.container; + let parent = container.get_parent(); + let index = 0; + if(this._settings.get_enum('position-in-panel') === Constants.MenuPosition.LEFT && + this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && + this._settings.get_int('menu-button-position-offset') == 0) + index = 1; + + if(showActivities && !isActivitiesButtonPresent){ + parent ? parent.remove_child(container) : null; + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, index); + } + else if(!showActivities && isActivitiesButtonPresent) + Main.panel._leftBox.remove_child(Main.panel.statusArea.activities.container); + } + + // Check if the activities button is present on the main panel + _isActivitiesButtonPresent() { + return (this._activitiesButton && + this._activitiesButton.container && + Main.panel._leftBox.contains(this._activitiesButton.container)); + } + + // Add or restore the activities button on the main panel + _addActivitiesButtonToMainPanel() { + if (!this._isActivitiesButtonPresent()) { + // Retsore the activities button at the default position + let parent = this._activitiesButton.container.get_parent(); + if(!parent) + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, 0); + } + } + + // Add the menu button to the main panel + _addMenuButtonToMainPanel() { + let [position, box] = this._getMenuPosition(); + this.panel.addToStatusArea('ArcMenu', this._menuButton, position, box); + } + + // Remove the menu button from the main panel + _removeMenuButtonFromMainPanel() { + this.panel.menuManager.removeMenu(this._menuButton.arcMenu); + this.panel.menuManager.removeMenu(this._menuButton.arcMenuContextMenu); + this.panel.statusArea['ArcMenu'] = null; + } + + // Enable the menu button + enableButton(index) { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.DASH){ + this.dashIndex = index; + this.reEstablishDash(); + } + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + this._addMenuButtonToMainPanel(); + } + + this._menuButton.initiate(); + } + + reEstablishDash(){ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + if(!DashToDock){ + global.log("ArcMenu Error - Failed to place ArcMenu in Dash-to-Dock"); + return; + } + + const DashContainer = DashToDock._dashContainer; + + DashToDock.arcMenuEnabled = true; + this.oldShowAppsIcon = DashToDock._showAppsIcon; + + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.menuButtonAdjustedActor; + DashContainer.add_child(DashToDock._showAppsIcon); + + this._setButtonIcon(); + const IconSize = DashToDock.iconSize; + this._menuButton.menuButtonWidget.icon.setIconSize(IconSize); + + DashToDock.updateShowAppsButton(); + + this.hoverID = this.menuButtonAdjustedActor.child.connect('notify::hover', () => { + DashToDock._syncLabel(this.menuButtonAdjustedActor, null); + }); + + this.hidingID = Main.overview.connect('hiding', () => { + DashToDock._labelShowing = false; + this.menuButtonAdjustedActor.hideLabel(); + }); + + if(this.isPrimary){ + this.oldDashOnDestroy = this.panel._deleteDocks; + this.panel._deleteDocks = () => { + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + const AllDocks = this.panel._allDocks; + + if(!AllDocks.length) + return; + + AllDocks.forEach(dock => { + let dash = dock.dash; + if(dash._dashContainer.contains(dash._showAppsIcon)) + dash._dashContainer.remove_child(dash._showAppsIcon); + dash._showAppsIcon = this.oldShowAppsIcon; + dash._dashContainer.add_child(dash._showAppsIcon); + dash.arcMenuEnabled = false; + }); + + this.oldDashOnDestroy.call(this.panel, ...arguments); + this.panel._deleteDocks = this.oldDashOnDestroy; + }; + } + } + + _disableButton() { + this._removeMenuButtonFromMainPanel(); + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + + _isButtonEnabled() { + return this.panel.statusArea['ArcMenu'] !== null; + } + + destroy() { + if(this.runnerMenu){ + this.runnerMenu.destroy(); + } + this.settingsChangeIds.forEach(id => this._settings.disconnect(id)); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.panel === null || this.panel._allDocks.length === 0){ + this._menuButton.destroy(); + } + else{ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + const DashContainer = DashToDock._dashContainer; + if(this.panel._allDocks[this.dashIndex] && DashToDock && DashToDock.arcMenuEnabled){ + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + if(this.panel._allDocks[this.dashIndex]){ + DashToDock.arcMenuEnabled = false; + if(DashContainer.contains(DashToDock._showAppsIcon)) + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.oldShowAppsIcon; + DashContainer.add_child(DashToDock._showAppsIcon); + this.panel._deleteDocks = this.oldDashOnDestroy; + DashToDock.updateShowAppsButton(); + } + } + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + } + else if(this.panel == undefined) + this._menuButton.destroy(); + else if (this._isButtonEnabled()) { + this._disableButton(); + } + + if(this.isPrimary){ + this.disconnectKeyRelease(); + this._menuHotKeybinder.destroy(); + this._keybindingManager.destroy(); + this._hotCornerManager.destroy(); + } + this._settings = null; + this._activitiesButton = null; + this._menuButton = null; + delete global.toggleArcMenu; + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/extension.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/extension.js new file mode 100644 index 0000000..d101a31 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/extension.js @@ -0,0 +1,307 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {GLib, Gio, St} = imports.gi; +const Constants = Me.imports.constants; +const Controller = Me.imports.controller; +const Config = imports.misc.config; +const ShellVersion = parseFloat(Config.PACKAGE_VERSION); + +const Main = imports.ui.main; +const Util = imports.misc.util; +const Utils = Me.imports.utils; + +// Initialize panel button variables +let settings; +let settingsControllers; +let extensionChangedId; +let dockToggleID; +let dockExtension; +let enableTimeoutID; + +// Initialize menu language translations +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +// Enable the extension +function enable() { + if (ShellVersion < 3.39 && ShellVersion >= 3.36) + throw new Error(`ArcMenu v${Me.metadata.version} does not work on GNOME Shell version ${ShellVersion}. Please visit https://extensions.gnome.org/extension/3628/arcmenu/ and download ArcMenu v17`); + else if (ShellVersion < 3.36) + throw new Error(`GNOME Shell version ${ShellVersion} is not supported. Please visit https://extensions.gnome.org/extension/1228/arc-menu/ which supports GNOME Shell versions 3.14 - 3.34`); + + enableTimeoutID = GLib.timeout_add(0, 300, () => { + if(imports.gi.Meta.is_wayland_compositor()) + Me.metadata.isWayland = true; + else + Me.metadata.isWayland = false; + + settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + settings.connect('changed::multi-monitor', () => _multiMonitorChanged()); + settings.connect('changed::arc-menu-placement', () => _placementChanged()); + settingsControllers = []; + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + let avaliablePlacementArray = settings.get_default_value('available-placement').deep_unpack(); + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + + _enableButtons(); + + // dash to panel might get enabled after Arc-Menu + extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === 'dash-to-panel@jderose9.github.com') { + _disconnectDtpSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + setAvaliablePlacement(Constants.ArcMenuPlacement.DTP, isEnabled); + + if(isEnabled && (arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP)){ + _connectDtpSignals(); + _enableButtons(); + } + } + + if ((extension.uuid === "dash-to-dock@micxgx.gmail.com" || extension.uuid === "ubuntu-dock@ubuntu.com")) { + _disconnectDtdSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!_getDockExtensions() || !isEnabled) + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, false); + else{ + _connectDtdSignals(); + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, true); + } + _disableButtons(); + _enableButtons(); + } + } + }); + + // listen to dash to panel / dash to dock if they are compatible and already enabled + _connectDtdSignals(); + _connectDtpSignals(); + enableTimeoutID = null; + return GLib.SOURCE_REMOVE; + }); +} + +function disable() { + if(enableTimeoutID){ + GLib.source_remove(enableTimeoutID); + enableTimeoutID = null; + } + if(extensionChangedId){ + Main.extensionManager.disconnect(extensionChangedId); + extensionChangedId = null; + } + + _disconnectDtpSignals(); + _disconnectDtdSignals(); + + _disableButtons(); + settingsControllers = null; + + settings.run_dispose(); + settings = null; +} + +function setAvaliablePlacement(placement, state){ + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + if(avaliablePlacementArray[placement] !== state){ + avaliablePlacementArray[placement] = state; + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + } +} + +function _connectDtpSignals() { + if(global.dashToPanel) + global.dashToPanel._amPanelsCreatedId = global.dashToPanel.connect('panels-created', () => _enableButtons()); +} + +function _disconnectDtpSignals() { + if(global.dashToPanel?._amPanelsCreatedId){ + global.dashToPanel.disconnect(global.dashToPanel._amPanelsCreatedId); + delete global.dashToPanel._amPanelsCreatedId; + } +} + +function _connectDtdSignals(){ + dockExtension = _getDockExtensions(); + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + dockToggleID = dock.connect("toggled",() => { + _disableButtons(); + _enableButtons(); + }); + } +} + +function _disconnectDtdSignals() { + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + if(dock && dockToggleID){ + dock.disconnect(dockToggleID); + dockToggleID = null; + } + } +} + +function _placementChanged() { + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + _disconnectDtdSignals(); + _disconnectDtpSignals(); + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + _connectDtpSignals(); + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + _connectDtdSignals(); + + _disableButtons(); + _enableButtons(); +} + +function _multiMonitorChanged() { + _disableButtons(); + _enableButtons(); +} + +function _getDockExtensions(){ + let dashToDock = Main.extensionManager.lookup("dash-to-dock@micxgx.gmail.com"); + let ubuntuDash = Main.extensionManager.lookup("ubuntu-dock@ubuntu.com"); + let dock; + if(dashToDock?.stateObj?.dockManager) + dock = dashToDock; + if(ubuntuDash?.stateObj?.dockManager) + dock = ubuntuDash; + return dock; +} + +function _enableButtons() { + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = false; + + let multiMonitor = settings.get_boolean('multi-monitor'); + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + dockExtension = _getDockExtensions(); + + if(arcMenuPlacement == Constants.ArcMenuPlacement.DASH && dockExtension){ + avaliablePlacementArray[Constants.ArcMenuPlacement.DASH] = true; + + let dock = dockExtension.stateObj.dockManager; + if(dock?._allDocks.length){ + let docksLength = multiMonitor ? dock._allDocks.length : 1; + for(var index = 0; index < docksLength; index++){ + if(!dock._allDocks[index].dash.arcMenuEnabled){ + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, dock, + index, Constants.ArcMenuPlacement.DASH); + settingsController.monitorIndex = dock._allDocks[index].dash._monitorIndex; + settingsController.enableButton(index); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + } + } + else{ + let isDtPLoaded = false; + let panelArray = [Main.panel]; + if(global.dashToPanel && global.dashToPanel.panels){ + panelArray = global.dashToPanel.panels.map(pw => pw); + isDtPLoaded = true; + } + + let panelLength = multiMonitor ? panelArray.length : 1; + for(var index = 0; index < panelLength; index++){ + let panel = isDtPLoaded ? panelArray[index].panel : panelArray[index]; + let panelParent = panelArray[index]; + + let isPrimaryStandAlone = isDtPLoaded ? ('isPrimary' in panelParent && panelParent.isPrimary) && panelParent.isStandalone : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && isPrimaryStandAlone){ + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + panel = Main.panel; + } + + if(isDtPLoaded) + avaliablePlacementArray[Constants.ArcMenuPlacement.DTP] = true; + else + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + + if (panel.statusArea['ArcMenu']) + continue; + else if (settingsControllers[index]) + _disableButton(settingsControllers[index], 1); + + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, panel, + index, Constants.ArcMenuPlacement.PANEL); + + settingsController.monitorIndex = panelParent.monitor?.index; + + if(isDtPLoaded) + panel._amDestroyId = panel.connect('destroy', () => extensionChangedId ? _disableButton(settingsController, 1) : null); + + settingsController.enableButton(); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + + if(!Utils.getArraysEqual(settings.get_value('available-placement').deep_unpack(), avaliablePlacementArray)) + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); +} + +function _disableButtons(){ + for (let i = settingsControllers.length - 1; i >= 0; --i) { + let sc = settingsControllers[i]; + _disableButton(sc, 1); + } +} + +function _disableButton(controller, remove) { + if(controller.panel._amDestroyId){ + controller.panel.disconnect(controller.panel._amDestroyId); + delete controller.panel._amDestroyId; + } + + controller.destroy(); + + if(remove) + settingsControllers.splice(settingsControllers.indexOf(controller), 1); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/helper.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/helper.js new file mode 100644 index 0000000..9dbc4d2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/helper.js @@ -0,0 +1,227 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gio, GObject, Gtk, Meta, Shell} = imports.gi; +const Constants = Me.imports.constants; +const Main = imports.ui.main; +const Util = imports.misc.util; + +const MUTTER_SCHEMA = 'org.gnome.mutter'; + +var MenuHotKeybinder = class { + constructor() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + + this._mutterSettings = new Gio.Settings({ 'schema': MUTTER_SCHEMA }); + + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + + this._overlayKeyChangedID = this._mutterSettings.connect('changed::overlay-key', () => { + if(!this._ignoreHotKeyChangedEvent) + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + }); + + this._mainStartUpComplete = Main.layoutManager.connect('startup-complete', () => this._setHotKey()); + } + + enableHotKey(menuToggler){ + this._menuToggler = menuToggler; + + this._ignoreHotKeyChangedEvent = true; + + this._mutterSettings.set_string('overlay-key', Constants.SUPER_L); + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + this.hotKeyEnabled = true; + if(!Main.layoutManager._startingUp) + this._setHotKey(); + this._ignoreHotKeyChangedEvent = false; + } + + disableHotKey(){ + this._ignoreHotKeyChangedEvent = true; + this._mutterSettings.set_value('overlay-key', this._oldOverlayKey); + if(this.overlayKeyID){ + global.display.disconnect(this.overlayKeyID); + this.overlayKeyID = null; + } + if(this.defaultOverlayKeyID){ + GObject.signal_handler_unblock(global.display, this.defaultOverlayKeyID); + this.defaultOverlayKeyID = null; + } + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + } + + _setHotKey(){ + if(this.hotKeyEnabled){ + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + //Find signal ID in Main.js that connects 'overlay-key' to global.display and toggles Main.overview + let [bool,signal_id, detail] = GObject.signal_parse_name('overlay-key', global.display, true); + this.defaultOverlayKeyID = GObject.signal_handler_find(global.display, GObject.SignalMatchType.ID, signal_id, detail, null, null, null); + + //If signal ID found, block it and connect new 'overlay-key' to toggle ArcMenu. + if(this.defaultOverlayKeyID){ + GObject.signal_handler_block(global.display, this.defaultOverlayKeyID); + this.overlayKeyID = global.display.connect('overlay-key', () => { + this._menuToggler(); + }); + } + else + global.log("ArcMenu Error - Failed to set Super_L hotkey"); + } + } + + destroy() { + if(this._overlayKeyChangedID){ + this._mutterSettings.disconnect(this._overlayKeyChangedID); + this._overlayKeyChangedID = null; + } + this.disableHotKey(); + if (this._mainStartUpComplete) { + Main.layoutManager.disconnect(this._mainStartUpComplete); + this._mainStartUpComplete = null; + } + } +}; + +var KeybindingManager = class { + constructor(settings) { + this._settings = settings; + this._keybindings = new Map(); + } + + bind(keybindingNameKey, keybindingValueKey, keybindingHandler) { + if (!this._keybindings.has(keybindingNameKey)) { + this._keybindings.set(keybindingNameKey, keybindingValueKey); + + Main.wm.addKeybinding(keybindingValueKey, ExtensionUtils.getSettings(), + Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP, + keybindingHandler); + } + } + + unbind(keybindingNameKey) { + if (this._keybindings.has(keybindingNameKey)) { + let keybindingValueKey = this._keybindings.get(keybindingNameKey); + Main.wm.removeKeybinding(keybindingValueKey); + this._keybindings.delete(keybindingNameKey); + } + } + + unbindAll() { + this._keybindings.forEach((value, key) => { + Main.wm.removeKeybinding(value); + this._keybindings.delete(key); + }); + } + + destroy() { + this.unbindAll(); + } +}; + +var HotCornerManager = class { + constructor(settings, menuToggler) { + this._settings = settings; + this._menuToggler = menuToggler; + this._hotCornersChangedId = Main.layoutManager.connect('hot-corners-changed', () => this._setCustomHotCorners()); + } + + _setCustomHotCorners() { + let hotCornerAction = this._settings.get_enum('hot-corners'); + + if(hotCornerAction === Constants.HotCornerAction.DISABLED) + this.disableHotCorners(); + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU || hotCornerAction === Constants.HotCornerAction.CUSTOM) + this.modifyHotCorners(); + } + + _getHotCorners() { + return Main.layoutManager.hotCorners; + } + + restoreDefaultHotCorners() { + Main.layoutManager._updateHotCorners(); + } + + disableHotCorners() { + let hotCorners = this._getHotCorners(); + hotCorners.forEach((corner) => { + if(corner){ + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { }; + } + }); + } + + modifyHotCorners() { + let hotCorners = this._getHotCorners(); + let hotCornerAction = this._settings.get_enum('hot-corners'); + + hotCorners.forEach((corner) => { + if (corner) { + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { + corner._pressureBarrier._isTriggered = true; + if(corner._ripples) + corner._ripples.playAnimation(corner._x, corner._y); + else + corner._rippleAnimation(); + if(hotCornerAction == Constants.HotCornerAction.TOGGLE_ARCMENU) + this._menuToggler(); + else if(hotCornerAction == Constants.HotCornerAction.CUSTOM){ + let cmd = this._settings.get_string('custom-hot-corner-cmd'); + if(cmd == "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(cmd == "ArcMenu_RunCommand") + Main.openRunDialog(); + else + Util.spawnCommandLine(this._settings.get_string('custom-hot-corner-cmd')); + } + corner._pressureBarrier._reset(); + }; + } + }); + } + + destroy() { + if (this._hotCornersChangedId>0) { + Main.layoutManager.disconnect(this._hotCornersChangedId); + this._hotCornersChangedId = 0; + } + + this.restoreDefaultHotCorners(); + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f06173f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..11c483b Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9cb7eaf Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..dd97be3 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..178df95 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7018c94 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..c08d48e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..99db3f1 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..b9d0c76 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0d4495f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..6158e6b Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ee7d15e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7b2cd8b Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..04eb49e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..25f1be6 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0f4968c Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..77836ed Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9c35974 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..49572c0 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..95fa04f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8a9f45d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef7005a Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..eb02f6c Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8b0241e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..22605ab Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..151addf Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9f4b060 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..defd162 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f048587 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ac057e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9dc0b4d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef34524 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ce757e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..68ad6a2 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/.keep b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/.keep new file mode 100644 index 0000000..e69de29 diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg new file mode 100644 index 0000000..b0037ad --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg new file mode 100644 index 0000000..985702d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg new file mode 100644 index 0000000..b87c15f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg @@ -0,0 +1 @@ + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg new file mode 100644 index 0000000..ba04343 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg new file mode 100644 index 0000000..27aa967 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg @@ -0,0 +1,1412 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg new file mode 100644 index 0000000..43e74e7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg new file mode 100644 index 0000000..7e35c7b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H: 2.5 x + 1/2 x + 1x + 1x + + 1x + + 1x + + + + + + + + + + + H: 2.5 x + + 1/2 x + + 1x + + 1x + + + + 1x + + + + 1x + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg new file mode 100644 index 0000000..b0037ad --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg new file mode 100644 index 0000000..985702d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg new file mode 100644 index 0000000..56c7967 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg @@ -0,0 +1,287 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg new file mode 100644 index 0000000..0a1afe7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg @@ -0,0 +1,330 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg new file mode 100644 index 0000000..0687ab4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg @@ -0,0 +1,312 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg new file mode 100644 index 0000000..e26d0b1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg @@ -0,0 +1,328 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg new file mode 100644 index 0000000..2955da8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg new file mode 100644 index 0000000..077fcc7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg @@ -0,0 +1,202 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg new file mode 100644 index 0000000..ff230a7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg @@ -0,0 +1,45 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg new file mode 100644 index 0000000..46b2317 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg @@ -0,0 +1,87 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg new file mode 100644 index 0000000..013cc7c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg @@ -0,0 +1,227 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg new file mode 100644 index 0000000..02caa74 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg @@ -0,0 +1,65 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg new file mode 100644 index 0000000..c969ff2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg new file mode 100644 index 0000000..2eeaae6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg new file mode 100644 index 0000000..447e292 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg new file mode 100644 index 0000000..78c769b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg @@ -0,0 +1,159 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg new file mode 100644 index 0000000..24067fd --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg @@ -0,0 +1,163 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg new file mode 100644 index 0000000..eab2c5c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg new file mode 100644 index 0000000..fc8dd05 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg new file mode 100644 index 0000000..020a8e3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg @@ -0,0 +1,322 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg new file mode 100644 index 0000000..501012f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg @@ -0,0 +1,297 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg new file mode 100644 index 0000000..ba4c27e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg @@ -0,0 +1,290 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg new file mode 100644 index 0000000..1e85ea4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg new file mode 100644 index 0000000..1d75e16 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg new file mode 100644 index 0000000..15e9d51 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg @@ -0,0 +1,76 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg new file mode 100644 index 0000000..49311b4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg new file mode 100644 index 0000000..8a69a7b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg @@ -0,0 +1,384 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg new file mode 100644 index 0000000..47fae59 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg new file mode 100644 index 0000000..e146519 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg @@ -0,0 +1,298 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg new file mode 100644 index 0000000..13d524c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg @@ -0,0 +1,37 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg new file mode 100644 index 0000000..8f94a84 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg @@ -0,0 +1,438 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg new file mode 100644 index 0000000..2d04fcf --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg @@ -0,0 +1,307 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg new file mode 100644 index 0000000..a2e9833 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg @@ -0,0 +1,610 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg new file mode 100644 index 0000000..fae1077 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg @@ -0,0 +1,208 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg new file mode 100644 index 0000000..fdd6224 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg new file mode 100644 index 0000000..5ccb02c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg @@ -0,0 +1,295 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg new file mode 100644 index 0000000..7acd64d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg new file mode 100644 index 0000000..04f57e3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg @@ -0,0 +1,210 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg new file mode 100644 index 0000000..ba1c723 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg @@ -0,0 +1,99 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg new file mode 100644 index 0000000..830e664 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg @@ -0,0 +1,543 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg new file mode 100644 index 0000000..b5219b3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg @@ -0,0 +1,793 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg new file mode 100644 index 0000000..ff813d5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg @@ -0,0 +1,504 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg new file mode 100644 index 0000000..022435a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg new file mode 100644 index 0000000..75ed8b9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg @@ -0,0 +1,392 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg new file mode 100644 index 0000000..f29c05d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg @@ -0,0 +1,86 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg new file mode 100644 index 0000000..ff8584d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg @@ -0,0 +1,52 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets new file mode 100644 index 0000000..f2c8e16 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets @@ -0,0 +1,52 @@ +ArcMenu Style//rgba(53,53,53,0.987)//rgb(223,223,223)//rgb(32,32,32)//rgb(21,83,158)//rgba(255,255,255,1)//rgb(32,32,32)//9//1//5//12//24//false// +Simply Dark//rgba(28, 28, 28, 0.98)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Blue//rgb(25,31,34)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Light Blue//rgb(255,255,255)//rgb(51,51,51)//rgb(235,235,235)//rgba(189,230,251,0.9)//rgba(89,89,89,1)//rgba(189,230,251,0.9)//9//1//5//12//24//true// +Silk Desert//rgba(50,52,73,0.820946)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Breeze//rgb(237,237,243)//rgb(36,36,40)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(36,36,40)//rgb(210,210,215)//9//1//0//0//0//false// +Breeze Dark//rgb(49,53,61)//rgb(237,237,243)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(237,237,243)//rgb(65,69,73)//9//1//0//0//0//false// +Dark Blue 2//rgb(50,52,61)//rgb(211,217,227)//rgba(211,217,227,0.2)//rgb(81,149,226)//rgba(255,255,255,1)//rgba(211,217,227,0.5)//9//1//4//0//0//false// +Dark Orange//rgb(51,51,51)//rgb(226,224,221)//rgba(174,167,159,0.2)//rgb(233,84,32)//rgba(255,255,255,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Light Orange//rgb(246,246,245)//rgb(76,76,76)//rgba(51,51,51,0.2)//rgb(233,84,32)//rgba(114,114,114,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Blue Orange//rgb(44,62,80)//rgb(189,195,199)//rgba(189,195,199,0.2)//rgb(231,76,60)//rgba(227,233,237,1)//rgba(189,195,199,0.5)//9//1//4//0//0//false// +Light Purple//rgb(237,245,252)//rgb(39,45,45)//rgba(39,45,45,0.2)//rgba(144,112,164,0.5)//rgba(77,83,83,1)//rgba(144,112,164,0.5)//9//1//6//0//0//false// +Dark Green//rgb(27,34,36)//rgb(243,243,243)//rgba(46,149,130,0.2)//rgb(46,149,130)//rgba(255,255,255,1)//rgba(46,149,130,0.35)//9//1//6//0//0//true// +Gray//rgb(142,142,142)//rgb(255,255,255)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Terminal Green//rgba(28, 28, 28, 0.98)//rgb(17,164,40)//rgb(63,62,64)//rgba(17,164,40,0.641892)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Sky Clear//rgba(64,145,191,0.756757)//rgb(243,243,243)//rgb(63,62,64)//rgba(135,64,191,0.253378)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Ubi Purple//rgba(174,64,191,0.523649)//rgb(243,243,243)//rgb(63,62,64)//rgba(189,191,64,0.763514)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Shade//rgb(46,52,54)//rgb(186,189,182)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Red Shade//rgba(191,64,74,0.753378)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Tilk Blue//rgba(74,179,228,0.716216)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Green Blue//rgb(87,121,89)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Gray Blue//rgb(136,138,133)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Pastel//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 2//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 3//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 4//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 2//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 3//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 4//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Yellow Shade//rgb(196,160,0)//rgb(46,52,54)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Adapta//rgb(250,251,252)//rgb(34,45,50)//rgb(81,84,86)//rgba(0,150,136,0.121711)//rgba(72,83,88,1)//rgb(0,150,136)//11//0//8//12//24//true// +Adapta Nokto//rgb(38,50,56)//rgb(205,215,218)//rgb(38,50,56)//rgba(125,131,134,0.207237)//rgba(243,253,255,1)//rgb(0,188,212)//11//0//8//12//24//true// +Arc//rgb(245,246,247)//rgb(55,54,68)//rgba(82,148,226,0.903915)//rgba(56,55,68,0.0782918)//rgba(93,92,106,1)//rgb(82,148,226)//11//0//8//12//24//true// +Arc Dark//rgb(56,60,74)//rgb(188,195,205)//rgba(82,148,226,0.903915)//rgba(188,195,205,0.188612)//rgba(226,233,243,1)//rgb(82,148,226)//11//0//8//12//24//true// +Pop!_OS Dark//rgb(69,63,63)//rgb(188,185,183)//rgb(68,61,58)//rgba(250,164,26,0.885135)//rgba(226,223,221,1)//rgb(50,128,138)//11//0//8//12//24//true// +Pop!_OS//rgb(250,251,252)//rgb(87,79,74)//rgba(188,185,183,0.722973)//rgba(250,164,26,0.885135)//rgba(125,117,112,1)//rgb(72,185,199)//11//0//8//12//24//true// +McOS CTLina//rgba(243,243,243,0.841549)//rgb(32,32,32)//rgba(243,243,243,0.841549)//rgb(203,204,207)//rgba(70,70,70,1)//rgb(61,140,248)//11//0//8//12//24//true// +McOS CTLina Dark//rgba(47,47,46,0.873239)//rgb(198,194,194)//rgb(44,45,44)//rgb(37,87,214)//rgba(236,232,232,1)//rgb(37,87,214)//11//0//8//12//24//true// +Android Dark Blue//rgb(63,62,64)//rgb(243,243,243)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(255,255,255,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Blue//rgb(255,255,255)//rgb(63,62,64)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(101,100,102,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Green//rgb(255,255,255)//rgb(63,62,64)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(101,100,102,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Green//rgb(46,52,54)//rgb(243,243,243)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(255,255,255,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Yaru//rgb(46,52,54)//rgb(243,243,243)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(255,255,255,1)//rgb(189,86,53)//11//0//4//12//24//true// +Android Light Yaru//rgb(255,255,255)//rgb(63,62,64)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(101,100,102,1)//rgb(189,86,53)//11//0//4//12//24//true// +Adapta 4k Dark//rgb(49,59,67)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Adapta 4k Light//rgb(255,255,255)//rgb(46,52,54)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(84,90,92,1)//rgb(4,149,90)//11//1//4//12//24//true// +Neon Yellow Punk//rgb(49,59,67)//rgb(237,250,12)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(248,255,109,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Blue//rgba(49,59,67,0.841216)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Jade//rgba(24,81,58,0.875)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Amber//rgba(84,34,18,0.881757)//rgb(243,243,243)//rgb(247,186,36)//rgba(247,186,36,0.472973)//rgba(255,255,255,1)//rgb(247,186,36)//11//1//4//12//24//true// +Elegant Purple Haze//rgba(41,1,31,0.881757)//rgb(243,243,243)//rgba(112,8,67,0.425676)//rgba(112,8,67,0.425676)//rgba(255,255,255,1)//rgb(176,52,139)//11//0//4//12//24//true// diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuButton.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuButton.js new file mode 100644 index 0000000..ba9c387 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuButton.js @@ -0,0 +1,875 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, GObject, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com'; +var DASH_TO_DOCK_UUID = 'dash-to-dock@micxgx.gmail.com'; +var UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +var MenuButton = GObject.registerClass(class Arc_Menu_MenuButton extends PanelMenu.Button{ + _init(settings, arcMenuPlacement, panel, dashIndex) { + super._init(0.5, null, true); + this._settings = settings; + this._panel = panel; + this.menu.destroy(); + this.menu = null; + this.add_style_class_name('arc-menu-panel-menu'); + this.arcMenuPlacement = arcMenuPlacement; + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + let menuManagerParent; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) + menuManagerParent = this._panel; + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + menuManagerParent = this; + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this, 0.5, St.Side.TOP); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.arcMenuContextMenu = new ArcMenuContextMenu(this, 0.5, St.Side.TOP); + this.arcMenuContextMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(menuManagerParent); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + this.menuManager.addMenu(this.arcMenuContextMenu); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this); + this.subMenuManager._changeMenu = (menu) => {}; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget = new MW.MenuButtonWidget(); + this.x_expand = false; + this.y_expand = false; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this._delegate = this; + this.menuButtonWidget = new MW.DashMenuButtonWidget(this, this._settings); + this.dash = this._panel._allDocks[dashIndex]; + this.style_class = 'dash-item-container'; + this.child = this.menuButtonWidget.actor; + this.icon = this.menuButtonWidget.icon; + this.label = this.menuButtonWidget.label; + this.container.showLabel = () => this.menuButtonWidget.showLabel(); + this.container.hideLabel = () => this.menuButtonWidget.hideLabel(); + this.container.toggleButton = this.menuButtonWidget.actor; + this.toggleButton = this.menuButtonWidget.actor; + this.container.setDragApp = () => {}; + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + } + + //Add Menu Button Widget to Button + this.add_child(this.menuButtonWidget.actor); + } + + initiate(){ + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + //Dash to Panel Integration + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 1) { + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.syncWithDashToPanel(); + } + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 2) { + this.dashToPanel = null; + this.arcMenuContextMenu.removeExtensionSettings(); + this.updateArrowSide(St.Side.TOP); + if(this.dtpPostionChangedID>0 && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = 0; + } + } + }); + if(this.dashToPanel && this.dashToPanel.stateObj){ + this.syncWithDashToPanel(); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + //Dash to Dock Integration + this.dtdPostionChangedID = this._panel._settings.connect('changed::dock-position', ()=> { + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side); + }); + } + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => { + this.updateHeight(); + }); + + this._startupCompleteId = Main.layoutManager.connect('startup-complete', () => { + this.updateHeight(); + }); + + this.initiateRecentlyInstalledApps(); + this.setMenuPositionAlignment(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + setDragApp(){ + } + + handleDragOver(source, _actor, _x, _y, _time) { + return imports.ui.dnd.DragMotionResult.NO_DROP; + } + + acceptDrop(source, _actor, _x, _y, _time) { + return false; + } + + syncWithDashToPanel(){ + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + this.extensionSettingsItem = Utils.getSettings('org.gnome.shell.extensions.dash-to-panel', DASH_TO_PANEL_UUID); + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + let dashToPanelPositionSettings = 'panel-positions' + try{ + this.extensionSettingsItem.get_string(dashToPanelPositionSettings); + } catch(e){ + dashToPanelPositionSettings = 'panel-position' + } + this.dtpPostionChangedID = this.extensionSettingsItem.connect('changed::' + dashToPanelPositionSettings, ()=> { + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + }); + if(global.dashToPanel && global.dashToPanel.panels){ + global.dashToPanel.panels.forEach(p => { + if(p.panel === this._panel){ + this.dtpPanel = p; + } + }); + } + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._menuInForcedLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._menuInForcedLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + setMenuPositionAlignment(){ + let layout = this._settings.get_enum('menu-layout'); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + let arrowAlignment = (this._settings.get_int('menu-position-alignment') / 100); + if(layout != Constants.MenuLayout.RUNNER){ + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + this.arcMenu._boxPointer.setSourceAlignment(.5); + } + else if(this.dashToPanel && this.dashToPanel.stateObj){ + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + else{ + this.updateArrowSide(St.Side.TOP, false); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(layout != Constants.MenuLayout.RUNNER){ + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + } + + updateArrowSide(side, setAlignment = true){ + let arrowAlignment; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.updateArrowIconSide(side); + if(side === St.Side.RIGHT || side === St.Side.LEFT) + arrowAlignment = 1.0; + else + arrowAlignment = 0.5; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + arrowAlignment = 0.5; + + this.arcMenuContextMenu._arrowSide = side; + this.arcMenuContextMenu._boxPointer._arrowSide = side; + this.arcMenuContextMenu._boxPointer._userArrowSide = side; + this.arcMenuContextMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenuContextMenu._arrowAlignment = arrowAlignment; + this.arcMenuContextMenu._boxPointer._border.queue_repaint(); + + this.arcMenu._arrowSide = side; + this.arcMenu._boxPointer._arrowSide = side; + this.arcMenu._boxPointer._userArrowSide = side; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = arrowAlignment; + this.arcMenu._boxPointer._border.queue_repaint(); + + if(setAlignment) + this.setMenuPositionAlignment(); + } + + forceMenuLocation(){ + let layout = this._settings.get_enum('menu-layout'); + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + return; + + if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + if(!this._menuInForcedLocation) + return; + this.arcMenu.sourceActor = this; + this.arcMenu.focusActor = this; + this.arcMenu._boxPointer.setPosition(this, 0.5); + this.setMenuPositionAlignment(); + this._menuInForcedLocation = false; + return; + } + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + if(!this.dummyWidget){ + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + } + + if(!this._menuInForcedLocation){ + this.arcMenu.sourceActor = this.dummyWidget; + this.arcMenu.focusActor = this.dummyWidget; + this.arcMenu._boxPointer.setPosition(this.dummyWidget, 0.5); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + this._menuInForcedLocation = true; + } + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let rect = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY; + if(forcedMenuLocation === Constants.ForcedMenuLocation.TOP_CENTERED) + positionY = rect.y + this.rise; + else if(forcedMenuLocation === Constants.ForcedMenuLocation.BOTTOM_CENTERED) + positionY = rect.y + rect.height - this.rise; + this.dummyWidget.set_position(positionX, positionY); + } + + updateStyle(){ + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let layout = this._settings.get_enum('menu-layout'); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let gapAdjustment = this._settings.get_int('gap-adjustment'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + this.arcMenuContextMenu.actor.set_style_class_name(null); + this.arcMenuContextMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenuContextMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(layout === Constants.MenuLayout.RAVEN){ + this.MenuLayout?.updateStyle(); + return; + } + + if(removeMenuArrow){ + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px; -boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = "margin:0px;"; + } + else if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + this.arcMenu.actor.style = "-boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = null; + } + + this.MenuLayout?.updateStyle(); + } + + vfunc_event(event){ + if (event.type() === Clutter.EventType.BUTTON_PRESS){ + if(event.get_button() == 1){ + this.toggleMenu(); + } + else if(event.get_button() == 3){ + this.arcMenuContextMenu.toggle(); + } + } + else if(event.type() === Clutter.EventType.TOUCH_BEGIN){ + this.toggleMenu(); + } + else if(event.type() === Clutter.EventType.ENTER && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + else if(event.type() === Clutter.EventType.LEAVE && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + return Clutter.EVENT_PROPAGATE; + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + this.forceMenuLocation(); + let layout = this._settings.get_enum('menu-layout'); + if(layout === Constants.MenuLayout.GNOME_OVERVIEW){ + if(this._settings.get_boolean('gnome-dash-show-applications')){ + Main.overview._overview._controls._toggleAppsPage(); + } + else + Main.overview.toggle(); + } + else if(!this.arcMenu.isOpen){ + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + this.MenuLayout.updateLocation(); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(this.dtpPanel){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpPanel.intellihide._revealPanel(true); + this.dtpPanel.intellihide.revealAndHold(1); + } + else if(!this.dtpPanel.panelBox.visible){ + this.dtpPanel.panelBox.visible = true; + this.dtpNeedsHiding = true; + } + } + else if(this._panel === Main.panel && !Main.layoutManager.panelBox.visible){ + Main.layoutManager.panelBox.visible = true; + this.mainPanelNeedsHiding = true; + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.dash.getDockState() === 0){ + this.dash._removeAnimations(); + this.dash._animateIn(0, 0); + } + } + this.arcMenu.toggle(); + if(this.arcMenu.isOpen && this.MenuLayout){ + if(this.MenuLayout.activeMenuItem && this.MenuLayout.layoutProperties.SupportsCategoryOnHover) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else if(this.arcMenuContextMenu.isOpen) + return this.arcMenuContextMenu; + else + return null; + } + + toggleArcMenuContextMenu(){ + if(this.arcMenuContextMenu.isOpen) + this.arcMenuContextMenu.toggle(); + } + + updateHeight(){ + let layout = this._settings.get_enum('menu-layout'); + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor); + + if(height > monitorWorkArea.height){ + height = (monitorWorkArea.height * 8) / 10; + } + + if(!(layout == Constants.MenuLayout.SIMPLE || layout == Constants.MenuLayout.SIMPLE_2 || layout == Constants.MenuLayout.RUNNER) && this.MenuLayout) + this.mainBox.style = `height: ${height}px`; + if(this.MenuLayout?.updateWidth) + this.MenuLayout.updateWidth(true); + } + + _onDestroy(){ + if (this._monitorsChangedId){ + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = null; + } + if (this._startupCompleteId){ + Main.layoutManager.disconnect(this._startupCompleteId); + this._startupCompleteId = null; + } + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + if(this.tooltipShowingID){ + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if(this.tooltipHidingID){ + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.extensionChangedId){ + Main.extensionManager.disconnect(this.extensionChangedId); + this.extensionChangedId = null; + } + if(this.dtpPostionChangedID && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = null; + } + if(this.dtdPostionChangedID && this._panel._settings){ + this._panel._settings.disconnect(this.dtdPostionChangedID); + this.dtdPostionChangedID = null; + } + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.arcMenuContextMenu) + this.arcMenuContextMenu.destroy(); + if(this.dummyWidget) + this.dummyWidget.destroy(); + + super._onDestroy(); + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout && this.MenuLayout.updateLocation) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + //Avoid Super L hotkey conflicts with Pop Shell extension by + //setting 'overlay-key' mode to Shell.ActionMode.ALL. + let hotKeyPos = this._settings.get_enum('menu-hotkey'); + if(hotKeyPos === Constants.HotKey.SUPER_L) + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.ALL); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.setActiveStylePseudoClass(true); + this.add_style_pseudo_class('active'); + + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + + if(this.dtpPanel && !this.dtpNeedsRelease){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpNeedsRelease = true; + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.hideLabel(); + if(this.dash._autohideIsEnabled || this.dash._intellihideIsEnabled){ + this.dtdNeedsHiding = true; + this.dash._autohideIsEnabled = false; + this.dash._intellihideIsEnabled = false; + } + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtpPanel && this.dtpNeedsRelease && !this.dtpNeedsHiding){ + this.dtpNeedsRelease = false; + this.dtpPanel.intellihide?.release(1); + } + if(this.dtpPanel && this.dtpNeedsHiding){ + this.dtpNeedsHiding = false; + this.dtpPanel.panelBox.visible = false; + } + if(this.mainPanelNeedsHiding){ + Main.layoutManager.panelBox.visible = false; + this.mainPanelNeedsHiding = false; + } + this.menuButtonWidget.setActiveStylePseudoClass(false); + this.remove_style_pseudo_class('active'); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtdNeedsHiding){ + let dtdSettings = Utils.getSettings('org.gnome.shell.extensions.dash-to-dock', DASH_TO_DOCK_UUID); + if(dtdSettings){ + this.dash._autohideIsEnabled = dtdSettings.get_boolean('autohide'); + this.dash._intellihideIsEnabled = dtdSettings.get_boolean('intellihide'); + } + this.dash._box.sync_hover(); + this.dash._updateDashVisibility(); + this.dtdNeedsHiding = false; + } + + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + if(!this.menuButtonWidget.actor.hover) + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + } + } +}); + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this._menuButton.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this._menuButton.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this._menuButton.contextMenuManager.activeMenu) + this._menuButton.contextMenuManager.activeMenu.toggle(); + if(this._menuButton.subMenuManager.activeMenu) + this._menuButton.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; + +var ArcMenuContextMenu = class Arc_Menu_ArcMenuContextMenu extends PopupMenu.PopupMenu { + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + this.extensionSettingsItem = false; + + this.actor.add_style_class_name('panel-menu'); + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + + this.addMenuItem(this.createQuickLinkItem(_("ArcMenu Settings"), Constants.PrefsVisiblePage.MAIN)); + + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + let item = new PopupMenu.PopupMenuItem(_("Settings Quick Links:"), { + activate: false, + reactive: false + }); + item.add_style_class_name("margin-box arcmenu-menu-item"); + this.addMenuItem(item); + + this.addMenuItem(this.createQuickLinkItem(_("Change Menu Layout"), Constants.PrefsVisiblePage.MENU_LAYOUT)); + this.addMenuItem(this.createQuickLinkItem(_("Layout Tweaks"), Constants.PrefsVisiblePage.LAYOUT_TWEAKS)); + this.addMenuItem(this.createQuickLinkItem(_("Customize Menu"), Constants.PrefsVisiblePage.CUSTOMIZE_MENU)); + this.addMenuItem(this.createQuickLinkItem(_("Button Appearance"), Constants.PrefsVisiblePage.BUTTON_APPEARANCE)); + + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + this.addMenuItem(this.createQuickLinkItem(_("About"), Constants.PrefsVisiblePage.ABOUT)); + } + + addExtensionSettings(arcMenuPlacement){ + if(!this.extensionSettingsItem){ + let extensionCommand, extensionName; + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + extensionName = _("Dash to Panel Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_PANEL_UUID; + } + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + let dashToDock = Main.extensionManager.lookup(DASH_TO_DOCK_UUID); + let ubuntuDash = Main.extensionManager.lookup(UBUNTU_DOCK_UUID); + if(dashToDock && dashToDock.stateObj && dashToDock.stateObj.dockManager){ + extensionName = _("Dash to Dock Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_DOCK_UUID; + } + if(ubuntuDash && ubuntuDash.stateObj && ubuntuDash.stateObj.dockManager){ + extensionName = _("Ubuntu Dock Settings"); + extensionCommand = 'gnome-control-center ubuntu'; + } + } + + let item = new PopupMenu.PopupMenuItem(_(extensionName)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + Util.spawnCommandLine(extensionCommand); + }); + this.addMenuItem(item, 1); + this.extensionSettingsItem = true; + } + } + + removeExtensionSettings(){ + let children = this._getMenuItems(); + children[1].destroy(); + this.extensionSettingsItem = false; + } + + createQuickLinkItem(title, prefsVisiblePage){ + let item = new PopupMenu.PopupMenuItem(_(title)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + this._settings.set_int('prefs-visible-page', prefsVisiblePage); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + }); + return item; + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js new file mode 100644 index 0000000..c38431f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js @@ -0,0 +1,3693 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const {Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Shell, St} = imports.gi; +const AccountsService = imports.gi.AccountsService; +const AppFavorites = imports.ui.appFavorites; +const BoxPointer = imports.ui.boxpointer; +const Constants = Me.imports.constants; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const _SystemActions = imports.misc.systemActions; +const SystemActions = _SystemActions.getDefault(); +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; +const { loadInterfaceXML } = imports.misc.fileUtils; + +const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration'); +const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface); + +Gio._promisify(Gio._LocalFilePrototype, 'query_info_async', 'query_info_finish'); +Gio._promisify(Gio._LocalFilePrototype, 'set_attributes_async', 'set_attributes_finish'); + +const INDICATOR_ICON_SIZE = 18; +const USER_AVATAR_SIZE = 28; + +function activatePowerOption(powerType, arcMenu){ + arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + if(powerType === Constants.PowerType.POWER_OFF) + SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.RESTART) + SystemActions.activateRestart ? SystemActions.activateRestart() : SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.LOCK) + SystemActions.activateLockScreen(); + else if(powerType === Constants.PowerType.LOGOUT) + SystemActions.activateLogout(); + else if(powerType === Constants.PowerType.SUSPEND) + SystemActions.activateSuspend(); + else if(powerType === Constants.PowerType.HYBRID_SLEEP) + Utils.activateHybridSleep(); + else if(powerType === Constants.PowerType.HIBERNATE) + Utils.activateHibernate(); +} + +var ApplicationContextItems = GObject.registerClass({ + Signals: { + 'close-context-menu': { }, + }, + +}, class Arc_Menu_ApplicationContextItems extends St.BoxLayout{ + _init(actor, app, menuLayout){ + super._init({ + vertical: true, + x_expand: true, + y_expand: true, + style_class: 'margin-box', + }); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.sourceActor = actor; + this.layout = this._settings.get_enum('menu-layout'); + + this.discreteGpuAvailable = false; + this._switcherooNotifyId = global.connect('notify::switcheroo-control', + () => this._updateDiscreteGpuAvailable()); + this._updateDiscreteGpuAvailable(); + } + + set path(path){ + this._path = path; + } + + _updateDiscreteGpuAvailable() { + this._switcherooProxy = global.get_switcheroo_control(); + if (this._switcherooProxy) { + let prop = this._switcherooProxy.get_cached_property('HasDualGpu'); + this.discreteGpuAvailable = prop?.unpack() ?? false; + } else { + this.discreteGpuAvailable = false; + } + } + + closeMenus(){ + this.close(); + this._menuLayout.arcMenu.toggle(); + } + + close(){ + this.emit('close-context-menu'); + } + + rebuildItems(){ + this.destroy_all_children(); + if(this._app instanceof Shell.App){ + this.appInfo = this._app.get_app_info(); + let actions = this.appInfo.list_actions(); + + let windows = this._app.get_windows().filter( + w => !w.skip_taskbar + ); + + if (windows.length > 0){ + let item = new PopupMenu.PopupMenuItem(_("Current Windows:"), { + reactive: false, + can_focus: false + }); + item.actor.add_style_class_name('inactive'); + this.add_child(item); + + windows.forEach(window => { + let title = window.title ? window.title + : this._app.get_name(); + let item = this._appendMenuItem(title); + item.connect('activate', () => { + this.closeMenus(); + Main.activateWindow(window); + }); + }); + this._appendSeparator(); + } + + if (!this._app.is_window_backed()) { + if (this._app.can_open_new_window() && !actions.includes('new-window')) { + let newWindowItem = this._appendMenuItem(_("New Window")); + newWindowItem.connect('activate', () => { + this.closeMenus(); + this._app.open_new_window(-1); + }); + } + if (this.discreteGpuAvailable && this._app.state == Shell.AppState.STOPPED) { + const appPrefersNonDefaultGPU = this.appInfo.get_boolean('PrefersNonDefaultGPU'); + const gpuPref = appPrefersNonDefaultGPU + ? Shell.AppLaunchGpu.DEFAULT + : Shell.AppLaunchGpu.DISCRETE; + + this._onGpuMenuItem = this._appendMenuItem(appPrefersNonDefaultGPU + ? _('Launch using Integrated Graphics Card') + : _('Launch using Discrete Graphics Card')); + + this._onGpuMenuItem.connect('activate', () => { + this.closeMenus(); + this._app.launch(0, -1, gpuPref); + }); + } + + for (let i = 0; i < actions.length; i++) { + let action = actions[i]; + let item; + if(action === "empty-trash-inactive"){ + item = new PopupMenu.PopupMenuItem(this.appInfo.get_action_name(action), {reactive:false, can_focus:false}); + item.actor.add_style_class_name('inactive'); + this._appendSeparator(); + this.add_child(item); + } + else if(action === "empty-trash"){ + this._appendSeparator(); + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + else{ + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + + item.connect('activate', (emitter, event) => { + this.closeMenus(); + this._app.launch_action(action, event.get_time(), -1); + }); + } + + //If Trash Can, we don't want to add the rest of the entries below. + if(this.appInfo.get_string('Id') === "ArcMenu_Trash") + return false; + + let desktopIcons = Main.extensionManager.lookup("desktop-icons@csoriano"); + let desktopIconsNG = Main.extensionManager.lookup("ding@rastersoft.com"); + if((desktopIcons && desktopIcons.stateObj) || (desktopIconsNG && desktopIconsNG.stateObj)){ + this._appendSeparator(); + let fileDestination = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP); + let src = Gio.File.new_for_path(this.appInfo.get_filename()); + let dst = Gio.File.new_for_path(GLib.build_filenamev([fileDestination, src.get_basename()])); + let exists = dst.query_exists(null); + if(exists) { + let item = this._appendMenuItem(_("Delete Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + dst.delete(null); + } catch (e) { + log(`Failed to delete shortcut: ${e.message}`); + } + } + this.close(); + }); + } + else { + let item = this._appendMenuItem(_("Create Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + // copy_async() isn't introspectable :-( + src.copy(dst, Gio.FileCopyFlags.OVERWRITE, null, null); + this._markTrusted(dst); + } catch (e) { + log(`Failed to copy to desktop: ${e.message}`); + } + } + this.close(); + }); + } + } + + let canFavorite = global.settings.is_writable('favorite-apps'); + if (canFavorite) { + this._appendSeparator(); + let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._app.get_id()); + if (isFavorite) { + let item = this._appendMenuItem(_("Remove from Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.removeFavorite(this._app.get_id()); + this.close(); + }); + } else { + let item = this._appendMenuItem(_("Add to Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.addFavorite(this._app.get_id()); + this.close(); + }); + } + } + + let pinnedApps = this._settings.get_strv('pinned-app-list'); + let pinnedAppID = []; + + //filter pinnedApps list by every 3rd entry in list. 3rd entry contains an appID or command + for(let i = 2; i < pinnedApps.length; i += 3){ + pinnedAppID.push(pinnedApps[i]); + } + let isAppPinned = pinnedAppID.find((element) => { + return element == this._app.get_id(); + }); + + //if app is pinned and menulayout has PinnedApps category, show Unpin from ArcMenu entry + if(isAppPinned && this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app.get_id()){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + else if(this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Pin to ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + pinnedApps.push(this.appInfo.get_display_name()); + pinnedApps.push(''); + pinnedApps.push(this._app.get_id()); + this._settings.set_strv('pinned-app-list',pinnedApps); + }); + } + + if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { + this._appendSeparator(); + let item = this._appendMenuItem(_("Show Details")); + item.connect('activate', () => { + let id = this._app.get_id(); + let args = GLib.Variant.new('(ss)', [id, '']); + Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => { + let bus = Gio.DBus.get_finish(res); + bus.call('org.gnome.Software', + '/org/gnome/Software', + 'org.gtk.Actions', 'Activate', + GLib.Variant.new('(sava{sv})', + ['details', [args], null]), + null, 0, -1, null, null); + this.closeMenus(); + }); + }); + } + } + } + else if(this._path){ + let newWindowItem = this._appendMenuItem(_("Open Folder Location")); + newWindowItem.connect('activate', () => { + let file = Gio.File.new_for_path(this._path); + let context = global.create_app_launch_context(Clutter.get_current_event().get_time(), -1) + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + this.closeMenus(); + }); + } + else if(this._menuLayout.hasPinnedApps && this.sourceActor instanceof PinnedAppsMenuItem) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', () => { + this.close(); + let pinnedApps = this._settings.get_strv('pinned-app-list'); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + } + + //_markTrusted function borrowed from + //https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/apps-menu + async _markTrusted(file) { + let modeAttr = Gio.FILE_ATTRIBUTE_UNIX_MODE; + let trustedAttr = 'metadata::trusted'; + let queryFlags = Gio.FileQueryInfoFlags.NONE; + let ioPriority = GLib.PRIORITY_DEFAULT; + + try { + let info = await file.query_info_async(modeAttr, queryFlags, ioPriority, null); + + let mode = info.get_attribute_uint32(modeAttr) | 0o100; + info.set_attribute_uint32(modeAttr, mode); + info.set_attribute_string(trustedAttr, 'yes'); + await file.set_attributes_async(info, queryFlags, ioPriority, null); + + // Hack: force nautilus to reload file info + info = new Gio.FileInfo(); + info.set_attribute_uint64( + Gio.FILE_ATTRIBUTE_TIME_ACCESS, GLib.get_real_time()); + try { + await file.set_attributes_async(info, queryFlags, ioPriority, null); + } catch (e) { + log(`Failed to update access time: ${e.message}`); + } + } catch (e) { + log(`Failed to mark file as trusted: ${e.message}`); + } + } + + _appendSeparator() { + let separator = new ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.add_child(separator); + } + + _appendMenuItem(labelText) { + let item = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.label = new St.Label({ + text: _(labelText), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + item.add_child(this.label); + this.add_child(item); + return item; + } +}); + +var ApplicationContextMenu = class Arc_Menu_ApplicationContextMenu extends PopupMenu.PopupMenu { + constructor(actor, app, menuLayout){ + super(actor, 0.0, St.Side.TOP); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.layout = this._settings.get_enum('menu-layout'); + this._boxPointer.setSourceAlignment(.20); + this._boxPointer._border.queue_repaint(); + this.blockSourceEvents = true; + Main.uiGroup.add_child(this.actor); + this._menuLayout.contextMenuManager.addMenu(this); + this.contextMenuItems = new ApplicationContextItems(actor, app, menuLayout); + this.contextMenuItems.connect('close-context-menu', () => this.toggle()); + this.contextMenuItems._delegate = this.contextMenuItems; + this.box.add_child(this.contextMenuItems); + this.sourceActor = actor; + this.sourceActor.connect("destroy", ()=> { + if(this.isOpen) + this.close(); + Main.uiGroup.remove_child(this.actor); + this.contextMenuItems.destroy(); + this.destroy(); + }); + } + + centerBoxPointerPosition(){ + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + rightBoxPointerPosition(){ + this._arrowSide = St.Side.LEFT; + this._boxPointer._arrowSide = St.Side.LEFT; + this._boxPointer._userArrowSide = St.Side.LEFT; + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + set path(path){ + this.contextMenuItems.path = path; + } + + open(animate){ + if(this._menuLayout.searchResults && this.sourceActor !== this._menuLayout.searchResults.getTopResult()) + this._menuLayout.searchResults.getTopResult()?.remove_style_pseudo_class('active'); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.sourceActor.tooltip){ + this.sourceActor.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + super.open(animate); + } + + close(animate){ + super.close(animate); + if(this.sourceActor instanceof ArcMenuButtonItem) + this.sourceActor.sync_hover(); + else{ + this.sourceActor.active = false; + } + + this.sourceActor.sync_hover(); + this.sourceActor.hovered = this.sourceActor.hover; + } + + rebuildItems(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(customStyle){ + this.actor.style_class = 'arc-menu-boxpointer'; + this.actor.add_style_class_name('arc-menu'); + } + else{ + this.actor.style_class = 'popup-menu-boxpointer'; + this.actor.add_style_class_name('popup-menu'); + } + + this.contextMenuItems.rebuildItems(); + } + + _onKeyPress(actor, event) { + return Clutter.EVENT_PROPAGATE; + } +}; + +var ArcMenuPopupBaseMenuItem = GObject.registerClass({ + Properties: { + 'active': GObject.ParamSpec.boolean('active', 'active', 'active', + GObject.ParamFlags.READWRITE, + false), + 'hovered': GObject.ParamSpec.boolean('hovered', 'hovered', 'hovered', + GObject.ParamFlags.READWRITE, + false), + 'sensitive': GObject.ParamSpec.boolean('sensitive', 'sensitive', 'sensitive', + GObject.ParamFlags.READWRITE, + true), + }, + Signals: { + 'activate': { param_types: [Clutter.Event.$gtype] }, + }, + +}, class Arc_Menu_PopupBaseMenuItem extends St.BoxLayout{ + _init(menuLayout, params){ + params = imports.misc.params.parse(params, { + reactive: true, + activate: true, + hover: true, + style_class: null, + can_focus: true, + }); + super._init({ style_class: 'popup-menu-item arcmenu-menu-item', + reactive: params.reactive, + track_hover: params.reactive, + can_focus: params.can_focus, + accessible_role: Atk.Role.MENU_ITEM + }); + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this.hasContextMenu = false; + this._delegate = this; + this._menuLayout = menuLayout; + this.arcMenu = this._menuLayout.arcMenu; + this.shouldShow = true; + this._parent = null; + this._active = false; + this._activatable = params.reactive && params.activate; + this._sensitive = true; + + this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' }); + this.add_child(this._ornamentLabel); + + this.x_align = Clutter.ActorAlign.FILL; + this.x_expand = true; + + if (!this._activatable) + this.add_style_class_name('popup-inactive-menu-item'); + + if (params.style_class) + this.add_style_class_name(params.style_class); + + if (params.reactive && params.hover) + this.bind_property('hover', this, 'hovered', GObject.BindingFlags.SYNC_CREATE); + + if(params.hover) + this.actor.connect('notify::hover', this._onHover.bind(this)); + + this.arcMenuOpenStateChangeID = this.arcMenu.connect('open-state-changed', (menu, open) =>{ + if(!open) + this.cancelPopupTimeout(); + }); + + let textureCache = St.TextureCache.get_default(); + let iconThemeChangedId = textureCache.connect('icon-theme-changed', this._updateIcon.bind(this)); + this.connect('destroy', () => { + textureCache.disconnect(iconThemeChangedId); + this._onDestroy(); + }); + } + + _updateIcon() { + if(!this._iconBin || !this.createIcon) + return; + + let icon = this.createIcon(); + this._iconBin.set_child(icon); + } + + get actor() { + return this; + } + + get active(){ + return this._active; + } + + set active(active) { + if(this.isDestroyed) + return; + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + if(this._menuLayout.activeMenuItem !== this) + this._menuLayout.activeMenuItem = this; + this.remove_style_class_name('selected'); + this.add_style_pseudo_class('active'); + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_pseudo_class('active'); + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + set hovered(hover) { + let hoverChanged = hover != this.hovered; + if(hoverChanged){ + let isActiveStyle = this.get_style_pseudo_class()?.includes('active') + if(hover && !isActiveStyle){ + this.add_style_class_name('selected'); + } + else{ + this.remove_style_class_name('selected'); + } + } + } + + setShouldShow(){ + //If a saved shortcut link is a desktop app, check if currently installed. + //Do NOT display if application not found. + if(this._command.endsWith(".desktop") && !Shell.AppSystem.get_default().lookup_app(this._command)){ + this.shouldShow = false; + } + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = this.description; + if(this._app) + description = this._app.get_description(); + Utils.createTooltip(this._menuLayout, this, this.label, description, this._displayType ? this._displayType : -1); + } + } + + vfunc_button_press_event(){ + let event = Clutter.get_current_event(); + this.pressed = false; + if(event.get_button() == 1){ + this._menuLayout._blockActivateEvent = false; + this.pressed = true; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + } + else if(event.get_button() == 3){ + this.pressed = true; + } + this.active = true; + return Clutter.EVENT_PROPAGATE; + } + + vfunc_button_release_event(){ + let event = Clutter.get_current_event(); + if(event.get_button() == 1 && !this._menuLayout._blockActivateEvent && this.pressed){ + this.pressed = false; + this.activate(event); + if(!(this instanceof CategoryMenuItem) && !(this instanceof ArcMenuButtonItem)) + this.active = false; + return Clutter.EVENT_STOP; + } + if(event.get_button() == 3 && this.pressed){ + this.pressed = false; + if(this.hasContextMenu) + this.popupContextMenu(); + else if(!(this instanceof CategoryMenuItem && !(this instanceof ArcMenuButtonItem))){ + this.active = false; + this.hovered = true; + } + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_key_focus_in() { + super.vfunc_key_focus_in(); + if(!this.actor.hover) + this._menuLayout._keyFocusIn(this.actor); + this.active = true; + } + + vfunc_key_focus_out() { + if(this.contextMenu && this.contextMenu.isOpen){ + return; + } + super.vfunc_key_focus_out(); + this.active = false; + } + + activate(event) { + this.emit('activate', event); + } + + vfunc_key_press_event(keyEvent) { + if (!this._activatable) + return super.vfunc_key_press_event(keyEvent); + + let state = keyEvent.modifier_state; + + // if user has a modifier down (except capslock and numlock) + // then don't handle the key press here + state &= ~Clutter.ModifierType.LOCK_MASK; + state &= ~Clutter.ModifierType.MOD2_MASK; + state &= Clutter.ModifierType.MODIFIER_MASK; + + if (state) + return Clutter.EVENT_PROPAGATE; + + let symbol = keyEvent.keyval; + if ( symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter) { + this.activate(Clutter.get_current_event()); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_touch_event(event){ + if(event.type == Clutter.EventType.TOUCH_END && !this._menuLayout._blockActivateEvent && this.pressed){ + this.remove_style_pseudo_class('active'); + this.activate(Clutter.get_current_event()); + this.pressed = false; + return Clutter.EVENT_STOP; + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && !this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = true; + this._menuLayout._blockActivateEvent = false; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + this.add_style_pseudo_class('active'); + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = false; + this._menuLayout._blockActivateEvent = false; + this._menuLayout.contextMenuManager.activeMenu.toggle(); + } + return Clutter.EVENT_PROPAGATE; + } + + contextMenuTimeOut(){ + this._popupTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 600, () => { + this.pressed = false; + this._popupTimeoutId = null; + if(this.hasContextMenu && this._menuLayout.arcMenu.isOpen && !this._menuLayout._blockActivateEvent) { + this.popupContextMenu(); + this._menuLayout.contextMenuManager.ignoreRelease(); + } + return GLib.SOURCE_REMOVE; + }); + } + + cancelPopupTimeout(){ + if(this._popupTimeoutId){ + GLib.source_remove(this._popupTimeoutId); + this._popupTimeoutId = null; + } + } + + _onDestroy(){ + this.isDestroyed = true; + if(this.arcMenuOpenStateChangeID){ + this.arcMenu.disconnect(this.arcMenuOpenStateChangeID); + this.arcMenuOpenStateChangeID = null; + } + } +}); + +var ArcMenuSeparator = GObject.registerClass( +class Arc_Menu_Separator extends PopupMenu.PopupBaseMenuItem { + _init(separatorLength, separatorAlignment, text) { + super._init({ + style_class: 'popup-separator-menu-item', + reactive: false, + can_focus: false, + }); + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + this.remove_child(this._ornamentLabel); + this.reactive = true; + this.label = new St.Label({ + text: text || '', + style: 'font-weight: bold' + }); + this.add_child(this.label); + this.label_actor = this.label; + + this.label.add_style_pseudo_class = () => { return false; }; + + this.label.connect('notify::text', + this._syncLabelVisibility.bind(this)); + this._syncLabelVisibility(); + + this._separator = new St.Widget({ + style_class: 'popup-separator-menu-item-separator separator-color-style', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(this._separator); + if(separatorAlignment === Constants.SeparatorAlignment.HORIZONTAL){ + this.style = "padding: 0px 5px;" + if(separatorLength === Constants.SeparatorStyle.SHORT) + this._separator.style = "margin: 5px 45px;"; + else if(separatorLength === Constants.SeparatorStyle.MEDIUM) + this._separator.style = "margin: 5px 15px;"; + else if(separatorLength === Constants.SeparatorStyle.LONG) + this._separator.style = "margin: 0px 5px;"; + else if(separatorLength === Constants.SeparatorStyle.MAX) + this._separator.style = "margin: 0px; padding: 0px;"; + else if(separatorLength === Constants.SeparatorStyle.HEADER_LABEL){ + this._separator.style = "margin: 0px 20px 0px 10px;"; + this.style = "padding: 5px 15px;" + } + } + else if(separatorAlignment === Constants.SeparatorAlignment.VERTICAL){ + if(separatorLength === Constants.SeparatorStyle.ALWAYS_SHOW){ + this.style = "padding: 8px 4px;" + } + else{ + this._syncVisibility(); + this.vertSeparatorChangedID = this._settings.connect('changed::vert-separator', this._syncVisibility.bind(this)); + this.style = "padding: 0px 4px;" + } + + this._separator.style = "margin: 0px; width: 1px; height: -1px;"; + this.remove_child(this.label); + this.x_expand = this._separator.x_expand = true; + this.x_align = this._separator.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = this._separator.y_expand = true; + this.y_align = this._separator.y_align = Clutter.ActorAlign.FILL; + } + + this.connect('destroy', () => { + if(this.vertSeparatorChangedID){ + this._settings.disconnect(this.vertSeparatorChangedID); + this.vertSeparatorChangedID = null; + } + }); + } + + _syncLabelVisibility() { + this.label.visible = this.label.text != ''; + } + + _syncVisibility() { + this._separator.visible = this._settings.get_boolean('vert-separator'); + } +}); + +var ActivitiesMenuItem = GObject.registerClass(class Arc_Menu_ActivitiesMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _("Activities Overview"), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + icon_name: 'view-fullscreen-symbolic', + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + activate(event) { + this._menuLayout.arcMenu.toggle(); + Main.overview.show(); + super.activate(event); + } +}); + +var Tooltip = class Arc_Menu_Tooltip{ + constructor(menuLayout, sourceActor, title, description) { + this._menuButton = menuLayout.menuButton; + this._settings = this._menuButton._settings; + this.sourceActor = sourceActor; + if(this.sourceActor.tooltipLocation) + this.location = this.sourceActor.tooltipLocation; + else + this.location = Constants.TooltipLocation.BOTTOM; + let descriptionLabel; + this.actor = new St.BoxLayout({ + vertical: true, + style_class: 'dash-label tooltip-menu-item', + opacity: 0 + }); + + if(title){ + this.titleLabel = new St.Label({ + text: _(title), + style: description ? "font-weight: bold;" : null, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this.titleLabel); + } + + if(description){ + descriptionLabel = new St.Label({ + text: description, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(descriptionLabel); + } + + global.stage.add_child(this.actor); + + this.actor.connect('destroy',()=>{ + if(this.destroyID){ + this.sourceActor.disconnect(this.destroyID); + this.destroyID = null; + } + if(this.activeID){ + this.sourceActor.disconnect(this.activeID); + this.activeID = null; + } + + if(this.hoverID){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.toggleID){ + this._settings.disconnect(this.toggleID); + this.toggleID = null; + } + }) + this.activeID = this.sourceActor.connect('notify::active', ()=> this.setActive(this.sourceActor.active)); + this.destroyID = this.sourceActor.connect('destroy',this.destroy.bind(this)); + this.hoverID = this.sourceActor.connect('notify::hover', this._onHover.bind(this)); + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + this.toggleID = this._settings.connect('changed::disable-tooltips', this.disableTooltips.bind(this)); + } + + setActive(active){ + if(!active) + this.hide(); + } + + disableTooltips() { + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + } + + _onHover() { + if(this._useTooltips){ + if(this.sourceActor.hover){ + if(this._menuButton.tooltipShowing){ + this.show(); + this._menuButton.activeTooltip = this.actor; + } + else{ + this._menuButton.tooltipShowingID = GLib.timeout_add(0, 750, () => { + this.show(); + this._menuButton.tooltipShowing = true; + this._menuButton.activeTooltip = this.actor; + this._menuButton.tooltipShowingID = null; + return GLib.SOURCE_REMOVE; + }); + } + if(this._menuButton.tooltipHidingID){ + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + } + else { + this.hide(); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + this._menuButton.tooltipHidingID = GLib.timeout_add(0, 750, () => { + this._menuButton.tooltipShowing = false; + this._menuButton.activeTooltip = null; + this._menuButton.tooltipHidingID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + } + + show() { + if(this._useTooltips){ + this.actor.opacity = 0; + this.actor.show(); + + let [stageX, stageY] = this.sourceActor.get_transformed_position(); + + let itemWidth = this.sourceActor.allocation.x2 - this.sourceActor.allocation.x1; + let itemHeight = this.sourceActor.allocation.y2 - this.sourceActor.allocation.y1; + + let labelWidth = this.actor.get_width(); + let labelHeight = this.actor.get_height(); + + let x, y; + let gap = 5; + + switch (this.location) { + case Constants.TooltipLocation.BOTTOM_CENTERED: + y = stageY + itemHeight + gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.TOP_CENTERED: + y = stageY - labelHeight - gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.BOTTOM: + y = stageY + itemHeight + gap; + x = stageX + gap; + break; + } + + // keep the label inside the screen + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + if (x - monitor.x < gap) + x += monitor.x - x + gap; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + else if (y - monitor.y < gap) + y += monitor.y - y + gap; + else if (y + labelHeight > monitor.y + monitor.height - gap) + y -= y + labelHeight - (monitor.y + monitor.height) + gap; + + this.actor.set_position(x, y); + this.actor.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + } + + hide() { + if(this._useTooltips){ + this.actor.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.actor.hide() + }); + } + } + + destroy() { + if (this._menuButton.tooltipShowingID) { + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + if (this._menuButton.tooltipHidingID) { + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + if(this.toggleID>0){ + this._settings.disconnect(this.toggleID); + this.toggleID = 0; + } + if(this.hoverID>0){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = 0; + } + if(this._menuButton.activeTooltip = this.actor) + this._menuButton.activeTooltip = null; + + global.stage.remove_child(this.actor); + this.actor.destroy(); + } +}; + +var ArcMenuButtonItem = GObject.registerClass( + class Arc_Menu_ArcMenuButtonItem extends ArcMenuPopupBaseMenuItem { + _init(menuLayout, tooltipText, iconName, gicon) { + super._init(menuLayout); + this.style_class = 'popup-menu-item arc-menu-button'; + this._settings = this._menuLayout._settings; + this._menuLayout = menuLayout; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.iconName = iconName; + this.gicon = gicon; + this.toggleMenuOnClick = true; + + if(tooltipText){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, tooltipText); + this.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + this.tooltip.hide(); + } + + if(this.iconName !== null){ + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + } + } + + createIcon(overrideIconSize){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this.gicon ? this.gicon : Gio.icon_new_for_string(this.iconName), + icon_size: overrideIconSize ? overrideIconSize : iconSize, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER + }); + } + + setIconSize(size){ + if(!this._iconBin) + return; + this._iconBin.set_child(this.createIcon(size)); + } + + activate(event){ + if(this.toggleMenuOnClick) + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +// Settings Button +var SettingsButton = GObject.registerClass(class Arc_Menu_SettingsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Settings"), 'emblem-system-symbolic'); + } + activate(event) { + super.activate(event); + Util.spawnCommandLine('gnome-control-center'); + } +}); + +// Runner Layout Tweaks Button +var RunnerTweaksButton = GObject.registerClass(class Arc_Menu_RunnerTweaksButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Configure Runner"), 'emblem-system-symbolic'); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + } + activate(event) { + super.activate(event); + this._menuLayout._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.RUNNER_TWEAKS); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + } +}); + +//'Insider' layout Pinned Apps hamburger button +var PinnedAppsButton = GObject.registerClass(class Arc_Menu_PinnedAppsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Pinned Apps"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.togglePinnedAppsMenu(); + } +}); + +//'Windows' layout extras hamburger button +var ExtrasButton = GObject.registerClass(class Arc_Menu_ExtrasButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Extras"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleExtrasMenu(); + } +}); + +//"Leave" Button with popupmenu that shows lock, power off, restart, etc +var LeaveButton = GObject.registerClass(class Arc_Menu_LeaveButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Leave"), 'system-shutdown-symbolic'); + this.toggleMenuOnClick = false; + this._menuLayout = menuLayout; + this.menuButton = menuLayout.menuButton; + this._settings = menuLayout._settings; + this._createLeaveMenu(); + } + + _createLeaveMenu(){ + this.leaveMenu = new PopupMenu.PopupMenu(this, 0.5 , St.Side.BOTTOM); + this.leaveMenu.blockSourceEvents = true; + let section = new PopupMenu.PopupMenuSection(); + this.leaveMenu.addMenuItem(section); + + let box = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + box._delegate = box; + + section.actor.add_child(box); + + box.add_child(this._menuLayout.createLabelRow(_("Session"))); + + this.lockItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOCK); + box.add_child(this.lockItem); + + let logOutItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOGOUT); + box.add_child(logOutItem); + + box.add_child(this._menuLayout.createLabelRow(_("System"))); + + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + let sleepItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HYBRID_SLEEP); + box.insert_child_at_index(sleepItem, 4); + } + }); + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + let hibernateItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HIBERNATE); + box.insert_child_at_index(hibernateItem, 5); + } + }); + + let suspendItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.SUSPEND); + box.add_child(suspendItem); + + let restartItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.RESTART); + box.add_child(restartItem); + + let powerOffItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.POWER_OFF); + box.add_child(powerOffItem); + + this._menuLayout.subMenuManager.addMenu(this.leaveMenu); + this.leaveMenu.actor.hide(); + Main.uiGroup.add_child(this.leaveMenu.actor); + this.leaveMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.active = false; + this.sync_hover(); + this.hovered = this.hover; + } + }); + } + + _onDestroy(){ + Main.uiGroup.remove_child(this.leaveMenu.actor); + this.leaveMenu.destroy(); + } + + activate(event) { + super.activate(event); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.leaveMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.leaveMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.leaveMenu.toggle(); + } +}); + +//'Unity' layout categories hamburger button +var CategoriesButton = GObject.registerClass(class Arc_Menu_CategoriesButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Categories"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleCategoriesMenu(); + } +}); + +var PowerButton = GObject.registerClass(class Arc_Menu_PowerButton extends ArcMenuButtonItem { + _init(menuLayout, powerType) { + super._init(menuLayout, Constants.PowerOptions[powerType].TITLE, Constants.PowerOptions[powerType].IMAGE); + this.powerType = powerType; + } + activate(event) { + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PowerMenuItem = GObject.registerClass(class Arc_Menu_PowerMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, type) { + super._init(menuLayout); + this.powerType = type; + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(Constants.PowerOptions[this.powerType].TITLE), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: Gio.icon_new_for_string(Constants.PowerOptions[this.powerType].IMAGE), + style_class: 'popup-menu-icon', + icon_size: iconSize, + }); + } + + activate(){ + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PlasmaMenuItem = GObject.registerClass(class Arc_Menu_PlasmaMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, title, iconPath) { + super._init(menuLayout); + this.remove_child(this._ornamentLabel); + this._menuLayout = menuLayout; + this.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.vertical = true; + this.name = "arc-menu-plasma-button"; + this.iconPath = iconPath; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(title), + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label.x_align = this.label.y_align = Clutter.ActorAlign.CENTER; + this.label.y_expand = true; + + this._iconBin.x_align = this._iconBin.y_align = Clutter.ActorAlign.CENTER; + this._iconBin.y_expand = true; + + this.label.get_clutter_text().set_line_wrap(true); + this.add_child(this.label); + this.actor.connect('notify::hover', this._onHover.bind(this)); + } + + createIcon(){ + return new St.Icon({ + gicon: Gio.icon_new_for_string(this.iconPath), + style_class: 'popup-menu-icon', + icon_size: Constants.MEDIUM_ICON_SIZE + }); + } + + _onHover(){ + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = null; + Utils.createTooltip(this._menuLayout, this, this.label, description, Constants.DisplayType.LIST); + } + let shouldHover = this._settings.get_boolean('plasma-enable-hover'); + if(shouldHover && this.actor.hover && !this.isActive){ + this.activate(Clutter.get_current_event()); + } + } + + set active(active) { + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + this.add_style_class_name('selected'); + this._menuLayout.activeMenuItem = this; + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + setActive(active){ + if(active){ + this.isActive = true; + this.set_style_pseudo_class("active-item"); + } + else{ + this.isActive = false; + this.set_style_pseudo_class(null); + } + } + + activate(event){ + this._menuLayout.searchBox.clearWithoutSearchChangeEvent(); + this._menuLayout.clearActiveItem(); + this.setActive(true); + super.activate(event); + } +}); + +var PlasmaCategoryHeader = GObject.registerClass(class Arc_Menu_PlasmaCategoryHeader extends St.BoxLayout{ + _init(menuLayout) { + super._init({ + style_class: "popup-menu-item", + style: 'padding: 0px;', + reactive: true, + track_hover:true, + can_focus: true, + accessible_role: Atk.Role.MENU_ITEM + }); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this.backButton = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.backButton.x_expand = false; + this.backButton.x_align = Clutter.ActorAlign.CENTER; + this.label = new St.Label({ + text: _("Applications"), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + style: 'font-weight: bold' + }); + + this.backButton.add_child(this.label); + + this.add_child(this.backButton); + this.backButton.connect("activate", () => this._menuLayout.displayCategories() ); + + this.categoryLabel = new St.Label({ + text: '', + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.categoryLabel); + } + + setActiveCategory(categoryText){ + if(categoryText){ + this.categoryLabel.text = _(categoryText); + this.categoryLabel.show(); + } + else + this.categoryLabel.hide(); + } +}); + +var AllAppsButton = GObject.registerClass(class Arc_Menu_AllAppsButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-next-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("All Apps"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.insert_child_at_index(this._label, 0); + } + + activate(event){ + super.activate(event); + this._menuLayout.displayAllApps(); + } +}); + +var BackButton = GObject.registerClass(class Arc_Menu_BackButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-previous-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("Back"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this._label); + } + + activate(event){ + super.activate(event); + this._menuLayout.setDefaultMenuView(); + } +}); + +// Menu item to go back to category view +var BackMenuItem = GObject.registerClass(class Arc_Menu_BackMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + let backLabel = new St.Label({ + text: _("Back"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-previous-symbolic', + icon_size: iconSize, + }); + } + + activate(event) { + if(this._layout === Constants.MenuLayout.ARCMENU){ + //If the current page is inside a category and + //previous page was the categories page, + //go back to categories page + if(this._menuLayout.previousCategoryType === Constants.CategoryType.CATEGORIES_LIST && (this._menuLayout.activeCategoryType <= 4 || this._menuLayout.activeCategoryType instanceof GMenu.TreeDirectory)) + this._menuLayout.displayCategories(); + else + this._menuLayout.setDefaultMenuView(); + } + else if(this._layout === Constants.MenuLayout.TOGNEE) + this._menuLayout.setDefaultMenuView(); + super.activate(event); + } +}); + +// Menu item to view all apps +var ViewAllPrograms = GObject.registerClass(class Arc_Menu_ViewAllPrograms extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + let backLabel = new St.Label({ + text: _("All Applications"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + this._updateIcon(); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-next-symbolic', + icon_size: iconSize, + x_align: Clutter.ActorAlign.START + }); + } + + activate(event) { + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this._menuLayout.displayCategories(); + else + this._menuLayout.displayAllApps(); + super.activate(event); + } +}); + +var ShortcutMenuItem = GObject.registerClass(class Arc_Menu_ShortcutMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + if(this._settings.get_enum('shortcut-icon-type') === Constants.CategoryIconType.FULL_COLOR) + this.add_style_class_name('regular-icons'); + else + this.add_style_class_name('symbolic-icons'); + this._command = command; + this._displayType = displayType; + this.isContainedInCategory = isContainedInCategory; + this.iconName = icon; + + //Check for default commands-------- + if(this._command == "ArcMenu_Software"){ + let softwareManager = Utils.findSoftwareManager(); + this._command = softwareManager ? softwareManager : 'ArcMenu_unfound.desktop'; + } + else if(this._command === "ArcMenu_Trash"){ + this.trash = new Me.imports.placeDisplay.Trash(this); + this._command = "ArcMenu_Trash"; + this._app = this.trash.getApp(); + } + if(!this._app) + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + + if(this._app && icon === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this.iconName = appIcon.gicon.to_string(); + } + } + //------------------------------------- + + this.hasContextMenu = this._app ? true : false; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(name), y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.layout = this._settings.get_enum('menu-layout'); + if(this.layout === Constants.MenuLayout.PLASMA && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + else if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.remove_child(this.label); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + this.setShouldShow(); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + iconSizeEnum = this._settings.get_enum('button-item-icon-size'); + defaultIconSize = LayoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + } + else if(this._displayType === Constants.DisplayType.GRID){ + iconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(iconSizeEnum, defaultIconStyle); + } + + return new St.Icon({ + icon_name: this.iconName, + gicon: Gio.icon_new_for_string(this.iconName), + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this._app && this.contextMenu == undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID || this.layout === Constants.MenuLayout.UNITY || this.layout === Constants.MenuLayout.AZ) + this.contextMenu.centerBoxPointerPosition(); + else if(this.layout === Constants.MenuLayout.MINT || this.layout === Constants.MenuLayout.TOGNEE) + this.contextMenu.rightBoxPointerPosition(); + if(this._path) + this.contextMenu.path = this._path; + } + if(this.contextMenu !== undefined){ + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen){ + this.contextMenu.rebuildItems(); + } + this.contextMenu.toggle(); + } + } + + activate(event) { + if(this._command === "ArcMenu_LogOut") + activatePowerOption(Constants.PowerType.LOGOUT, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Lock") + activatePowerOption(Constants.PowerType.LOCK, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_PowerOff") + activatePowerOption(Constants.PowerType.POWER_OFF, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Restart") + activatePowerOption(Constants.PowerType.RESTART, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Suspend") + activatePowerOption(Constants.PowerType.SUSPEND, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_HybridSleep") + activatePowerOption(Constants.PowerType.HYBRID_SLEEP, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Hibernate") + activatePowerOption(Constants.PowerType.HIBERNATE, this._menuLayout.arcMenu); + + else{ + this._menuLayout.arcMenu.toggle(); + if(this._command === "ArcMenu_ActivitiesOverview") + Main.overview.show(); + else if(this._command === "ArcMenu_RunCommand") + Main.openRunDialog(); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(this._app) + this._app.open_new_window(-1); + else + Util.spawnCommandLine(this._command); + } + } +}); + +// Menu item which displays the current user +var UserMenuItem = GObject.registerClass(class Arc_Menu_UserMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, displayType) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._settings = this._menuLayout._settings; + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + this.iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + this.iconSize = Utils.getIconSize(IconSizeEnum, USER_AVATAR_SIZE); + } + + this.userMenuIcon = new UserMenuIcon(menuLayout, this.iconSize, false); + + this.add_child(this.userMenuIcon.actor); + this.label = this.userMenuIcon.label; + if(this._displayType !== Constants.DisplayType.BUTTON) + this.add_child(this.label); + } + + activate(event) { + Util.spawnCommandLine("gnome-control-center user-accounts"); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var UserMenuIcon = class Arc_Menu_UserMenuIcon{ + constructor(menuLayout, size, hasTooltip) { + this._menuLayout = menuLayout; + this.iconSize = size; + + let username = GLib.get_user_name(); + this._user = AccountsService.UserManager.get_default().get_user(username); + + this.actor = new St.Bin({ + style_class: 'menu-user-avatar user-icon', + track_hover: true, + reactive: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label = new St.Label({ + text: GLib.get_real_name(), + y_align: Clutter.ActorAlign.CENTER + }); + + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + + this._userLoadedId = this._user.connect('notify::is-loaded', this._onUserChanged.bind(this)); + this._userChangedId = this._user.connect('changed', this._onUserChanged.bind(this)); + this.actor.connect('destroy', this._onDestroy.bind(this)); + if(hasTooltip) + this.actor.connect('notify::hover',this._onHover.bind(this)); + + this._onUserChanged(); + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, GLib.get_real_name()); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + this.tooltip._onHover(); + } + } + + _onUserChanged() { + if (this._user.is_loaded) { + this.label.set_text(this._user.get_real_name()); + if(this.tooltip) + this.tooltip.titleLabel.text = this._user.get_real_name(); + + let iconFile = this._user.get_icon_file(); + if (iconFile && !GLib.file_test(iconFile ,GLib.FileTest.EXISTS)) + iconFile = null; + + if (iconFile) { + this.actor.child = null; + this.actor.add_style_class_name('user-avatar'); + this.actor.style = 'background-image: url("%s");'.format(iconFile) + "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + } + else { + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + this.actor.child = new St.Icon({ + icon_name: 'avatar-default-symbolic', + icon_size: this.iconSize, + style: "padding: 5px; width: " + this.iconSize + "px; height: " + this.iconSize + "px;" + }); + } + } + } + + _onDestroy() { + if (this._userLoadedId) { + this._user.disconnect(this._userLoadedId); + this._userLoadedId = null; + } + if (this._userChangedId) { + this._user.disconnect(this._userChangedId); + this._userChangedId = null; + } + } +}; + +// Menu pinned apps item class +var PinnedAppsMenuItem = GObject.registerClass({ + Signals: { 'saveSettings': {}, }, +}, class Arc_Menu_PinnedAppsMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._menuButton = menuLayout.menuButton; + this._settings = this._menuLayout._settings; + this._command = command; + this._iconString = this._iconPath = icon; + this._name = name; + this._displayType = displayType; + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + this.hasContextMenu = true; + this.gridLocation = [-1, -1]; + this.isContainedInCategory = isContainedInCategory; + + //Modifiy the Default Pinned Apps--------------------- + if(this._name == "ArcMenu Settings"){ + this._name = _("ArcMenu Settings"); + } + else if(this._name == "Terminal"){ + this._name = _("Terminal"); + } + else if(this._name == "Files"){ + this._name = _("Files"); + } + if(this._iconPath === "ArcMenu_ArcMenuIcon" || this._iconPath === Me.path + '/media/icons/arc-menu-symbolic.svg'){ + this._iconString = this._iconPath = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + //------------------------------------------------------- + + if(this._app && this._iconPath === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this._iconString = appIcon.gicon ? appIcon.gicon.to_string() : appIcon.fallback_icon_name; + if(!this._iconString) + this._iconString = ""; + } + } + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(this._name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + if(this._displayType === Constants.DisplayType.LIST && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this._draggable = DND.makeDraggable(this.actor); + this._draggable._animateDragEnd = (eventTime) => { + this._draggable._animationInProgress = true; + this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime); + }; + this.isDraggableApp = true; + this._draggable.connect('drag-begin', this._onDragBegin.bind(this)); + this._draggable.connect('drag-end', this._onDragEnd.bind(this)); + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.setShouldShow(); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this.contextMenu == undefined){ + let app = this._app ? this._app : this._command; + this.contextMenu = new ApplicationContextMenu(this.actor, app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + _onDragBegin() { + this.isDragging = true; + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + if(this.contextMenu && this.contextMenu.isOpen) + this.contextMenu.toggle(); + + this.cancelPopupTimeout(); + + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this) + }; + DND.addDragMonitor(this._dragMonitor); + this._parentBox = this.actor.get_parent(); + let p = this._parentBox.get_transformed_position(); + this.posX = p[0]; + this.posY = p[1]; + + this.actor.opacity = 55; + this.get_allocation_box(); + this.rowHeight = this.height; + this.rowWidth = this.width; + } + + _onDragMotion(dragEvent) { + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + this.xIndex = Math.floor((this._draggable._dragX - this.posX) / (this.rowWidth + layoutManager.column_spacing)); + this.yIndex = Math.floor((this._draggable._dragY - this.posY) / (this.rowHeight + layoutManager.row_spacing)); + + if(this.xIndex === this.gridLocation[0] && this.yIndex === this.gridLocation[1]){ + return DND.DragMotionResult.CONTINUE; + } + else{ + this.gridLocation = [this.xIndex, this.yIndex]; + } + + this._parentBox.remove_child(this); + let children = this._parentBox.get_children(); + let childrenCount = children.length; + let columns = layoutManager.gridColumns; + let rows = Math.floor(childrenCount / columns); + if(this.yIndex >= rows) + this.yIndex = rows; + if(this.yIndex < 0) + this.yIndex = 0; + if(this.xIndex >= columns - 1) + this.xIndex = columns - 1; + if(this.xIndex < 0) + this.xIndex = 0; + + if(((this.xIndex + 1) + (this.yIndex * columns)) > childrenCount) + this.xIndex = Math.floor(childrenCount % columns); + + this._parentBox.remove_all_children(); + + let x = 0, y = 0; + for(let i = 0; i < children.length; i++){ + if(this.xIndex === x && this.yIndex === y) + [x, y] = this.gridLayoutIter(x, y, columns); + layoutManager.attach(children[i], x, y, 1, 1); + [x, y] = this.gridLayoutIter(x, y, columns); + } + layoutManager.attach(this, this.xIndex, this.yIndex, 1, 1); + } + return DND.DragMotionResult.CONTINUE; + } + + _onDragEnd() { + if (this._dragMonitor) { + DND.removeDragMonitor(this._dragMonitor); + this._dragMonitor = null; + } + this.actor.opacity = 255; + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + let x = 0, y = 0; + let columns = layoutManager.gridColumns; + let orderedList = []; + let children = this._parentBox.get_children(); + for(let i = 0; i < children.length; i++){ + orderedList.push(this._parentBox.layout_manager.get_child_at(x, y)); + [x, y] = this.gridLayoutIter(x, y, columns); + } + this._menuLayout.pinnedAppsArray = orderedList; + } + this.emit('saveSettings'); + } + + getDragActor() { + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let icon = new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + style_class: 'popup-menu-icon', + icon_size: this._iconBin.get_child().icon_size + }); + let iconColor = this._settings.get_string('menu-foreground-color'); + if(customStyle) + icon.style = `color: ${iconColor};`; + return icon; + } + + getDragActorSource() { + return this.actor; + } + + gridLayoutIter(x, y, columns){ + x++; + if(x === columns){ + y++; + x = 0; + } + return [x, y]; + } + + activate(event) { + if(this._app) + this._app.open_new_window(-1); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else + Util.spawnCommandLine(this._command); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var ApplicationMenuItem = GObject.registerClass(class Arc_Menu_ApplicationMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, app, displayType, metaInfo, isContainedInCategory) { + super._init(menuLayout); + this._app = app; + this._menuLayout = menuLayout; + this.metaInfo = metaInfo; + this._settings = this._menuLayout._settings; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._displayType = displayType; + this.hasContextMenu = true; + this.isSearchResult = this.metaInfo ? true : false; + this.isContainedInCategory = isContainedInCategory; + + if(this._app){ + let disableRecentAppsIndicator = this._settings.get_boolean("disable-recently-installed-apps") + if(!disableRecentAppsIndicator){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + this.isRecentlyInstalled = recentApps.some((appIter) => appIter === this._app.get_id()); + } + } + + this._iconBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._app ? this._app.get_name() : this.metaInfo['name'], + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.description = this._app ? this._app.get_description() : this.metaInfo['description']; + + let searchResultsDescriptionsSetting = this._settings.get_boolean("show-search-result-details"); + let appsShowDescriptionsSetting = this._settings.get_boolean("apps-show-extra-details"); + this.searchResultsDescriptions = searchResultsDescriptionsSetting && this.isSearchResult; + this.appsShowDescriptions = appsShowDescriptionsSetting && !this.isSearchResult; + + if(this.description && (this.searchResultsDescriptions || this.appsShowDescriptions) && this._displayType === Constants.DisplayType.LIST){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionText = this.description.split('\n')[0]; + this.descriptionLabel = new St.Label({ + text: descriptionText, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + labelBox.add_child(this.descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this.label_actor = this.label; + + if(this.isRecentlyInstalled){ + this._indicator = new St.Label({ + text: _('New'), + style_class: "arc-menu-menu-item-text-indicator", + style: "border-radius: 15px; margin: 0px; padding: 0px 10px;", + x_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.hoverID = this.connect("notify::hover", () => this.removeIndicator()); + this.keyFocusInID = this.connect("key-focus-in", () => this.removeIndicator()); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + this._iconBin.x_align = Clutter.ActorAlign.CENTER; + + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory || this.isSearchResult ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + return this.metaInfo ? this.metaInfo['createIcon'](iconSize) : this._app.create_icon_texture(iconSize); + } + + removeIndicator(){ + if(this.isRecentlyInstalled){ + this.isRecentlyInstalled = false; + let recentApps = this._settings.get_strv('recently-installed-apps'); + let index = recentApps.indexOf(this._app.get_id()); + if(index > -1){ + recentApps.splice(index, 1); + } + this._settings.set_strv('recently-installed-apps', recentApps); + + this._indicator.hide(); + this._menuLayout.setRecentlyInstalledIndicator(); + } + } + + popupContextMenu(){ + this.removeIndicator(); + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activateSearchResult(provider, metaInfo, terms, event){ + this._menuLayout.arcMenu.toggle(); + if(provider.activateResult){ + provider.activateResult(metaInfo.id, terms); + if (metaInfo.clipboardText) + St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, metaInfo.clipboardText); + } + else{ + if (metaInfo.id.endsWith('.desktop')) { + let app = Shell.AppSystem.get_default().lookup_app(metaInfo.id); + if (app.can_open_new_window()) + app.open_new_window(-1); + else + app.activate(); + } + else{ + this._menuLayout.arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + SystemActions.activateAction(metaInfo.id); + } + } + } + + activate(event) { + this.removeIndicator(); + + if(this.metaInfo){ + this.activateSearchResult(this.provider, this.metaInfo, this.resultsView.terms, event); + return Clutter.EVENT_STOP; + } + else + this._app.open_new_window(-1); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _onDestroy(){ + if(this.hoverID){ + this.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.keyFocusInID){ + this.disconnect(this.keyFocusInID); + this.keyFocusInID = null; + } + } +}); + +// Menu Category item class +var CategoryMenuItem = GObject.registerClass(class Arc_Menu_CategoryMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, category, displayType) { + super._init(menuLayout); + this.appList = []; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._layout = this._settings.get_enum('menu-layout'); + this._category = category; + this._name = ""; + this._horizontalFlip = this._settings.get_boolean('enable-horizontal-flip'); + this._displayType = displayType; + this.layoutProps = this._menuLayout.layoutProperties; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._name, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + + if(this.isRecentlyInstalled) + this.setRecentlyInstalledIndicator(true); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.remove_child(this.label); + } + + this.label_actor = this.label; + this._menuLayout._oldX = -1; + this._menuLayout._oldY = -1; + this.connect('motion-event', this._onMotionEvent.bind(this)); + this.connect('enter-event', this._onEnterEvent.bind(this)); + this.connect('leave-event', this._onLeaveEvent.bind(this)); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + + let defaultIconSize = this.layoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + let defaultIconSize = this.layoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + let icon = new St.Icon({ + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + icon.gicon = gicon; + else if(iconName) + icon.icon_name = iconName; + else + icon.fallback_icon_name = fallbackIconName; + + return icon; + } + + setRecentlyInstalledIndicator(shouldShow){ + if(this._displayType === Constants.DisplayType.BUTTON) + return; + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + else if(this._indicator && this.contains(this._indicator)) + this.remove_child(this._indicator); + } + + displayAppList(){ + this._menuLayout.searchBox?.clearWithoutSearchChangeEvent(); + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, null); + } + + activate(event) { + this.displayAppList(); + if(this.layoutProps.SupportsCategoryOnHover) + this._menuLayout.setActiveCategory(this, true); + super.activate(event); + } + + _onEnterEvent(actor, event) { + if(this._menuLayout.navigatingCategoryLeaveEventID){ + GLib.source_remove(this._menuLayout.navigatingCategoryLeaveEventID); + this._menuLayout.navigatingCategoryLeaveEventID = null; + } + } + + _onLeaveEvent(actor, event) { + if(!this._menuLayout.navigatingCategoryLeaveEventID){ + this._menuLayout.navigatingCategoryLeaveEventID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { + this._menuLayout.navigatingCategory = null; + this._menuLayout.navigatingCategoryLeaveEventID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + + _onMotionEvent(actor, event) { + if(this.layoutProps.SupportsCategoryOnHover && this._settings.get_boolean('activate-on-hover')){ + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategoryType !== this._category && this._menuLayout.navigatingCategory === this) + this.activate(Clutter.get_current_event()); + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } + } + + _isInTriangle([x, y]){ + let [posX, posY] = this._menuLayout.navigatingCategory.get_transformed_position(); + + //the mouse is still in the active category + if (this._menuLayout.navigatingCategory === this){ + this._menuLayout._oldX = x; + this._menuLayout._oldY = y; + return true; + } + + if(!this._menuLayout.navigatingCategory) + return false; + + let width = this._menuLayout.navigatingCategory.width; + let height = this._menuLayout.navigatingCategory.height; + + let maxX = this._horizontalFlip ? posX : posX + width; + let maxY = posY + height; + + let distance = Math.abs(maxX - this._menuLayout._oldX); + let point1 = [this._menuLayout._oldX, this._menuLayout._oldY] + let point2 = [maxX, posY - distance]; + let point3 = [maxX, maxY + distance]; + + let area = Utils.areaOfTriangle(point1, point2, point3); + let a1 = Utils.areaOfTriangle([x, y], point2, point3); + let a2 = Utils.areaOfTriangle(point1, [x, y], point3); + let a3 = Utils.areaOfTriangle(point1, point2, [x, y]); + return area === a1 + a2 + a3; + } +}); + +var SimpleMenuItem = GObject.registerClass(class Arc_Menu_SimpleMenuItem extends CategoryMenuItem{ + _init(menuLayout, category) { + super._init(menuLayout, category); + this.subMenu = new PopupMenu.PopupMenu(this.actor,.5,St.Side.LEFT); + this.subMenu.connect("open-state-changed", (menu, open) => { + if(!open){ + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + }); + + Main.uiGroup.add_child(this.subMenu.actor); + this.section = new PopupMenu.PopupMenuSection(); + this.subMenu.addMenuItem(this.section); + + this.applicationsScrollBox = this._menuLayout._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this._menuLayout.subMenuManager.addMenu(this.subMenu); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.applicationsScrollBox.style = 'max-height: 25em;'; + this.applicationsBox._delegate = this.applicationsBox; + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.section.actor.add_child(this.applicationsScrollBox); + + if(this.subMenu._keyPressId) + this.actor.disconnect(this.subMenu._keyPressId); + this.applicationsScrollBox.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Right: + case Clutter.KEY_Left: + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + } + return Clutter.EVENT_STOP; + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.actor.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + } + return Clutter.EVENT_STOP; + case Clutter.KEY_Left: + case Clutter.KEY_Right: + case Clutter.KEY_Return: + if(!this.subMenu.isOpen){ + let navigateFocus = true; + this.activate(event, navigateFocus); + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + return Clutter.EVENT_STOP; + } + else{ + return Clutter.EVENT_PROPAGATE; + } + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.updateStyle(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.subMenu.actor.hide(); + if(customStyle){ + this.subMenu.actor.style_class = 'arc-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('arc-menu'); + } + else + { + this.subMenu.actor.style_class = 'popup-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('popup-menu'); + } + } + + displayAppList(){ + this._menuLayout.activeCategory = this._name; + } + + activate(event, navigateFocus = true) { + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + this.subMenu.toggle(); + if(navigateFocus) + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + this._menuLayout.setActiveCategory(this, true); + } + + _onMotionEvent(actor, event) { + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategory !== this._name && this._menuLayout.navigatingCategory === this){ + let navigateFocus = false; + this.activate(event, navigateFocus); + } + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } +}); +// SubMenu Category item class +var CategorySubMenuItem = GObject.registerClass(class Arc_Menu_CategorySubMenuItem extends PopupMenu.PopupSubMenuMenuItem{ + _init(menuLayout, category) { + super._init('', true); + this.add_style_class_name("arcmenu-menu-item"); + this.add_style_class_name('margin-box'); + this._category = category; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._name = ""; + this.isSimpleMenuItem = false; + this._active = false; + this.applicationsMap = new Map(); + this.appList = []; + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + this.icon.gicon = gicon; + else if(iconName) + this.icon.icon_name = iconName; + else + this.icon.fallback_icon_name = fallbackIconName; + + this.label.text = this._name; + + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + this.icon.icon_size = iconSize; + + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._menuLayout._blockActivateEvent = true; + this._menuLayout.onPan(action, this.menu.actor); + }); + panAction.connect('gesture-cancel',(action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + panAction.connect('gesture-end', (action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + this.menu.actor.add_action(panAction); + + this.menu.actor.style = 'max-height: 250px;'; + this.menu.actor.overlay_scrollbars = true; + this.menu.actor.style_class = 'popup-sub-menu ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'); + this.menu._needsScrollbar = () => this._needsScrollbar(); + + this.menu.connect('open-state-changed', () => { + if(!this.menu.isOpen){ + let scrollbar= this.menu.actor.get_vscroll_bar().get_adjustment(); + scrollbar.set_value(0); + } + }); + this.menu.box.style_class = 'margin-box'; + } + + setRecentlyInstalledIndicator(shouldShow){ + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this._indicator); + } + else if(this._indicator && this.actor.contains(this._indicator)) + this.actor.remove_child(this._indicator); + } + + _needsScrollbar() { + let topMenu = this.menu; + let [, topNaturalHeight] = topMenu.actor.get_preferred_height(-1); + let topThemeNode = topMenu.actor.get_theme_node(); + + let topMaxHeight = topThemeNode.get_max_height(); + let needsScrollbar = topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight; + if(needsScrollbar) + this.menu.actor.style = 'min-height:150px; max-height: 250px;'; + else + this.menu.actor.style = 'max-height: 250px;'; + + this.menu.actor.vscrollbar_policy = St.PolicyType.AUTOMATIC; + + if (needsScrollbar) + this.menu.actor.add_style_pseudo_class('scrolled'); + else + this.menu.actor.remove_style_pseudo_class('scrolled'); + + return needsScrollbar; + } + + loadMenu(){ + let children = this.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let item = children[i]; + this.menu.box.remove_child(item); + } + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + for (let i = 0; i < appList.length; i++) { + let app = appList[i]; + let item = this.applicationsMap.get(app); + if(item.actor.get_parent()){ + item.actor.get_parent().remove_child(item.actor); + } + if (!item.actor.get_parent()) { + this.menu.box.add_child(item.actor); + } + } + } + + _setOpenState(open){ + if(this.isSimpleMenuItem && open){ + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + } + else if(open) + this.loadMenu(); + + this.setSubmenuShown(open); + } +}); + +// Place Info class +var PlaceInfo = class Arc_Menu_PlaceInfo { + constructor(file, name, icon) { + this.file = file; + this.name = name ? name : this._getFileName(); + this.icon = icon ? icon : null; + this.gicon = icon ? null : this.getIcon(); + } + + launch(timestamp) { + let context = global.create_app_launch_context(timestamp, -1); + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(this._getFileName()), e.message); + reject(e); + } + }); + }); + } + + getIcon() { + try { + let info = this.file.query_info('standard::symbolic-icon', 0, null); + return info.get_symbolic_icon(); + + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!this.file.is_native()) { + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + return this.file.get_basename(); + } + } + } + + destroy(){ + } +}; +Signals.addSignalMethods(PlaceInfo.prototype); + +// Menu Place Shortcut item class +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._info = info; + this._settings = menuLayout._settings; + this.isContainedInCategory = isContainedInCategory; + this.hasContextMenu = true; + + this.label = new St.Label({ + text: _(info.name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = this.y_expand = false; + this.x_align = this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + this.add_child(this.label); + } + + this._changedId = this._info.connect('changed', this._propertiesChanged.bind(this)); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: this._info.gicon ? this._info.gicon : this._info.icon, + icon_size: iconSize, + }); + } + + _onDestroy() { + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = null; + } + if(this._info) + this._info.destroy(); + super._onDestroy(); + } + + popupContextMenu(){ + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this.createIcon(); + if(this.label) + this.label.text = info.name; + } +}); + +var SearchBox = GObject.registerClass({ +Signals: { + 'search-changed': { param_types: [GObject.TYPE_STRING] }, + 'entry-key-focus-in': { }, + 'entry-key-press': { param_types: [Clutter.Event.$gtype] }, +},}, +class Arc_Menu_SearchBox extends St.Entry { + _init(menuLayout) { + super._init({ + hint_text: _("Search…"), + track_hover: true, + can_focus: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + name: "ArcSearchEntry" + }); + this.searchResults = menuLayout.searchResults; + this._settings = menuLayout._settings; + this.triggerSearchChangeEvent = true; + + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.EXTRA_SMALL_ICON_SIZE); + + this._findIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-find-symbolic', + icon_size: iconSize + }); + + this._clearIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-clear-symbolic', + icon_size: iconSize + }); + + this.set_primary_icon(this._findIcon); + + this._text = this.get_clutter_text(); + this._textChangedId = this._text.connect('text-changed', this._onTextChanged.bind(this)); + this._keyPressId = this._text.connect('key-press-event', this._onKeyPress.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-in', this._onKeyFocusIn.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-out', this._onKeyFocusOut.bind(this)); + this._searchIconClickedId = this.connect('secondary-icon-clicked', () => this.clear()); + this.connect('destroy', this._onDestroy.bind(this)); + } + + updateStyle(removeBorder){ + let style = this.style; + this.style = style.replace("border-width: 0;", ""); + if(removeBorder) + this.style += 'border-width: 0;'; + } + + get entryBox(){ + return this; + } + + get actor(){ + return this; + } + + getText() { + return this.get_text(); + } + + setText(text) { + this.set_text(text); + } + + clearWithoutSearchChangeEvent(){ + this.triggerSearchChangeEvent = false; + this.set_text(''); + this.triggerSearchChangeEvent = true; + } + + hasKeyFocus() { + return this.contains(global.stage.get_key_focus()); + } + + clear() { + this.set_text(''); + } + + isEmpty() { + return this.get_text() == ''; + } + + _onKeyFocusOut(){ + if(!this.isEmpty()){ + this.add_style_pseudo_class('focus'); + return Clutter.EVENT_STOP; + } + } + + _onTextChanged() { + let searchString = this.get_text(); + if(!this.isEmpty()){ + if(!this.hasKeyFocus()) + this.grab_key_focus(); + if (!this.searchResults.getTopResult()?.has_style_pseudo_class("active")) + this.searchResults.getTopResult()?.add_style_pseudo_class("active") + this.add_style_pseudo_class('focus'); + this.set_secondary_icon(this._clearIcon); + } + else{ + if(!this.hasKeyFocus()) + this.remove_style_pseudo_class('focus'); + this.set_secondary_icon(null); + } + + if(this.triggerSearchChangeEvent) + this.emit('search-changed', searchString); + } + + _onKeyPress(actor, event) { + let symbol = event.get_key_symbol(); + if (symbol == Clutter.KEY_Return || + symbol == Clutter.KEY_KP_Enter) { + if (!this.isEmpty()) { + if (this.searchResults.getTopResult()) { + this.searchResults.getTopResult().activate(event); + } + } + return Clutter.EVENT_STOP; + } + this.emit('entry-key-press', event); + return Clutter.EVENT_PROPAGATE; + } + + _onKeyFocusIn() { + this.add_style_pseudo_class('focus'); + this.emit('entry-key-focus-in'); + return Clutter.EVENT_PROPAGATE; + } + + _onDestroy() { + if (this._textChangedId) { + this._text.disconnect(this._textChangedId); + this._textChangedId = null; + } + if (this._keyPressId) { + this._text.disconnect(this._keyPressId); + this._keyPressId = null; + } + if (this._keyFocusInId) { + this._text.disconnect(this._keyFocusInId); + this._keyFocusInId = null; + } + if(this._searchIconClickedId){ + this.disconnect(this._searchIconClickedId); + this._searchIconClickedId = null; + } + } +}); + +/** + * This class is responsible for the appearance of the menu button. + */ +var MenuButtonWidget = class Arc_Menu_MenuButtonWidget{ + constructor() { + this.actor = new St.BoxLayout({ + style_class: 'panel-status-menu-box', + pack_start: false + }); + this._arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + this._arrowIcon.add_style_class_name('arc-menu-arrow'); + + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + reactive: true, + }); + this._label = new St.Label({ + text: _("Applications"), + y_expand: true, + style_class: 'arc-menu-text', + y_align: Clutter.ActorAlign.CENTER, + }); + + this.actor.add_child(this._icon); + this.actor.add_child(this._label); + this.actor.add_child(this._arrowIcon); + } + + setActiveStylePseudoClass(enable){ + if(enable){ + this._arrowIcon.add_style_pseudo_class('active'); + this._icon.add_style_pseudo_class('active'); + this._label.add_style_pseudo_class('active'); + } + else{ + this._arrowIcon.remove_style_pseudo_class('active'); + this._icon.remove_style_pseudo_class('active'); + this._label.remove_style_pseudo_class('active'); + } + } + + updateArrowIconSide(side){ + let iconName; + switch (side) { + case St.Side.TOP: + iconName = 'pan-down-symbolic'; + break; + case St.Side.RIGHT: + iconName = 'pan-start-symbolic'; + break; + case St.Side.BOTTOM: + iconName = 'pan-up-symbolic'; + break; + case St.Side.LEFT: + iconName = 'pan-end-symbolic'; + break; + } + this._arrowIcon.icon_name = iconName; + } + + getPanelLabel() { + return this._label; + } + + getPanelIcon() { + return this._icon; + } + + showArrowIcon() { + if (!this.actor.contains(this._arrowIcon)) { + this.actor.add_child(this._arrowIcon); + } + } + + hideArrowIcon() { + if (this.actor.contains(this._arrowIcon)) { + this.actor.remove_child(this._arrowIcon); + } + } + + showPanelIcon() { + if (!this.actor.contains(this._icon)) { + this.actor.add_child(this._icon); + } + } + + hidePanelIcon() { + if (this.actor.contains(this._icon)) { + this.actor.remove_child(this._icon); + } + } + + showPanelText() { + if (!this.actor.contains(this._label)) { + this.actor.add_child(this._label); + } + } + + hidePanelText() { + this._label.style = ''; + if (this.actor.contains(this._label)) { + this.actor.remove_child(this._label); + } + } + + setPanelTextStyle(style){ + this._label.style = style; + } +}; + +var DashMenuButtonWidget = class Arc_Menu_DashMenuButtonWidget{ + constructor(menuButton, settings) { + this._menuButton = menuButton; + this._settings = settings; + this.actor = new St.Button({ + style_class: 'show-apps', + track_hover: true, + can_focus: true, + toggle_mode: false, + reactive: false + }); + this.actor._delegate = this; + this.icon = new imports.ui.iconGrid.BaseIcon(_("ArcMenu"), + { setSizeManually: true, + showLabel: false, + createIcon: this._createIcon.bind(this) }); + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + icon_size: 15, + track_hover:true, + reactive: true + }); + this.icon._delegate = this.actor; + this._labelText = _("ArcMenu"); + this.label = new St.Label({ style_class: 'dash-label' }); + this.label.hide(); + Main.layoutManager.addChrome(this.label); + this.label_actor = this.label; + this.actor.set_child(this.icon); + + this.child = this.actor; + } + showLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.actor.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1; + let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let x, y, xOffset, yOffset; + + let position = this._menuButton._panel._settings.get_enum('dock-position'); + this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); + let labelOffset = node.get_length('-x-offset'); + switch (position) { + case St.Side.LEFT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = stageX + this.actor.get_width() + xOffset; + break; + case St.Side.RIGHT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = Math.round(stageX) - labelWidth - xOffset; + break; + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + case St.Side.BOTTOM: + yOffset = labelOffset; + y = stageY - labelHeight - yOffset; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + } + + // keep the label inside the screen border + // Only needed fot the x coordinate. + + // Leave a few pixel gap + let gap = 5; + let monitor = Main.layoutManager.findMonitorForActor(this.actor); + if (x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + + this.label.remove_all_transitions(); + this.label.set_position(x, y); + this.label.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD + }); + } + hideLabel() { + this.label.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.label.hide() + }); + } + _createIcon(size) { + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + icon_size: size, + reactive: true + }); + let path = this._settings.get_string('custom-menu-button-icon'); + let iconString = Utils.getMenuButtonIcon(this._settings, path); + this._icon.set_gicon(Gio.icon_new_for_string(iconString)); + + return this._icon; + } + getPanelIcon() { + return this._icon; + } +}; + +var WorldClocksSection = GObject.registerClass(class Arc_Menu_WorldClocksSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this._clock = new imports.gi.GnomeDesktop.WallClock(); + this._clockNotifyId = 0; + + this._locations = []; + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._grid = new St.Widget({ style_class: 'world-clocks-grid', + x_expand: true, + layout_manager: layout }); + layout.hookup_style(this._grid); + + this.add_child(this._grid); + + this._clocksApp = null; + this._clocksProxy = new ClocksProxy( + Gio.DBus.session, + 'org.gnome.clocks', + '/org/gnome/clocks', + this._onProxyReady.bind(this), + null /* cancellable */, + Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES); + + this._clockSettings = new Gio.Settings({ + schema_id: 'org.gnome.shell.world-clocks', + }); + this.clocksChangedID = this._clockSettings.connect('changed', this._clocksChanged.bind(this)); + this._clocksChanged(); + + this._appSystem = Shell.AppSystem.get_default(); + this.syncID = this._appSystem.connect('installed-changed', + this._sync.bind(this)); + this._sync(); + } + + _onDestroy(){ + if(this.syncID){ + this._appSystem.disconnect(this.syncID); + this.syncID = null; + } + if(this.clocksChangedID){ + this._clockSettings.disconnect(this.clocksChangedID); + this.clocksChangedID = null; + } + if(this.clocksProxyID){ + this._clocksProxy.disconnect(this.clocksProxyID); + this.clocksProxyID = null; + } + if (this._clockNotifyId){ + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = null; + } + } + + activate(event) { + super.activate(event); + if (this._clocksApp){ + this._clocksApp.activate(); + } + } + + _sync() { + this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); + this.visible = this._clocksApp != null; + } + + _clocksChanged() { + this._grid.destroy_all_children(); + this._locations = []; + + let world = imports.gi.GWeather.Location.get_world(); + let clocks = this._clockSettings.get_value('locations').deep_unpack(); + for (let i = 0; i < clocks.length; i++) { + let l = world.deserialize(clocks[i]); + if (l && l.get_timezone() != null) + this._locations.push({ location: l }); + } + + this._locations.sort((a, b) => { + return a.location.get_timezone().get_offset() - + b.location.get_timezone().get_offset(); + }); + + let layout = this._grid.layout_manager; + let title = this._locations.length == 0 + ? _("Add world clocks…") + : _("World Clocks"); + let header = new St.Label({ x_align: Clutter.ActorAlign.START, + text: title }); + header.style = "font-weight: bold;"; + layout.attach(header, 0, 0, 2, 1); + this.label_actor = header; + + let localOffset = GLib.DateTime.new_now_local().get_utc_offset(); + + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i].location; + + let name = l.get_city_name() || l.get_name(); + let label = new St.Label({ text: name, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true }); + label.style = "font-weight: normal; font-size: 0.9em;"; + let time = new St.Label(); + time.style = "font-feature-settings: \"tnum\"; font-size: 1.2em;"; + let otherOffset = this._getTimeAtLocation(l).get_utc_offset(); + let offset = (otherOffset - localOffset) / GLib.TIME_SPAN_HOUR; + let fmt = Math.trunc(offset) == offset ? '%s%.0f' : '%s%.1f'; + let prefix = offset >= 0 ? '+' : '-'; + let tz = new St.Label({ text: fmt.format(prefix, Math.abs(offset)), + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER }); + tz.style = "font-feature-settings: \"tnum\"; font-size: 0.9em;"; + if (this._grid.text_direction == Clutter.TextDirection.RTL) { + layout.attach(tz, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(label, 2, i + 1, 1, 1); + } else { + layout.attach(label, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(tz, 2, i + 1, 1, 1); + } + + this._locations[i].actor = time; + } + + if (this._grid.get_n_children() > 1) { + if (!this._clockNotifyId) { + this._clockNotifyId = + this._clock.connect('notify::clock', this._updateLabels.bind(this)); + } + this._updateLabels(); + } else { + if (this._clockNotifyId) + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = 0; + } + } + + _getTimeAtLocation(location) { + let tz = GLib.TimeZone.new(location.get_timezone().get_tzid()); + return GLib.DateTime.new_now(tz); + } + + _updateLabels() { + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i]; + let now = this._getTimeAtLocation(l.location); + l.actor.text = Util.formatTime(now, { timeOnly: true }); + } + } + + _onProxyReady(proxy, error) { + if (error) { + log(`Failed to create GNOME Clocks proxy: ${error}`); + return; + } + + this.clocksProxyID = this._clocksProxy.connect('g-properties-changed', + this._onClocksPropertiesChanged.bind(this)); + this._onClocksPropertiesChanged(); + } + + _onClocksPropertiesChanged() { + if (this._clocksProxy.g_name_owner == null) + return; + + this._clockSettings.set_value('locations', + new GLib.Variant('av', this._clocksProxy.Locations)); + } +}); + +var WeatherSection = GObject.registerClass(class Arc_Menu_WeatherSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this.x_align = Clutter.ActorAlign.FILL; + this._weatherClient = new imports.misc.weather.WeatherClient(); + + let box = new St.BoxLayout({ + vertical: true, + x_expand: true, + }); + + this.add_child(box); + + let titleBox = new St.BoxLayout({ }); + let label = new St.Label({ + x_align: Clutter.ActorAlign.START, + x_expand: true, + y_align: Clutter.ActorAlign.END, + text: _('Weather'), + }) + label.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(label); + box.add_child(titleBox); + + this._titleLocation = new St.Label({ + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.END, + }); + this._titleLocation.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(this._titleLocation); + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._forecastGrid = new St.Widget({ + style_class: 'weather-grid', + layout_manager: layout, + }); + layout.hookup_style(this._forecastGrid); + box.add_child(this._forecastGrid); + + this.syncID = this._weatherClient.connect('changed', this._sync.bind(this)); + this._sync(); + + } + _onDestroy(){ + if(this.syncID){ + this._weatherClient.disconnect(this.syncID); + this.syncID = null; + } + this._weatherClient = null; + } + vfunc_map() { + this._weatherClient.update(); + super.vfunc_map(); + } + + activate(event) { + super.activate(event); + this._weatherClient.activateApp(); + } + + _getInfos() { + let forecasts = this._weatherClient.info.get_forecast_list(); + + let now = GLib.DateTime.new_now_local(); + let current = GLib.DateTime.new_from_unix_local(0); + let infos = []; + for (let i = 0; i < forecasts.length; i++) { + const [valid, timestamp] = forecasts[i].get_value_update(); + if (!valid || timestamp === 0) + continue; // 0 means 'never updated' + + const datetime = GLib.DateTime.new_from_unix_local(timestamp); + if (now.difference(datetime) > 0) + continue; // Ignore earlier forecasts + + if (datetime.difference(current) < GLib.TIME_SPAN_HOUR) + continue; // Enforce a minimum interval of 1h + + if (infos.push(forecasts[i]) == 5) + break; // Use a maximum of five forecasts + + current = datetime; + } + return infos; + } + + _addForecasts() { + let layout = this._forecastGrid.layout_manager; + + let infos = this._getInfos(); + if (this._forecastGrid.text_direction == Clutter.TextDirection.RTL) + infos.reverse(); + + let col = 0; + infos.forEach(fc => { + const [valid_, timestamp] = fc.get_value_update(); + let timeStr = Util.formatTime(new Date(timestamp * 1000), { + timeOnly: true + }); + const [, tempValue] = fc.get_value_temp(imports.gi.GWeather.TemperatureUnit.DEFAULT); + const tempPrefix = tempValue >= 0 ? ' ' : ''; + + let time = new St.Label({ + text: timeStr, + x_align: Clutter.ActorAlign.CENTER, + }); + time.style = "font-size: 0.8em;" + let icon = new St.Icon({ + style_class: 'weather-forecast-icon', + icon_name: fc.get_symbolic_icon_name(), + x_align: Clutter.ActorAlign.CENTER, + x_expand: true, + }); + let temp = new St.Label({ + text: '%s%.0f°'.format(tempPrefix, tempValue), + x_align: Clutter.ActorAlign.CENTER, + }); + + temp.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + time.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + + layout.attach(time, col, 0, 1, 1); + layout.attach(icon, col, 1, 1, 1); + layout.attach(temp, col, 2, 1, 1); + col++; + }); + } + + _setStatusLabel(text) { + let layout = this._forecastGrid.layout_manager; + let label = new St.Label({ text }); + layout.attach(label, 0, 0, 1, 1); + } + + _updateForecasts() { + this._forecastGrid.destroy_all_children(); + + if (!this._weatherClient.hasLocation) { + this._setStatusLabel(_("Select a location…")); + return; + } + + let info = this._weatherClient.info; + let loc = info.get_location(); + if (loc.get_level() !== imports.gi.GWeather.LocationLevel.CITY && loc.has_coords()) { + let world = imports.gi.GWeather.Location.get_world(); + loc = world.find_nearest_city(...loc.get_coords()); + } + this._titleLocation.text = loc.get_name(); + + if (this._weatherClient.loading) { + this._setStatusLabel(_("Loading…")); + return; + } + + if (info.is_valid()) { + this._addForecasts(); + return; + } + + if (info.network_error()) + this._setStatusLabel(_("Go online for weather information")); + else + this._setStatusLabel(_("Weather information is currently unavailable")); + } + + _sync() { + this.visible = this._weatherClient.available; + + if (!this.visible) + return; + + this._titleLocation.visible = this._weatherClient.hasLocation; + + this._updateForecasts(); + } +}); + +function _isToday(date) { + let now = new Date(); + return now.getYear() == date.getYear() && + now.getMonth() == date.getMonth() && + now.getDate() == date.getDate(); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js new file mode 100644 index 0000000..a0c1d16 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js @@ -0,0 +1,456 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.buttonPressEventID = global.stage.connect("button-press-event", () => { + if(this.arcMenu.isOpen && this.backButton.visible){ + let event = Clutter.get_current_event(); + if(event.get_button() === 8){ + this.backButton.activate(event); + } + } + }); + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'left-panel' + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + this.leftBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBox.add_child(separator); + + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(this.backButton.actor); + + this.viewProgramsButton = new MW.ViewAllPrograms(this); + this.navigateBox.add_child(this.viewProgramsButton.actor); + this.leftBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 5px 10px 0px 10px;"; + this.leftBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length > 0){ + this.placesShortcuts = true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length > 0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw = true; + if(shouldDraw){ + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px; padding: 0px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + this.extraCategoriesLinksBox = new St.BoxLayout({ + vertical: true + }); + this.extraCategoriesLinksBox.hide(); + this.extraCategoriesSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + + let extraCategoriesLinksLocation = this._settings.get_enum('arcmenu-extra-categories-links-location'); + if(extraCategoriesLinksLocation === Constants.MenuItemLocation.TOP) + this.leftBox.insert_child_below(this.extraCategoriesLinksBox, this.applicationsScrollBox); + else + this.navigateBox.insert_child_above(this.extraCategoriesLinksBox, this.navigateBox.get_child_at_index(0)); + this.extraCategoriesLinksBox.add_child(this.extraCategoriesSeparator); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + _createExtraCategoriesLinks(){ + this.showExtraCategoriesLinksBox = false; + let extraCategories = this._settings.get_value("arcmenu-extra-categories-links").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + //Don't create extra categories quick links if + //the default menu view is the categories list + if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + return; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.ALL_PROGRAMS && shouldShow && defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + shouldShow = false; + if(shouldShow){ + let extraCategoryItem = this.categoryDirectories.get(categoryEnum); + if(!extraCategoryItem) + continue; + + this.showExtraCategoriesLinksBox = true; + if(extraCategoryItem.get_parent()) + extraCategoryItem.get_parent().remove_child(extraCategoryItem); + + this.extraCategoriesLinksBox.insert_child_below(extraCategoryItem, this.extraCategoriesSeparator); + } + } + if(this.showExtraCategoriesLinksBox) + this.extraCategoriesLinksBox.show(); + else + this.extraCategoriesLinksBox.hide(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.hasPinnedApps = true; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + this._createExtraCategoriesLinks(); + } + + displayPinnedApps(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS){ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayAllApps(showBackButton = true){ + super.displayAllApps(); + this.viewProgramsButton.actor.hide(); + + if(showBackButton){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + } + else{ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.backButton.actor.hide(); + } + } + + displayCategories(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else{ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.displayPinnedApps(); + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this.displayFrequentApps(); + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + this.displayAllApps(false); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let isContainedInCategory = false; + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST, null, isContainedInCategory); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + displayRecentFiles(){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + super.displayRecentFiles(); + } + + _clearActorsFromBox(box){ + //keep track of the previous category for the back button. + this.previousCategoryType = this.activeCategoryType; + super._clearActorsFromBox(box); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.buttonPressEventID){ + global.stage.disconnect(this.buttonPressEventID); + this.buttonPressEventID = null; + } + super.destroy() + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js new file mode 100644 index 0000000..dce09de --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js @@ -0,0 +1,285 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 4, + RowSpacing: 4, + VerticalMainBox: true, + DefaultMenuWidth: 460, + DefaultIconGridStyle: 'LargeRectIconGrid', + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBoxStyle = "margin: 0px 0px 10px 0px; spacing: 0px; background-color: rgba(186, 196,201, 0.1); padding: 11px 5px;"+ + "border-color:rgba(186, 196,201, 0.2); border-bottom-width: 1px;"; + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.topBoxStyle + }); + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 5px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.subMainBox.add_child(this.topBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 12px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "margin: 0px 15px; spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.x_expand = true; + this.user.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + + let filesButton = new MW.ShortcutMenuItem(this, _("Files"), "system-file-manager", "org.gnome.Nautilus.desktop", Constants.DisplayType.BUTTON); + if(filesButton.shouldShow) + this.actionsBox.add_child(filesButton.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton) + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton) + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.IconGridSize = 42; + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + setDefaultMenuView(){ + this.setGridLayout(Constants.DisplayType.GRID, 4, 4); + this.layoutProperties.IconGridSize = 42; + super.setDefaultMenuView(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 3); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 4, 4, false); + } + + updateStyle(){ + super.updateStyle(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + const RoundBottomBorder = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + const RoundTopBorder = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + RoundBottomBorder; + this.topBox.style = this.topBoxStyle + RoundTopBorder; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.layoutProperties.IconGridSize = 26; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.subMainBox.insert_child_at_index(this.allAppsButton, 1); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.subMainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.subMainBox.contains(this.backButton)) + this.subMainBox.remove_child(this.backButton); + if(this.subMainBox.contains(this.allAppsButton)) + this.subMainBox.remove_child(this.allAppsButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.style = 'padding: 0px 15px 10px 15px;' + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.leaveButton.destroy(); + this.backButton.destroy(); + this.allAppsButton.destroy(); + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js new file mode 100644 index 0000000..af9d2c4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js @@ -0,0 +1,1128 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, GMenu, Gtk, Shell, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const appSys = Shell.AppSystem.get_default(); +const ArcSearch = Me.imports.search; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MenuLayouts = Me.imports.menulayouts; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const Utils = Me.imports.utils; + +//This class handles the core functionality of all the menu layouts. +//Each menu layout extends this class. +var BaseLayout = class { + constructor(menuButton, layoutProperties){ + this.menuButton = menuButton; + this._settings = menuButton._settings; + this.mainBox = menuButton.mainBox; + this.contextMenuManager = menuButton.contextMenuManager; + this.subMenuManager = menuButton.subMenuManager; + this.arcMenu = menuButton.arcMenu; + this.section = menuButton.section; + this.layout = this._settings.get_enum('menu-layout'); + this.layoutProperties = layoutProperties; + this._focusChild = null; + this.shouldLoadPinnedApps = true; + this.hasPinnedApps = false; + + if(this.layoutProperties.Search){ + this.searchResults = new ArcSearch.SearchResults(this); + this.searchBox = new MW.SearchBox(this); + this._searchBoxChangedId = this.searchBox.connect('search-changed', this._onSearchBoxChanged.bind(this)); + this._searchBoxKeyPressId = this.searchBox.connect('entry-key-press', this._onSearchBoxKeyPress.bind(this)); + } + + this._mainBoxKeyPressId = this.mainBox.connect('key-press-event', this._onMainBoxKeyPress.bind(this)); + + this._tree = new GMenu.Tree({ menu_basename: 'applications.menu' }); + this._treeChangedId = this._tree.connect('changed', () => this.reloadApplications()); + + this._gnomeFavoritesReloadID = AppFavorites.getAppFavorites().connect('changed', () => { + if(this.categoryDirectories){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem) + this._loadGnomeFavorites(categoryMenuItem); + } + }); + + this.mainBox.vertical = this.layoutProperties.VerticalMainBox; + + this.createLayout(); + this.updateStyle(); + } + + createLayout(){ + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.activeCategoryType = -1; + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.applicationsGrid = new St.Widget({ + x_expand: true, + x_align: this.layoutProperties.DisplayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.applicationsGrid); + } + + setDefaultMenuView(){ + if(this.layoutProperties.Search){ + this.searchBox.clearWithoutSearchChangeEvent(); + this.searchResults.setTerms([]); + } + + this._clearActorsFromBox(); + this.resetScrollBarPosition(); + } + + getColumnsFromActor(actor){ + let gridIconWidth = this.getActorWidthFromStyleClass(actor.name); + return this.getBestFitColumns(gridIconWidth); + } + + getColumnsFromGridIconSizeSetting(){ + let gridIconWidth; + let iconSizeEnum = this._settings.get_enum("menu-item-grid-icon-size"); + + if(iconSizeEnum === Constants.GridIconSize.DEFAULT) + gridIconWidth = this.getActorWidthFromStyleClass(this.layoutProperties.DefaultIconGridStyle); + else{ + Constants.GridIconInfo.forEach((info) => { + if(iconSizeEnum === info.ENUM){ + gridIconWidth = info.SIZE; + return; + } + }); + } + return this.getBestFitColumns(gridIconWidth); + } + + getBestFitColumns(gridIconWidth){ + let width = this.layoutProperties.MenuWidth; + let spacing = this.layoutProperties.ColumnSpacing; + let columns = Math.floor(width / (gridIconWidth + spacing)); + return columns; + } + + getActorWidthFromStyleClass(name){ + let size; + + Constants.GridIconInfo.forEach((info) => { + if(name === info.NAME){ + size = info.SIZE; + return; + } + }); + return size; + } + + resetScrollBarPosition(){ + let appsScrollBoxAdj; + + if(this.applicationsScrollBox){ + appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.categoriesScrollBox){ + appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.shortcutsScrollBox){ + appsScrollBoxAdj = this.shortcutsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.actionsScrollBox){ + appsScrollBoxAdj = this.actionsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + } + + reloadApplications(){ + //Don't reload applications if the menu is open. + //Instead, reload on menu-closed event. + //Prevents the menu from jumping to its default view + //when reloadApplications() is called. + if(this.arcMenu.isOpen){ + if(!this._menuClosedID){ + this._menuClosedID = this.arcMenu.connect('menu-closed', () => { + this.reloadApplications(); + if(this._menuClosedID){ + this.arcMenu.disconnect(this._menuClosedID); + this._menuClosedID = null; + } + }); + } + return; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(this.layoutProperties.Search){ + this.searchBox.updateStyle(this._settings.get_boolean('disable-searchbox-border')) + customStyle ? this.searchResults.setStyle('arc-menu-status-text') : this.searchResults.setStyle(''); + if(customStyle){ + this.searchBox.remove_style_class_name('default-search-entry'); + this.searchBox.add_style_class_name('arc-search-entry'); + } + else{ + this.searchBox.remove_style_class_name('arc-search-entry'); + this.searchBox.add_style_class_name('default-search-entry'); + } + } + } + + loadCategories(displayType = Constants.DisplayType.LIST){ + this.applicationsMap = new Map(); + this._tree.load_sync(); + let root = this._tree.get_root_directory(); + let iter = root.iter(); + let nextType; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.DIRECTORY) { + let dir = iter.get_directory(); + if (!dir.get_is_nodisplay()) { + let categoryId = dir.get_menu_id(); + let categoryMenuItem; + if(displayType === Constants.DisplayType.SIMPLE_CATEGORY) + categoryMenuItem = new MW.SimpleMenuItem(this, dir); + else if(displayType === Constants.DisplayType.SUBMENU_CATEGORY) + categoryMenuItem = new MW.CategorySubMenuItem(this, dir); + else + categoryMenuItem = new MW.CategoryMenuItem(this, dir, displayType); + this.categoryDirectories.set(categoryId, categoryMenuItem); + let foundRecentlyInstallApp = this._loadCategory(categoryId, dir); + categoryMenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + //Sort the App List Alphabetically + categoryMenuItem.appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + } + } + } + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.ALL_PROGRAMS); + if(categoryMenuItem){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + //Show Recently Installed Indicator on All Programs category + if(value.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + categoryMenuItem.appList = appList; + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem){ + this._loadGnomeFavorites(categoryMenuItem); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + if(categoryMenuItem){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this.hasPinnedApps = true; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + if(categoryMenuItem){ + this._loadRecentFiles(categoryMenuItem); + } + + } + + _loadCategory(categoryId, dir, submenuItem) { + let iter = dir.iter(); + let nextType; + let foundRecentlyInstallApp = false; + let isLayoutSimple2 = this.layout === Constants.MenuLayout.SIMPLE_2; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.ENTRY) { + let entry = iter.get_entry(); + let id; + try { + id = entry.get_desktop_file_id(); + } catch (e) { + continue; + } + let app = appSys.lookup_app(id); + if (!app) + app = new Shell.App({ app_info: entry.get_app_info() }); + if (app.get_app_info().should_show()){ + let item = this.applicationsMap.get(app); + if (!item) { + let isContainedInCategory = true; + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType, null, isContainedInCategory); + } + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled && item.isRecentlyInstalled) + foundRecentlyInstallApp = true; + if(!submenuItem){ + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(app); + this.applicationsMap.set(app, item); + } + else{ + submenuItem.applicationsMap.set(app, item); + } + } + } + else if (nextType == GMenu.TreeItemType.DIRECTORY) { + let subdir = iter.get_directory(); + if (!subdir.get_is_nodisplay()){ + if(this._settings.get_boolean('enable-sub-menus') && this.layoutProperties.DisplayType === Constants.DisplayType.LIST && !isLayoutSimple2){ + let submenuItem = this.applicationsMap.get(subdir); + if (!submenuItem) { + submenuItem = new MW.CategorySubMenuItem(this, subdir); + submenuItem._setParent(this.arcMenu); + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(subdir); + this.applicationsMap.set(subdir, submenuItem); + } + let recentlyInstallApp = this._loadCategory(categoryId, subdir, submenuItem); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + submenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + } + else{ + let recentlyInstallApp = this._loadCategory(categoryId, subdir); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + } + } + } + } + return foundRecentlyInstallApp; + } + + setRecentlyInstalledIndicator(){ + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.setRecentlyInstalledIndicator(false); + for(let i = 0; i < categoryMenuItem.appList.length; i++){ + let item = this.applicationsMap.get(categoryMenuItem.appList[i]); + if(!item) + continue; + if(item instanceof MW.CategorySubMenuItem){ + item.setRecentlyInstalledIndicator(false); + for(let menuItem of item.applicationsMap.values()){ + if(menuItem.isRecentlyInstalled){ + item.setRecentlyInstalledIndicator(true); + break; + } + } + } + if(item.isRecentlyInstalled){ + categoryMenuItem.setRecentlyInstalledIndicator(true); + break; + } + } + } + } + } + + displayCategories(categoriesBox){ + if(!categoriesBox){ + categoriesBox = this.applicationsBox; + } + this._clearActorsFromBox(categoriesBox); + + this._futureActiveItem = false; + + for(let categoryMenuItem of this.categoryDirectories.values()){ + if(categoryMenuItem.get_parent()) + continue; + categoriesBox.add_child(categoryMenuItem.actor); + if(!this._futureActiveItem){ + this._futureActiveItem = categoryMenuItem; + } + } + + this.activeMenuItem = this._futureActiveItem; + } + + _loadGnomeFavorites(categoryMenuItem){ + let appList = AppFavorites.getAppFavorites().getFavorites(); + + //Show Recently Installed Indicator on GNOME favorites category + for(let i = 0; i < appList.length; i++){ + let item = this.applicationsMap.get(appList[i]); + if(item && item.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + } + + categoryMenuItem.appList = appList; + if(this.activeCategoryType === Constants.CategoryType.FAVORITES) + categoryMenuItem.displayAppList(); + } + + _loadRecentFiles(){ + if(!this.recentFilesManager) + this.recentFilesManager = new RecentFilesManager(); + } + + displayRecentFiles(box = this.applicationsBox, callback){ + const homeRegExp = new RegExp('^(' + GLib.get_home_dir() + ')'); + this._clearActorsFromBox(box); + this._futureActiveItem = false; + + this.recentFilesManager.filterRecentFiles(recentFile => { + let file = Gio.File.new_for_uri(recentFile.get_uri()); + let filePath = file.get_path(); + let name = recentFile.get_display_name(); + let icon = Gio.content_type_get_symbolic_icon(recentFile.get_mime_type()).to_string(); + let isContainedInCategory = true; + + let placeMenuItem = this.createMenuItem([name, icon, filePath], Constants.DisplayType.LIST, isContainedInCategory); + placeMenuItem._path = file.get_parent()?.get_path() // can be null + placeMenuItem.style = "padding-right: 15px;"; + placeMenuItem.description = recentFile.get_uri_display().replace(homeRegExp, '~'); + placeMenuItem.fileUri = recentFile.get_uri(); + + placeMenuItem._removeBtn = new MW.ArcMenuButtonItem(this, null, 'edit-delete-symbolic'); + placeMenuItem._removeBtn.toggleMenuOnClick = false; + placeMenuItem._removeBtn.x_align = Clutter.ActorAlign.END; + placeMenuItem._removeBtn.x_expand = true; + placeMenuItem._removeBtn.add_style_class_name("arcmenu-small-button"); + placeMenuItem._removeBtn.setIconSize(14); + placeMenuItem._removeBtn.connect('activate', () => { + try { + let recentManager = this.recentFilesManager.getRecentManager(); + recentManager.remove_item(placeMenuItem.fileUri); + } catch(err) { + log(err); + } + + placeMenuItem.cancelPopupTimeout(); + placeMenuItem.contextMenu?.close(); + box.remove_child(placeMenuItem); + placeMenuItem.destroy(); + }); + + placeMenuItem.add_child(placeMenuItem._removeBtn); + box.add_child(placeMenuItem); + + if(!this._futureActiveItem){ + this._futureActiveItem = placeMenuItem; + this.activeMenuItem = this._futureActiveItem; + } + + if(callback) + callback(); + }); + } + + _displayPlaces() { + var SHORTCUT_TRANSLATIONS = [_("Home"), _("Documents"), _("Downloads"), _("Music"), _("Pictures"), _("Videos"), _("Computer"), _("Network")]; + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem) + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadExtraPinnedApps(pinnedAppsArray, separatorIndex){ + let pinnedApps = pinnedAppsArray; + //if the extraPinnedApps array is empty, create a default list of apps. + if(!pinnedApps.length || !Array.isArray(pinnedApps)){ + pinnedApps = this._createExtraPinnedAppsList(); + } + + for(let i = 0;i < pinnedApps.length; i += 3){ + if(i === separatorIndex * 3 && i !== 0) + this._addSeparator(); + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2]], Constants.DisplayType.BUTTON, isContainedInCategory); + placeMenuItem.actor.x_expand = false; + placeMenuItem.actor.y_expand = false; + placeMenuItem.actor.y_align = Clutter.ActorAlign.CENTER; + placeMenuItem.actor.x_align = Clutter.ActorAlign.CENTER; + this.actionsBox.add_child(placeMenuItem.actor); + } + } + + createMenuItem(menuItemArray, displayType, isContainedInCategory){ + let placeInfo, placeMenuItem; + let command = menuItemArray[2]; + let app = Shell.AppSystem.get_default().lookup_app(command); + + if(command === "ArcMenu_Home"){ + let homePath = GLib.get_home_dir(); + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(homePath), _("Home")); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Computer"){ + placeInfo = new PlaceDisplay.RootInfo(); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Network"){ + placeInfo = new PlaceDisplay.PlaceInfo('network', Gio.File.new_for_uri('network:///'), _('Network'),'network-workgroup-symbolic'); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Software"){ + let software = Utils.findSoftwareManager(); + if(software) + placeMenuItem = new MW.ShortcutMenuItem(this, _("Software"), 'system-software-install-symbolic', software, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Trash"){ + placeMenuItem = new MW.ShortcutMenuItem(this, _("Trash"), '', "ArcMenu_Trash", displayType, isContainedInCategory); + } + else if(command === Constants.ArcMenuSettingsCommand || command === "ArcMenu_Suspend" || command === "ArcMenu_LogOut" || command === "ArcMenu_PowerOff" + || command === "ArcMenu_Lock" || command === "ArcMenu_Restart" || command === "ArcMenu_HybridSleep" || command === "ArcMenu_Hibernate" || app){ + + placeMenuItem = new MW.ShortcutMenuItem(this, menuItemArray[0], menuItemArray[1], menuItemArray[2], displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Recent"){ + let uri = "recent:///"; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_uri(uri), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command.startsWith("ArcMenu_")){ + let path = command.replace("ArcMenu_",''); + + if(path === "Documents") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS; + else if(path === "Downloads") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOWNLOAD; + else if(path === "Music") + path = imports.gi.GLib.UserDirectory.DIRECTORY_MUSIC; + else if(path === "Pictures") + path = imports.gi.GLib.UserDirectory.DIRECTORY_PICTURES; + else if(path === "Videos") + path = imports.gi.GLib.UserDirectory.DIRECTORY_VIDEOS; + + path = GLib.get_user_special_dir(path); + if (path !== null){ + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + } + else{ + let path = command; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0]), (menuItemArray[1] !== "ArcMenu_Folder") ? Gio.icon_new_for_string(menuItemArray[1]) : null); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + return placeMenuItem; + } + + loadPinnedApps(){ + let pinnedApps = this._settings.get_strv('pinned-app-list'); + + this.pinnedAppsArray = null; + this.pinnedAppsArray = []; + + let categoryMenuItem = this.categoryDirectories ? this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS) : null; + let isContainedInCategory = categoryMenuItem ? true : false; + + for(let i = 0; i < pinnedApps.length; i += 3){ + if(i === 0 && pinnedApps[0] === "ArcMenu_WebBrowser") + this._updatePinnedAppsWebBrowser(pinnedApps); + + let pinnedAppsMenuItem = new MW.PinnedAppsMenuItem(this, pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2], this.layoutProperties.DisplayType, isContainedInCategory); + pinnedAppsMenuItem.connect('saveSettings', ()=> { + let array = []; + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + array.push(this.pinnedAppsArray[i]._name); + array.push(this.pinnedAppsArray[i]._iconPath); + array.push(this.pinnedAppsArray[i]._command); + } + this._settings.set_strv('pinned-app-list',array); + }); + this.pinnedAppsArray.push(pinnedAppsMenuItem); + } + + if(categoryMenuItem){ + categoryMenuItem.appList = null; + categoryMenuItem.appList = []; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + } + + _updatePinnedAppsWebBrowser(pinnedApps){ + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + if(pinnedApps[0] === "ArcMenu_WebBrowser"){ + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + + this._app = appSys.lookup_app(browserName); + if(this._app){ + pinnedApps[0] = this._app.get_name(); + pinnedApps[1] = ''; + pinnedApps[2] = this._app.get_id(); + } + else{ + pinnedApps.splice(0,3); + } + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + } + } + + displayPinnedApps(){ + this._clearActorsFromBox(); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + placesAddSeparator(id){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this._sections[id].add_child(separator); + } + + _redisplayPlaces(id) { + if(this._sections[id].get_n_children() > 0){ + this.bookmarksShorctus = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this._sections[id].destroy_all_children(); + } + this._createPlaces(id); + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + if(this.placesManager.get('network').length > 0) + this.networkDevicesShorctus = true; + if(this.placesManager.get('devices').length > 0) + this.externalDevicesShorctus=true; + if(this.placesManager.get('bookmarks').length > 0) + this.bookmarksShorctus = true; + + if(this._settings.get_boolean('show-bookmarks')){ + if(id === 'bookmarks' && places.length > 0){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + //create a separator if bookmark and software shortcut are both shown + if(this.bookmarksShorctus && this.softwareShortcuts){ + this.placesAddSeparator(id); + } + } + } + if(this._settings.get_boolean('show-external-devices')){ + if(id === 'devices'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if((this.externalDevicesShorctus && !this.networkDevicesShorctus) && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + if(id === 'network'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if(this.networkDevicesShorctus && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + } + } + + setActiveCategory(category, setActive = true){ + this._futureActiveItem = category; + this.activeMenuItem = category; + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + + _clearActorsFromBox(box){ + this.recentFilesManager?.cancelCurrentQueries(); + if(!box){ + box = this.applicationsBox; + this.activeCategoryType = -1; + } + let parent = box.get_parent(); + if(parent instanceof St.ScrollView){ + let scrollBoxAdj = parent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = box.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + box.remove_child(actor); + } + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + this.activeCategoryType = category; + grid.remove_all_children(); + let count = 0; + let top = -1; + let left = 0; + this._futureActiveItem = false; + let currentCharacter; + let alphabetizeAllPrograms = this._settings.get_boolean("alphabetize-all-programs") && this.layoutProperties.DisplayType === Constants.DisplayType.LIST; + let rtl = this.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + let columns = -1; + + for (let i = 0; i < apps.length; i++) { + let app = apps[i]; + let item; + let shouldShow = true; + + if(category === Constants.CategoryType.PINNED_APPS || category === Constants.CategoryType.HOME_SCREEN){ + item = app; + if(!item.shouldShow) + shouldShow = false; + } + else{ + item = this.applicationsMap.get(app); + if (!item) { + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType); + this.applicationsMap.set(app, item); + } + } + + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + + if(shouldShow){ + if(columns === -1){ + if(grid.layout_manager.forceGridColumns) + columns = grid.layout_manager.forceGridColumns; + else if(this.layoutProperties.DisplayType === Constants.DisplayType.GRID) + columns = this.getColumnsFromActor(item); + else + columns = 1; + grid.layout_manager.gridColumns = columns; + } + + if(!rtl && (count % columns === 0)){ + top++; + left = 0; + } + else if(rtl && (left === 0)){ + top++; + left = columns; + } + + if(alphabetizeAllPrograms && category === Constants.CategoryType.ALL_PROGRAMS){ + if(currentCharacter !== app.get_name().charAt(0).toLowerCase()){ + currentCharacter = app.get_name().charAt(0).toLowerCase(); + + let label = this._createLabelWithSeparator(currentCharacter.toUpperCase()); + grid.layout_manager.attach(label, left, top, 1, 1); + top++; + } + } + + grid.layout_manager.attach(item, left, top, 1, 1); + item.gridLocation = [left, top]; + + if(item instanceof MW.CategorySubMenuItem){ + top++; + grid.layout_manager.attach(item.menu.actor, left, top, 1, 1); + } + + if(!rtl) + left++; + else if(rtl) + left--; + count++; + + if(!this._futureActiveItem && grid === this.applicationsGrid){ + this._futureActiveItem = item; + } + } + } + if(this.applicationsBox && !this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + if(this._futureActiveItem) + this.activeMenuItem = this._futureActiveItem; + } + + displayAllApps(){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + } + + get activeMenuItem() { + return this._activeMenuItem; + } + + set activeMenuItem(item) { + let itemChanged = item !== this._activeMenuItem; + if(itemChanged){ + this._activeMenuItem = item; + if(this.arcMenu.isOpen && item && this.layoutProperties.SupportsCategoryOnHover) + item.grab_key_focus(); + else if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + if(this.layout === Constants.MenuLayout.LAUNCHER && !this.layoutProperties.StandaloneRunner && item) + this.createActiveSearchItemPanel(item); + } + } + + _onSearchBoxChanged(searchBox, searchString) { + if(searchBox.isEmpty()){ + this.searchResults.hide(); + this.setDefaultMenuView(); + } + else{ + this._clearActorsFromBox(); + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.show(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms(searchString.split(/\s+/)); + } + } + + _onSearchBoxKeyPress(searchBox, event) { + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_Up) + return Clutter.EVENT_PROPAGATE; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + let cursorPosition = this.searchBox.clutter_text.get_cursor_position(); + + if(cursorPosition === Constants.CaretPosition.END && symbol === Clutter.KEY_Right) + cursorPosition = Constants.CaretPosition.END; + else if(cursorPosition === Constants.CaretPosition.START && symbol === Clutter.KEY_Left) + cursorPosition = Constants.CaretPosition.START; + else + cursorPosition = Constants.CaretPosition.MIDDLE; + + if(cursorPosition === Constants.CaretPosition.END || cursorPosition === Constants.CaretPosition.START){ + let navigateActor = this.activeMenuItem; + if(this.searchResults.hasActiveResult()){ + navigateActor = this.searchResults.getTopResult(); + if(navigateActor.has_style_pseudo_class("active")){ + navigateActor.grab_key_focus(); + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + navigateActor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + if(!navigateActor) + return Clutter.EVENT_PROPAGATE; + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + return Clutter.EVENT_PROPAGATE; + default: + return Clutter.EVENT_PROPAGATE; + } + } + + _onMainBoxKeyPress(actor, event) { + if (event.has_control_modifier()) { + if(this.searchBox) + this.searchBox.grab_key_focus(); + return Clutter.EVENT_PROPAGATE; + } + + let symbol = event.get_key_symbol(); + let unicode = Clutter.keysym_to_unicode(symbol); + + switch (symbol) { + case Clutter.KEY_BackSpace: + if(this.searchBox && !this.searchBox.hasKeyFocus() && !this.searchBox.isEmpty()){ + this.searchBox.grab_key_focus(); + let newText = this.searchBox.getText().slice(0, -1); + this.searchBox.setText(newText); + } + return Clutter.EVENT_PROPAGATE; + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down) + direction = St.DirectionType.DOWN; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT + if (symbol === Clutter.KEY_Up) + direction = St.DirectionType.UP; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + if(this.layoutProperties.Search && this.searchBox.hasKeyFocus() && this.searchResults.hasActiveResult() && this.searchResults.get_parent()){ + if(this.searchResults.getTopResult().has_style_pseudo_class("active")){ + this.searchResults.getTopResult().actor.grab_key_focus(); + return actor.navigate_focus(global.stage.key_focus, direction, false); + } + this.searchResults.getTopResult().actor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + else if(global.stage.key_focus === this.mainBox && symbol === Clutter.KEY_Up){ + return actor.navigate_focus(global.stage.key_focus, direction, true); + } + else if(global.stage.key_focus === this.mainBox){ + this.activeMenuItem.grab_key_focus(); + return Clutter.EVENT_STOP; + } + + return actor.navigate_focus(global.stage.key_focus, direction, false); + case Clutter.KEY_Tab: + case Clutter.KEY_KP_Tab: + case Clutter.KEY_KP_Enter: + case Clutter.KEY_Return: + case Clutter.KEY_Escape: + return Clutter.EVENT_PROPAGATE; + default: + if (unicode !== 0 && this.searchBox) { + global.stage.set_key_focus(this.searchBox.clutter_text); + let synthEvent = event.copy(); + synthEvent.set_source(this.searchBox.clutter_text); + this.searchBox.clutter_text.event(synthEvent, false); + } + } + return Clutter.EVENT_PROPAGATE; + } + + destroy(){ + if(this.recentFilesManager){ + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + } + + if(this._treeChangedId){ + this._tree.disconnect(this._treeChangedId); + this._treeChangedId = null; + this._tree = null; + } + + if(this.applicationsBox){ + if(this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.remove_child(this.applicationsGrid); + } + + if(this.network){ + this.network.destroy(); + this.networkMenuItem.destroy(); + } + + if(this.computer){ + this.computer.destroy(); + this.computerMenuItem.destroy(); + } + + if(this.placesManager){ + for(let id in this._sections){ + this._sections[id].get_children().forEach((child) =>{ + child.destroy(); + }); + }; + if(this.placeManagerUpdatedID){ + this.placesManager.disconnect(this.placeManagerUpdatedID); + this.placeManagerUpdatedID = null; + } + this.placesManager.destroy(); + this.placesManager = null + } + + if(this._searchBoxChangedId){ + this.searchBox?.disconnect(this._searchBoxChangedId); + this._searchBoxChangedId = null;; + } + if(this._searchBoxKeyPressId){ + this.searchBox?.disconnect(this._searchBoxKeyPressId); + this._searchBoxKeyPressId = null; + } + if(this._searchBoxKeyFocusInId){ + this.searchBox?.disconnect(this._searchBoxKeyFocusInId); + this._searchBoxKeyFocusInId = null; + } + + if(this.searchBox) + this.searchBox.destroy(); + + if(this.searchResults){ + this.searchResults.setTerms([]); + this.searchResults.destroy(); + this.searchResults = null; + } + + if (this._mainBoxKeyPressId) { + this.mainBox.disconnect(this._mainBoxKeyPressId); + this._mainBoxKeyPressId = null; + } + + if(this._gnomeFavoritesReloadID){ + AppFavorites.getAppFavorites().disconnect(this._gnomeFavoritesReloadID); + this._gnomeFavoritesReloadID = null; + } + + if(this.pinnedAppsArray){ + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + this.pinnedAppsArray[i].destroy(); + } + this.pinnedAppsArray = null; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.mainBox.destroy_all_children(); + } + + _createScrollBox(params){ + let scrollBox = new St.ScrollView(params); + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._blockActivateEvent = true; + this.onPan(action, scrollBox); + }); + panAction.connect('gesture-cancel',(action) => this.onPanEnd(action, scrollBox)); + panAction.connect('gesture-end', (action) => this.onPanEnd(action, scrollBox)); + scrollBox.add_action(panAction); + + scrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); + scrollBox.clip_to_allocation = true; + + return scrollBox; + } + + _createLabelWithSeparator(headerLabel){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.HEADER_LABEL, Constants.SeparatorAlignment.HORIZONTAL, headerLabel); + return separator; + } + + createLabelRow(title){ + let labelRow = new PopupMenu.PopupMenuItem(_(title), { + hover: false, + can_focus: false + }); + labelRow.actor.add_style_pseudo_class = () => { return false;}; + labelRow.label.style = 'font-weight: bold;'; + return labelRow; + } + + _keyFocusIn(actor) { + if (this._focusChild == actor) + return; + this._focusChild = actor; + Utils.ensureActorVisibleInScrollView(actor); + } + + onPan(action, scrollbox) { + let [dist_, dx_, dy] = action.get_motion_delta(0); + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + adjustment.value -= dy; + return false; + } + + onPanEnd(action, scrollbox) { + let velocity = -action.get_velocity(0)[2]; + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + let endPanValue = adjustment.value + velocity * 2; + adjustment.value = endPanValue; + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js new file mode 100644 index 0000000..fefdcd6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js @@ -0,0 +1,206 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus70' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.actionsBox.style = "padding: 5px 0px 0px 0px;" + this.leftBox.add_child(this.actionsBox); + + //create new section for Power, Lock, Logout, Suspend Buttons + this.sessionBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.sessionBox.style = "spacing: 6px;"; + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.sessionBox.add_child(powerButton); + } + } + this.leftBox.add_child(this.sessionBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + let pinnedApps = this._settings.get_strv('brisk-shortcuts-list'); + + for(let i = 0;i < pinnedApps.length; i += 3){ + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i],pinnedApps[i+1], pinnedApps[i+2]], Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem){ + this.actionsBox.add_child(placeMenuItem.actor); + } + } + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js new file mode 100644 index 0000000..46107c5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js @@ -0,0 +1,184 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * Budgie.js Layout Created By: MagneFire https://gitlab.com/MagneFire + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-bottom: 6px;"; + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel-plus70', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + // Disable horizontal scrolling, hide vertical scrollbar, but allow vertical scrolling. + this.applicationsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + if(this._settings.get_boolean('enable-activities-shortcut')){ + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(this.activities.actor); + this.leftBox.add_child(this.activitiesBox); + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-top: 6px;"; + this.mainBox.add_child(separator); + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px; margin: 0; spacing: 0;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js new file mode 100644 index 0000000..e0d862c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive: true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js new file mode 100644 index 0000000..79de6aa --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox= new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive:true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;" + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js new file mode 100644 index 0000000..1b3f548 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultMenuWidth: 650, + DefaultIconGridStyle: "MediumRectIconGrid", + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 10px 15px;"; + + this.topBox.add_child(this.searchBox.actor); + this.mainBox.insert_child_at_index(this.topBox, 0); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px; background-color:rgba(186, 196,201, 0.1); padding: 12px 25px;"+ + "border-color: rgba(186, 196,201, 0.2); border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true, + style: 'padding: 0px 25px;' + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 5, + column_homogeneous: true + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + layout.forceGridColumns = 2; + this.shortcutsBox.add_child(this.shortcutsGrid); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.actionsBox.add_child(this.user.actor); + + this.quickLinksBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER, + vertical: false, + style: 'spacing: 10px;' + }); + let path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Downloads")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + let settingsButton = new MW.SettingsButton(this); + this.quickLinksBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.quickLinksBox.add_child(this.leaveButton.actor); + + this.actionsBox.add_child(this.quickLinksBox); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton); + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton); + this.frequentAppsHeader = this._createNavigationButtons(_("Frequent"), null); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + + this.disableFrequentAppsID = this._settings.connect("changed::eleven-disable-frequent-apps", () => this.setDefaultMenuView()); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + loadFrequentApps(){ + this.frequentAppsList = []; + + if(this._settings.get_boolean("eleven-disable-frequent-apps")) + return; + + let labelRow = this.createLabelRow(_("Frequent")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + + if(mostUsed.length < 1) + return; + + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + + const MaxItems = 8; + if(this.frequentAppsList.length > MaxItems) + this.frequentAppsList.splice(MaxItems); + } + + setDefaultMenuView(){ + this.layoutProperties.IconGridSize = 34; + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + super.setDefaultMenuView(); + this.loadFrequentApps(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 5); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0, false); + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + + if(this.frequentAppsList.length > 0 && !this._settings.get_boolean("eleven-disable-frequent-apps")){ + this.activeCategory = _("Frequent"); + this.setGridLayout(Constants.DisplayType.GRID, 2, 0); + this._displayAppList(this.frequentAppsList, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + } + else if(this.applicationsBox.contains(this.shortcutsBox)){ + this.applicationsBox.remove_child(this.shortcutsBox); + } + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.applicationsBox.insert_child_at_index(this.allAppsButton, 0); + } + else if(category === Constants.CategoryType.HOME_SCREEN){ + this.applicationsBox.insert_child_at_index(this.frequentAppsHeader, 2); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.mainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.mainBox.contains(this.backButton)) + this.mainBox.remove_child(this.backButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.label.style = 'padding: 15px 0px;'; + navButton.style = 'padding: 0px 25px;' + if(ButtonClass) + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.backButton.destroy(); + this.allAppsButton.destroy(); + if(this.disableFrequentAppsID){ + this._settings.disconnect(this.disableFrequentAppsID); + this.disableFrequentAppsID = null; + } + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js new file mode 100644 index 0000000..8b66793 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js @@ -0,0 +1,161 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(activities.actor); + this.leftBox.add_child(this.activitiesBox); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js new file mode 100644 index 0000000..e298283 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js @@ -0,0 +1,337 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + PinnedAppsColumns: 1, + DefaultMenuWidth: 525, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.pinnedAppsButton = new MW.PinnedAppsButton(this); + this.pinnedAppsButton.actor.y_expand = true; + this.pinnedAppsButton.actor.y_align= Clutter.ActorAlign.START; + this.pinnedAppsButton.actor.margin = 5; + this.actionsBox.add_child(this.pinnedAppsButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + settingsButton.actor.expand = false; + settingsButton.actor.margin = 5; + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.leaveButton.actor.expand = false; + this.leaveButton.actor.margin = 5; + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + let userMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + vertical: false, + }) + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.user.label.x_align = Clutter.ActorAlign.CENTER; + this.user.label.style = "margin-left: 10px;" + userMenuBox.add_child(this.user.actor); + userMenuBox.add_child(this.user.label); + this.subMainBox.add_child(userMenuBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 10px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor( this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createPinnedAppsMenu(); + this.setDefaultMenuView(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + super.loadPinnedApps(); + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + } + + _createPinnedAppsMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.pinnedAppsMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.pinnedAppsMenu.blockSourceEvents = true; + this.section = new PopupMenu.PopupMenuSection(); + this.pinnedAppsMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.togglePinnedAppsMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + headerBox.add_child(this.createLabelRow(_("Pinned Apps"))); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + + this.leftPanelPopup.add_child(this.pinnedAppsScrollBox); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 0, + row_spacing: 0 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.forceGridColumns = 1; + layout.hookup_style(this.pinnedAppsGrid); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.displayPinnedApps(); + this.subMenuManager.addMenu(this.pinnedAppsMenu); + this.pinnedAppsMenu.actor.hide(); + Main.uiGroup.add_child(this.pinnedAppsMenu.actor); + this.pinnedAppsMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.pinnedAppsButton.tooltip){ + this.pinnedAppsButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.pinnedAppsButton.active = false; + this.pinnedAppsButton.sync_hover(); + this.pinnedAppsButton.hovered = this.pinnedAppsButton.hover; + } + }); + } + + togglePinnedAppsMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.pinnedAppsMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.pinnedAppsMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.pinnedAppsButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.pinnedAppsMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base: 0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.pinnedAppsMenu.toggle(); + if(this.pinnedAppsMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + this.activeMenuItem = this.applicationsGrid.layout_manager.get_child_at(0, 0); + if(!this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + this._clearActorsFromBox(this.pinnedAppsBox); + this.layoutProperties.GridColumns = 1; + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + this.updateStyle(); + this.layoutProperties.GridColumns = 5; + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js new file mode 100644 index 0000000..7dbeccc --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const MORE_PROVIDERS_POP_UP = -1; +const MAX_VISIBLE_PROVIDERS = 4; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + MenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.activeResult = null; + this.searchProvidersBoxStyle = "padding: 0px 15px; margin-bottom: 10px; height: 50px; background-color: rgba(186, 196, 201, 0.1); border-color:rgba(186, 196, 201, 0.2); border-bottom-width: 1px;" + this.themeNodeBorderRadius = ""; + this.searchProvidersBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.searchProvidersBoxStyle + this.themeNodeBorderRadius + }); + this.searchProvidersBox.clip_to_allocation = true; + this.mainBox.add_child(this.searchProvidersBox); + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px;"; + this.searchTermsChangedID = this.searchResults.connect('have-results', () => { + this.searchResultsChangedEvent(); + }); + this.searchNoResultsID = this.searchResults.connect('no-results', () => { + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + }) + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.subMainBox.style = "width:750px; spacing: 8px;"; + + this.searchResultDetailsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + style: 'width: 415px; spacing: 20px;' + }); + + this.searchResultDetailsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.searchResultDetailsScrollBox.add_actor(this.searchResultDetailsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.mainBox.add_child(this.searchBox); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.arcMenu.box.style = "padding-top: 0px;"; + this.hasPinnedApps = true; + this.loadPinnedApps(); + this.loadCategories(); + + this.moreItem = this.createProviderMenuItem(_("More"), MORE_PROVIDERS_POP_UP); + let arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + arrowIcon.y_expand = false; + this.moreItem.add_child(arrowIcon); + this._createMoreProvidersMenu(); + + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + super.loadPinnedApps(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.FREQUENT_APPS, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.FREQUENT_APPS, categoryMenuItem); + + super.loadCategories(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.moveProvidersMenuItems = []; + this.moreProvidersBox.remove_all_children(); + this.searchResults.setProvider(Constants.CategoryType.SEARCH_RESULTS); + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + this.displayPinnedApps(); + this.searchProvidersBox.remove_all_children(); + let allProvidersItem = this.createProviderMenuItem(_("All"), Constants.CategoryType.SEARCH_RESULTS); + this.searchProvidersBox.add_child(allProvidersItem); + let searchProviders = this.searchResults.getProviders(); + + let currentItems = 1; + for(let provider of searchProviders){ + provider = provider.appInfo ? provider : _("Applications"); + let item = this.createProviderMenuItem(provider, provider.appInfo ? null : Constants.CategoryType.ALL_PROGRAMS); + + if(currentItems < MAX_VISIBLE_PROVIDERS) + this.searchProvidersBox.add_child(item); + else{ + this.moveProvidersMenuItems.push(item); + item.moreIndex = currentItems - MAX_VISIBLE_PROVIDERS; + item.x_expand = true; + item.x_align = Clutter.ActorAlign.FILL; + this.moreProvidersBox.add_child(item); + } + + currentItems++; + } + + this.searchProvidersBox.add_child(this.moreItem); + + this.activeProvider = allProvidersItem; + this.activeProvider.add_style_class_name("active-item"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + createProviderMenuItem(provider, providerEnum){ + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + + let providerMenuItem = new MW.ArcMenuPopupBaseMenuItem(this); + providerMenuItem.name = "arc-menu-launcher-button"; + providerMenuItem.x_expand = false; + providerMenuItem.remove_child(providerMenuItem._ornamentLabel); + providerMenuItem.x_align = Clutter.ActorAlign.START; + providerMenuItem.style = 'padding: 10px 14px; margin: 0px;'; + providerMenuItem.provider = provider; + let label = new St.Label({ + text: _(providerName), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + }); + providerMenuItem.label = label; + providerMenuItem.add_child(label); + + providerMenuItem.connect("activate", () => this.activateProviderMenuItem(providerMenuItem, providerEnum)); + return providerMenuItem; + } + + activateProviderMenuItem(providerMenuItem, providerEnum){ + if(providerEnum && providerEnum === MORE_PROVIDERS_POP_UP){ + this.moreItem.add_style_class_name("active-item"); + this.toggleMoreProvidersMenu(); + } + else{ + if(this.activeProvider) + this.activeProvider.remove_style_class_name("active-item"); + + if(this.moreProvidersMenu.isOpen) + this.moreProvidersMenu.toggle(); + + this.moreItem.remove_style_class_name("active-item"); + this.moreItem.active = false; + + let potentialMovedItem = this.searchProvidersBox.get_child_at_index(MAX_VISIBLE_PROVIDERS); + + if(potentialMovedItem.wasMoved) + this.moveProviderMenuItem(potentialMovedItem, this.searchProvidersBox, this.moreProvidersBox, true); + + if(providerMenuItem.get_parent() === this.moreProvidersBox) + this.moveProviderMenuItem(providerMenuItem, this.moreProvidersBox, this.searchProvidersBox, false); + + this.activeProvider = providerMenuItem; + providerMenuItem.add_style_class_name("active-item"); + + this.displayProviderPage(providerMenuItem.provider, providerEnum); + this.searchResults.setProvider(providerMenuItem.provider.appInfo ? providerMenuItem.provider.appInfo.get_id() : providerEnum); + + if(!this.searchBox.isEmpty()){ + this._clearActorsFromBox(); + let searchString = this.searchBox.get_text(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms([]); + + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.setTerms(searchString.split(/\s+/)); + this.searchResults.highlightDefault(true); + this.activeProvider.grab_key_focus(); + } + } + } + + moveProviderMenuItem(menuItem, currentBox, newBox, wasMoved){ + let expand = wasMoved ? true : false; + let align = wasMoved ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.START; + let index = wasMoved ? menuItem.moreIndex : MAX_VISIBLE_PROVIDERS; + + currentBox.remove_child(menuItem); + newBox.insert_child_at_index(menuItem, index); + menuItem.x_expand = expand; + menuItem.x_align = align; + menuItem.wasMoved = !wasMoved; + } + + displayProviderPage(provider, providerEnum){ + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + if(providerEnum){ + if(providerEnum === Constants.CategoryType.SEARCH_RESULTS) + this.displayPinnedApps(); + if(providerEnum === Constants.CategoryType.ALL_PROGRAMS) + this.displayFrequentApps(); + return; + } + this._clearActorsFromBox(); + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + let providerIcon = provider.appInfo ? provider.appInfo.get_icon() : Gio.icon_new_for_string(''); + + this.setSearchHintText(providerName); + + let providerBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let icon = new St.Icon({ + icon_size: 76, + gicon: providerIcon, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let label = new St.Label({ + text: _("Search") + " " + _(providerName), + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: false, + y_align: Clutter.ActorAlign.START, + }); + providerBox.add_child(icon); + providerBox.add_child(label); + this.applicationsBox.add_child(providerBox); + } + + _createMoreProvidersMenu(){ + this.moreProvidersMenu = new PopupMenu.PopupMenu(this.moreItem, 0.5, St.Side.TOP); + this.moreProvidersMenu.connect('open-state-changed', (menu, open) => { + if(!open) + this.moreItem.remove_style_class_name("active-item"); + }); + + this.section = new PopupMenu.PopupMenuSection(); + this.moreProvidersMenu.addMenuItem(this.section); + + this.moreProvidersBox = new St.BoxLayout({ + vertical: true + }); + + this.moreProvidersScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'vfade', + overlay_scrollbars: true, + reactive: true + }); + this.moreProvidersScrollBox._delegate = this.moreProvidersBoxScrollBox; + this.moreProvidersScrollBox.add_actor(this.moreProvidersBox); + this.moreProvidersScrollBox.clip_to_allocation = true; + + this.moreProvidersScrollBox.style = "max-height: 350px;"; + this.section.actor.add_child(this.moreProvidersScrollBox); + this.subMenuManager.addMenu(this.moreProvidersMenu); + this.moreProvidersMenu.actor.hide(); + Main.uiGroup.add_child(this.moreProvidersMenu.actor); + } + + toggleMoreProvidersMenu(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.moreProvidersMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.moreProvidersMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + + this.moreProvidersMenu.toggle(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + this.setSearchHintText(_("Applications")); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + let label = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(categoryMenuItem.appList, Constants.CategoryType.FREQUENT_APPS, this.applicationsGrid); + } + + setSearchHintText(providerName){ + this.searchBox.hint_text = _("Search") + " " + _(providerName) + "…"; + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.searchProvidersBox.style = this.searchProvidersBoxStyle + this.themeNodeBorderRadius; + if(removeMenuArrow) + this.arcMenu.box.style = "padding-top: 0px; margin: 0px;"; + else + this.arcMenu.box.style = "padding-top: 0px;"; + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayPinnedApps() { + super._clearActorsFromBox(); + let label = this.createLabelRow(_("Pinned Apps")); + this.searchBox.hint_text = _("Search…"); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + searchResultsChangedEvent(){ + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.add_child(this.searchResultDetailsScrollBox); + if(this.activeResult === this.searchResults.getTopResult()) + return; + + this.activeResult = this.searchResults.getTopResult(); + if(!this.activeResult || this.activeResult === null){ + return; + } + + this.createActiveSearchItemPanel(this.searchResults.getTopResult()); + } + + createActiveSearchItemPanel(activeResult){ + if(!activeResult) + return; + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + return; + if(!activeResult.provider || activeResult === this.activeResultMenuItem) + return; + this.activeCategoryType = -1; + this.searchResultDetailsBox.destroy_all_children(); + + if(!activeResult.metaInfo) + return; + + let app = activeResult.app ? activeResult.app : null; + let path = activeResult._path ? activeResult._path : null; + + this.activeResultMenuItem = new MW.ApplicationMenuItem(this, app, Constants.DisplayType.GRID, activeResult.metaInfo); + this.activeResultMenuItem.name = "ExtraLargeIconGrid"; + this.activeResultMenuItem.provider = activeResult.provider; + this.activeResultMenuItem.resultsView = activeResult.resultsView; + this.activeResultMenuItem._path = path; + this.activeResultMenuItem.x_expand = false; + this.activeResultMenuItem.x_align = Clutter.ActorAlign.CENTER; + let iconSize = 76; + let icon = activeResult.metaInfo ?activeResult.metaInfo['createIcon'](iconSize) : app.create_icon_texture(iconSize); + this.activeResultMenuItem._iconBin.set_child(icon); + if(!this.activeResultMenuItem._iconBin.get_child()){ + let icon = new St.Icon({ + icon_size: iconSize, + gicon: activeResult.provider.appInfo.get_icon() + }); + this.activeResultMenuItem._iconBin.set_child(icon); + } + this.searchResultDetailsBox.add_child(this.activeResultMenuItem); + this.searchResultContextItems = new MW.ApplicationContextItems(this.activeResultMenuItem, app, this); + this.searchResultContextItems.path = path; + this.searchResultContextItems.rebuildItems(); + this.searchResultDetailsBox.add_child(this.searchResultContextItems); + } + + destroy(){ + this.arcMenu.box.style = null; + + if(this.searchTermsChangedID){ + this.searchResults.disconnect(this.searchTermsChangedID); + this.searchTermsChangedID = null; + } + + if(this.searchNoResultsID){ + this.searchResults.disconnect(this.searchNoResultsID); + this.searchNoResultsID = null; + } + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js new file mode 100644 index 0000000..3185f2d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js @@ -0,0 +1,250 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + //Stores the Pinned Icons on the left side + this.actionsScrollBox = new St.ScrollView({ + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'small-vfade' + }); + this.actionsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + this.actionsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsScrollBox.add_actor(this.actionsBox); + this.actionsScrollBox.clip_to_allocation = true; + + this.actionsScrollBox.style = "padding: 21px 0px; width: 62px; margin: 0px 10px 10px 20px; background-color:rgba(186, 196,201, 0.1); border-color:rgba(186, 196,201, 0.2); border-width: 1px; border-radius: 5px;"; + this.actionsBox.style = "spacing: 10px;"; + //check if custom ArcMenu is enabled + if( this._settings.get_boolean('enable-custom-arc-menu')) + this.actionsBox.add_style_class_name('arc-menu'); + + this.mainBox.add_child(this.actionsScrollBox); + this.rightMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.rightMenuBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + else + this.rightMenuBox.style = "margin-top: 10px;"; + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.rightMenuBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + + this.categoriesScrollBox.add_actor( this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + _addSeparator(){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + super.loadExtraPinnedApps(this._settings.get_strv('mint-pinned-app-list'), this._settings.get_int('mint-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + this._app = appSys.lookup_app(browserName); + if(this._app){ + let appIcon = this._app.create_icon_texture(25); + let iconName = ''; + if(appIcon.icon_name) + iconName = appIcon.icon_name; + else if(appIcon.gicon) + iconName = appIcon.gicon.to_string(); + pinnedApps.push(this._app.get_name(), iconName, this._app.get_id()); + } + else{ + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + } + pinnedApps.push(_("Terminal"), "utilities-terminal", "org.gnome.Terminal.desktop"); + pinnedApps.push(_("Settings"), "emblem-system-symbolic", "gnome-control-center.desktop"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('mint-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js new file mode 100644 index 0000000..2135cc5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js @@ -0,0 +1,453 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 450, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.leftTopBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + vertical: false, + y_align: Clutter.ActorAlign.CENTER, + style: "padding-left: 10px; margin-left: 0.4em" + }); + this.rightTopBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + style_class: 'popup-menu-item', + style: "padding: 0px; margin: 0px; spacing: 0px;" + }); + + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_expand = false; + this.user.actor.y_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.leftTopBox.add_child(this.user.actor); + this.rightTopBox.add_child(this.user.label); + this.user.label.style = "padding-left: 0.4em; margin: 0px 10px 0px 15px; font-weight: bold;"; + this.user.label.y_expand = false; + this.user.label.x_expand = true; + this.user.label.x_align = Clutter.ActorAlign.START; + this.rightTopBox.add_child(this.searchBox.actor); + + this.topBox.add_child(this.leftTopBox); + this.topBox.add_child(this.rightTopBox); + + this.searchBarLocation = this._settings.get_enum('searchbar-default-top-location'); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? 'margin-box' : 'margin-box small-vfade', + overlay_scrollbars: true, + reactive:true, + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBoxContainer = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.navigateBox = new St.BoxLayout({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 6px;", + }); + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_homogeneous: true, + column_spacing: 10, + row_spacing: 10 + }); + this.grid = new St.Widget({ + layout_manager: layout + }); + layout.hookup_style(this.grid); + this.navigateBox.add_child(this.grid); + + this.pinnedAppsButton = new MW.PlasmaMenuItem(this, _("Pinned Apps"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'); + this.pinnedAppsButton.connect("activate", () => this.displayPinnedApps() ); + this.grid.layout_manager.attach(this.pinnedAppsButton, 0, 0, 1, 1); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + + this.applicationsButton = new MW.PlasmaMenuItem(this, _("Applications"), 'preferences-desktop-apps-symbolic'); + this.applicationsButton.connect("activate", () => this.displayCategories() ); + this.grid.layout_manager.attach(this.applicationsButton, 1, 0, 1, 1); + + this.computerButton = new MW.PlasmaMenuItem(this, _("Computer"), 'computer-symbolic'); + this.computerButton.connect("activate", () => this.displayComputerCategory() ); + this.grid.layout_manager.attach(this.computerButton, 2, 0, 1, 1); + + this.leaveButton = new MW.PlasmaMenuItem(this, _("Leave"), 'system-shutdown-symbolic'); + this.leaveButton.connect("activate", () => this.displayPowerItems() ); + this.grid.layout_manager.attach(this.leaveButton, 3, 0, 1, 1); + + this.categoryHeader = new MW.PlasmaCategoryHeader(this); + this.categoryHeader.add_style_class_name('margin-box'); + + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 3px 10px 5px 10px;"; + this.topBox.style = 'padding-top: 0.5em;' + + this.navigateBoxContainer.add_child(this.navigateBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.y_expand = false; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.START; + this.mainBox.add_child(this.navigateBoxContainer); + this.mainBox.add_child(this.applicationsScrollBox); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + + this.mainBox.add_child(this.topBox); + } + else if(this.searchBarLocation === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 3px 10px 10px 10px;"; + + this.mainBox.add_child(this.topBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + this.mainBox.add_child(this.applicationsScrollBox); + this.navigateBoxContainer.y_expand = true; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.END; + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.add_child(this.navigateBox); + this.mainBox.add_child(this.navigateBoxContainer); + } + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + this.updateWidth(); + this._createPowerItems(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + categoryMenuItem.appList.push(mostUsed[i]); + let item = this.applicationsMap.get(mostUsed[i]); + if (!item) { + item = new MW.ApplicationMenuItem(this, mostUsed[i], this.layoutProperties.DisplayType); + this.applicationsMap.set(mostUsed[i], item); + } + } + } + } + + _clearActorsFromBox(box){ + this.categoryHeader.setActiveCategory(null); + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + super._clearActorsFromBox(box); + } + + clearActiveItem(){ + this.pinnedAppsButton.setActive(false); + this.computerButton.setActive(false); + this.applicationsButton.setActive(false); + this.leaveButton.setActive(false); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum === Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayComputerCategory(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.applicationsBox.add_child(this.applicationShortcuts[i]); + } + this.applicationsBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.applicationsBox.add_child(this.directoryShortcuts[i]); + } + this.applicationsBox.add_child(this.externalDevicesBox); + this.activeMenuItem = this.applicationShortcuts[0]; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + displayPinnedApps(){ + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + super.displayPinnedApps(); + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let isContainedInCategory = false; + let directory = directoryShortcutsList[i]; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createPowerItems(){ + this.lock = new MW.PowerMenuItem(this, Constants.PowerType.LOCK); + this.logOut = new MW.PowerMenuItem(this, Constants.PowerType.LOGOUT); + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + this.sleep = new MW.PowerMenuItem(this, Constants.PowerType.HYBRID_SLEEP); + } + }); + + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + this.hibernate = new MW.PowerMenuItem(this, Constants.PowerType.HIBERNATE); + } + }); + this.suspend = new MW.PowerMenuItem(this, Constants.PowerType.SUSPEND); + this.restart = new MW.PowerMenuItem(this, Constants.PowerType.RESTART); + this.powerOff = new MW.PowerMenuItem(this, Constants.PowerType.POWER_OFF); + } + + displayPowerItems(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Session"))); + this.applicationsBox.add_child(this.lock); + this.applicationsBox.add_child(this.logOut); + this.applicationsBox.add_child(this.createLabelRow(_("System"))); + this.applicationsBox.add_child(this.suspend); + if(this.sleep) + this.applicationsBox.insert_child_at_index(this.sleep, 4); + + if(this.hibernate) + this.applicationsBox.insert_child_at_index(this.hibernate, 5); + this.applicationsBox.add_child(this.restart); + this.applicationsBox.add_child(this.powerOff); + this.activeMenuItem = this.lock; + } + + displayCategories(){ + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this._clearActorsFromBox(this.applicationsBox); + + this.categoryHeader.setActiveCategory(null); + this._insertCategoryHeader(); + + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.applicationsBox.add_child(categoryMenuItem.actor); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.clearActiveItem(); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + this.displayPinnedApps(); + } + + _insertCategoryHeader(){ + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM) + this.mainBox.insert_child_at_index(this.categoryHeader, 1); + else + this.mainBox.insert_child_at_index(this.categoryHeader, 2); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._insertCategoryHeader(); + this.categoryHeader.setActiveCategory(this.activeCategory); + this._displayAppList(appList, category, this.applicationsGrid); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this._insertCategoryHeader(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.categoryHeader.setActiveCategory(this.activeCategory); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.clearActiveItem(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.sleep) + this.sleep.destroy(); + if(this.hibernate) + this.hibernate.destroy(); + + this.lock.destroy(); + this.logOut.destroy(); + this.suspend.destroy(); + this.restart.destroy(); + this.powerOff.destroy(); + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js new file mode 100644 index 0000000..2630ef5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js @@ -0,0 +1,395 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 410, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + SupportsCategoryOnHover: true, + DefaultCategoryIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.ravenPositionChangedID = this._settings.connect('changed::raven-position', () => this._updatePosition()); + + this.dummyCursor = new St.Widget({ width: 1, height: 0, opacity: 0}); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.actionsBoxContainer = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + this.actionsBoxContainer.add_child(this.actionsBox); + this.actionsBox.style = "spacing: 5px;"; + this.actionsBoxContainerStyle = "margin: 0px 0px 0px 0px; spacing: 10px; background-color: rgba(186, 196,201, 0.1); padding: 5px 5px;"+ + "border-color: rgba(186, 196,201, 0.2);"; + + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + //Sub Main Box -- stores left and right box + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.subMainBox.add_child(this.topBox); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 25px 10px 10px 10px;"; + this.topBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + x_align: Clutter.ActorAlign.FILL, + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.weatherBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: true + }); + + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.x_expand = true; + this._clocksItem.x_align = Clutter.ActorAlign.FILL; + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + + this.weatherBox.add_child(this._clocksItem); + this.weatherBox.add_child(this._weatherItem); + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this._updatePosition(); + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.weatherBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _updatePosition(){ + let ravenPosition = this._settings.get_enum('raven-position'); + if(this.mainBox.contains(this.actionsBoxContainer)){ + this.mainBox.remove_child(this.actionsBoxContainer); + } + if(ravenPosition === Constants.RavenPosition.LEFT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 0); + this.actionsBoxContainer.style = "border-right-width: 1px;" + this.actionsBoxContainerStyle; + } + else if(ravenPosition === Constants.RavenPosition.RIGHT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 1); + this.actionsBoxContainer.style = "border-left-width: 1px;" + this.actionsBoxContainerStyle; + } + } + + updateLocation(){ + let ravenPosition = this._settings.get_enum('raven-position'); + + let alignment = ravenPosition === Constants.RavenPosition.LEFT ? 0 : 1; + this.arcMenu._boxPointer.setSourceAlignment(alignment); + this.arcMenu._arrowAlignment = alignment; + + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + let positionX = ravenPosition === Constants.RavenPosition.LEFT ? monitorWorkArea.x : monitorWorkArea.x + monitorWorkArea.width - 1; + let positionY = this.arcMenu._arrowSide === St.Side.BOTTOM ? monitorWorkArea.y + monitorWorkArea.height : monitorWorkArea.y; + + this.dummyCursor.set_position(positionX, positionY); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let screenHeight = monitorWorkArea.height; + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderWidth = themeNode.get_length('-arrow-border-width'); + + let height = Math.round((screenHeight - borderWidth * 2) / scaleFactor); + this.mainBox.style = `height: ${height}px;`; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + updateStyle(){ + super.updateStyle(); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px;"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.updateLocation(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.BUTTON); + this.displayCategories(); + } + + displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.actionsBox.add_child(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + let actors = this.weatherBox.get_children(); + for (let i = 0; i < actors.length; i++) { + this.weatherBox.remove_child(actors[i]); + } + if(this._settings.get_boolean('enable-clock-widget-raven')){ + this.weatherBox.add_child(this._clocksItem); + } + if(this._settings.get_boolean('enable-weather-widget-raven')){ + this.weatherBox.add_child(this._weatherItem); + } + if(!this.subMainBox.contains(this.weatherBox)) + this.subMainBox.add_child(this.weatherBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.subMainBox.contains(this.weatherBox)){ + this.subMainBox.remove_child(this.weatherBox); + } + + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + let label = this._createLabelWithSeparator(this.activeCategory); + + if(grid === this.applicationsGrid){ + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label.actor, 0); + } + else{ + label.actor.style += "padding-left: 10px; padding-top: 20px;"; + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + if(this.ravenPositionChangedID){ + this._settings.disconnect(this.ravenPositionChangedID); + this.ravenPositionChangedID = null; + } + + this.arcMenu.actor.style = null; + this.arcMenu.box.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js new file mode 100644 index 0000000..d0cb17d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js @@ -0,0 +1,229 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP) + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + y_align: Clutter.ActorAlign.FILL, + y_expand: true, + vertical: true, + style_class: 'right-panel margin-box' + }); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0){ + this.placesShortcuts=true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length>0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw=true; + if(shouldDraw){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.mainBox.add_child(horizonalFlip ? this.rightBox : this.subMainBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.mainBox.add_child(verticalSeparator); + this.mainBox.add_child(horizonalFlip ? this.subMainBox: this.rightBox); + horizonalFlip ? this.rightBox.style += "margin-right: 0px" : this.rightBox.style += "margin-left: 0px" + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js new file mode 100644 index 0000000..7386301 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js @@ -0,0 +1,208 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton, isStandalone) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + StandaloneRunner: isStandalone + }); + } + + createLayout(){ + super.createLayout(); + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0.5); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: false, + style: "margin: 5px 0px 0px 0px;" + }); + + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + this.runnerTweaksButton = new MW.RunnerTweaksButton(this); + this.runnerTweaksButton.actor.x_expand = false; + this.runnerTweaksButton.actor.y_expand = true; + this.runnerTweaksButton.actor.y_align = this.searchBox.y_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.x_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.style = "margin: 0px 6px;"; + + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.runnerTweaksButton); + this.mainBox.add_child(this.topBox); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: false, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + reactive:true + }); + + this.mainBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "margin: 5px 6px 0px 16px;" + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.activeMenuItem = null; + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + this.activeMenuItem = null; + super.setDefaultMenuView(); + if(this._settings.get_boolean("runner-show-frequent-apps")) + this.displayFrequentApps(); + } + + displayFrequentApps(){ + let labelRow = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_actor(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + /** + * if button is hidden, menu should appear on current monitor, unless preference is to always show on primary monitor + * @returns index of monitor where menu should appear + */ + _getMonitorIndexForPlacement() { + if (this.layoutProperties.StandaloneRunner) { + return this._settings.get_boolean('runner-hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + } + else if (this._settings.get_enum('menu-button-appearance') === Constants.MenuButtonAppearance.NONE) + return this._settings.get_boolean('hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + else + return Main.layoutManager.findIndexForActor(this.menuButton); + } + + updateLocation(){ + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + + let rect = Main.layoutManager.getWorkAreaForMonitor(this._getMonitorIndexForPlacement()); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + (this._settings.get_boolean('runner-use-theme-gap') ? this.rise : 0); + if(this._settings.get_enum('runner-position') == 1) + positionY = Math.round(rect.y + (rect.height / 2) - 125); + this.dummyCursor.set_position(positionX, positionY); + + if(!this.topBox) + return; + + this._runnerWidth = this._settings.get_int("runner-menu-width"); + this._runnerHeight = this._settings.get_int("runner-menu-height"); + this._runnerFontSize = this._settings.get_int("runner-font-size"); + this.mainBox.style = `max-height: ${this._runnerHeight}px;`; + if(this._runnerFontSize > 0){ + this.mainBox.style += `font-size: ${this._runnerFontSize}pt;` + this.searchBox.style += `font-size: ${this._runnerFontSize}pt;` + } + else{ + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + } + this.topBox.style = `width: ${this._runnerWidth}px; margin: 5px 0px 0px 0px;`; + this.applicationsScrollBox.style = `width: ${this._runnerWidth}px;`; + } + + updateStyle(){ + super.updateStyle(); + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + } + + loadCategories(){ + } + + destroy(){ + this.arcMenu.actor.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js new file mode 100644 index 0000000..0e971e4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js @@ -0,0 +1,159 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GMenu, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.section = this.menuButton.section; + let actors = this.section.actor.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + this.section.actor.remove_child(actor); + } + this.section.actor.add_child(this.mainBox); + + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + updateStyle(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.updateStyle(); + } + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.SimpleMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SIMPLE_CATEGORY); + } + + displayCategories(){ + super.displayCategories(this.mainBox); + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + let children = categoryMenuItem.applicationsBox.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.applicationsBox.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.applicationsBox); + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + if(!categoryMenuItem.applicationsBox.contains(this.applicationsGrid)) + categoryMenuItem.applicationsBox.add_child(this.applicationsGrid); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js new file mode 100644 index 0000000..ec5b2cf --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js @@ -0,0 +1,179 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + this.arcMenu.actor.style = 'max-height: ' + (this.arcMenu.actor.height + 250) + 'px;'; + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + let actors = this.mainBox.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + } + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategorySubMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SUBMENU_CATEGORY); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem._setParent(this.arcMenu); + categoryMenuItem.isSimpleMenuItem = true; + } + } + + displayCategories(){ + this._clearActorsFromBox(); + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.arcMenu.addMenuItem(categoryMenuItem); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + super._clearActorsFromBox(this.mainBox); + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + this._clearActorsFromBox(); + this.applicationsGrid.remove_all_children(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + + let children = categoryMenuItem.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.menu.box.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.menu.box, () => categoryMenuItem._needsScrollbar()); + if(!categoryMenuItem.menu.box.contains(this.applicationsGrid)) + categoryMenuItem.menu.box.add_child(this.applicationsGrid); + + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + let box = categoryMenuItem.menu.box; + if(!box.contains(this.applicationsGrid)) + box.add_child(this.applicationsGrid); + } + + destroy(){ + this.arcMenu.actor.style = null; + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js new file mode 100644 index 0000000..9d279ee --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js @@ -0,0 +1,290 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * tognee Layout Created By: tognee https://gitlab.com/tognee + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 290, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + // The "Left Box" + // Contains the app list and the searchbar + this.appBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + this.appBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL)); + this.navigateBox.add_child(this.backButton.actor); + this.appBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + + // The "Right Box" + // Contains some useful shortcuts + this.quickBox = new St.BoxLayout({ + vertical: true, + style: "margin: 0px 1px;", + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.subMainBox.add_child(horizonalFlip ? this.appBox : this.quickBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.quickBox : this.appBox); + + this.placesShortcuts= this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0; + this.softwareShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack().length>0; + + this.shortcutsBox = new St.BoxLayout({ + vertical: true, + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + style: "spacing: 5px; padding-bottom: 5px;" + }); + + this.shortcutsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + this.shortcutsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.quickBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //check to see if should draw separator + if(this.placesShortcuts && this.softwareShortcuts){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.BUTTON, isContainedInCategory); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + // Bottom Section for Power etc... + this.actionsScrollBox = new St.ScrollView({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.actionsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.actionsScrollBox.clip_to_allocation = true; + + //create new section for Leave Button + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 3px;" + }); + this.actionsScrollBox.add_actor(this.actionsBox); + + let leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(leaveButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.insert_child_at_index(separator, 0); + this.quickBox.add_child(this.actionsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 175px minimum limit for the menu width + menuWidth = Math.max(175, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _displayPlaces() { + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.BUTTON, isContainedInCategory); + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayPinnedApps(){ + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + this.navigateBox.show(); + } + + displayAllApps(){ + this.navigateBox.hide(); + super.displayAllApps() + } + + displayCategories(){ + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this.navigateBox.hide(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view-tognee'); + + if(defaultMenuView === Constants.DefaultMenuViewTognee.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuViewTognee.ALL_PROGRAMS) + this.displayAllApps(); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.navigateBox.show(); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.navigateBox.show(); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(searchBox.isEmpty()){ + this.navigateBox.hide(); + } + else if(!searchBox.isEmpty()){ + this.navigateBox.show(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js new file mode 100644 index 0000000..290a169 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js @@ -0,0 +1,1286 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Prefs = Me.imports.prefs; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var TweaksPage = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_TweaksPage extends Gtk.Box { + _init(settings, layoutName) { + this._settings = settings; + this.addResponse = false; + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.layoutNameLabel = new Gtk.Label({ + label: "" + _(layoutName) + "", + use_markup: true, + xalign: 0, + hexpand: true, + halign: Gtk.Align.CENTER + }) + + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + }); + backButton.halign = Gtk.Align.START; + backButton.connect('clicked', ()=> { + this.emit('response', -20); + }); + this.headerBox = new Gtk.Grid({ + hexpand: true, + halign: Gtk.Align.FILL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + }); + + this.headerBox.attach(backButton, 0, 0, 1, 1); + this.headerBox.attach(this.layoutNameLabel, 0, 0, 1, 1); + this.mainScrollWindow = new Gtk.ScrolledWindow(); + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.append(this.headerBox); + this.mainScrollWindow.set_child(this.mainBox); + this.mainScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.append(this.mainScrollWindow); + this._createLayout(); + } + + setActiveLayout(menuLayout, layoutName){ + if(layoutName) + this.layoutNameLabel.label = "" + _(layoutName) + ""; + let children = [...this.mainBox]; + for(let child of children){ + this.mainBox.remove(child); + } + this._createLayout(menuLayout); + } + + _createLayout(menuLayout) { + if(!menuLayout) + menuLayout = this._settings.get_enum('menu-layout'); + + if(menuLayout == Constants.MenuLayout.ARCMENU) + this._loadArcMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.BRISK) + this._loadBriskMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WHISKER) + this._loadWhiskerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_MENU) + this._loadGnomeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.MINT) + this._loadMintMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEMENTARY) + this._loadElementaryTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_OVERVIEW) + this._loadGnomeOverviewTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE_2) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.REDMOND) + this._loadRedmondMenuTweaks() + else if(menuLayout == Constants.MenuLayout.UNITY) + this._loadUnityTweaks(); + else if(menuLayout == Constants.MenuLayout.RAVEN) + this._loadRavenTweaks(); + else if(menuLayout == Constants.MenuLayout.BUDGIE) + this._loadBudgieMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.INSIDER) + this._loadInsiderMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.RUNNER) + this._loadRunnerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.CHROMEBOOK) + this._loadChromebookTweaks(); + else if(menuLayout == Constants.MenuLayout.TOGNEE) + this._loadTogneeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.PLASMA) + this._loadPlasmaMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WINDOWS) + this._loadWindowsTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEVEN) + this._loadElevenTweaks(); + else + this._loadPlaceHolderTweaks(); + } + + _createActivateOnHoverRow(){ + let activateOnHoverRow = new PW.FrameBoxRow(); + let activateOnHoverLabel = new Gtk.Label({ + label: _("Category Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let activateOnHoverCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + activateOnHoverCombo.append_text(_("Mouse Click")); + activateOnHoverCombo.append_text(_("Mouse Hover")); + if(this._settings.get_boolean('activate-on-hover')) + activateOnHoverCombo.set_active(1); + else + activateOnHoverCombo.set_active(0); + activateOnHoverCombo.connect('changed', (widget) => { + if(widget.get_active()==0) + this._settings.set_boolean('activate-on-hover',false); + if(widget.get_active()==1) + this._settings.set_boolean('activate-on-hover',true); + }); + + activateOnHoverRow.add(activateOnHoverLabel); + activateOnHoverRow.add(activateOnHoverCombo); + return activateOnHoverRow; + } + _createAvatarShapeRow(){ + let avatarStyleRow = new PW.FrameBoxRow(); + let avatarStyleLabel = new Gtk.Label({ + label: _('Avatar Icon Shape'), + xalign:0, + hexpand: true, + }); + let avatarStyleCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + avatarStyleCombo.append_text(_("Circular")); + avatarStyleCombo.append_text(_("Square")); + avatarStyleCombo.set_active(this._settings.get_enum('avatar-style')); + avatarStyleCombo.connect('changed', (widget) => { + this._settings.set_enum('avatar-style', widget.get_active()); + this._settings.set_boolean('reload-theme', true); + }); + avatarStyleRow.add(avatarStyleLabel); + avatarStyleRow.add(avatarStyleCombo); + return avatarStyleRow; + } + _createSearchBarLocationRow(bottomDefault){ + let searchBarLocationSetting = bottomDefault ? 'searchbar-default-bottom-location' : 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting )); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + return searchbarLocationRow; + } + _createFlipHorizontalRow(){ + let horizontalFlipRow = new PW.FrameBoxRow(); + let horizontalFlipLabel = new Gtk.Label({ + label: _("Flip Layout Horizontally"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let horizontalFlipSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + horizontalFlipSwitch.set_active(this._settings.get_boolean('enable-horizontal-flip')); + horizontalFlipSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-horizontal-flip', widget.get_active()); + }); + horizontalFlipRow.add(horizontalFlipLabel); + horizontalFlipRow.add(horizontalFlipSwitch); + return horizontalFlipRow; + } + _disableAvatarRow(){ + let disableAvatarRow = new PW.FrameBoxRow(); + let disableAvatarLabel = new Gtk.Label({ + label: _('Disable User Avatar'), + xalign:0, + hexpand: true, + }); + let disableAvatarSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableAvatarSwitch.set_active(this._settings.get_boolean('disable-user-avatar')); + disableAvatarSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('disable-user-avatar', widget.get_active()); + }); + disableAvatarRow.add(disableAvatarLabel); + disableAvatarRow.add(disableAvatarSwitch); + return disableAvatarRow; + } + + _loadElevenTweaks(){ + let elevenTweaksFrame = new PW.FrameBox(); + let disableFrequentAppsRow = new PW.FrameBoxRow(); + let disableFrequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let disableFrequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableFrequentAppsSwitch.set_active(this._settings.get_boolean('eleven-disable-frequent-apps')); + disableFrequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('eleven-disable-frequent-apps', widget.get_active()); + }); + disableFrequentAppsRow.add(disableFrequentAppsLabel); + disableFrequentAppsRow.add(disableFrequentAppsSwitch); + elevenTweaksFrame.add(disableFrequentAppsRow); + this.mainBox.append(elevenTweaksFrame); + } + + _loadGnomeOverviewTweaks(){ + let gnomeOverviewTweaksFrame = new PW.FrameBox(); + let appsGridRow = new PW.FrameBoxRow(); + let appsGridLabel = new Gtk.Label({ + label: _("Show Applications Grid"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appsGridSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appsGridSwitch.set_active(this._settings.get_boolean('gnome-dash-show-applications')); + appsGridSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('gnome-dash-show-applications', widget.get_active()); + }); + appsGridRow.add(appsGridLabel); + appsGridRow.add(appsGridSwitch); + gnomeOverviewTweaksFrame.add(appsGridRow); + this.mainBox.append(gnomeOverviewTweaksFrame); + } + + _loadWindowsTweaks(){ + let windowsTweaksFrame = new PW.FrameBox(); + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let frequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + frequentAppsSwitch.set_active(this._settings.get_boolean('windows-disable-frequent-apps')); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + windowsTweaksFrame.add(frequentAppsRow); + + let pinnedAppsRow = new PW.FrameBoxRow(); + let pinnedAppsLabel = new Gtk.Label({ + label: _("Disable Pinned Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let pinnedAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + pinnedAppsSwitch.set_active(this._settings.get_boolean('windows-disable-pinned-apps')); + pinnedAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-pinned-apps', widget.get_active()); + }); + pinnedAppsRow.add(pinnedAppsLabel); + pinnedAppsRow.add(pinnedAppsSwitch); + windowsTweaksFrame.add(pinnedAppsRow); + + this.mainBox.append(windowsTweaksFrame); + } + + _loadPlasmaMenuTweaks(){ + let plasmaMenuTweaksFrame = new PW.FrameBox(); + + let searchBarLocationSetting = 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + plasmaMenuTweaksFrame.add(searchbarLocationRow); + + let hoverRow = new PW.FrameBoxRow(); + let hoverLabel = new Gtk.Label({ + label: _("Activate on Hover"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hoverSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + hoverSwitch.set_active(this._settings.get_boolean('plasma-enable-hover')); + hoverSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('plasma-enable-hover', widget.get_active()); + }); + hoverRow.add(hoverLabel); + hoverRow.add(hoverSwitch); + plasmaMenuTweaksFrame.add(hoverRow); + + let foregroundColorRow = new PW.FrameBoxRow(); + let foregroundColorLabel = new Gtk.Label({ + label: _('Selected Button Border Color'), + xalign:0, + hexpand: true, + }); + let foregroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-color')); + foregroundColorChooser.set_rgba(color); + foregroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-color', foregroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + foregroundColorRow.add(foregroundColorLabel); + foregroundColorRow.add(foregroundColorChooser); + plasmaMenuTweaksFrame.add(foregroundColorRow); + + let backgroundColorRow = new PW.FrameBoxRow(); + let backgroundColorLabel = new Gtk.Label({ + label: _('Selected Button Background Color'), + xalign:0, + hexpand: true, + }); + let backgroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-background-color')); + backgroundColorChooser.set_rgba(color); + backgroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-background-color',backgroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + backgroundColorRow.add(backgroundColorLabel); + backgroundColorRow.add(backgroundColorChooser); + plasmaMenuTweaksFrame.add(backgroundColorRow); + + this.mainBox.append(plasmaMenuTweaksFrame); + + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true + }); + resetButton.set_sensitive(true); + resetButton.connect('clicked', ()=> { + let foregroundColor = this._settings.get_default_value('plasma-selected-color').unpack(); + let backgroundColor = this._settings.get_default_value('plasma-selected-background-color').unpack(); + let hoverEnabled = this._settings.get_default_value('plasma-enable-hover').unpack(); + let showDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this._settings.reset('searchbar-default-top-location'); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + hoverSwitch.set_active(hoverEnabled); + color.parse(foregroundColor); + foregroundColorChooser.set_rgba(color); + color.parse(backgroundColor); + backgroundColorChooser.set_rgba(color); + descriptionsSwitch.set_active(showDescriptions); + this._settings.reset('plasma-selected-color'); + this._settings.reset('plasma-selected-background-color'); + this._settings.reset('plasma-enable-hover'); + this._settings.reset('apps-show-extra-details'); + this._settings.set_boolean('reload-theme', true); + }); + this.mainBox.append(resetButton); + } + _loadBriskMenuTweaks(){ + let briskMenuTweaksFrame = new PW.FrameBox(); + briskMenuTweaksFrame.add(this._createActivateOnHoverRow()); + briskMenuTweaksFrame.add(this._createSearchBarLocationRow()); + briskMenuTweaksFrame.add(this._createFlipHorizontalRow()); + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_max_content_height(100); + pinnedAppsScrollWindow.set_min_content_height(100); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('brisk-shortcuts-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('brisk-shortcuts-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Brisk Menu Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + + this.mainBox.append(briskMenuTweaksFrame); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + } + _loadChromebookTweaks(){ + let chromeBookTweaksFrame = new PW.FrameBox(); + chromeBookTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(chromeBookTweaksFrame); + } + _loadElementaryTweaks(){ + let elementaryTweaksFrame = new PW.FrameBox(); + elementaryTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(elementaryTweaksFrame); + } + _loadBudgieMenuTweaks(){ + let budgieMenuTweaksFrame = new PW.FrameBox(); + budgieMenuTweaksFrame.add(this._createActivateOnHoverRow()); + budgieMenuTweaksFrame.add(this._createSearchBarLocationRow()); + budgieMenuTweaksFrame.add(this._createFlipHorizontalRow()); + + let enableActivitiesRow = new PW.FrameBoxRow(); + let enableActivitiesLabel = new Gtk.Label({ + label: _('Enable Activities Overview Shortcut'), + xalign:0, + hexpand: true, + }); + let enableActivitiesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableActivitiesSwitch.set_active(this._settings.get_boolean('enable-activities-shortcut')); + enableActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-activities-shortcut', widget.get_active()); + }); + enableActivitiesRow.add(enableActivitiesLabel); + enableActivitiesRow.add(enableActivitiesSwitch); + budgieMenuTweaksFrame.add(enableActivitiesRow); + + this.mainBox.append(budgieMenuTweaksFrame); + } + _loadRunnerMenuTweaks(){ + let runnerMenuTweaksFrame = new PW.FrameBox(); + let runnerPositionRow = new PW.FrameBoxRow(); + let runnerPositionLabel = new Gtk.Label({ + label: _('Position'), + xalign:0, + hexpand: true, + }); + let runnerPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + runnerPositionCombo.append_text(_("Top")); + runnerPositionCombo.append_text(_("Centered")); + runnerPositionCombo.set_active(this._settings.get_enum('runner-position')); + runnerPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('runner-position', widget.get_active()); + }); + runnerPositionRow.add(runnerPositionLabel); + runnerPositionRow.add(runnerPositionCombo); + runnerMenuTweaksFrame.add(runnerPositionRow); + + let runnerWidthRow = new PW.FrameBoxRow(); + let runnerWidthLabel = new Gtk.Label({ + label: _("Width"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerWidthScale.add_mark(500, Gtk.PositionType.TOP, _("Default")); + runnerWidthScale.set_value(this._settings.get_int('runner-menu-width')); + runnerWidthScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-width', widget.get_value()); + }); + runnerWidthRow.add(runnerWidthLabel); + runnerWidthRow.add(runnerWidthScale); + runnerMenuTweaksFrame.add(runnerWidthRow); + + let runnerHeightRow = new PW.FrameBoxRow(); + let runnerHeightLabel = new Gtk.Label({ + label: _("Height"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerHeightScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerHeightScale.add_mark(400, Gtk.PositionType.TOP, _("Default")); + runnerHeightScale.set_value(this._settings.get_int('runner-menu-height')); + runnerHeightScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-height', widget.get_value()); + }); + + runnerHeightRow.add(runnerHeightLabel); + runnerHeightRow.add(runnerHeightScale); + runnerMenuTweaksFrame.add(runnerHeightRow); + + let runnerFontSizeRow = new PW.FrameBoxRow(); + let runnerFontSizeLabel = new Gtk.Label({ + label: _("Font Size"), + hexpand: true, + use_markup: true, + xalign: 0 + }); + let runnerFontSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 30, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + + runnerFontSizeScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); + runnerFontSizeScale.set_value(this._settings.get_int('runner-font-size')); + runnerFontSizeScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-font-size', widget.get_value()); + }); + runnerFontSizeRow.add(runnerFontSizeLabel); + runnerFontSizeRow.add(runnerFontSizeScale); + runnerMenuTweaksFrame.add(runnerFontSizeRow); + + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Show Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let frequentAppsSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-show-frequent-apps')) + frequentAppsSwitch.set_active(true); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-show-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + runnerMenuTweaksFrame.add(frequentAppsRow); + + let inheritThemeGapRow = new PW.FrameBoxRow(); + let inheritThemeGapLabel = new Gtk.Label({ + label: _("Inherit Shell Theme Popup Gap"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let inheritThemeGapSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-use-theme-gap')) + inheritThemeGapSwitch.set_active(true); + inheritThemeGapSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-use-theme-gap', widget.get_active()); + }); + inheritThemeGapRow.add(inheritThemeGapLabel); + inheritThemeGapRow.add(inheritThemeGapSwitch); + runnerMenuTweaksFrame.add(inheritThemeGapRow); + + this.mainBox.append(runnerMenuTweaksFrame); + } + _loadUnityTweaks(){ + let pinnedAppsFrame = new PW.FrameBox(); + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.UNITY); + this.mainBox.append(widgetFrame); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('unity-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('unity-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Unity Layout Buttons") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Button Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('unity-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('unity-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadRavenTweaks(){ + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let ravenPositionRow = new PW.FrameBoxRow(); + let ravenPositionLabel = new Gtk.Label({ + label: _('Position on Monitor'), + xalign:0, + hexpand: true, + }); + let ravenPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + ravenPositionCombo.append_text(_("Left")); + ravenPositionCombo.append_text(_("Right")); + let ravenPosition = this._settings.get_enum('raven-position'); + ravenPositionCombo.set_active(ravenPosition); + ravenPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('raven-position', widget.get_active()); + }); + ravenPositionRow.add(ravenPositionLabel); + ravenPositionRow.add(ravenPositionCombo); + generalTweaksFrame.add(ravenPositionRow); + generalTweaksFrame.add(this._createActivateOnHoverRow()); + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.RAVEN); + this.mainBox.append(widgetFrame); + } + _loadMintMenuTweaks(){ + let mintMenuTweaksFrame = new PW.FrameBox(); + mintMenuTweaksFrame.add(this._createActivateOnHoverRow()); + mintMenuTweaksFrame.add(this._createSearchBarLocationRow()); + mintMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(mintMenuTweaksFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Mint Layout Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('mint-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('mint-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + this.mainBox.append(pinnedAppsScrollWindow); + + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Shortcut Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('mint-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('mint-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadPinnedApps(array,frame, savePinnedAppsButton, scrollWindow) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(scrollWindow); + frameRow._name = array[i]; + frameRow._icon = Prefs.getIconPath([array[i], array[i+1], array[i+2]]); + frameRow._cmd = array[i+2]; + frameRow.saveButton = savePinnedAppsButton; + frameRow.hasEditButton = true; + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + frameRow.add(frameLabel); + + Prefs.checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: frame, + buttons: [savePinnedAppsButton], + modifyButton: true, + changeButton: true + }); + + buttonBox.connect('change', ()=> { + let dialog = new Prefs.AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.OTHER); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + let icon = Prefs.getIconPath(newPinnedApps); + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new Prefs.AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.OTHER, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(buttonBox); + frame.add(frameRow); + } + } + _loadWhiskerMenuTweaks(){ + let whiskerMenuTweaksFrame = new PW.FrameBox(); + whiskerMenuTweaksFrame.add(this._createActivateOnHoverRow()); + whiskerMenuTweaksFrame.add(this._createAvatarShapeRow()); + whiskerMenuTweaksFrame.add(this._createSearchBarLocationRow()); + whiskerMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(whiskerMenuTweaksFrame); + } + _loadRedmondMenuTweaks(){ + let redmondMenuTweaksFrame = new PW.FrameBox(); + redmondMenuTweaksFrame.add(this._createSearchBarLocationRow()); + + redmondMenuTweaksFrame.add(this._createFlipHorizontalRow()); + redmondMenuTweaksFrame.add(this._createAvatarShapeRow()); + redmondMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(redmondMenuTweaksFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + + } + _loadInsiderMenuTweaks(){ + let insiderMenuTweaksFrame = new PW.FrameBox(); + insiderMenuTweaksFrame.add(this._createAvatarShapeRow()); + this.mainBox.append(insiderMenuTweaksFrame); + } + _loadGnomeMenuTweaks(){ + let gnomeMenuTweaksFrame = new PW.FrameBox(); + gnomeMenuTweaksFrame.add(this._createActivateOnHoverRow()); + gnomeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(gnomeMenuTweaksFrame); + } + _loadPlaceHolderTweaks(){ + let placeHolderFrame = new PW.FrameBox(); + let placeHolderRow = new PW.FrameBoxRow(); + let placeHolderLabel = new Gtk.Label({ + label: _("Nothing Yet!"), + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + placeHolderRow.add(placeHolderLabel); + placeHolderFrame.add(placeHolderRow); + this.mainBox.append(placeHolderFrame); + } + _loadTogneeMenuTweaks(){ + let togneeMenuTweaksFrame = new PW.FrameBox(); + let searchBarBottomDefault = true; + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END + }); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view-tognee')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view-tognee', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + togneeMenuTweaksFrame.add(defaultLeftBoxRow); + togneeMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + togneeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(togneeMenuTweaksFrame); + } + _loadArcMenuTweaks(){ + let arcMenuTweaksFrame = new PW.FrameBox(); + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + defaultLeftBoxCombo.append_text(_("Pinned Apps")); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("Frequent Apps")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + arcMenuTweaksFrame.add(defaultLeftBoxRow); + + let searchBarBottomDefault = true; + arcMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + arcMenuTweaksFrame.add(this._createFlipHorizontalRow()); + arcMenuTweaksFrame.add(this._createAvatarShapeRow()); + arcMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(arcMenuTweaksFrame); + + let extraCategoriesFrame = new PW.FrameBox(); + let extraCategoriesRow = new PW.FrameBoxRow(); + let extraCategoriesButtonRow = new PW.FrameBoxRow(); + let extraCategoriesLocationRow = new PW.FrameBoxRow(); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Categories Quick Links") + "" + + "\n" + '' + _("Display quick links of extra categories on the home page") + "" + + "\n" + '' + _("See Customize Menu -> Extra Categories") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + let extraCategoriesLinksBox = new Prefs.MenuSettingsCategoriesPage(this._settings, "arcmenu-extra-categories-links"); + extraCategoriesLinksBox.categoriesFrame.unparent(); + extraCategoriesLinksBox.buttonRow.unparent(); + extraCategoriesRow.add(extraCategoriesLinksBox.categoriesFrame); + extraCategoriesLinksBox.categoriesFrame.hexpand = true; + extraCategoriesLinksBox.categoriesFrame.halign = Gtk.Align.FILL; + extraCategoriesButtonRow.add(extraCategoriesLinksBox.buttonRow); + extraCategoriesFrame.add(extraCategoriesRow); + extraCategoriesFrame.add(extraCategoriesButtonRow); + + this.mainBox.append(extraCategoriesFrame); + + let extraCategoriesLocationFrame = new PW.FrameBox(); + let extraCategoriesLocationLabel = new Gtk.Label({ + label: _("Quick Links Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let extraCategoriesLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + extraCategoriesLocationCombo.append_text(_("Bottom")); + extraCategoriesLocationCombo.append_text(_("Top")); + extraCategoriesLocationCombo.set_active(this._settings.get_enum('arcmenu-extra-categories-links-location')); + extraCategoriesLocationCombo.connect('changed', (widget) => { + this._settings.set_enum('arcmenu-extra-categories-links-location' , widget.get_active()); + }); + + extraCategoriesLocationRow.add(extraCategoriesLocationLabel); + extraCategoriesLocationRow.add(extraCategoriesLocationCombo); + extraCategoriesLocationFrame.add(extraCategoriesLocationRow); + this.mainBox.append(extraCategoriesLocationFrame); + } + _createWidgetsRows(layout){ + let weatherWidgetSetting = 'enable-weather-widget-raven'; + let clockWidgetSetting = 'enable-clock-widget-raven'; + if(layout == Constants.MenuLayout.RAVEN){ + weatherWidgetSetting = 'enable-weather-widget-raven'; + clockWidgetSetting = 'enable-clock-widget-raven'; + } + else{ + weatherWidgetSetting = 'enable-weather-widget-unity'; + clockWidgetSetting = 'enable-clock-widget-unity'; + } + + let widgetFrame = new PW.FrameBox(); + let weatherWidgetRow = new PW.FrameBoxRow(); + let weatherWidgetLabel = new Gtk.Label({ + label: _("Enable Weather Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let weatherWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + weatherWidgetSwitch.set_active(this._settings.get_boolean(weatherWidgetSetting)); + weatherWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(weatherWidgetSetting, widget.get_active()); + }); + + weatherWidgetRow.add(weatherWidgetLabel); + weatherWidgetRow.add(weatherWidgetSwitch); + widgetFrame.add(weatherWidgetRow); + + let clockWidgetRow = new PW.FrameBoxRow(); + let clockWidgetLabel = new Gtk.Label({ + label: _("Enable Clock Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clockWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + clockWidgetSwitch.set_active(this._settings.get_boolean(clockWidgetSetting)); + clockWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(clockWidgetSetting, widget.get_active()); + }); + + clockWidgetRow.add(clockWidgetLabel); + clockWidgetRow.add(clockWidgetSwitch); + widgetFrame.add(clockWidgetRow); + + return widgetFrame; + } +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js new file mode 100644 index 0000000..b29a5bb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js @@ -0,0 +1,445 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + VerticalMainBox: true, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: 'padding-bottom: 10px; padding-right: 15px;' + }); + + this.mainBox.add_child(this.topBox); + this.categoriesButton = new MW.CategoriesButton(this); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.actor.y_align = Clutter.ActorAlign.CENTER; + this.searchBox.actor.y_expand = true; + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 15px 0px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.categoriesButton.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 5px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.widgetBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: false, + style_class: 'datemenu-displays-box' + }); + + this.widgetBox.style = "margin: 0px; spacing: 10px; padding: 10px 50px;"; + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; width: 350px; padding: 10px; margin: 0px"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px"; + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID, isContainedInCategory); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this._createCategoriesMenu(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _addSeparator(){ + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.ALWAYS_SHOW, Constants.SeparatorAlignment.VERTICAL); + this.actionsBox.add_child(verticalSeparator); + } + + loadExtraPinnedApps(){ + this.actionsContainerBox.remove_child(this.actionsBox); + this.actionsBox.destroy_all_children(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px; padding: 5px 0px;"; + this.actionsContainerBox.add_child(this.actionsBox); + + super.loadExtraPinnedApps(this._settings.get_strv('unity-pinned-app-list'), this._settings.get_int('unity-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + pinnedApps.push(_("Downloads"), "ArcMenu_Downloads", "ArcMenu_Downloads"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('unity-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + _createCategoriesMenu(){ + this.categoriesMenu = new PopupMenu.PopupMenu(this.categoriesButton.actor, 0.5, St.Side.TOP); + this.categoriesMenu.blockSourceEvents = true; + this.categoriesMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.categoriesButton.tooltip){ + this.categoriesButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.categoriesButton.active = false; + this.categoriesButton.sync_hover(); + this.categoriesButton.hovered = this.categoriesButton.hover; + } + }); + this.section = new PopupMenu.PopupMenuSection(); + this.categoriesMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + this.leftPanelPopup.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(350 / scaleFactor); + this.leftPanelPopup.style = `max-height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this._displayCategories(); + this.subMenuManager.addMenu(this.categoriesMenu); + this.categoriesMenu.actor.hide(); + Main.uiGroup.add_child(this.categoriesMenu.actor); + } + + toggleCategoriesMenu(){ + let appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.categoriesMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.categoriesMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.categoriesButton.tooltip.hide(); + + this.categoriesMenu.toggle(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + _displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.categoriesBox.add_actor(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.subMainBox.remove_child(this.actionsContainerBox); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + this.widgetBox.remove_all_children(); + if(this._settings.get_boolean('enable-clock-widget-unity')) + this.widgetBox.add_child(this._clocksItem); + if(this._settings.get_boolean('enable-weather-widget-unity')) + this.widgetBox.add_child(this._weatherItem); + if(!this.subMainBox.contains(this.widgetBox)) + this.subMainBox.add_child(this.widgetBox); + this.subMainBox.add_child(this.actionsContainerBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.categoriesMenu.isOpen) + this.categoriesMenu.toggle(); + if(this.subMainBox.contains(this.widgetBox)){ + this.subMainBox.remove_child(this.widgetBox); + } + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + let label = this._createLabelWithSeparator(this.activeCategory); + if(grid === this.applicationsGrid) + this.applicationsBox.insert_child_at_index(label.actor, 0); + else + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js new file mode 100644 index 0000000..ab4958e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js @@ -0,0 +1,187 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.actionsBox.style = "spacing: 6px; margin: 0px 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.actor.x_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + else{ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js new file mode 100644 index 0000000..047bd63 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.LIST, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 300, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.extrasButton = new MW.ExtrasButton(this); + this.extrasButton.actor.y_expand = true; + this.extrasButton.actor.y_align= Clutter.ActorAlign.START; + this.actionsBox.add_child(this.extrasButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade' + }); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true, + x_expand: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 10 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.pinnedAppsGrid); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 0px 10px;"; + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.subMainBox.add_child(this.searchBox.actor); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createExtrasMenu(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.pinnedAppsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView){ + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + this.pinnedAppsGrid.layout_manager.forceGridColumns = this.getColumnsFromGridIconSizeSetting(); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let directory = directoryShortcutsList[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createExtrasMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.extrasMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.section = new PopupMenu.PopupMenuSection(); + this.extrasMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.toggleExtrasMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + + this.computerScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + reactive:true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + + this.leftPanelPopup.add_child(this.computerScrollBox); + + this.computerBox = new St.BoxLayout({ + vertical: true + }); + this.computerScrollBox.add_actor(this.computerBox); + + this.computerBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.computerBox.add_child(this.applicationShortcuts[i]); + } + this.computerBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.computerBox.add_child(this.directoryShortcuts[i]); + } + this.computerBox.add_child(this.externalDevicesBox); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.subMenuManager.addMenu(this.extrasMenu); + this.extrasMenu.actor.hide(); + Main.uiGroup.add_child(this.extrasMenu.actor); + this.extrasMenu.connect('open-state-changed', (menu, open) => { + if(!open){ + this.extrasButton.active = false; + this.extrasButton.sync_hover(); + this.extrasButton.hovered = this.extrasButton.hover; + } + else{ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.extrasButton.tooltip){ + this.extrasButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + }); + } + + toggleExtrasMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.extrasMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.extrasMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.extrasButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.extrasMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base:0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.extrasMenu.toggle(); + if(this.extrasMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + + this.displayAllApps(); + if(!this._settings.get_boolean('windows-disable-pinned-apps')){ + if(!this.mainBox.contains(this.pinnedAppsScrollBox)) + this.mainBox.add_child(this.pinnedAppsScrollBox); + this.displayPinnedApps(); + } + + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + + displayAllApps(){ + this._clearActorsFromBox(); + let label = this._createLabelWithSeparator(_("Frequent")); + this.activeMenuItemSet = false; + + if(!this._settings.get_boolean('windows-disable-frequent-apps')){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + this.frequentAppsList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + const MaxItems = 8; + if(this.frequentAppsList.length > 0){ + this.applicationsBox.add_child(label.actor); + for (let i = 0; i < this.frequentAppsList.length && i < MaxItems; i++) { + let item = this.frequentAppsList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!this.activeMenuItemSet){ + this._frequentActiveItem = item; + this.activeMenuItemSet = true; + } + } + } + } + + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + super._clearActorsFromBox(this.pinnedAppsBox); + this.pinnedAppsGrid.remove_all_children(); + let label = this.createLabelRow(_("Pinned Apps")); + label.remove_child(label._ornamentLabel); + this.pinnedAppsBox.add_child(label); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.HOME_SCREEN, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/metadata.json b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/metadata.json new file mode 100644 index 0000000..f6d4800 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/metadata.json @@ -0,0 +1,15 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Application menu for GNOME Shell\n\nFeatures include: various menu layouts, built in GNOME search, quick access to system shortcuts, and much more!\n\nCommon solutions for ERROR message:\n - Restart your GNOME session after updating ArcMenu.\n - Install one of the following packages: 'gir1.2-gmenu-3.0' or 'gnome-menus'\n\nGeneral Help:\n - Visit https://gitlab.com/arcmenu/ArcMenu/-/wikis/home\n\nPlease report all bugs or issues at https://gitlab.com/arcmenu/ArcMenu", + "extension-id": "arcmenu", + "gettext-domain": "arcmenu", + "name": "ArcMenu", + "settings-schema": "org.gnome.shell.extensions.arcmenu", + "shell-version": [ + "40", + "41" + ], + "url": "https://gitlab.com/arcmenu/ArcMenu", + "uuid": "arcmenu@arcmenu.com", + "version": 27 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js new file mode 100644 index 0000000..4e58333 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js @@ -0,0 +1,764 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from places-menu extension + * (https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/places-menu) + * and Dash to Dock extension 'location.js' file to implement a trash shortcut + * (https://github.com/micheleg/dash-to-dock/blob/master/locations.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {St, Gio, GLib, Shell } = imports.gi; +const Clutter = imports.gi.Clutter; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const GObject = imports.gi.GObject; +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const ShellMountOperation = imports.ui.shellMountOperation; +const Signals = imports.signals; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const BACKGROUND_SCHEMA = 'org.gnome.desktop.background'; +const Hostname1Iface = ' \ + \ + \ + \ +'; +const Hostname1 = Gio.DBusProxy.makeProxyWrapper(Hostname1Iface); + +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem2 extends MW.ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info) { + super._init(menuLayout); + this._info = info; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ text: info.name, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER }); + + this.add_child(this.label); + + if (info.isRemovable()) { + this.style = "padding-right: 15px;"; + this._ejectButton = new MW.ArcMenuButtonItem(this._menuLayout, null, 'media-eject-symbolic'); + this._ejectButton.add_style_class_name("arcmenu-small-button") + this._ejectButton.setIconSize(14); + this._ejectButton.x_align = Clutter.ActorAlign.END; + this._ejectButton.x_expand = true; + this._ejectButton.connect('activate', info.eject.bind(info)); + this.add_child(this._ejectButton); + } + + this._changedId = info.connect('changed', + this._propertiesChanged.bind(this)); + this.actor.connect('destroy',()=>{ + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = 0; + } + }); + + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + let defaultIconSize = this._menuLayout.layoutProperties.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this._info.icon, + icon_size: iconSize + }); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this._iconBin.set_child(this.createIcon()); + this.label.text = info.name; + } +}); + +var PlaceInfo = class Arc_Menu_PlaceInfo2 { + constructor() { + this._init.apply(this, arguments); + } + + _init(kind, file, name, icon) { + this.kind = kind; + this.file = file; + this.name = name || this._getFileName(); + this.icon = icon ? new Gio.ThemedIcon({ name: icon }) : this.getIcon(); + } + + destroy() { + } + + isRemovable() { + return false; + } + + async _ensureMountAndLaunch(context, tryMount) { + try { + await this._launchDefaultForUri(this.file.get_uri(), context, null); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_MOUNTED)) { + Main.notifyError(_('Failed to launch “%s”').format(this.name), e.message); + return; + } + + let source = { + get_icon: () => this.icon + }; + let op = new ShellMountOperation.ShellMountOperation(source); + try { + await this._mountEnclosingVolume(0, op.mountOp, null); + + if (tryMount) + this._ensureMountAndLaunch(context, false); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED)) + Main.notifyError(_('Failed to mount volume for “%s”').format(this.name), e.message); + } finally { + op.close(); + } + } + } + + launch(timestamp) { + let launchContext = global.create_app_launch_context(timestamp, -1); + this._ensureMountAndLaunch(launchContext, true); + } + + getIcon() { + this.file.query_info_async('standard::symbolic-icon', 0, 0, null, + (file, result) => { + try { + let info = file.query_info_finish(result); + this.icon = info.get_symbolic_icon(); + this.emit('changed'); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return; + throw e; + } + }); + + // return a generic icon for this kind for now, until we have the + // icon from the query info above + switch (this.kind) { + case 'network': + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + case 'devices': + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + case 'special': + case 'bookmarks': + default: + if (!this.file.is_native()) + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + else + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return this.file.get_basename(); + throw e; + } + } + + _launchDefaultForUri(uri, context, cancel) { + return new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(uri, context, cancel, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } + + _mountEnclosingVolume(flags, mountOp, cancel) { + return new Promise((resolve, reject) => { + this.file.mount_enclosing_volume(flags, mountOp, cancel, (o, res) => { + try { + this.file.mount_enclosing_volume_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } +} +Signals.addSignalMethods(PlaceInfo.prototype); + +var RootInfo = class Arc_Menu_RootInfo extends PlaceInfo { + _init() { + super._init('devices', Gio.File.new_for_path('/'), _('Computer')); + + let busName = 'org.freedesktop.hostname1'; + let objPath = '/org/freedesktop/hostname1'; + new Hostname1(Gio.DBus.system, busName, objPath, (obj, error) => { + if (error) + return; + + this._proxy = obj; + this._proxyID = this._proxy.connect('g-properties-changed', + this._propertiesChanged.bind(this)); + this._propertiesChanged(obj); + }); + + } + + getIcon() { + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + } + + _propertiesChanged(proxy) { + // GDBusProxy will emit a g-properties-changed when hostname1 goes down + // ignore it + if (proxy.g_name_owner) { + this.name = proxy.PrettyHostname || _('Computer'); + this.emit('changed'); + } + } + + destroy() { + if (this._proxyID) { + this._proxy.disconnect(this._proxyID); + this._proxy = 0; + } + if (this._proxy) { + this._proxy.run_dispose(); + this._proxy = null; + } + super.destroy(); + } +}; + + +var PlaceDeviceInfo = class Arc_Menu_PlaceDeviceInfo extends PlaceInfo { + _init(kind, mount) { + this._mount = mount; + super._init(kind, mount.get_root(), mount.get_name()); + } + + getIcon() { + return this._mount.get_symbolic_icon(); + } + + isRemovable() { + return this._mount.can_eject(); + } + + eject() { + let unmountArgs = [ + Gio.MountUnmountFlags.NONE, + (new ShellMountOperation.ShellMountOperation(this._mount)).mountOp, + null // Gio.Cancellable + ]; + + if (this._mount.can_eject()) + this._mount.eject_with_operation(...unmountArgs, + this._ejectFinish.bind(this)); + else + this._mount.unmount_with_operation(...unmountArgs, + this._unmountFinish.bind(this)); + } + + _ejectFinish(mount, result) { + try { + mount.eject_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _unmountFinish(mount, result) { + try { + mount.unmount_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _reportFailure(exception) { + let msg = _('Ejecting drive “%s” failed:').format(this._mount.get_name()); + Main.notifyError(msg, exception.message); + } +}; + +var PlaceVolumeInfo = class Arc_Menu_PlaceVolumeInfo extends PlaceInfo { + _init(kind, volume) { + this._volume = volume; + super._init(kind, volume.get_activation_root(), volume.get_name()); + } + + launch(timestamp) { + if (this.file) { + super.launch(timestamp); + return; + } + + this._volume.mount(0, null, null, (volume, result) => { + volume.mount_finish(result); + + let mount = volume.get_mount(); + this.file = mount.get_root(); + super.launch(timestamp); + }); + } + + getIcon() { + return this._volume.get_symbolic_icon(); + } +}; + +const DefaultDirectories = [ + GLib.UserDirectory.DIRECTORY_DOCUMENTS, + GLib.UserDirectory.DIRECTORY_PICTURES, + GLib.UserDirectory.DIRECTORY_MUSIC, + GLib.UserDirectory.DIRECTORY_DOWNLOAD, + GLib.UserDirectory.DIRECTORY_VIDEOS, +]; + +var PlacesManager = class Arc_Menu_PlacesManager { + constructor() { + this._places = { + special: [], + devices: [], + bookmarks: [], + network: [], + }; + + this._settings = new Gio.Settings({ schema_id: BACKGROUND_SCHEMA }); + this._showDesktopIconsChangedId = + this._settings.connect('changed::show-desktop-icons', + this._updateSpecials.bind(this)); + this._updateSpecials(); + + /* + * Show devices, code more or less ported from nautilus-places-sidebar.c + */ + this._volumeMonitor = Gio.VolumeMonitor.get(); + this._connectVolumeMonitorSignals(); + this._updateMounts(); + + this._bookmarksFile = this._findBookmarksFile(); + this._bookmarkTimeoutId = 0; + this._monitor = null; + + if (this._bookmarksFile) { + this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null); + this._monitor.connect('changed', () => { + if (this._bookmarkTimeoutId > 0) + return; + /* Defensive event compression */ + this._bookmarkTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 100, () => { + this._bookmarkTimeoutId = 0; + this._reloadBookmarks(); + return false; + }); + }); + + this._reloadBookmarks(); + } + } + + _connectVolumeMonitorSignals() { + const signals = [ + 'volume-added', + 'volume-removed', + 'volume-changed', + 'mount-added', + 'mount-removed', + 'mount-changed', + 'drive-connected', + 'drive-disconnected', + 'drive-changed' + ]; + + this._volumeMonitorSignals = []; + let func = this._updateMounts.bind(this); + for (let i = 0; i < signals.length; i++) { + let id = this._volumeMonitor.connect(signals[i], func); + this._volumeMonitorSignals.push(id); + } + } + + destroy() { + if (this._settings) + this._settings.disconnect(this._showDesktopIconsChangedId); + this._settings = null; + + for (let i = 0; i < this._volumeMonitorSignals.length; i++) + this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]); + + if (this._monitor) + this._monitor.cancel(); + if (this._bookmarkTimeoutId) + GLib.source_remove(this._bookmarkTimeoutId); + } + + _updateSpecials() { + this._places.special.forEach(p => p.destroy()); + this._places.special = []; + + let homePath = GLib.get_home_dir(); + + this._places.special.push(new PlaceInfo('special', + Gio.File.new_for_path(homePath), + _('Home'))); + + let specials = []; + let dirs = DefaultDirectories.slice(); + + if (this._settings.get_boolean('show-desktop-icons')) + dirs.push(GLib.UserDirectory.DIRECTORY_DESKTOP); + + for (let i = 0; i < dirs.length; i++) { + let specialPath = GLib.get_user_special_dir(dirs[i]); + if (specialPath == null || specialPath == homePath) + continue; + + let file = Gio.File.new_for_path(specialPath), info; + try { + info = new PlaceInfo('special', file); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + continue; + throw e; + } + + specials.push(info); + } + + specials.sort((a, b) => GLib.utf8_collate(a.name, b.name)); + this._places.special = this._places.special.concat(specials); + + this.emit('special-updated'); + } + + _updateMounts() { + let networkMounts = []; + let networkVolumes = []; + + this._places.devices.forEach(p => p.destroy()); + this._places.devices = []; + this._places.network.forEach(p => p.destroy()); + this._places.network = []; + + /* Add standard places */ + // this._places.devices.push(new RootInfo()); + /* this._places.network.push(new PlaceInfo('network', + Gio.File.new_for_uri('network:///'), + _('Network'), + 'network-workgroup-symbolic'));*/ + + /* first go through all connected drives */ + let drives = this._volumeMonitor.get_connected_drives(); + for (let i = 0; i < drives.length; i++) { + let volumes = drives[i].get_volumes(); + + for (let j = 0; j < volumes.length; j++) { + let identifier = volumes[j].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[j]); + } else { + let mount = volumes[j].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + } + + /* add all volumes that is not associated with a drive */ + let volumes = this._volumeMonitor.get_volumes(); + for (let i = 0; i < volumes.length; i++) { + if (volumes[i].get_drive() != null) + continue; + + let identifier = volumes[i].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[i]); + } else { + let mount = volumes[i].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + + /* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */ + let mounts = this._volumeMonitor.get_mounts(); + for (let i = 0; i < mounts.length; i++) { + if (mounts[i].is_shadowed()) + continue; + + if (mounts[i].get_volume()) + continue; + + let root = mounts[i].get_default_location(); + if (!root.is_native()) { + networkMounts.push(mounts[i]); + continue; + } + this._addMount('devices', mounts[i]); + } + + for (let i = 0; i < networkVolumes.length; i++) { + let mount = networkVolumes[i].get_mount(); + if (mount) { + networkMounts.push(mount); + continue; + } + this._addVolume('network', networkVolumes[i]); + } + + for (let i = 0; i < networkMounts.length; i++) { + this._addMount('network', networkMounts[i]); + } + + this.emit('devices-updated'); + this.emit('network-updated'); + } + + _findBookmarksFile() { + let paths = [ + GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']), + GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']), + ]; + + for (let i = 0; i < paths.length; i++) { + if (GLib.file_test(paths[i], GLib.FileTest.EXISTS)) + return Gio.File.new_for_path(paths[i]); + } + + return null; + } + + _reloadBookmarks() { + + this._bookmarks = []; + + let content = Shell.get_file_contents_utf8_sync(this._bookmarksFile.get_path()); + let lines = content.split('\n'); + + let bookmarks = []; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let components = line.split(' '); + let bookmark = components[0]; + + if (!bookmark) + continue; + + let file = Gio.File.new_for_uri(bookmark); + if (file.is_native() && !file.query_exists(null)) + continue; + + let duplicate = false; + for (let i = 0; i < this._places.special.length; i++) { + if (file.equal(this._places.special[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + for (let i = 0; i < bookmarks.length; i++) { + if (file.equal(bookmarks[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + let label = null; + if (components.length > 1) + label = components.slice(1).join(' '); + + bookmarks.push(new PlaceInfo('bookmarks', file, label)); + } + + this._places.bookmarks = bookmarks; + + this.emit('bookmarks-updated'); + } + + _addMount(kind, mount) { + let devItem; + + try { + devItem = new PlaceDeviceInfo(kind, mount); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(devItem); + } + + _addVolume(kind, volume) { + let volItem; + + try { + volItem = new PlaceVolumeInfo(kind, volume); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(volItem); + } + + get(kind) { + return this._places[kind]; + } +}; +Signals.addSignalMethods(PlacesManager.prototype); + +//Trash can class implemented from Dash to Dock https://github.com/micheleg/dash-to-dock/blob/master/locations.js +var Trash = class Arc_Menu_Trash { + constructor(menuItem) { + this._menuItem = menuItem; + let trashPath = GLib.get_home_dir() + '/.local/share/Trash/files/'; + this._file = Gio.file_new_for_path(trashPath); + try { + this._monitor = this._file.monitor_directory(0, null); + this._signalId = this._monitor.connect( + 'changed', + this._onTrashChange.bind(this) + ); + } catch (e) { + log(`Impossible to monitor trash: ${e}`); + } + this._lastEmpty = true; + this._empty = true; + this._schedUpdateId = 0; + this._updateTrash(); + } + + destroy() { + if (this._monitor) { + this._monitor.disconnect(this._signalId); + this._monitor.run_dispose(); + } + this._file.run_dispose(); + } + + _onTrashChange() { + if (this._schedUpdateId) { + GLib.source_remove(this._schedUpdateId); + } + this._schedUpdateId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 500, () => { + this._schedUpdateId = 0; + this._updateTrash(); + return GLib.SOURCE_REMOVE; + }); + } + + _updateTrash() { + try { + let children = this._file.enumerate_children('*', 0, null); + this._empty = children.next_file(null) == null; + children.close(null); + } catch (e) { + log(`Impossible to enumerate trash children: ${e}`) + return; + } + + this._ensureApp(); + } + + _ensureApp() { + if (this._trashApp == null || + this._lastEmpty != this._empty) { + let trashKeys = new GLib.KeyFile(); + trashKeys.set_string('Desktop Entry', 'Name', _('Trash')); + trashKeys.set_string('Desktop Entry', 'Id', 'ArcMenu_Trash'); + trashKeys.set_string('Desktop Entry', 'Icon', + this._empty ? 'user-trash-symbolic' : 'user-trash-full-symbolic'); + trashKeys.set_string('Desktop Entry', 'Type', 'Application'); + trashKeys.set_string('Desktop Entry', 'Exec', 'gio open trash:///'); + trashKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); + trashKeys.set_string('Desktop Entry', 'XdtdUri', 'trash:///'); + if (!this._empty) { + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash;'); + trashKeys.set_string('Desktop Action empty-trash', 'Name', _('Empty Trash')); + trashKeys.set_string('Desktop Action empty-trash', 'Exec', + 'dbus-send --print-reply --dest=org.gnome.Nautilus /org/gnome/Nautilus org.gnome.Nautilus.FileOperations.EmptyTrash'); + } + else{ + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash-inactive;'); + trashKeys.set_string('Desktop Action empty-trash-inactive', 'Name', _('Empty Trash')); + } + + let trashAppInfo = Gio.DesktopAppInfo.new_from_keyfile(trashKeys); + this._trashApp = new Shell.App({appInfo: trashAppInfo}); + this._lastEmpty = this._empty; + + this._menuItem._app = this._trashApp; + if(this._menuItem.contextMenu) + this._menuItem.contextMenu._app = this._trashApp; + let trashIcon = this._trashApp.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(this._menuItem._iconBin && trashIcon) + this._menuItem.iconName = trashIcon.gicon.to_string(); + this._menuItem._updateIcon(); + this.emit('changed'); + } + } + + getApp() { + this._ensureApp(); + return this._trashApp; + } +} +Signals.addSignalMethods(Trash.prototype); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefs.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefs.js new file mode 100644 index 0000000..916491b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefs.js @@ -0,0 +1,6786 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const ByteArray = imports.byteArray; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const LayoutTweaks = Me.imports.menulayouts.tweaks; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/arcmenu/'; +const GSET = 'gnome-shell-extension-tool'; + +var MenuSettingsPinnedAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPinnedAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + + this.pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.pinnedAppsScrollWindow.set_min_content_height(300); + this.pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.frame = new PW.FrameBox(); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END, + vexpand: false, + valign: Gtk.Align.END + }); + this._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + this.pinnedAppsScrollWindow.set_child(this.frame); + this.mainBox.append(this.pinnedAppsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array = []; + for(let i = 0; i < newPinnedApps.length; i++){ + array.push(newPinnedApps[i]._name); + array.push(newPinnedApps[i]._icon); + array.push(newPinnedApps[i]._cmd); + } + this._loadPinnedApps(array); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addPinnedAppsFrameRow.add(addPinnedAppsFrameLabel); + addPinnedAppsFrameRow.add(addPinnedAppsButton); + addPinnedAppsFrame.add(addPinnedAppsFrameRow); + this.mainBox.append(addPinnedAppsFrame); + + let addCustomAppFrame = new PW.FrameBox(); + let addCustomAppFrameRow = new PW.FrameBoxRow(); + let addCustomAppFrameLabel = new Gtk.Label({ + label: _("Add Custom Shortcut"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addCustomAppButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addCustomAppButton.connect('clicked', ()=> { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps(newPinnedApps); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let x = 0; x < this.frame.count; x++) { + array.push(this.frame.get_index(x)._name); + array.push(this.frame.get_index(x)._icon); + array.push(this.frame.get_index(x)._cmd); + } + this._settings.set_strv('pinned-app-list',array); + this.saveButton.set_sensitive(false); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + _loadPinnedApps(array) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(this.pinnedAppsScrollWindow); + let iconString; + frameRow._name = array[i]; + frameRow._icon = array[i + 1]; + frameRow._cmd = array[i + 2]; + frameRow.saveButton = this.saveButton; + if(frameRow._icon === "ArcMenu_ArcMenuIcon"){ + frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + + checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + frameRow.add(frameLabel); + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.frame, + buttons: [this.saveButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)) + arcMenuImage.gicon = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon(); + else + arcMenuImage.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + frameRow.add(buttonBox); + this.frame.add(frameRow); + } + } +}); + +var AddAppsToPinnedListWindow = GObject.registerClass( + class Arc_Menu_AddAppsToPinnedListWindow extends PW.DialogWindow { + _init(settings, parent, dialogType) { + this._settings = settings; + this._dialogType = dialogType; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(_('Add to your Pinned Apps'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(_('Change Selected Pinned App'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(_('Select Application Shortcuts'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(_('Select Directory Shortcuts'), parent); + this.newPinnedAppsArray=[]; + this.addResponse = false; + } + + _createLayout(vbox) { + let searchBar = new Gtk.SearchEntry({ + placeholder_text: _("Search…") + }); + searchBar.connect('search-changed', ()=> { + this._loadCategories(); + let applist = Gio.app_info_get_all(); + + let pattern = searchBar.text; + let searchResults = []; + let res = []; + for (let i in applist) { + let app = applist[i]; + let match; + + match = app.get_name().toLowerCase() + " "; + let info = Gio.DesktopAppInfo.new(app.get_id()); + + if (info.get_display_name()) + match += info.get_display_name().toLowerCase() + " "; + if (info.get_executable()) + match += info.get_executable().toLowerCase() + " "; + if (info.get_keywords()) + match += info.get_keywords().toString().toLowerCase() + " "; + if (app.get_description()) + match += app.get_description().toLowerCase(); + + + let index = match.indexOf(pattern); + if (index != -1) { + searchResults.push([index, app]); + } + } + let arcMenuSettings = _("ArcMenu Settings").toLowerCase(); + let index = arcMenuSettings.indexOf(pattern); + let showArcMenuSettings = false; + if (index != -1) { + showArcMenuSettings = true; + } + + searchResults.sort(function(a,b) { + return a[0] > b[0]; + }); + res = searchResults.map(function(value,index) { return value[1]; }); + this.appsFrame.remove_all_children(); + this._loadCategories(res, showArcMenuSettings); + this.appsFrame.show(); + + }); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_min_content_width(650); + this.appsFrame = new PW.FrameBox(); + let addAppsButton; + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS + || this._dialogType == Constants.DiaglogType.DIRECTORIES){ + addAppsButton = new Gtk.Button({ + label: _("Add") + }); + + addAppsButton.connect('clicked', ()=> { + this.addResponse = true; + this.response(-10); + }); + addAppsButton.set_halign(Gtk.Align.END); + } + + pinnedAppsScrollWindow.set_child(this.appsFrame); + vbox.append(pinnedAppsScrollWindow); + if(this._dialogType == Constants.DiaglogType.DEFAULT){ + this._loadCategories(); + vbox.append(addAppsButton); + vbox.prepend(searchBar); + } + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Recent"), "document-open-recent-symbolic", "ArcMenu_Recent"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + this.appsFrame.add(frameRow); + } + vbox.append(addAppsButton); + } + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS){ + this._loadCategories(); + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + let defaultApplicationShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("ArcMenu Settings"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg', Constants.ArcMenuSettingsCommand]); + defaultApplicationShortcuts.push([_("Run Command..."), "system-run-symbolic", "ArcMenu_RunCommand"]); + defaultApplicationShortcuts.push([_("Show All Applications"), "view-fullscreen-symbolic", "ArcMenu_ShowAllApplications"]); + + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(frameRow._icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) { + this.newPinnedAppsArray.push(frameRow); + } + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Default Apps")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultApplicationShortcutsFrame); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + vbox.append(addAppsButton); + } + else{ + this._loadCategories(); + let defaultAppsWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + defaultAppsWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + defaultAppsWindow.set_min_content_width(500); + defaultAppsWindow.set_min_content_width(500); + + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + defaultAppsWindow.set_child(defaultApplicationShortcutsFrame); + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"]); + defaultApplicationShortcuts.push([_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"]); + defaultApplicationShortcuts.push([_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"]); + defaultApplicationShortcuts.push([_("Restart"), 'system-reboot-symbolic', "ArcMenu_Restart"]); + defaultApplicationShortcuts.push([_("Suspend"), "media-playback-pause-symbolic", "ArcMenu_Suspend"]); + defaultApplicationShortcuts.push([_("Hybrid Sleep"), Me.path + Constants.SleepIcon.PATH, "ArcMenu_HybridSleep"]); + defaultApplicationShortcuts.push([_("Hibernate"), "document-save-symbolic", "ArcMenu_Hibernate"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Presets")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultAppsWindow); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + } + } + + get_newPinnedAppsArray() { + return this.newPinnedAppsArray; + } + + get_response() { + return this.addResponse; + } + + _loadCategories(searchResults, showArcMenuSettings) { + let allApps = searchResults ? searchResults : Gio.app_info_get_all(); + allApps.sort((a, b) => { + let _a = a.get_display_name(); + let _b = b.get_display_name(); + return GLib.strcmp0(_a, _b); + }); + + let iter = -1; + if(searchResults) + iter = 0; + if(showArcMenuSettings) + iter = -1; + for(let i = iter; i < allApps.length; i++) { + if(i == -1 ? true : allApps[i].should_show()) { + let frameRow = new PW.FrameBoxRow(); + let icon; + if(i == -1){ + frameRow._name = _("ArcMenu Settings"); + icon = frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + frameRow._cmd = Constants.ArcMenuSettingsCommand; + } + else{ + frameRow._app = allApps[i]; + frameRow._name = allApps[i].get_display_name(); + frameRow._icon = ''; + if(allApps[i].get_icon()) + icon = allApps[i].get_icon().to_string(); + else + icon = "dialog-information"; + + frameRow._cmd = allApps[i].get_id(); + } + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS|| + this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + } + else{ + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + } + + this.appsFrame.add(frameRow); + } + } + } +}); + +var AddCustomLinkDialogWindow = GObject.registerClass( + class Arc_Menu_AddCustomLinkDialogWindow extends PW.DialogWindow { + _init(settings, parent, dialogType, isAppEdit=false, appArray=null) { + this._settings = settings; + this.newPinnedAppsArray=[]; + this.addResponse = false; + this.isAppEdit = isAppEdit; + this._dialogType = dialogType; + this.appArray = appArray; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(isAppEdit?_('Edit Shortcut'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(isAppEdit?_('Edit Custom Shortcut'):_('Add a Custom Shortcut'), parent); + } + + _createLayout(vbox) { + let mainFrame = new PW.FrameBox(); + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Shortcut Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let nameEntry = new Gtk.Entry(); + nameEntry.set_width_chars(35); + nameFrameRow.add(nameFrameLabel); + nameFrameRow.add(nameEntry); + nameEntry.grab_focus(); + mainFrame.add(nameFrameRow); + + let iconFrameRow = new PW.FrameBoxRow(); + let iconFrameLabel = new Gtk.Label({ + label: _("Icon:"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconEntry = new Gtk.Entry(); + iconEntry.set_width_chars(35); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Browse...') + }); + + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.set_filter(fileFilter); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + let iconFilepath = dialog.get_file().get_path(); + iconEntry.set_text(iconFilepath); + dialog.destroy(); + } + else if(response === Gtk.ResponseType.CANCEL) + dialog.destroy(); + }) + + dialog.show(); + }); + + iconFrameRow.add(iconFrameLabel); + iconFrameRow.add(fileChooserButton); + iconFrameRow.add(iconEntry); + mainFrame.add(iconFrameRow); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + iconEntry.set_text("ArcMenu_Folder"); + + let cmdFrameRow = new PW.FrameBoxRow(); + let cmdFrameLabel = new Gtk.Label({ + label: _('Terminal Command:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + cmdFrameLabel.label = _("Shortcut Path:"); + let cmdEntry = new Gtk.Entry(); + cmdEntry.set_width_chars(35); + cmdFrameRow.add(cmdFrameLabel); + cmdFrameRow.add(cmdEntry); + mainFrame.add(cmdFrameRow); + + let addButton = new Gtk.Button({ + label: this.isAppEdit ?_("Apply") :_("Add") + }); + + if(this.appArray!=null) { + nameEntry.text=this.appArray[0]; + iconEntry.text=this.appArray[1]; + cmdEntry.text=this.appArray[2]; + } + addButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(nameEntry.get_text()); + this.newPinnedAppsArray.push(iconEntry.get_text()); + this.newPinnedAppsArray.push(cmdEntry.get_text()); + this.addResponse = true; + this.response(-10); + }); + addButton.set_halign(Gtk.Align.END); + + vbox.append(mainFrame); + vbox.append(addButton); + } + + get_newPinnedAppsArray(){ + return this.newPinnedAppsArray; + } + + get_response(){ + return this.addResponse; + } +}); + +var GeneralPage = GObject.registerClass( + class Arc_Menu_GeneralPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let arcMenuPlacementHeader = new Gtk.Label({ + label: "" + _("Display Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(arcMenuPlacementHeader); + let menuPlacementFrame = new PW.FrameBox(); + this._createDisplayOnFrame(menuPlacementFrame, true); + this._settings.connect('changed::available-placement', ()=>{ + menuPlacementFrame.remove_all_children(); + this._createDisplayOnFrame(menuPlacementFrame, false); + menuPlacementFrame.show(); + }) + + this.mainBox.append(menuPlacementFrame); + + let hotCornerHeader = new Gtk.Label({ + label: "" + _("Hot Corner Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(hotCornerHeader); + + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Modify Hot Corner"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let modifyHotCornerButton = new PW.Button({ + icon_name: 'emblem-system-symbolic', + }); + modifyHotCornerButton.connect('clicked', ()=> { + let dialog = new ModifyHotCornerDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + dialog.destroy(); + }); + }); + let modifyHotCornerSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + modifyHotCornerSwitch.set_active(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerButton.set_sensitive(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('override-hot-corners',widget.get_active()); + modifyHotCornerButton.set_sensitive(widget.get_active()); + if(!widget.get_active()){ + this._settings.set_enum('hot-corners',Constants.HotCornerAction.DEFAULT); + } + }); + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(modifyHotCornerButton); + modifyHotCornerRow.add(modifyHotCornerSwitch); + modifyHotCornerFrame.add(modifyHotCornerRow); + this.mainBox.append(modifyHotCornerFrame); + + let menuHotkeyHeader = new Gtk.Label({ + label: "" + _("Hotkey Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuHotkeyHeader); + + let menuHotKeyFrame = this._createHotkeyFrame(true); + this.mainBox.append(menuHotKeyFrame); + + let runnerHeaderLabel = new Gtk.Label({ + label: "" + _("Standalone Runner Menu") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(runnerHeaderLabel); + + let runnerHotkeyFrame = this._createHotkeyFrame(false); + this.mainBox.append(runnerHotkeyFrame); + } + + _createHotkeyFrame(isMenuHotkey){ + let hotkeyFrame = new PW.FrameBox(); + let enableRunnerMenuSwitch, hotkeyEnumSetting, customHotkeySetting, primaryMonitorSetting; + if(isMenuHotkey){ + hotkeyEnumSetting = 'menu-hotkey'; + customHotkeySetting = 'toggle-arcmenu'; + primaryMonitorSetting = 'hotkey-open-primary-monitor'; + } + else{ + hotkeyEnumSetting = 'runner-menu-hotkey'; + customHotkeySetting = 'toggle-runner-menu'; + primaryMonitorSetting = 'runner-hotkey-open-primary-monitor'; + let enableRunnerMenuRow = new PW.FrameBoxRow(); + let enableRunnerMenuLabel = new Gtk.Label({ + label: _("Enable a standalone Runner menu"), + use_markup: true, + xalign: 0, + hexpand: true + }); + enableRunnerMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + enableRunnerMenuSwitch.set_active(this._settings.get_boolean('enable-standlone-runner-menu')); + enableRunnerMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-standlone-runner-menu', widget.get_active()); + if(!widget.get_active()){ + hotkeyFrame.removeChildrenAfterIndex(0); + } + else{ + hotkeyFrame.add(hotkeyRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 0) + hotkeyFrame.add(primaryMonitorRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 1){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + } + }); + enableRunnerMenuRow.add(enableRunnerMenuLabel); + enableRunnerMenuRow.add(enableRunnerMenuSwitch); + hotkeyFrame.add(enableRunnerMenuRow); + } + + let hotkeyActivationRow = new PW.FrameBoxRow(); + let hotkeyActivationLabel = new Gtk.Label({ + label: _("Hotkey Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotkeyActivationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotkeyActivationCombo.append_text(_("Key Release")); + hotkeyActivationCombo.append_text(_("Key Press")); + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + hotkeyActivationCombo.set_active(1); + else + hotkeyActivationCombo.set_active(0); + hotkeyActivationCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + this._settings.set_boolean('disable-hotkey-onkeyrelease',false); + if(widget.get_active() === 1) + this._settings.set_boolean('disable-hotkey-onkeyrelease',true); + }); + + hotkeyActivationRow.add(hotkeyActivationLabel); + hotkeyActivationRow.add(hotkeyActivationCombo); + + let primaryMonitorRow = new PW.FrameBoxRow(); + let primaryMonitorLabel = new Gtk.Label({ + label: _("Open on Primary Monitor"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let primaryMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + primaryMonitorSwitch.set_active(this._settings.get_boolean(primaryMonitorSetting)); + primaryMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(primaryMonitorSetting, widget.get_active()); + }); + primaryMonitorRow.add(primaryMonitorLabel); + primaryMonitorRow.add(primaryMonitorSwitch); + + + let hotkeyRow = new PW.FrameBoxRow(); + let hotkeyLabel = new Gtk.Label({ + label: isMenuHotkey ? _("Menu Hotkey") : _("Runner Hotkey"), + use_markup: true, + xalign: 0, + hexpand: true + }); + hotkeyRow.add(hotkeyLabel); + + let hotkeyCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + if(isMenuHotkey) + hotkeyCombo.append("NONE", _("None")); + hotkeyCombo.append("SUPER_L", _("Left Super Key")); + hotkeyCombo.append("CUSTOM", _("Custom Hotkey")); + hotkeyCombo.set_active(this._settings.get_enum(hotkeyEnumSetting)); + hotkeyCombo.connect('changed', (widget) => { + let removeIndex = isMenuHotkey ? 0 : 1; + if(widget.get_active_id() === "NONE"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + } + else if(widget.get_active_id() === "SUPER_L"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(primaryMonitorRow); + } + else if(widget.get_active_id() === "CUSTOM"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + hotkeyFrame.show(); + } + this._settings.set_enum(hotkeyEnumSetting, widget.get_active()); + }); + hotkeyRow.add(hotkeyCombo); + + hotkeyFrame.add(hotkeyRow); + + let customHotkeyRow = new PW.FrameBoxRow(); + let currentHotkeyLabel = new Gtk.Label( { + label: _("Current Hotkey"), + use_markup: true, + xalign: 0, + hexpand: false + }); + + let shortcutCell = new Gtk.ShortcutsShortcut({ + halign: Gtk.Align.START, + hexpand: true, + }); + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + + let modifyHotkeyButton = new Gtk.Button({ + label: _("Modify Hotkey"), + halign: Gtk.Align.END, + hexpand: false, + }); + customHotkeyRow.add(currentHotkeyLabel); + customHotkeyRow.add(shortcutCell); + customHotkeyRow.add(modifyHotkeyButton); + modifyHotkeyButton.connect('clicked', () => { + let dialog = new CustomHotkeyDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', () => { + let customHotKeyEnum = isMenuHotkey ? 2 : 1; + if(dialog.addResponse) { + this._settings.set_enum(hotkeyEnumSetting, 0); + this._settings.set_strv(customHotkeySetting, [dialog.resultsText]); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + shortcutCell.accelerator = dialog.resultsText; + dialog.destroy(); + } + else { + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + dialog.destroy(); + } + }); + }); + + if(hotkeyCombo.get_active_id() === "SUPER_L"){ + hotkeyFrame.add(primaryMonitorRow); + } + else if(hotkeyCombo.get_active_id() === "CUSTOM"){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + + if(!isMenuHotkey && !enableRunnerMenuSwitch.get_active()) + hotkeyFrame.removeChildrenAfterIndex(0); + return hotkeyFrame; + } + + _createDisplayOnFrame(menuPlacementFrame, setComboBox){ + let menuPlacementRow = new PW.FrameBoxRow(); + let menuPlacementLabel = new Gtk.Label({ + label: _("Display ArcMenu On"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuPlacementCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + let avaliablePlacement = this._settings.get_value('available-placement').deep_unpack(); + let dashExtensionName = _("Dash to Dock"); + let gnomeSettings = Gio.Settings.new("org.gnome.shell"); + let enabledExtensions = gnomeSettings.get_strv('enabled-extensions'); + if (enabledExtensions.includes('ubuntu-dock@ubuntu.com')) { + dashExtensionName = _("Ubuntu Dock"); + } + + menuPlacementCombo.append_text(_("Main Panel")); + menuPlacementCombo.append_text(_("Dash to Panel")); + menuPlacementCombo.append_text(dashExtensionName); + + menuPlacementRow.add(menuPlacementLabel); + menuPlacementRow.add(menuPlacementCombo); + menuPlacementFrame.add(menuPlacementRow); + + let dashToDockWarningRow = new PW.FrameBoxRow(); + let dashToDockWarningLabel = new Gtk.Label({ + label: _("Dash to Dock extension not running!") + "\n" + _("Enable Dash to Dock for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesRow = new PW.FrameBoxRow(); + let showActivitiesLabel = new Gtk.Label({ + label: _("Show Activities Button"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + showActivitiesSwitch.set_active(this._settings.get_boolean('show-activities-button')); + showActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('show-activities-button', widget.get_active()); + }); + showActivitiesRow.add(showActivitiesLabel); + showActivitiesRow.add(showActivitiesSwitch); + + let warningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let warningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + warningImageBox.append(warningImage); + + if(!avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + dashToDockWarningRow.add(warningImageBox); + } + dashToDockWarningRow.add(dashToDockWarningLabel); + + let panelWarningRow = new PW.FrameBoxRow(); + let panelWarningLabel = new Gtk.Label({ + label: avaliablePlacement[Constants.ArcMenuPlacement.DTP] ? _("Main Panel not found!") : + _("Dash to Panel extension not running!") + "\n" + _("Enable Dash to Panel for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + let panelWarningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let panelWarningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + panelWarningImageBox.append(panelWarningImage); + panelWarningRow.add(panelWarningImageBox); + panelWarningRow.add(panelWarningLabel); + + let menuPositionRow = new PW.FrameBoxRow(); + let menuPositionBoxLabel = new Gtk.Label({ + label: _("Position in Panel"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuPositionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + menuPositionCombo.append_text(_('Left')); + menuPositionCombo.append_text(_('Center')); + menuPositionCombo.append_text(_('Right')); + menuPositionCombo.set_active(this._settings.get_enum('position-in-panel')); + menuPositionCombo.connect('changed', (widget) => { + if(widget.get_active() === Constants.MenuPosition.LEFT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + else if(widget.get_active() === Constants.MenuPosition.CENTER){ + if(menuPlacementFrame.get_index(2) != menuPositionAdjustmentRow){ + menuPlacementFrame.insert(menuPositionAdjustmentRow, 2); + menuPlacementFrame.show(); + } + } + else if(widget.get_active() === Constants.MenuPosition.RIGHT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + this._settings.set_enum('position-in-panel', widget.get_active()); + }); + + menuPositionRow.add(menuPositionBoxLabel); + menuPositionRow.add(menuPositionCombo); + + let menuPositionAdjustmentRow = new PW.FrameBoxRow(); + let menuPositionAdjustmentLabel = new Gtk.Label({ + label: _("Menu Alignment"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alignmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 100, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + }); + alignmentScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Left")); + alignmentScale.add_mark(50, Gtk.PositionType.BOTTOM, _("Center")); + alignmentScale.add_mark(100, Gtk.PositionType.BOTTOM, _("Right")); + + alignmentScale.set_value(this._settings.get_int('menu-position-alignment')); + alignmentScale.connect('value-changed', (widget) => { + this._settings.set_int('menu-position-alignment', widget.get_value()); + }); + menuPositionAdjustmentRow.add(menuPositionAdjustmentLabel); + menuPositionAdjustmentRow.add(alignmentScale); + + let multiMonitorRow = new PW.FrameBoxRow(); + let multiMonitorLabel = new Gtk.Label({ + label: _("Display ArcMenu on all monitors"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let multiMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + multiMonitorSwitch.set_active(this._settings.get_boolean('multi-monitor')); + multiMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('multi-monitor', widget.get_active()); + }); + + multiMonitorRow.add(multiMonitorLabel); + multiMonitorRow.add(multiMonitorSwitch); + + menuPlacementCombo.connect('changed', (widget) => { + let placement = widget.get_active(); + this._settings.set_enum('arc-menu-placement', placement); + menuPlacementFrame.remove_all_children(); + menuPlacementFrame.add(menuPlacementRow); + if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.PANEL){ + if(avaliablePlacement[Constants.ArcMenuPlacement.PANEL] === false){ + menuPlacementFrame.add(panelWarningRow); + } + else{ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + menuPlacementFrame.show(); + } + else if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.DTP){ + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]){ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(panelWarningRow); + + menuPlacementFrame.show(); + } + else{ + if(avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(dashToDockWarningRow); + + menuPlacementFrame.show(); + } + }); + let placement = this._settings.get_enum('arc-menu-placement'); + if(setComboBox){ + if(placement == Constants.ArcMenuPlacement.PANEL && !avaliablePlacement[Constants.ArcMenuPlacement.PANEL]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.DTP); + else if(placement == Constants.ArcMenuPlacement.DTP && !avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.PANEL); + else + menuPlacementCombo.set_active(placement); + } + else + menuPlacementCombo.set_active(placement); + } +}); + +var ModifyHotCornerDialogWindow = GObject.registerClass( + class Arc_Menu_ModifyHotCornerDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + super._init(_('Modify Hot Corner'), parent); + this.set_default_size(600,250); + } + + _createLayout(vbox) { + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Hot Corner Action"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerActionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotCornerActionCombo.append_text(_("GNOME Default")); + hotCornerActionCombo.append_text(_("Disabled")); + hotCornerActionCombo.append_text(_("Open ArcMenu")); + hotCornerActionCombo.append_text(_("Custom")); + + let customHotCornerFrame = new PW.FrameBox(); + let customHeaderHotCornerRow = new PW.FrameBoxRow(); + + let customHeaderHotCornerLabel = new Gtk.Label({ + label: ""+_("Custom Hot Corner Action") + "\n" + _("Choose from a list of preset commands or use your own terminal command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + customHeaderHotCornerRow.add(customHeaderHotCornerLabel); + + let presetCustomHotCornerRow = new PW.FrameBoxRow(); + let presetCustomHotCornerLabel = new Gtk.Label({ + label: _("Preset commands"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerPresetsCombo = new Gtk.ComboBoxText({ + hexpand: true + }); + + hotCornerPresetsCombo.append_text(_("Show all Applications")); + hotCornerPresetsCombo.append_text(_("GNOME Terminal")); + hotCornerPresetsCombo.append_text(_("GNOME System Monitor")); + hotCornerPresetsCombo.append_text(_("GNOME Calculator")); + hotCornerPresetsCombo.append_text(_("GNOME gedit")); + hotCornerPresetsCombo.append_text(_("GNOME Screenshot")); + hotCornerPresetsCombo.append_text(_("GNOME Weather")); + hotCornerPresetsCombo.append_text(_("Run Command...")); + hotCornerPresetsCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + customHotCornerEntry.set_text("ArcMenu_ShowAllApplications"); + else if(widget.get_active() === 1) + customHotCornerEntry.set_text("gnome-terminal"); + else if(widget.get_active() === 2) + customHotCornerEntry.set_text("gnome-system-monitor"); + else if(widget.get_active() === 3) + customHotCornerEntry.set_text("gnome-calculator"); + else if(widget.get_active() === 4) + customHotCornerEntry.set_text("gedit"); + else if(widget.get_active() === 5) + customHotCornerEntry.set_text("gnome-screenshot"); + else if(widget.get_active() === 6) + customHotCornerEntry.set_text("gnome-weather"); + else if(widget.get_active() === 7) + customHotCornerEntry.set_text("ArcMenu_RunCommand"); + }); + presetCustomHotCornerRow.add(presetCustomHotCornerLabel); + presetCustomHotCornerRow.add(hotCornerPresetsCombo); + + let customHotCornerRow = new PW.FrameBoxRow(); + let customHotCornerLabel = new Gtk.Label({ + label: _("Terminal Command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let customHotCornerEntry = new Gtk.Entry({ + }); + customHotCornerEntry.set_text(this._settings.get_string('custom-hot-corner-cmd')); + customHotCornerEntry.connect('changed', (widget) => { + applyButton.set_sensitive(true); + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + }); + customHotCornerEntry.set_width_chars(40); + + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + customHotCornerRow.add(customHotCornerLabel); + customHotCornerRow.add(customHotCornerEntry); + + customHotCornerFrame.add(customHeaderHotCornerRow); + customHotCornerFrame.add(presetCustomHotCornerRow); + customHotCornerFrame.add(customHotCornerRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + }); + applyButton.connect('clicked', () => { + this._settings.set_string('custom-hot-corner-cmd',customHotCornerEntry.get_text()); + this._settings.set_enum('hot-corners',hotCornerActionCombo.get_active()); + applyButton.set_sensitive(false); + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + applyButton.set_sensitive(false); + + + let hotCornerAction = this._settings.get_enum('hot-corners'); + hotCornerActionCombo.set_active(hotCornerAction); + hotCornerActionCombo.connect('changed', (widget) => { + applyButton.set_sensitive(true); + if(widget.get_active()==Constants.HotCornerAction.CUSTOM){ + customHotCornerFrame.set_sensitive(true); + } + else{ + customHotCornerFrame.set_sensitive(false); + } + }); + + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(hotCornerActionCombo); + modifyHotCornerFrame.add(modifyHotCornerRow); + if(hotCornerActionCombo.get_active() == Constants.HotCornerAction.CUSTOM) + customHotCornerFrame.set_sensitive(true); + else + customHotCornerFrame.set_sensitive(false); + vbox.append(modifyHotCornerFrame); + vbox.append(customHotCornerFrame); + vbox.append(applyButton); + } + checkIfMatch(text){ + if(text === "ArcMenu_ShowAllApplications") + return 0; + else if(text === "gnome-terminal") + return 1; + else if(text === "gnome-system-monitor") + return 2; + else if(text === "gnome-calculator") + return 3; + else if(text === "gedit") + return 4; + else if(text === "gnome-screenshot") + return 5; + else if(text === "gnome-weather") + return 6; + else if(text === "ArcMenu_RunCommand") + return 7; + else + return -1; + } +}); + +var CustomHotkeyDialogWindow = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_CustomHotkeyDialogWindow extends Gtk.Window { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.keyEventController = new Gtk.EventControllerKey(); + + super._init({ + modal: true, + title: _("Set Custom Hotkey"), + transient_for: parent.get_root() + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + this.set_child(vbox); + this._createLayout(vbox); + this.add_controller(this.keyEventController); + this.set_size_request(500, 250); + } + + _createLayout(vbox) { + let hotkeyKey = ''; + + let modLabel = new Gtk.Label({ + label:_("Choose Modifiers"), + use_markup: true, + hexpand: true, + halign: Gtk.Align.START + }); + let modFrame = new PW.FrameBox(); + let modRow = new PW.FrameBoxRow(); + modRow.add(modLabel); + + let buttonBox = new Gtk.Box({ + hexpand: true, + halign: Gtk.Align.END, + spacing: 5 + }); + modRow.add(buttonBox); + let ctrlButton = new Gtk.ToggleButton({ + label: _("Ctrl") + }); + let superButton = new Gtk.ToggleButton({ + label: _("Super") + }); + let shiftButton = new Gtk.ToggleButton({ + label: _("Shift") + }); + let altButton = new Gtk.ToggleButton({ + label: _("Alt") + }); + ctrlButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + superButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + shiftButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + altButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + buttonBox.append(ctrlButton); + buttonBox.append(superButton); + buttonBox.append(shiftButton); + buttonBox.append(altButton); + modFrame.add(modRow); + vbox.append(modFrame); + + let keyFrame = new PW.FrameBox(); + let keyLabel = new Gtk.Label({ + label: _("Press any key"), + use_markup: true, + xalign: .5, + hexpand: true, + halign: Gtk.Align.CENTER + }); + vbox.append(keyLabel); + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/keyboard-symbolic.svg', 256, 72); + let keyboardImage = Gtk.Picture.new_for_pixbuf(pixbuf); + keyboardImage.hexpand = true; + keyboardImage.vexpand = true; + keyboardImage.halign = Gtk.Align.CENTER; + keyboardImage.valign = Gtk.Align.CENTER; + vbox.append(keyboardImage) + + let resultsRow = new PW.FrameBoxRow(); + let resultsLabel = new Gtk.Label({ + label: _("New Hotkey"), + use_markup: true, + xalign: .5, + hexpand: false, + halign: Gtk.Align.START + }); + let resultsWidget = new Gtk.ShortcutsShortcut({ + hexpand: true, + halign: Gtk.Align.END + }); + resultsRow.add(resultsLabel); + resultsRow.add(resultsWidget); + keyFrame.add(resultsRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + halign: Gtk.Align.END + }); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.emit("response", -10); + }); + applyButton.set_sensitive(false); + + this.keyEventController.connect('key-released', (controller, keyval, keycode, state) => { + this.resultsText = ""; + let key = keyval; + hotkeyKey = Gtk.accelerator_name(key, 0); + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += Gtk.accelerator_name(key,0); + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + + vbox.append(keyFrame); + vbox.append(applyButton); + } +}); + +function getIconPixbuf(filePath){ + if (GLib.file_test(filePath, GLib.FileTest.EXISTS)) + return GdkPixbuf.Pixbuf.new_from_file_at_size(filePath, 25, 25); + else + return null; +} + +var ButtonAppearancePage = GObject.registerClass( + class Arc_Menu_ButtonAppearancePage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + this.menuButtonColor = this._settings.get_string('menu-button-color'); + this.menuButtonHoverColor = this._settings.get_string('menu-button-hover-color'); + this.menuButtonActiveColor = this._settings.get_string('menu-button-active-color'); + this.menuButtonHoverBackgroundcolor = this._settings.get_string('menu-button-hover-backgroundcolor'); + this.menuButtonActiveBackgroundcolor = this._settings.get_string('menu-button-active-backgroundcolor'); + this._createLayout(this.mainBox); + } + + _createLayout(vbox) { + this.arcMenuPlacement = this._settings.get_enum('arc-menu-placement'); + let menuButtonAppearanceHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonAppearanceHeaderLabel); + + let menuButtonAppearanceFrame = new PW.FrameBox(); + let menuButtonAppearanceRow = new PW.FrameBoxRow(); + let menuButtonAppearanceLabel = new Gtk.Label({ + label: _('Appearance'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonAppearanceCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + menuButtonAppearanceCombo.append_text(_("Icon")); + menuButtonAppearanceCombo.append_text(_("Text")); + menuButtonAppearanceCombo.append_text(_("Icon and Text")); + menuButtonAppearanceCombo.append_text(_("Text and Icon")); + menuButtonAppearanceCombo.append_text(_("Hidden")); + menuButtonAppearanceCombo.set_active(this._settings.get_enum('menu-button-appearance')); + menuButtonAppearanceCombo.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + menuButtonAppearanceFrame.removeChildrenAfterIndex(0); + if(widget.get_active() === Constants.MenuButtonAppearance.NONE){ + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON_TEXT || widget.get_active() === Constants.MenuButtonAppearance.TEXT_ICON || + widget.get_active() === Constants.MenuButtonAppearance.TEXT){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + menuButtonAppearanceFrame.show(); + } + this._settings.set_enum('menu-button-appearance', widget.get_active()); + }); + + menuButtonAppearanceRow.add(menuButtonAppearanceLabel); + menuButtonAppearanceRow.add(menuButtonAppearanceCombo); + menuButtonAppearanceFrame.add(menuButtonAppearanceRow); + + let menuButtonArrowIconBoxRow = new PW.FrameBoxRow(); + let menuButtonArrowIconLabel = new Gtk.Label({ + label: _('Show Arrow'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let enableArrowIconSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableArrowIconSwitch.set_active(this._settings.get_boolean('enable-menu-button-arrow')); + enableArrowIconSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-menu-button-arrow', widget.get_active()); + this.resetButton.set_sensitive(true); + }); + + menuButtonArrowIconBoxRow.add(menuButtonArrowIconLabel); + menuButtonArrowIconBoxRow.add(enableArrowIconSwitch); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + + let menuButtonPaddingRow = new PW.FrameBoxRow(); + let menuButtonPadding = this._settings.get_int('button-padding'); + let menuButtonPaddingLabel = new Gtk.Label({ + label: _('Menu Button Padding'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let paddingScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, + upper: 25, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + paddingScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + paddingScale.add_mark(-1, Gtk.PositionType.TOP, _("Default")); + paddingScale.set_value(menuButtonPadding); + paddingScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('button-padding', paddingScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonPaddingRow.add(menuButtonPaddingLabel); + menuButtonPaddingRow.add(paddingScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + + ///// Row for menu button offset ///// + let menuButtonOffsetRow = new PW.FrameBoxRow(); + let menuButtonOffset = this._settings.get_int('menu-button-position-offset'); + let menuButtonOffsetLabel = new Gtk.Label({ + label: _('Menu Button Position'), + use_markup: true, + xalign: 0, + hexpand: true, + }); + let offsetScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 10, // arbitrary value + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + offsetScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); // offset 0 is default + offsetScale.add_mark(1, Gtk.PositionType.TOP, null); + offsetScale.add_mark(2, Gtk.PositionType.TOP, null); + offsetScale.set_value(menuButtonOffset); + offsetScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-position-offset', offsetScale.get_value()); + }); + menuButtonOffsetRow.add(menuButtonOffsetLabel); + menuButtonOffsetRow.add(offsetScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE && + (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP)) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + //////////////////// + + let menuButtonCustomTextBoxRow = new PW.FrameBoxRow(); + let menuButtonCustomTextLabel = new Gtk.Label({ + label: _('Text'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonCustomTextEntry = new Gtk.Entry({ halign: Gtk.Align.END }); + menuButtonCustomTextEntry.set_width_chars(30); + menuButtonCustomTextEntry.set_text(this._settings.get_string('custom-menu-button-text')); + menuButtonCustomTextEntry.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + let customMenuButtonText = widget.get_text(); + this._settings.set_string('custom-menu-button-text', customMenuButtonText); + }); + + menuButtonCustomTextBoxRow.add(menuButtonCustomTextLabel); + menuButtonCustomTextBoxRow.add(menuButtonCustomTextEntry); + if(this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.ICON && this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + vbox.append(menuButtonAppearanceFrame); + + let menuButtonIconHeaderLabel = new Gtk.Label({ + label: "" + _('Icon Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonIconHeaderLabel); + + let menuButtonIconFrame = new PW.FrameBox(); + let menuButtonIconRow = new PW.FrameBoxRow(); + let menuButtonIconLabel = new Gtk.Label({ + label: _('Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuButtonIconButton = new PW.Button({ + title: _("Browse Icons") + " ", + icon_name: 'icon-preview-symbolic', + hexpand: false, + }); + menuButtonIconButton.connect('clicked', () => { + let dialog = new ArcMenuIconsDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + dialog.destroy(); + }); + }); + + menuButtonIconRow.add(menuButtonIconLabel); + menuButtonIconRow.add(menuButtonIconButton); + menuButtonIconFrame.add(menuButtonIconRow); + + let menuButtonIconSizeRow = new PW.FrameBoxRow(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let menuButtonIconSizeLabel = new Gtk.Label({ + label: _('Icon Size'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonIconSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 14, + upper: 64, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonIconSizeScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonIconSizeScale.set_value(iconSize); + menuButtonIconSizeScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_double('custom-menu-button-icon-size', menuButtonIconSizeScale.get_value()); + }); + + menuButtonIconSizeRow.add(menuButtonIconSizeLabel); + menuButtonIconSizeRow.add(menuButtonIconSizeScale); + menuButtonIconFrame.add(menuButtonIconSizeRow); + + vbox.append(menuButtonIconFrame); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true, + valign: Gtk.Align.END, + vexpand: true + }); + + let menuButtonColorHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Styling') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonColorHeaderLabel); + + this.menuButtonIconColorFrame = new PW.FrameBox(); + + let[menuButtonColorSwitch, menuButtonColorChooser] = this.newColorChooserRow({ + color: this.menuButtonColor, + label: _("Color"), + settingColorName: 'menu-button-color', + settingOverrideName: 'override-menu-button-color', + }); + + let[menuButtonHoverColorSwitch, menuButtonHoverColorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverColor, + label: _("Hover Color"), + settingColorName: 'menu-button-hover-color', + settingOverrideName: 'override-menu-button-hover-color', + }); + + let[menuButtonActiveColorSwitch, menuButtonActiveColorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveColor, + label: _("Active Color"), + settingColorName: 'menu-button-active-color', + settingOverrideName: 'override-menu-button-active-color', + }); + + let[menuButtonHoverBackgroundcolorSwitch, menuButtonHoverBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverBackgroundcolor, + label: _("Hover Background Color"), + settingColorName: 'menu-button-hover-backgroundcolor', + settingOverrideName: 'override-menu-button-hover-background-color', + }); + + let[menuButtonActiveBackgroundcolorSwitch, menuButtonActiveBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveBackgroundcolor, + label: _("Active Background Color"), + settingColorName: 'menu-button-active-backgroundcolor', + settingOverrideName: 'override-menu-button-active-background-color', + }); + + let roundedCornersRow = new PW.FrameBoxRow(); + + let roundedCornersLabel = new Gtk.Label({ + label: _("Override Border Radius"), + xalign:0, + hexpand: true, + }); + let roundedCornersSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean('menu-button-override-border-radius') + }); + roundedCornersSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean('menu-button-override-border-radius', widget.get_active()) + this._settings.set_boolean('reload-theme', true); + menuButtonBorderRadiusRow.set_sensitive(widget.get_active()); + }); + + roundedCornersRow.add(roundedCornersLabel); + roundedCornersRow.add(roundedCornersSwitch); + + this.menuButtonIconColorFrame.add(roundedCornersRow); + + let menuButtonBorderRadiusRow = new PW.FrameBoxRow(); + let borderRadius = this._settings.get_int('menu-button-border-radius'); + let menuButtonBorderRadiusLabel = new Gtk.Label({ + label: _('Border Radius'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonBorderRadiusScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 20, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonBorderRadiusScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonBorderRadiusScale.set_value(borderRadius); + menuButtonBorderRadiusScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-border-radius', menuButtonBorderRadiusScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusLabel); + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusScale); + menuButtonBorderRadiusRow.set_sensitive(this._settings.get_boolean('menu-button-override-border-radius')); + this.menuButtonIconColorFrame.add(menuButtonBorderRadiusRow); + + vbox.append(this.menuButtonIconColorFrame); + + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + menuButtonAppearanceCombo.set_active(0); + menuButtonCustomTextEntry.set_text('Applications'); + paddingScale.set_value(-1); + menuButtonIconSizeScale.set_value(20); + let colorParse = new Gdk.RGBA(); + colorParse.parse('rgb(240,240,240)'); + menuButtonActiveColorChooser.set_rgba(colorParse); + menuButtonColorChooser.set_rgba(colorParse); + colorParse.parse('rgb(214,214,214)'); + menuButtonHoverColorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.1)'); + menuButtonHoverBackgroundcolorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.18)'); + menuButtonActiveBackgroundcolorChooser.set_rgba(colorParse); + enableArrowIconSwitch.set_active(false); + menuButtonColorSwitch.set_active(false); + menuButtonHoverColorSwitch.set_active(false); + menuButtonActiveColorSwitch.set_active(false); + menuButtonHoverBackgroundcolorSwitch.set_active(false); + menuButtonActiveBackgroundcolorSwitch.set_active(false); + roundedCornersSwitch.set_active(false); + menuButtonBorderRadiusScale.set_value(0); + offsetScale.set_value(0); + this._settings.reset('menu-button-icon'); + this._settings.reset('arc-menu-icon'); + this._settings.reset('distro-icon'); + this._settings.reset('custom-menu-button-icon'); + this._settings.reset('menu-button-hover-color'); + this._settings.reset('menu-button-active-color'); + this._settings.reset('menu-button-hover-backgroundcolor'); + this._settings.reset('menu-button-active-backgroundcolor'); + this._settings.reset('menu-button-color'); + this._settings.reset('override-menu-button-hover-color'); + this._settings.reset('override-menu-button-active-color'); + this._settings.reset('override-menu-button-hover-background-color'); + this._settings.reset('override-menu-button-active-background-color'); + this._settings.reset('override-menu-button-color'); + this._settings.reset('menu-button-override-border-radius'); + this._settings.reset('menu-button-border-radius'); + this._settings.reset('menu-button-position-offset'); + this._settings.set_boolean('reload-theme', true); + + this.resetButton.set_sensitive(false); + }); + vbox.append(this.resetButton); + } + + newColorChooserRow(params){ + let colorParse = new Gdk.RGBA(); + let colorRow = new PW.FrameBoxRow(); + let buttonsGrid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + + let colorLabel = new Gtk.Label({ + label: params.label, + xalign:0, + hexpand: true, + }); + let colorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean(params.settingOverrideName) + }); + colorSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean(params.settingOverrideName, widget.get_active()) + colorChooser.sensitive = widget.get_active(); + this._settings.set_boolean('reload-theme', true); + }); + + let colorChooser = new Gtk.ColorButton({ + use_alpha: true, + sensitive: colorSwitch.get_active() + }); + + colorParse.parse(params.color); + colorChooser.set_rgba(colorParse); + + colorChooser.connect('color-set', ()=>{ + this.resetButton.set_sensitive(true); + params.color = colorChooser.get_rgba().to_string(); + this._settings.set_string(params.settingColorName, params.color); + this._settings.set_boolean('reload-theme', true); + }); + + colorRow.add(colorLabel); + buttonsGrid.attach(colorSwitch, 0, 0, 1, 1); + buttonsGrid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 1, 0, 1, 1); + buttonsGrid.attach(colorChooser, 2, 0, 1, 1); + colorRow.add(buttonsGrid); + this.menuButtonIconColorFrame.add(colorRow); + return [colorSwitch, colorChooser]; + } + + checkIfResetButtonSensitive(){ + if( this._settings.get_string('menu-button-hover-backgroundcolor') != 'rgba(238,238,236,0.1)' || + this._settings.get_string('menu-button-active-backgroundcolor') != 'rgba(238,238,236,0.18)' || + this._settings.get_string('menu-button-active-color') != 'rgb(240,240,240)' || + this._settings.get_string('menu-button-hover-color') != 'rgb(214,214,214)' || + this._settings.get_string('menu-button-color') != 'rgb(240,240,240)' || + this._settings.get_double('custom-menu-button-icon-size') != 20 || + this._settings.get_int('button-padding') != -1 || + this._settings.get_enum('menu-button-icon') != 0 || + this._settings.get_int('arc-menu-icon') != 0 || + this._settings.get_string('custom-menu-button-text') != 'Applications' || + this._settings.get_enum('menu-button-appearance') != 0 || + this._settings.get_boolean('enable-menu-button-arrow') || + this._settings.get_boolean('override-menu-button-color') || + this._settings.get_boolean('override-menu-button-hover-color') || + this._settings.get_boolean('override-menu-button-active-color') || + this._settings.get_boolean('override-menu-button-hover-background-color') || + this._settings.get_boolean('override-menu-button-active-background-color') || + this._settings.get_boolean('menu-button-override-border-radius') || + this._settings.get_int('menu-button-border-radius') != 0 || + this._settings.get_int('menu-button-position-offset') != 0 ) + return true; + else + return false; + } +}); + +var ArcMenuIconsDialogWindow = GObject.registerClass( + class Arc_Menu_ArcMenuIconsDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + super._init(_('ArcMenu Icons'), parent); + this.set_default_size(550, 400); + } + + _createLayout(vbox){ + this.stack = new Gtk.Stack({ + halign: Gtk.Align.FILL, + hexpand: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let arcMenuIconsBox = new Gtk.ScrolledWindow(); + + let arcMenuIconsFlowBox = new PW.IconGrid(); + arcMenuIconsFlowBox.connect('child-activated', ()=> { + distroIconsBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = arcMenuIconsFlowBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.ARC_MENU); + this._settings.set_int('arc-menu-icon', selectedChildIndex); + }); + arcMenuIconsBox.set_child(arcMenuIconsFlowBox); + Constants.MenuIcons.forEach((icon)=>{ + let iconName = icon.PATH.replace("/media/icons/menu_button_icons/icons/", ''); + iconName = iconName.replace(".svg", ''); + let iconImage = new Gtk.Image({ + icon_name: iconName, + pixel_size: 36 + }); + arcMenuIconsFlowBox.add(iconImage); + }); + + let distroIconsBox = new PW.IconGrid(); + distroIconsBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = distroIconsBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.DISTRO_ICON); + this._settings.set_int('distro-icon', selectedChildIndex); + }); + Constants.DistroIcons.forEach((icon)=>{ + let iconImage; + if(icon.PATH === 'start-here-symbolic'){ + iconImage = new Gtk.Image({ + icon_name: 'start-here-symbolic', + pixel_size: 36 + }); + } + else{ + let iconName1 = icon.PATH.replace("/media/icons/menu_button_icons/distro_icons/", ''); + iconName1 = iconName1.replace(".svg", ''); + iconImage = new Gtk.Image({ + icon_name: iconName1, + pixel_size: 36 + }); + } + distroIconsBox.add(iconImage); + }); + + let customIconBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + let customIconFlowBox = new PW.IconGrid(); + customIconFlowBox.vexpand = false; + customIconFlowBox.homogeneous = false; + customIconFlowBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + let customIconPath = this._settings.get_string('custom-menu-button-icon'); + this._settings.set_string('custom-menu-button-icon', customIconPath) + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + }); + customIconBox.append(customIconFlowBox); + let customIconImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(this._settings.get_string('custom-menu-button-icon')), + pixel_size: 36 + }); + customIconFlowBox.add(customIconImage); + + let fileChooserFrame = new PW.FrameBox(); + fileChooserFrame.margin_top = 20; + fileChooserFrame.margin_bottom = 20; + fileChooserFrame.margin_start = 20; + fileChooserFrame.margin_end = 20; + let fileChooserRow = new PW.FrameBoxRow(); + let fileChooserLabel = new Gtk.Label({ + label: _('Browse for a Custom Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Select an Icon') + }); + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + + if(dialog.get_parent()) + dialog.unparent(); + dialog.set_filter(fileFilter); + + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + customIconImage.gicon = Gio.icon_new_for_string(dialog.get_file().get_path()); + this._settings.set_string('custom-menu-button-icon', dialog.get_file().get_path()); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + dialog.destroy(); + } + else + dialog.destroy(); + }) + + dialog.show(); + }); + + fileChooserRow.add(fileChooserLabel); + fileChooserRow.add(fileChooserButton); + fileChooserFrame.add(fileChooserRow); + customIconBox.append(fileChooserFrame); + + this.stack.add_titled(arcMenuIconsBox, 'ArcMenu Icons', _('ArcMenu Icons')); + this.stack.add_titled(distroIconsBox, 'Distro Icons', _('Distro Icons')); + this.stack.add_titled(customIconBox, 'Custom Icon', _('Custom Icon')); + + let stackSwitcher = new Gtk.StackSwitcher({ + stack: this.stack, + halign: Gtk.Align.CENTER + }); + + vbox.append(stackSwitcher); + vbox.append(this.stack); + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU){ + let children = arcMenuIconsFlowBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('arc-menu-icon')){ + arcMenuIconsFlowBox.select_child(arcMenuIconsFlowBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON){ + let children = distroIconsBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('distro-icon')){ + distroIconsBox.select_child(distroIconsBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM){ + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + } + + let distroInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + distroInfoButton.halign = Gtk.Align.START; + distroInfoButton.connect('clicked', ()=> { + let dialog = new DistroIconsDisclaimerWindow(this._settings, this); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + vbox.append(distroInfoButton); + } + + setVisibleChild(){ + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + } +}); + +var DistroIconsDisclaimerWindow = GObject.registerClass( + class Arc_Menu_DistroIconsDisclaimerWindow extends Gtk.MessageDialog { + _init(settings, parent) { + this._settings = settings; + super._init({ + text: "" + _("Legal disclaimer for Distro Icons...") + "", + use_markup: true, + message_type: Gtk.MessageType.OTHER, + transient_for: parent.get_root(), + modal: true, + buttons: Gtk.ButtonsType.OK + }); + + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + }); + this.get_content_area().append(vbox); + this._createLayout(vbox); + } + + _createLayout(vbox) { + let scrollWindow = new Gtk.ScrolledWindow({ + min_content_width: 500, + max_content_width: 500, + min_content_height: 400, + max_content_height: 400, + hexpand: false, + halign: Gtk.Align.START, + }); + scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + let frame = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + halign: Gtk.Align.START + }); + + let bodyLabel = new Gtk.Label({ + label: Constants.DistroIconsDisclaimer, + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true + }); + bodyLabel.set_size_request(500,-1); + + frame.append(bodyLabel); + scrollWindow.set_child(frame); + vbox.append(scrollWindow); + } +}); + +var MenuLayoutPage = GObject.registerClass( + class Arc_Menu_MenuLayoutPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + this._settings = settings; + + this.scrollBox = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_child(this.mainBox); + + let currentLayoutLabel = new Gtk.Label({ + label: "" + _("Current Menu Layout") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("Available Menu Layouts") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(currentLayoutLabel); + + let currentLayoutFrame = new PW.FrameBox(); + + let currentLayoutBoxLabel = new Gtk.Label({ + label: "" + this.getMenuLayoutName(this._settings.get_enum('menu-layout')) + "", + use_markup: true, + hexpand: true, + vexpand: true, + halign: Gtk.Align.CENTER, + valign: Gtk.Align.CENTER + }); + let currentLayoutBoxRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + currentLayoutBoxRow.activatable = true; + currentLayoutBoxRow._grid.row_spacing = 0; + currentLayoutBoxRow._grid.column_spacing = 0; + + let goNextImage = new Gtk.Image({ + icon_name: 'go-next-symbolic', + halign: Gtk.Align.END + }); + + currentLayoutFrame._listBox.connect('row-activated', () => { + this.displayLayoutTweaksPage(); + }); + + this.layoutsTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout'))); + this.layoutsTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + + let currentLayoutImagePath = this.getMenuLayoutImagePath(this._settings.get_enum('menu-layout')); + + let currentLayoutImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(currentLayoutImagePath), + pixel_size: 155, + hexpand: false, + halign: Gtk.Align.START, + valign: Gtk.Align.CENTER, + }); + let tweaksLabel = new Gtk.Label({ + label: this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')), + use_markup: true, + halign: Gtk.Align.END, + vexpand: true, + hexpand: true + }); + currentLayoutBoxRow._grid.attach(currentLayoutImage, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(currentLayoutBoxLabel, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(goNextImage, 0, 0, 1, 1); + currentLayoutFrame.add(currentLayoutBoxRow); + + this.mainBox.append(currentLayoutFrame); + this.mainBox.append(chooseNewLayoutLabel); + + this.stack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + this.layoutTilesBox = new Gtk.Grid({ + column_homogeneous: true, + column_spacing: 14, + row_spacing: 6, + hexpand: true, + halign: Gtk.Align.FILL, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.mainBox.append(this.layoutTilesBox); + this.stack.add_named(this.scrollBox, "LayoutsBox"); + this.stack.add_named(this.layoutsTweaksPage, "LayoutsTweaks") + let gridY = 0; + Constants.MenuStyles.STYLES.forEach((style) => { + let tile = new PW.LayoutTile(style.TITLE, style.IMAGE, style); + this.layoutTilesBox.attach(tile, 0, gridY, 1, 1); + let menuLayoutsBox = new MenuLayoutCategoryPage(this._settings, this, tile, style.TITLE); + gridY++; + menuLayoutsBox.connect('menu-layout-response', (dialog, response) => { + if(response === -10) { + this._settings.set_enum('menu-layout', dialog.index); + this._settings.set_boolean('reload-theme', true); + currentLayoutBoxLabel.label = "" + this.getMenuLayoutName(dialog.index) + ""; + tweaksLabel.label = this.getMenuLayoutTweaksName(dialog.index); + currentLayoutImage.gicon = Gio.icon_new_for_string(this.getMenuLayoutImagePath(dialog.index)); + this.stack.set_visible_child_name("LayoutsBox"); + this.scrollBox.vadjustment.set_value(this.scrollBox.vadjustment.get_lower()); + } + if(response === -20){ + this.stack.set_visible_child_name("LayoutsBox"); + } + }); + this.stack.add_named(menuLayoutsBox, "Layout_" + style.TITLE); + tile._listBox.connect('row-activated', ()=> { + this.stack.set_visible_child_name("Layout_" + style.TITLE); + menuLayoutsBox.enableSelectionMode(); + }); + }); + + this.append(this.stack); + } + + displayLayoutTweaksPage(){ + let layoutName = this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')); + this.layoutsTweaksPage.setActiveLayout(this._settings.get_enum('menu-layout'), layoutName); + this.stack.set_visible_child_name("LayoutsTweaks"); + } + + displayRunnerTweaksPage(){ + if(!this.runnerTweaksPage){ + let activeLayoutName = this.getMenuLayoutTweaksName(Constants.MenuLayout.RUNNER); + this.runnerTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, activeLayoutName); + this.stack.add_named(this.runnerTweaksPage, "RunnerTweaks") + this.runnerTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + this.runnerTweaksPage.setActiveLayout(Constants.MenuLayout.RUNNER); + } + this.stack.set_visible_child_name("RunnerTweaks"); + } + + getMenuLayoutName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _(style.TITLE); + } + } + } + } + + getMenuLayoutTweaksName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _("%s Layout Tweaks", style.TITLE).format(style.TITLE); + } + } + } + } + + getMenuLayoutImagePath(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return style.IMAGE; + } + } + } + } + +}); + +var MenuThemePage = GObject.registerClass( + class Arc_Menu_MenuThemePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.checkIfPresetMatch(); + + let overrideArcMenuHeaderLabel = new Gtk.Label({ + label: "" + _('Enable Custom Menu Theme') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(overrideArcMenuHeaderLabel); + + let overrideArcMenuFrame = new PW.FrameBox(); + let overrideArcMenuRow = new PW.FrameBoxRow(); + let overrideArcMenuLabel = new Gtk.Label({ + label: _("Override Menu Theme"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let overrideArcMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + overrideArcMenuSwitch.set_active(this._settings.get_boolean('enable-custom-arc-menu')); + overrideArcMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-custom-arc-menu',widget.get_active()); + this._settings.set_boolean('reload-theme', true); + if(widget.get_active()){ + this.mainBox.append(this.menuThemeCustomizationBox); + this.menuThemeCustomizationBox.show(); + this.append(this.buttonRow); + this.buttonRow.show(); + } + else{ + this.mainBox.remove(this.menuThemeCustomizationBox); + this.remove(this.buttonRow); + } + this.mainBox.show(); + }); + + this.menuThemeCustomizationBox = new OverrideArcMenuThemeWindow(this._settings, this.mainBox, this); + this.menuThemeCustomizationBox.connect('menu-theme-response', (dialog, response) => { + if(response === -10) { + this._settings.set_string('separator-color', dialog.separatorColor); + this._settings.set_boolean('vert-separator', dialog.verticalSeparator); + this._settings.set_string('menu-color', dialog.menuColor); + this._settings.set_string('menu-foreground-color', dialog.menuForegroundColor); + this._settings.set_string('border-color', dialog.borderColor); + this._settings.set_string('highlight-color', dialog.highlightColor ); + this._settings.set_string('highlight-foreground-color', dialog.highlightForegroundColor); + this._settings.set_int('menu-font-size', dialog.fontSize); + this._settings.set_int('menu-border-size', dialog.borderSize); + this._settings.set_int('menu-corner-radius', dialog.cornerRadius); + this._settings.set_int('menu-margin', dialog.menuMargin); + this._settings.set_int('menu-arrow-size', dialog.menuArrowSize); + this._settings.set_boolean('reload-theme', true); + this.presetName = dialog.presetName; + } + else{ + this.checkIfPresetMatch(); + } + }); + + overrideArcMenuRow.add(overrideArcMenuLabel); + overrideArcMenuRow.add(overrideArcMenuSwitch); + overrideArcMenuFrame.add(overrideArcMenuRow); + + this.mainBox.append(overrideArcMenuFrame); + if(overrideArcMenuSwitch.get_active()) + this.mainBox.append(this.menuThemeCustomizationBox); + else + this.remove(this.buttonRow); + } + + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < all_color_themes.length; i++){ + this.isEqual = true; + for(let l = 0; l < this.currentSettingsArray.length; l++){ + if(this.currentSettingsArray[l] !== all_color_themes[i][l + 1]){ + this.isEqual=false; + break; + } + } + if(this.isEqual){ + this.presetName = all_color_themes[i][0]; + break; + } + } + } +}); + +var MenuLayoutCategoryPage = GObject.registerClass({ + Signals: { + 'menu-layout-response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_MenuLayoutCategoryPage extends Gtk.ScrolledWindow { + _init(settings, parent, tile, title) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this.title = title; + this._parent = parent; + this._settings = settings; + this.index = this._settings.get_enum('menu-layout'); + this.layoutStyle = tile.layout; + + this._params = { + maxColumns: tile.layout.length > 3 ? 3 : tile.layout.length, + imageHeight: 155, + imageWidth: 155, + styles: tile.layout + }; + let layoutsFrame = new PW.FrameBox(); + let layoutsRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false, + }) + layoutsRow._grid.orientation = Gtk.Orientation.VERTICAL; + layoutsFrame.add(layoutsRow); + let buttonBox = new Gtk.Box({ + spacing: 10 + }); + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: false, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + let selectedBox = this._tileGrid.get_selected_children(); + this.index = selectedBox[0].get_child().layout; + this._tileGrid.unselect_all(); + applyButton.set_sensitive(false); + this.emit('menu-layout-response', -10); + }); + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + halign: Gtk.Align.START + }); + backButton.connect('clicked', ()=> { + this.emit('menu-layout-response', -20); + }); + buttonBox.append(backButton); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", this.title).format(this.title) + "", + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + buttonBox.append(chooseNewLayoutLabel); + buttonBox.append(applyButton); + applyButton.set_sensitive(false); + + this.mainBox.append(buttonBox); + this.mainBox.append(layoutsFrame); + this._tileGrid = new PW.TileGrid(this._params.maxColumns); + + this._params.styles.forEach((style) => { + this._addTile(style.TITLE, style.IMAGE, style.LAYOUT); + }); + + layoutsRow.add(this._tileGrid); + + this._tileGrid.connect('selected-children-changed', () => { + applyButton.set_sensitive(true); + }); + + this._tileGrid.set_selection_mode(Gtk.SelectionMode.NONE); + } + + + enableSelectionMode(){ + this._tileGrid.set_selection_mode(Gtk.SelectionMode.SINGLE); + } + + _addTile(name, image, layout) { + let tile = new PW.Tile(name, image, this._params.imageWidth, this._params.imageHeight, layout); + this._tileGrid.insert(tile, -1); + } +}); + +var MenuSettingsGeneralPage = GObject.registerClass( + class Arc_Menu_MenuSettingsGeneralPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.heightValue = this._settings.get_int('menu-height'); + this.widthValue = this._settings.get_int('menu-width-adjustment'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.menuWidth = this._settings.get_int('menu-width'); + this.forcedMenuLocation = this._settings.get_enum('force-menu-location'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.appDescriptions = this._settings.get_boolean('apps-show-extra-details'); + this.categoryIconType = this._settings.get_enum('category-icon-type'); + this.shortcutsIconType = this._settings.get_enum('shortcut-icon-type'); + + let menuSizeFrame = new PW.FrameBox(); + //find the greatest screen height of all monitors + //use that value to set Menu Height cap + let display = Gdk.Display.get_default(); + let monitors = display.get_monitors(); + let nMonitors = monitors.get_n_items(); + let greatestHeight = 0; + let scaleFactor = 1; + for (let i = 0; i < nMonitors; i++) { + let monitor = monitors.get_item(i); + let monitorHeight = monitor.get_geometry().height; + if(monitorHeight > greatestHeight){ + scaleFactor = monitor.get_scale_factor(); + greatestHeight = monitorHeight; + } + } + let monitorHeight = greatestHeight * scaleFactor; + monitorHeight = Math.round((monitorHeight * 8) / 10); + + let menuSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuSizeHeaderLabel); + + this.mainBox.append(menuSizeFrame); + let heightRow = new PW.FrameBoxRow(); + let heightLabel = new Gtk.Label({ + label: _('Height'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let hscale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: monitorHeight, + step_increment: 10, + page_increment: 10, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + hscale.set_value(this.heightValue); + hscale.connect('value-changed', () => { + this.heightValue = hscale.get_value(); + if(hSpinButton.value !== this.heightValue) + hSpinButton.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let hSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: monitorHeight, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + hSpinButton.set_value(this.heightValue); + hSpinButton.connect('value-changed', () => { + this.heightValue = hSpinButton.get_value(); + if(hscale.value !== this.heightValue) + hscale.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + heightRow.add(heightLabel); + heightRow.add(hscale); + heightRow.add(hSpinButton); + menuSizeFrame.add(heightRow); + + let menuWidthTwoPanelsHeaderRow = new PW.FrameBoxRow(); + let menuWidthTwoPanelsHeaderLabel = new Gtk.Label({ + label: _("Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + menuWidthTwoPanelsHeaderRow.add(menuWidthTwoPanelsHeaderLabel) + menuSizeFrame.add(menuWidthTwoPanelsHeaderRow); + + let menuWidthRow = new PW.FrameBoxRow(); + menuWidthRow._grid.margin_start = 25; + let menuWidthLabel = new Gtk.Label({ + label: _('Left-Panel'), + xalign:0, + hexpand: false, + }); + let menuWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuWidthScale.set_value(this.menuWidth); + menuWidthScale.connect('value-changed', () => { + this.menuWidth = menuWidthScale.get_value(); + if(menuWidthSpinButton.value !== this.menuWidth) + menuWidthSpinButton.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let menuWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + menuWidthSpinButton.set_value(this.menuWidth); + menuWidthSpinButton.connect('value-changed', () => { + this.menuWidth = menuWidthSpinButton.get_value(); + if(menuWidthScale.value !== this.menuWidth) + menuWidthScale.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + menuWidthRow.add(menuWidthLabel); + menuWidthRow.add(menuWidthScale); + menuWidthRow.add( menuWidthSpinButton); + menuSizeFrame.add(menuWidthRow); + + let rightPanelWidthRow = new PW.FrameBoxRow(); + rightPanelWidthRow._grid.margin_start = 25; + let rightPanelWidthLabel = new Gtk.Label({ + label: _('Right-Panel'), + xalign:0, + hexpand: false, + }); + let rightPanelWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + rightPanelWidthScale.set_value(this.rightPanelWidth); + rightPanelWidthScale.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthScale.get_value(); + if(rightPanelWidthSpinButton.value !== this.rightPanelWidth) + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let rightPanelWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + rightPanelWidthSpinButton.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthSpinButton.get_value(); + if(rightPanelWidthScale.value !== this.rightPanelWidth) + rightPanelWidthScale.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + rightPanelWidthRow.add(rightPanelWidthLabel); + rightPanelWidthRow.add(rightPanelWidthScale); + rightPanelWidthRow.add(rightPanelWidthSpinButton); + menuSizeFrame.add(rightPanelWidthRow); + + let otherWidthHeaderRow = new PW.FrameBoxRow(); + let otherWidthHeaderLabel = new Gtk.Label({ + label: _("Non-Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + otherWidthHeaderRow.add(otherWidthHeaderLabel) + menuSizeFrame.add(otherWidthHeaderRow); + + let widthRow = new PW.FrameBoxRow(); + widthRow._grid.margin_start = 25; + let widthLabel = new Gtk.Label({ + label: _('Width Offset'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let widthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -350, + upper: 600, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + widthScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Default")); + widthScale.set_value(this.widthValue); + widthScale.connect('value-changed', (widget) => { + this.widthValue = widget.get_value(); + if(widthSpinButton.value !== this.widthValue) + widthSpinButton.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let widthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: -350, upper: 600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + valign: Gtk.Align.START + }); + widthSpinButton.set_value(this.widthValue); + widthSpinButton.connect('value-changed', () => { + this.widthValue = widthSpinButton.get_value(); + if(widthScale.value !== this.widthValue) + widthScale.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + widthRow.add(widthLabel); + widthRow.add(widthScale); + widthRow.add(widthSpinButton); + menuSizeFrame.add(widthRow); + + let iconsSizeFrame = new PW.FrameBox(); + let menuItemSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Items Icon Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuItemSizeHeaderLabel); + + let gridIconsSizeRow = new PW.FrameBoxRow(); + let gridIconsSizeLabel = new Gtk.Label({ + label: _("Grid Icons"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.gridIconsSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + this.gridIconsSizeCombo.append("Default", _("Default")); + this.gridIconsSizeCombo.append("Small", _("Small") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Medium", _("Medium") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Large", _("Large") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Small Rect", _("Small") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Medium Rect", _("Medium") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Large Rect", _("Large") + " - " + _("Wide")); + this.gridIconsSizeCombo.set_active(this._settings.get_enum('menu-item-grid-icon-size')); + this.gridIconsSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + gridIconsSizeRow.add(gridIconsSizeLabel); + gridIconsSizeRow.add(this.gridIconsSizeCombo); + iconsSizeFrame.add(gridIconsSizeRow); + + [this.menuItemIconSizeCombo, this.menuItemIconSizeRow] = this.createIconSizeRow(_("Categories & Applications"), this._settings.get_enum('menu-item-icon-size')); + iconsSizeFrame.add(this.menuItemIconSizeRow); + [this.buttonIconSizeCombo, this.buttonIconSizeRow] = this.createIconSizeRow(_("Buttons"), this._settings.get_enum('button-item-icon-size')); + iconsSizeFrame.add(this.buttonIconSizeRow); + [this.quicklinksIconSizeCombo, this.quicklinksIconSizeRow] = this.createIconSizeRow(_("Quick Links"), this._settings.get_enum('quicklinks-item-icon-size')); + iconsSizeFrame.add(this.quicklinksIconSizeRow); + [this.miscIconSizeCombo, this.miscIconSizeRow] = this.createIconSizeRow(_("Misc"), this._settings.get_enum('misc-item-icon-size')); + iconsSizeFrame.add(this.miscIconSizeRow); + + this.mainBox.append(iconsSizeFrame); + + let generalHeaderLabel = new Gtk.Label({ + label: "" + _("General Settings") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(generalHeaderLabel); + + let generalSettingsFrame = new PW.FrameBox(); + let menuLocationRow = new PW.FrameBoxRow(); + let menuLocationLabel = new Gtk.Label({ + label: _('Override Menu Location'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let menuLocationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + menuLocationCombo.append_text(_("Off")); + menuLocationCombo.append_text(_("Top Centered")); + menuLocationCombo.append_text(_("Bottom Centered")); + menuLocationCombo.set_active(this._settings.get_enum('force-menu-location')); + menuLocationCombo.connect('changed', (widget) => { + this.forcedMenuLocation = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + menuLocationRow.add(menuLocationLabel); + menuLocationRow.add(menuLocationCombo); + generalSettingsFrame.add(menuLocationRow); + this.mainBox.append(generalSettingsFrame); + + let appDescriptionsRow = new PW.FrameBoxRow(); + let appDescriptionsLabel = new Gtk.Label({ + label: _("Show Application Descriptions"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appDescriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appDescriptionsSwitch.set_active(this.appDescriptions); + appDescriptionsSwitch.connect('notify::active', (widget) => { + this.appDescriptions = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appDescriptionsRow.add(appDescriptionsLabel); + appDescriptionsRow.add(appDescriptionsSwitch); + generalSettingsFrame.add(appDescriptionsRow); + + let categoryIconTypeRow = new PW.FrameBoxRow(); + let categoryIconTypeLabel = new Gtk.Label({ + label: _('Category Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let categoryIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + categoryIconTypeCombo.append_text(_("Full Color")); + categoryIconTypeCombo.append_text(_("Symbolic")); + categoryIconTypeCombo.set_active(this.categoryIconType); + categoryIconTypeCombo.connect('changed', (widget) => { + this.categoryIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + categoryIconTypeRow.add(categoryIconTypeLabel); + categoryIconTypeRow.add(categoryIconTypeCombo); + generalSettingsFrame.add(categoryIconTypeRow); + + let shortcutsIconTypeRow = new PW.FrameBoxRow(); + let shortcutsIconTypeLabel = new Gtk.Label({ + label: _('Shortcuts Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let shortcutsIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + shortcutsIconTypeCombo.append_text(_("Full Color")); + shortcutsIconTypeCombo.append_text(_("Symbolic")); + shortcutsIconTypeCombo.set_active(this.shortcutsIconType); + shortcutsIconTypeCombo.connect('changed', (widget) => { + this.shortcutsIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + shortcutsIconTypeRow.add(shortcutsIconTypeLabel); + shortcutsIconTypeRow.add(shortcutsIconTypeCombo); + generalSettingsFrame.add(shortcutsIconTypeRow); + + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + generalSettingsFrame.add(vertSeparatorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.heightValue = this._settings.get_default_value('menu-height').unpack(); + this.widthValue = this._settings.get_default_value('menu-width-adjustment').unpack(); + this.rightPanelWidth = this._settings.get_default_value('right-panel-width').unpack(); + this.menuWidth = this._settings.get_default_value('menu-width').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.appDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this.categoryIconType = 0; + this.shortcutsIconType = 1; + this.forcedMenuLocation = 0; + hscale.set_value(this.heightValue); + widthScale.set_value(this.widthValue); + menuWidthScale.set_value(this.menuWidth); + rightPanelWidthScale.set_value(this.rightPanelWidth); + vertSeparatorSwitch.set_active(this.verticalSeparator); + this.gridIconsSizeCombo.set_active(0); + this.menuItemIconSizeCombo.set_active(0); + this.buttonIconSizeCombo.set_active(0); + this.quicklinksIconSizeCombo.set_active(0); + this.miscIconSizeCombo.set_active(0); + appDescriptionsSwitch.set_active(this.appDescriptions); + menuLocationCombo.set_active(this.forcedMenuLocation); + categoryIconTypeCombo.set_active(0); + shortcutsIconTypeCombo.set_active(1); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('menu-height', this.heightValue); + this._settings.set_int('menu-width-adjustment', this.widthValue); + this._settings.set_int('right-panel-width', this.rightPanelWidth); + this._settings.set_int('menu-width', this.menuWidth); + this._settings.set_enum('force-menu-location', this.forcedMenuLocation); + this._settings.set_boolean('vert-separator', this.verticalSeparator); + this._settings.set_enum('menu-item-icon-size', this.menuItemIconSizeCombo.get_active()); + this._settings.set_enum('menu-item-grid-icon-size', this.gridIconsSizeCombo.get_active()); + this._settings.set_enum('button-item-icon-size', this.buttonIconSizeCombo.get_active()); + this._settings.set_enum('quicklinks-item-icon-size', this.quicklinksIconSizeCombo.get_active()); + this._settings.set_enum('misc-item-icon-size', this.miscIconSizeCombo.get_active()); + this._settings.set_boolean('reload-theme', true); + this._settings.set_boolean('apps-show-extra-details', this.appDescriptions); + this._settings.set_enum('category-icon-type', this.categoryIconType); + this._settings.set_enum('shortcut-icon-type', this.shortcutsIconType); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + createIconSizeRow(title, iconSizeEnum){ + let iconsSizeRow = new PW.FrameBoxRow(); + let iconsSizeLabel = new Gtk.Label({ + label: _(title), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + iconSizeCombo.append("Default", _("Default")); + iconSizeCombo.append("ExtraSmall", _("Extra Small")); + iconSizeCombo.append("Small", _("Small")); + iconSizeCombo.append("Medium", _("Medium")); + iconSizeCombo.append("Large", _("Large")); + iconSizeCombo.append("ExtraLarge", _("Extra Large")); + iconSizeCombo.set_active(iconSizeEnum); + iconSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + iconsSizeRow.add(iconsSizeLabel); + iconsSizeRow.add(iconSizeCombo); + return [iconSizeCombo, iconsSizeRow]; + } + + checkIfResetButtonSensitive(){ + return ( + this.heightValue !== this._settings.get_default_value('menu-height').unpack() || + this.widthValue !== this._settings.get_default_value('menu-width-adjustment').unpack() || + this.rightPanelWidth !== this._settings.get_default_value('right-panel-width').unpack() || + this.menuWidth !== this._settings.get_default_value('menu-width').unpack() || + this.forcedMenuLocation !== 0 || + this.verticalSeparator !== this._settings.get_default_value('vert-separator').unpack() || + this.gridIconsSizeCombo.get_active() !== 0 || + this.menuItemIconSizeCombo.get_active() !== 0 || + this.buttonIconSizeCombo.get_active() !== 0 || + this.quicklinksIconSizeCombo.get_active() !== 0 || + this.miscIconSizeCombo.get_active() !== 0 || + this.appDescriptions !== this._settings.get_default_value('apps-show-extra-details').unpack() || + this.categoryIconType !== 0 || + this.shortcutsIconType !== 1 ) ? true : false + } +}); + +var MenuSettingsFineTunePage = GObject.registerClass( + class Arc_Menu_MenuSettingsFineTunePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.gapAdjustment = this._settings.get_int('gap-adjustment'); + this.removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + this.disableSearchStyle = this._settings.get_boolean('disable-searchbox-border'); + this.alphabetizeAllPrograms = this._settings.get_boolean('alphabetize-all-programs') + this.multiLinedLabels = this._settings.get_boolean('multi-lined-labels'); + this.disableTooltips = this._settings.get_boolean('disable-tooltips'); + this.subMenus = this._settings.get_boolean('enable-sub-menus'); + this.showHiddenRecentFiles = this._settings.get_boolean('show-hidden-recent-files'); + + let searchStyleFrame = new PW.FrameBox(); + let searchStyleRow = new PW.FrameBoxRow(); + let searchStyleLabel = new Gtk.Label({ + label: _("Disable Searchbox Border"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let searchStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + searchStyleSwitch.set_active(this._settings.get_boolean('disable-searchbox-border')); + searchStyleSwitch.connect('notify::active', (widget) => { + this.disableSearchStyle = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + searchStyleRow.add(searchStyleLabel); + searchStyleRow.add(searchStyleSwitch); + searchStyleFrame.add(searchStyleRow); + this.mainBox.append(searchStyleFrame); + + let tweakStyleFrame = new PW.FrameBox(); + let tweakStyleRow = new PW.FrameBoxRow(); + let tweakStyleLabel = new Gtk.Label({ + label: _("Disable Menu Arrow"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let tweakStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tweakStyleSwitch.set_active(this._settings.get_boolean('remove-menu-arrow')); + tweakStyleSwitch.connect('notify::active', (widget) => { + this.removeMenuArrow = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tweakStyleRow.add(tweakStyleLabel); + tweakStyleRow.add(tweakStyleSwitch); + tweakStyleFrame.add(tweakStyleRow); + this.mainBox.append(tweakStyleFrame); + + let fadeEffectFrame = new PW.FrameBox(); + let fadeEffectRow = new PW.FrameBoxRow(); + let fadeEffectLabel = new Gtk.Label({ + label: _("Disable ScrollView Fade Effects"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fadeEffectSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + fadeEffectSwitch.set_active(this._settings.get_boolean('disable-scrollview-fade-effect')); + fadeEffectSwitch.connect('notify::active', (widget) => { + this.disableFadeEffect = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + fadeEffectRow.add(fadeEffectLabel); + fadeEffectRow.add(fadeEffectSwitch); + fadeEffectFrame.add(fadeEffectRow); + this.mainBox.append(fadeEffectFrame); + + let tooltipFrame = new PW.FrameBox(); + let tooltipRow = new PW.FrameBoxRow(); + let tooltipLabel = new Gtk.Label({ + label: _("Disable Tooltips"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let tooltipSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tooltipSwitch.set_active(this.disableTooltips); + tooltipSwitch.connect('notify::active', (widget) => { + this.disableTooltips = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tooltipRow.add(tooltipLabel); + tooltipRow.add(tooltipSwitch); + tooltipFrame.add(tooltipRow); + this.mainBox.append(tooltipFrame); + + let alphabetizeAllProgramsFrame = new PW.FrameBox(); + let alphabetizeAllProgramsRow = new PW.FrameBoxRow(); + let alphabetizeAllProgramsLabel = new Gtk.Label({ + label: _("Alphabetize 'All Programs' Category"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alphabetizeAllProgramsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + alphabetizeAllProgramsSwitch.set_active(this._settings.get_boolean('alphabetize-all-programs')); + alphabetizeAllProgramsSwitch.connect('notify::active', (widget) => { + this.alphabetizeAllPrograms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsLabel); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsSwitch); + alphabetizeAllProgramsFrame.add(alphabetizeAllProgramsRow); + this.mainBox.append(alphabetizeAllProgramsFrame); + + let subMenusFrame = new PW.FrameBox(); + let subMenusRow = new PW.FrameBoxRow(); + let subMenusLabel = new Gtk.Label({ + label: _('Category Sub Menus'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let subMenusSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + subMenusSwitch.set_active(this.subMenus); + subMenusSwitch.connect('notify::active', (widget) => { + this.subMenus = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + subMenusRow.add(subMenusLabel); + subMenusRow.add(subMenusSwitch); + subMenusFrame.add(subMenusRow); + this.mainBox.append(subMenusFrame); + + let hiddenFilesFrame = new PW.FrameBox(); + let hiddenFilesRow = new PW.FrameBoxRow(); + let hiddenFilesLabel = new Gtk.Label({ + label: _('Show Hidden Recent Files'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let hiddenFilesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + hiddenFilesSwitch.connect('notify::active', (widget) => { + this.showHiddenRecentFiles = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + hiddenFilesRow.add(hiddenFilesLabel); + hiddenFilesRow.add(hiddenFilesSwitch); + hiddenFilesFrame.add(hiddenFilesRow); + this.mainBox.append(hiddenFilesFrame); + + let multiLinedLabelFrame = new PW.FrameBox(); + let multiLinedLabelRow = new PW.FrameBoxRow(); + let multiLinedLabelLabel = new Gtk.Label({ + label: _("Multi-Lined Labels"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let multiLinedLabelSwitch = new Gtk.Switch({ halign: Gtk.Align.END, vexpand: false, valign: Gtk.Align.CENTER }); + multiLinedLabelSwitch.set_active(this._settings.get_boolean('multi-lined-labels')); + multiLinedLabelSwitch.connect('notify::active', (widget) => { + this.multiLinedLabels = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + let multiLinedLabelInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + multiLinedLabelInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Multi-Lined Labels"), + secondaryText: _('Enable/Disable multi-lined labels on large application icon layouts.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + multiLinedLabelRow.add(multiLinedLabelLabel); + multiLinedLabelRow.add(multiLinedLabelSwitch); + multiLinedLabelRow.add(multiLinedLabelInfoButton); + multiLinedLabelFrame.add(multiLinedLabelRow); + this.mainBox.append(multiLinedLabelFrame); + + let gapAdjustmentFrame = new PW.FrameBox(); + let gapAdjustmentRow = new PW.FrameBoxRow(); + let gapAdjustmentLabel = new Gtk.Label({ + label: _('Gap Adjustment'), + xalign:0, + hexpand: false, + }); + let gapAdjustmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, upper: 20, step_increment: 1, page_increment: 1, page_size: 0 + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT, + draw_value: true, + }); + gapAdjustmentScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + gapAdjustmentScale.set_value(this.gapAdjustment); + gapAdjustmentScale.connect('value-changed', () => { + this.gapAdjustment = gapAdjustmentScale.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let gapAdjustmentInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + gapAdjustmentInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Adjust the gap between the ArcMenu button and the menu."), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + gapAdjustmentRow.add(gapAdjustmentLabel); + gapAdjustmentRow.add(gapAdjustmentScale); + gapAdjustmentRow.add(gapAdjustmentInfoButton); + gapAdjustmentFrame.add(gapAdjustmentRow); + this.mainBox.append(gapAdjustmentFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.gapAdjustment = this._settings.get_default_value('gap-adjustment').unpack(); + this.removeMenuArrow = this._settings.get_default_value('remove-menu-arrow').unpack(); + this.disableSearchStyle = this._settings.get_default_value('disable-searchbox-border').unpack(); + this.alphabetizeAllPrograms = this._settings.get_default_value('alphabetize-all-programs').unpack(); + this.multiLinedLabels = this._settings.get_default_value('multi-lined-labels').unpack(); + this.subMenus = this._settings.get_default_value('enable-sub-menus').unpack(); + this.showHiddenRecentFiles = this._settings.get_default_value('show-hidden-recent-files').unpack(); + this.disableTooltips = this._settings.get_default_value('disable-tooltips').unpack(); + this.disableFadeEffect = this._settings.get_default_value('disable-scrollview-fade-effect').unpack(); + alphabetizeAllProgramsSwitch.set_active(this.alphabetizeAllPrograms); + gapAdjustmentScale.set_value(this.gapAdjustment); + searchStyleSwitch.set_active(this.disableSearchStyle); + tweakStyleSwitch.set_active(this.removeMenuArrow); + multiLinedLabelSwitch.set_active(this.multiLinedLabels); + tooltipSwitch.set_active(this.disableTooltips); + subMenusSwitch.set_active(this.subMenus); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + fadeEffectSwitch.set_active(this.disableFadeEffect); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('gap-adjustment', this.gapAdjustment); + this._settings.set_boolean('remove-menu-arrow', this.removeMenuArrow); + this._settings.set_boolean('disable-searchbox-border', this.disableSearchStyle); + this._settings.set_boolean('alphabetize-all-programs', this.alphabetizeAllPrograms); + this._settings.set_boolean('multi-lined-labels', this.multiLinedLabels); + this._settings.set_boolean('disable-scrollview-fade-effect', this.disableFadeEffect); + this._settings.set_boolean('disable-tooltips', this.disableTooltips); + this._settings.set_boolean('enable-sub-menus', this.subMenus); + this._settings.set_boolean('show-hidden-recent-files', this.showHiddenRecentFiles); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.subMenus !== this._settings.get_default_value('enable-sub-menus').unpack() || + this.disableTooltips !== this._settings.get_default_value('disable-tooltips').unpack() || + this.gapAdjustment !== this._settings.get_default_value('gap-adjustment').unpack() || + this.removeMenuArrow !== this._settings.get_default_value('remove-menu-arrow').unpack() || + this.disableSearchStyle !== this._settings.get_default_value('disable-searchbox-border').unpack()|| + this.alphabetizeAllPrograms !== this._settings.get_default_value('alphabetize-all-programs').unpack()|| + this.multiLinedLabels !== this._settings.get_default_value('multi-lined-labels').unpack() || + this.disableFadeEffect !== this._settings.get_default_value('disable-scrollview-fade-effect').unpack() || + this.showHiddenRecentFiles !== this._settings.get_default_value('show-hidden-recent-files').unpack()) ? true : false; + } +}); + +var MenuSettingsNewAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsNewAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableRecentApps = this._settings.get_boolean('disable-recently-installed-apps'); + this.indicatorColor = this._settings.get_string('indicator-color'); + this.indicatorTextColor = this._settings.get_string('indicator-text-color'); + + let recentAppsFrame = new PW.FrameBox(); + let recentAppsRow = new PW.FrameBoxRow(); + let recentAppsLabel = new Gtk.Label({ + label: _("Disable New Apps Tracker"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentAppsSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + + recentAppsSwitch.connect('notify::active', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + this.disableRecentApps = widget.get_active(); + + if(widget.get_active()){ + appIndicatorColorFrame.hide(); + recentlyInstalledInfoLabel.hide(); + clearRecentAppsFrame.hide(); + } + else{ + appIndicatorColorFrame.show(); + recentlyInstalledInfoLabel.show(); + clearRecentAppsFrame.show(); + this.mainBox.show(); + } + this._settings.set_boolean('disable-recently-installed-apps', widget.get_active()); + }); + + recentAppsSwitch.set_active(this._settings.get_boolean('disable-recently-installed-apps')); + + recentAppsRow.add(recentAppsLabel); + recentAppsRow.add(recentAppsSwitch); + recentAppsFrame.add(recentAppsRow); + this.mainBox.append(recentAppsFrame); + + let appIndicatorColorFrame = new PW.FrameBox(); + let recentlyInstalledInfoLabel = new Gtk.Label({ + label: "" + _("Customize New Apps Indicator") + "", + use_markup: true, + xalign: 0, + hexpand: true, + }); + this.mainBox.append(recentlyInstalledInfoLabel); + let appIndicatorColorRow = new PW.FrameBoxRow(); + let appIndicatorColorLabel = new Gtk.Label({ + label: _('Category Indicator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + appIndicatorColorChooser.connect('color-set', ()=>{ + this.indicatorColor = appIndicatorColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorColorRow.add(appIndicatorColorLabel); + appIndicatorColorRow.add(appIndicatorColorChooser); + appIndicatorColorFrame.add(appIndicatorColorRow); + + let appIndicatorTextColorRow = new PW.FrameBoxRow(); + let appIndicatorTextColorLabel = new Gtk.Label({ + label: _('App Indicator Label Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorTextColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + color = new Gdk.RGBA(); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + appIndicatorTextColorChooser.connect('color-set', ()=>{ + this.indicatorTextColor = appIndicatorTextColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorTextColorRow.add(appIndicatorTextColorLabel); + appIndicatorTextColorRow.add(appIndicatorTextColorChooser); + appIndicatorColorFrame.add(appIndicatorTextColorRow); + this.mainBox.append(appIndicatorColorFrame); + + let clearRecentAppsFrame = new PW.FrameBox(); + let clearRecentAppsRow = new PW.FrameBoxRow(); + let clearRecentAppsLabel = new Gtk.Label({ + label: _("Clear Apps Marked 'New'"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clearRecentAppsButton = new Gtk.Button({ + halign: Gtk.Align.END, + label: _("Clear All"), + }); + let sensitive = this._settings.get_strv('recently-installed-apps').length > 0; + clearRecentAppsButton.set_sensitive(sensitive); + clearRecentAppsButton.connect('clicked', (widget) => { + clearRecentAppsButton.set_sensitive(false); + this._settings.reset('recently-installed-apps'); + }); + clearRecentAppsRow.add(clearRecentAppsLabel); + clearRecentAppsRow.add(clearRecentAppsButton); + clearRecentAppsFrame.add(clearRecentAppsRow); + this.mainBox.append(clearRecentAppsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.disableRecentApps = this._settings.get_default_value('disable-recently-installed-apps').unpack(); + this.indicatorColor = this._settings.get_default_value('indicator-color').unpack(); + this.indicatorTextColor = this._settings.get_default_value('indicator-text-color').unpack(); + recentAppsSwitch.set_active(this.disableRecentApps); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('disable-recently-installed-apps', this.disableRecentApps); + this._settings.set_string('indicator-color', this.indicatorColor); + this._settings.set_string('indicator-text-color', this.indicatorTextColor); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.disableRecentApps !== this._settings.get_default_value('disable-recently-installed-apps').unpack() || + this.indicatorColor !== this._settings.get_default_value('indicator-color').unpack() || + this.indicatorTextColor !== this._settings.get_default_value('indicator-text-color').unpack() + ) ? true : false; + } +}); + +var MenuSettingsSearchOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsSearchOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.searchResultsDetails = this._settings.get_boolean('show-search-result-details'); + this.openWindowsSearchProvider = this._settings.get_boolean('search-provider-open-windows'); + this.recentFilesSearchProvider = this._settings.get_boolean('search-provider-recent-files'); + this.highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + this.maxSearchResults = this._settings.get_int('max-search-results'); + + let searchProvidersFrame = new PW.FrameBox(); + let searchProvidersLabel = new Gtk.Label({ + label: "" + _("Search Providers") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchProvidersLabel); + let openWindowsRow = new PW.FrameBoxRow(); + let openWindowsLabel = new Gtk.Label({ + label: _("Search for open windows across all workspaces"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let openWindowsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + openWindowsSwitch.connect('notify::active', (widget) => { + this.openWindowsSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + openWindowsRow.add(openWindowsLabel); + openWindowsRow.add(openWindowsSwitch); + searchProvidersFrame.add(openWindowsRow); + + let recentFilesRow = new PW.FrameBoxRow(); + let recentFilesLabel = new Gtk.Label({ + label: _("Search for recent files"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentFilesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + recentFilesSwitch.connect('notify::active', (widget) => { + this.recentFilesSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + recentFilesRow.add(recentFilesLabel); + recentFilesRow.add(recentFilesSwitch); + searchProvidersFrame.add(recentFilesRow); + this.mainBox.append(searchProvidersFrame); + + let searchOptionsFrame = new PW.FrameBox(); + let searchOptionsLabel = new Gtk.Label({ + label: "" + _("Search Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchOptionsLabel); + let descriptionsRow = new PW.FrameBoxRow(); + let descriptionsLabel = new Gtk.Label({ + label: _("Show descriptions of search results"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let descriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + descriptionsSwitch.set_active(this.searchResultsDetails); + descriptionsSwitch.connect('notify::active', (widget) => { + this.searchResultsDetails = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + descriptionsRow.add(descriptionsLabel); + descriptionsRow.add(descriptionsSwitch); + searchOptionsFrame.add(descriptionsRow); + + let highlightSearchResultRow = new PW.FrameBoxRow(); + let highlightSearchResultLabel = new Gtk.Label({ + label: _("Highlight search result terms"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let highlightSearchResultSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + highlightSearchResultSwitch.connect('notify::active', (widget) => { + this.highlightSearchResultTerms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + highlightSearchResultRow.add(highlightSearchResultLabel); + highlightSearchResultRow.add(highlightSearchResultSwitch); + searchOptionsFrame.add(highlightSearchResultRow); + + let maxSearchResultsRow = new PW.FrameBoxRow(); + let maxSearchResultsLabel = new Gtk.Label({ + label: _('Max Search Results'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let maxSearchResultsScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 2, + upper: 10, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + maxSearchResultsScale.set_value(this.maxSearchResults); + maxSearchResultsScale.connect('value-changed', (widget) => { + this.maxSearchResults = widget.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + maxSearchResultsRow.add(maxSearchResultsLabel); + maxSearchResultsRow.add(maxSearchResultsScale); + searchOptionsFrame.add( maxSearchResultsRow); + this.mainBox.append(searchOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.searchResultsDetails = this._settings.get_default_value('show-search-result-details').unpack(); + this.openWindowsSearchProvider = this._settings.get_default_value('search-provider-open-windows').unpack(); + this.recentFilesSearchProvider = this._settings.get_default_value('search-provider-recent-files').unpack(); + this.highlightSearchResultTerms = this._settings.get_default_value('highlight-search-result-terms').unpack(); + this.maxSearchResults = this._settings.get_default_value('max-search-results').unpack(); + descriptionsSwitch.set_active(this.searchResultsDetails); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + maxSearchResultsScale.set_value(this.maxSearchResults); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('show-search-result-details', this.searchResultsDetails); + this._settings.set_boolean('search-provider-open-windows', this.openWindowsSearchProvider); + this._settings.set_boolean('search-provider-recent-files', this.recentFilesSearchProvider); + this._settings.set_boolean('highlight-search-result-terms', this.highlightSearchResultTerms); + this._settings.set_int('max-search-results', this.maxSearchResults); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.searchResultsDetails !== this._settings.get_default_value('show-search-result-details').unpack() || + this.openWindowsSearchProvider !== this._settings.get_default_value('search-provider-open-windows').unpack() || + this.recentFilesSearchProvider !== this._settings.get_default_value('search-provider-recent-files').unpack() || + this.highlightSearchResultTerms !== this._settings.get_default_value('highlight-search-result-terms').unpack() || + this.maxSearchResults !== this._settings.get_default_value('max-search-results').unpack()) ? true : false; + } +}); + +var MenuSettingsCategoriesPage = GObject.registerClass( + class Arc_Menu_MenuSettingsCategoriesPage extends Gtk.Box { + _init(settings, settingType) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.settingType = settingType; + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.categoriesFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value(this.settingType).deep_unpack()); + this.mainBox.append(this.categoriesFrame); + + this.buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.categoriesFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value(this.settingType).deep_unpack()); + this.categoriesFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.categoriesFrame.count; i++) { + let frame = this.categoriesFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value(this.settingType, new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + this.buttonRow.append(this.resetButton); + this.buttonRow.append(this.saveButton); + this.append(this.buttonRow); + } + + getSensitive(){ + let defaultExtraCategories = this._settings.get_default_value(this.settingType).deep_unpack(); + let currentExtraCategories = this._settings.get_value(this.settingType).deep_unpack(); + return !Utils.getArraysEqual(defaultExtraCategories, currentExtraCategories); + } + + _createFrame(extraCategories){ + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let name = Constants.Categories[categoryEnum].NAME; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = extraCategories[i][0]; + frameRow._shouldShow = extraCategories[i][1]; + frameRow._name = Constants.Categories[categoryEnum].NAME; + frameRow._gicon = Gio.icon_new_for_string(Constants.Categories[categoryEnum].ICON); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.categoriesFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + this.categoriesFrame.add(frameRow); + } + } +}); + +var ColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent, themeName="") { + this._settings = settings; + this.addResponse = false; + this.themeName = themeName; + super._init(_('Color Theme Name'), parent); + } + + _createLayout(vbox) { + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + nameFrameRow.add(nameFrameLabel); + this.nameEntry = new Gtk.Entry(); + this.nameEntry.set_width_chars(35); + + nameFrameRow.add(this.nameEntry); + this.nameEntry.grab_focus(); + if(this.themeName!=""){ + this.nameEntry.set_text(this.themeName); + } + this.nameEntry.connect('changed',()=>{ + if(this.nameEntry.get_text().length > 0) + saveButton.set_sensitive(true); + else + saveButton.set_sensitive(false); + }); + + vbox.append(nameFrameRow); + let saveButton = new Gtk.Button({ + label: _("Save Theme"), + halign: Gtk.Align.END + }); + saveButton.set_sensitive(false); + saveButton.connect('clicked', ()=> { + this.themeName = this.nameEntry.get_text(); + this.addResponse=true; + this.response(-10); + }); + vbox.append(saveButton); + } + get_response(){ + return this.addResponse; + } +}); + +var ExportColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ExportColorThemeDialogWindow extends PW.DialogWindow { + + _init(settings, parent, themes=null) { + this._settings = settings; + this._themes = themes; + this.addResponse = false; + this.selectedThemes = []; + super._init(this._themes ? _('Select Themes to Import'): _('Select Themes to Export'), parent); + } + + _createLayout(vbox) { + vbox.spacing = 0; + this.checkButtonArray = []; + this.shouldToggle =true; + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + + let themesListButton = new Gtk.Button({ + label: this._themes ?_("Import"): _("Export"), + }); + + themesListButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + themesListButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + this.checkAllButton = new Gtk.CheckButton({ + margin_end: 23 + }); + + this.checkAllButton.set_halign(Gtk.Align.END); + this.checkAllButton.set_active(true); + this.checkAllButton.connect('toggled', () => { + let isActive = this.checkAllButton.get_active(); + if(this.shouldToggle){ + for(let i = 0; i< this.checkButtonArray.length; i++){ + this.checkButtonArray[i].set_active(isActive); + } + } + }); + let checkAllRow = new PW.FrameBoxRow(); + let checkAllLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + hexpand: true, + label: _("Select All"), + halign: Gtk.Align.END + }); + checkAllRow.add(checkAllLabel); + checkAllRow.add(this.checkAllButton); + vbox.append(checkAllRow); + vbox.append(themesListScrollWindow); + vbox.append(new PW.FrameBoxRow()); + vbox.append(themesListButton); + + this.color_themes = this._themes ? this._themes : this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', () => { + if(checkButton.get_active()){ + this.selectedThemes.push(theme); + } + else{ + this.shouldToggle = false; + this.checkAllButton.set_active(false); + this.shouldToggle = true; + let index= this.selectedThemes.indexOf(theme); + this.selectedThemes.splice(index,1); + } + }); + this.checkButtonArray.push(checkButton); + frameRow.add(checkButton); + this.mainFrame.add(frameRow); + checkButton.set_active(true); + } + } + get_response(){ + return this.addResponse; + } +}); + +var ManageColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ManageColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.selectedThemes = []; + super._init( _('Manage Presets'), parent); + } + + _createLayout(vbox) { + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + let buttonRow = new PW.FrameBoxRow(); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + applyButton.set_sensitive(false); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + vbox.append(themesListScrollWindow); + buttonRow.add(applyButton); + vbox.append(buttonRow); + + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.mainFrame, + buttons: [applyButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', () => { + let dialog = new ColorThemeDialogWindow(this._settings, this, theme[0]); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()) { + let index = frameRow.get_index(); + let array = [dialog.themeName, theme[1], theme[2], theme[3], theme[4], theme[5], + theme[6], theme[7], theme[8], theme[9], theme[10], theme[11], theme[12]]; + this.color_themes.splice(index,1,array); + theme = array; + frameLabel.label = dialog.themeName; + dialog.destroy(); + } + else + dialog.destroy(); + }); + applyButton.set_sensitive(true); + }); + buttonBox.connect('move-up', () => { + let index = frameRow.get_index(); + if(index > 0){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index - 1, 0, theme); + } + }); + + buttonBox.connect('move-down', () => { + let index = frameRow.get_index(); + if(index + 1 < this.mainFrame.count){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index + 1, 0, theme); + } + }); + + buttonBox.connect('delete', () => { + let index = frameRow.get_index(); + this.color_themes.splice(index, 1); + }); + + frameRow.add(buttonBox); + this.mainFrame.add(frameRow); + } + } + get_response(){ + return this.addResponse; + } +}); + +var OverrideArcMenuThemeWindow = GObject.registerClass({ + Signals: { + 'menu-theme-response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_OverrideArcMenuThemeWindow extends Gtk.Box { + _init(settings, parentBox, parentMainBox) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + }); + this.parentBox = parentBox; + this._parentMainBox = parentMainBox; + this._settings = settings; + this.addResponse = false; + this.heightValue = this._settings.get_int('menu-height'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.menuWidth = this._settings.get_int('menu-width'); + this.updatePresetComboBox = true; + this.shouldDeselect = true; + this._createLayout(this); + } + createIconList(store){ + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i= 0; i" + _('Menu Theme Presets') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(colorPresetHeaderLabel); + + this.colorPresetFrame = new PW.FrameBox(); + let colorPresetRow = new PW.FrameBoxRow(); + let colorPresetLabel = new Gtk.Label({ + label: _('Current Menu Theme Preset'), + xalign:0, + hexpand: true, + }); + let store = new Gtk.ListStore(); + store.set_column_types([GdkPixbuf.Pixbuf, GObject.TYPE_STRING]); + this.colorPresetCombo = new Gtk.ComboBox({ + model: store, + }); + + this.createIconList(store); + + let renderer = new Gtk.CellRendererPixbuf({xpad: 5}); + this.colorPresetCombo.pack_start(renderer, false); + this.colorPresetCombo.add_attribute(renderer, "pixbuf", 0); + renderer = new Gtk.CellRendererText(); + this.colorPresetCombo.pack_start(renderer, true); + this.colorPresetCombo.add_attribute(renderer, "text", 1); + + this.saveButton = new Gtk.Button({ + label: _("Save as Preset"), + hexpand: true, + halign: Gtk.Align.END + }); + this.checkIfPresetMatch(); + this.colorPresetCombo.connect('changed', (widget) => { + if(this.updatePresetComboBox){ + let index = widget.get_active(); + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Hightlight Foreground Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + if(index>=0){ + this.menuColor = this.color_themes[index][1]; + this.menuForegroundColor = this.color_themes[index][2]; + this.borderColor = this.color_themes[index][3]; + this.highlightColor = this.color_themes[index][4]; + this.highlightForegroundColor = this.color_themes[index][5]; + this.separatorColor = this.color_themes[index][6]; + this.fontSize = parseInt(this.color_themes[index][7]); + this.borderSize = parseInt(this.color_themes[index][8]); + this.cornerRadius = parseInt(this.color_themes[index][9]); + this.menuArrowSize = parseInt(this.color_themes[index][10]); + this.menuMargin = parseInt(this.color_themes[index][11]); + this.verticalSeparator = (this.color_themes[index][12] === 'true'); + + this.shouldDeselect = false; + this.presetName=this.color_themes[index][0]; + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + this.saveButton.set_sensitive(false); + applyButton.set_sensitive(true); + this.shouldDeselect = true; + resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + } + } + }); + colorPresetRow.add(colorPresetLabel); + colorPresetRow.add(this.colorPresetCombo); + this.colorPresetFrame.add(colorPresetRow); + + let presetsButtonRow = new PW.FrameBoxRow(); + + this.saveButton.connect('clicked', () => { + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + let dialog = new ColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let array = [dialog.themeName, this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + this.color_themes.push(array); + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + let manageButton = new Gtk.Button({ + label: _("Manage Presets") + }); + manageButton.connect('clicked', ()=> { + let dialog = new ManageColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response)=>{ + if(dialog.get_response()){ + this.color_themes = dialog.color_themes; + this._settings.set_value('color-themes',new GLib.Variant('aas',dialog.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + let addButton = new PW.Button({ + title: _("Browse Presets"), + icon_name: "browse-presets-symbolic", + hexpand: false + }); + addButton.connect('clicked', () => { + let settingsFile = Gio.File.new_for_path(Me.path + '/media/misc/ArcMenuDefaultPresets'); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + let colorThemes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + colorThemes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, colorThemes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + presetsButtonRow.add(manageButton); + presetsButtonRow.add(addButton); + presetsButtonRow.add(this.saveButton); + this.colorPresetFrame.add(presetsButtonRow); + vbox.append(this.colorPresetFrame); + + this._settings.connect("changed::color-themes", () => { + store.clear(); + this.createIconList(store); + this.colorPresetCombo.model = store; + this.colorPresetCombo.show(); + + this.checkIfPresetMatch(); + }); + + let menuSettingsHeaderLabel = new Gtk.Label({ + label: "" + _('Theme Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(menuSettingsHeaderLabel); + + let themeSettingsFrame = new PW.FrameBox(); + let themeSettingsFrameScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + themeSettingsFrameScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themeSettingsFrameScrollWindow.set_min_content_height(250); + themeSettingsFrameScrollWindow.set_child(themeSettingsFrame); + vbox.append(themeSettingsFrameScrollWindow); + + //ROW 1 - MENU BACKGROUND COLOR-------------------------------------- + let menuBackgroudColorRow = new PW.FrameBoxRow(); + let menuBackgroudColorLabel = new Gtk.Label({ + label: _('Menu Background Color'), + xalign:0, + hexpand: true, + }); + let menuBackgroudColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + menuBackgroudColorChooser.connect('color-set', () => { + this.menuColor = menuBackgroudColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuBackgroudColorRow.add(menuBackgroudColorLabel); + menuBackgroudColorRow.add(menuBackgroudColorChooser); + themeSettingsFrame.add(menuBackgroudColorRow); + + //ROW 2 - MENU FOREGROUND COLOR-------------------------------------- + let menuForegroundColorRow = new PW.FrameBoxRow(); + let menuForegroundColorLabel = new Gtk.Label({ + label: _('Menu Foreground Color'), + xalign:0, + hexpand: true, + }); + let menuForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + menuForegroundColorChooser.connect('color-set', () => { + this.menuForegroundColor = menuForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuForegroundColorRow.add(menuForegroundColorLabel); + menuForegroundColorRow.add(menuForegroundColorChooser); + themeSettingsFrame.add(menuForegroundColorRow); + + //ROW 3 - FONT SIZE-------------------------------------------------- + let fontSizeRow = new PW.FrameBoxRow(); + let fontSizeLabel = new Gtk.Label({ + label: _('Font Size'), + xalign:0, + hexpand: true, + }); + + let fontScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 8, upper: 14, step_increment: 1, page_increment: 1, page_size: 0 }), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + fontScale.set_format_value_func( (scale, value) => { + return value + "pt"; + }); + fontScale.set_value(this.fontSize); + fontScale.connect('value-changed', () => { + this.fontSize = fontScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + fontSizeRow.add(fontSizeLabel); + fontSizeRow.add(fontScale); + themeSettingsFrame.add(fontSizeRow); + + //ROW 4- Border Color------------------------------------------------- + let borderColorRow = new PW.FrameBoxRow(); + let borderColorLabel = new Gtk.Label({ + label: _('Border Color'), + xalign:0, + hexpand: true, + }); + let borderColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + borderColorChooser.connect('color-set', ()=>{ + this.borderColor = borderColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderColorRow.add(borderColorLabel); + borderColorRow.add(borderColorChooser); + themeSettingsFrame.add(borderColorRow); + + //ROW 5 - Border Size------------------------------------------------------- + let borderSizeRow = new PW.FrameBoxRow(); + let borderSizeLabel = new Gtk.Label({ + label: _('Border Size'), + xalign:0, + hexpand: true, + }); + let borderScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 4, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + borderScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + borderScale.set_value(this.borderSize); + borderScale.connect('value-changed', () => { + this.borderSize = borderScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderSizeRow.add(borderSizeLabel); + borderSizeRow.add(borderScale); + themeSettingsFrame.add(borderSizeRow); + + //ROW 6 - Active Item Background Color----------------------------------------------- + let itemColorRow = new PW.FrameBoxRow(); + let itemColorLabel = new Gtk.Label({ + label: _('Active Item Background Color'), + xalign:0, + hexpand: true, + }); + let itemColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + itemColorChooser.connect('color-set', () => { + this.highlightColor = itemColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemColorRow.add(itemColorLabel); + itemColorRow.add(itemColorChooser); + themeSettingsFrame.add(itemColorRow); + + //ROW 7 - Active Item Foreground Color----------------------------------------------- + let itemForegroundColorRow = new PW.FrameBoxRow(); + let itemForegroundColorLabel = new Gtk.Label({ + label: _('Active Item Foreground Color'), + xalign:0, + hexpand: true, + }); + let itemForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + itemForegroundColorChooser.connect('color-set', () => { + this.highlightForegroundColor = itemForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemForegroundColorRow.add(itemForegroundColorLabel); + itemForegroundColorRow.add(itemForegroundColorChooser); + themeSettingsFrame.add(itemForegroundColorRow); + + //ROW 8 - Corner Radius----------------------------------------------------- + let cornerRadiusRow = new PW.FrameBoxRow(); + let cornerRadiusLabel = new Gtk.Label({ + label: _('Corner Radius'), + xalign:0, + hexpand: true, + }); + let cornerScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + cornerScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + cornerScale.set_value(this.cornerRadius); + cornerScale.connect('value-changed', () => { + this.cornerRadius = cornerScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + cornerRadiusRow.add(cornerRadiusLabel); + cornerRadiusRow.add(cornerScale); + themeSettingsFrame.add(cornerRadiusRow); + + //ROW 9 - Menu Arrow Size------------------------------------------------------- + let menuMarginRow = new PW.FrameBoxRow(); + let menuMarginLabel = new Gtk.Label({ + label: _('Menu Arrow Size'), + xalign:0, + hexpand: true, + }); + let marginScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 30, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + marginScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + marginScale.set_value(this.menuMargin); + marginScale.connect('value-changed', () => { + this.menuMargin = marginScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuMarginRow.add(menuMarginLabel); + menuMarginRow.add(marginScale); + themeSettingsFrame.add(menuMarginRow); + + //ROW 10 - Menu Displacement------------------------------------------------------ + let menuArrowRow = new PW.FrameBoxRow(); + let menuArrowLabel = new Gtk.Label({ + label: _('Menu Displacement'), + xalign:0, + hexpand: true, + }); + let arrowScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + arrowScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + arrowScale.set_value(this.menuArrowSize); + arrowScale.connect('value-changed', () => { + this.menuArrowSize = arrowScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuArrowRow.add(menuArrowLabel); + menuArrowRow.add(arrowScale); + themeSettingsFrame.add(menuArrowRow); + + //ROW 11 - Vertical Separator------------------------------------------------------ + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ halign: Gtk.Align.END}); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + applyButton.set_sensitive(true); + resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + themeSettingsFrame.add(vertSeparatorRow); + + //ROW 12 - Separator Color------------------------------------------------------ + let separatorColorRow = new PW.FrameBoxRow(); + let separatorColorLabel = new Gtk.Label({ + label: _('Separator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let colorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + colorChooser.connect('color-set', ()=>{ + this.separatorColor = colorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + separatorColorRow.add(separatorColorLabel); + separatorColorRow.add(colorChooser); + themeSettingsFrame.add(separatorColorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this._parentMainBox.buttonRow = buttonRow; + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + valign: Gtk.Align.END, + vexpand: false + }); + resetButton.set_sensitive( this.checkIfResetButtonSensitive()); + resetButton.connect('clicked', ()=> { + this.separatorColor = this._settings.get_default_value('separator-color').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.menuColor = this._settings.get_default_value('menu-color').unpack(); + this.menuForegroundColor = this._settings.get_default_value('menu-foreground-color').unpack(); + this.borderColor = this._settings.get_default_value('border-color').unpack(); + this.highlightColor = this._settings.get_default_value('highlight-color').unpack(); + this.highlightForegroundColor = this._settings.get_default_value('highlight-foreground-color').unpack(); + this.fontSize = this._settings.get_default_value('menu-font-size').unpack(); + this.borderSize = this._settings.get_default_value('menu-border-size').unpack(); + this.cornerRadius = this._settings.get_default_value('menu-corner-radius').unpack(); + this.menuMargin = this._settings.get_default_value('menu-margin').unpack(); + this.menuArrowSize = this._settings.get_default_value('menu-arrow-size').unpack(); + + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + + resetButton.set_sensitive(false); + applyButton.set_sensitive(true); + }); + + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + applyButton.set_sensitive(false); + this.emit('menu-theme-response', -10); + }); + applyButton.set_sensitive(false); + + buttonRow.append(resetButton); + buttonRow.append(applyButton); + + this._parentMainBox.append(buttonRow); + } + get_response(){ + return this.addResponse; + } + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + let currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0;i < all_color_themes.length;i++){ + this.isEqual=true; + for(let l = 0; l { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('directory-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name, frame._icon, frame._cmd]); + } + this._settings.set_value('directory-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = _(applicationShortcuts[i][0]); + let editable = true; + if(applicationShortcuts[i][2].startsWith("ArcMenu_")){ + editable = false; + } + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + frameRow._name = applicationName; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._gicon = Gio.icon_new_for_string(getIconPath(applicationShortcuts[i])); + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.resetButton, this.saveButton], + modifyButton: editable, + deleteButton: true + }); + + if(editable){ + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + applicationIcon.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + } + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsShortcutApplicationsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsShortcutApplicationsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + let softwareShortcutsFrame = new PW.FrameBox(); + this.softwareShortcutsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.softwareShortcutsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.softwareShortcutsScrollWindow.set_min_content_height(300); + this.softwareShortcutsScrollWindow.set_child(softwareShortcutsFrame); + + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._loadPinnedApps(applicationShortcuts,softwareShortcutsFrame); + this.mainBox.append(this.softwareShortcutsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('application-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name,frame._icon, frame._cmd]); + } + this._settings.set_value('application-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + let iconString; + frameRow._name = applicationShortcuts[i][0]; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + checkIfValidShortcut(frameRow, softwareShortcutsLabel, applicationIcon); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.saveButton, this.resetButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + applicationIcon.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsPowerOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPowerOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.powerOptionsFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value("power-options").deep_unpack()); + this.mainBox.append(this.powerOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.powerOptionsFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value('power-options').deep_unpack()); + this.powerOptionsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.powerOptionsFrame.count; i++) { + let frame = this.powerOptionsFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value('power-options', new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultPowerOptions = this._settings.get_default_value("power-options").deep_unpack(); + let currentPowerOptions = this._settings.get_value("power-options").deep_unpack(); + return !Utils.getArraysEqual(defaultPowerOptions, currentPowerOptions); + } + + _createFrame(powerOptions){ + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let name = Constants.PowerOptions[powerType].TITLE; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = powerOptions[i][0]; + frameRow._shouldShow = powerOptions[i][1]; + frameRow._name = Constants.PowerOptions[powerType].TITLE; + frameRow._gicon = Gio.icon_new_for_string(Constants.PowerOptions[powerType].IMAGE); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let powerIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let powerImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + powerImageBox.append(dragImage); + powerImageBox.append(powerIcon); + frameRow.add(powerImageBox); + + let powerLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.powerOptionsFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(powerLabel); + frameRow.add(buttonBox); + this.powerOptionsFrame.add(frameRow); + } + } + }); + +var MiscPage = GObject.registerClass( + class Arc_Menu_MiscPage extends Gtk.ScrolledWindow { + _init(settings, parentBox) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let settingsHeaderLabel = new Gtk.Label({ + label: "" + _('Export or Import Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsHeaderLabel); + + let importFrame = new PW.FrameBox(); + let importRow = new PW.FrameBoxRow(); + let importLabel = new Gtk.Label({ + label: _("All ArcMenu Settings"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let settingsImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + settingsImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import All ArcMenu Settings"), + secondaryText: _('Importing settings from file may replace ALL saved settings.\nThis includes all saved pinned apps.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importButtonsRow = new PW.FrameBoxRow(); + let importButton = new Gtk.Button({ + label: _("Import from File"), + hexpand: true, + vexpand: true, + }); + importButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success_, pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + ); + }); + let exportButton = new Gtk.Button({ + label: _("Export to File"), + hexpand: true, + vexpand: true, + }); + exportButton.connect('clicked', ()=> { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE}, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + importRow.add(importLabel); + importRow.add(settingsImportInfoButton); + importButtonsRow.add(exportButton); + importButtonsRow.add(importButton); + importFrame.add(importRow); + importFrame.add(importButtonsRow); + this.mainBox.append(importFrame); + + let importColorPresetFrame = new PW.FrameBox(); + let importColorPresetRow = new PW.FrameBoxRow(); + let importColorPresetLabel = new Gtk.Label({ + label: _("Menu Theme Presets"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let colorThemesImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + colorThemesImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import Menu Theme Presets"), + secondaryText: _('Menu theme presets are located in the "Menu Theme" section'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importColorPresetButtonsRow = new PW.FrameBoxRow(); + let importColorPresetButton = new Gtk.Button({ + label: _("Import Theme Preset"), + hexpand: true, + vexpand: true, + }); + importColorPresetButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import Theme Preset'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + this.color_themes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + this.color_themes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, this.color_themes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + + dialog.destroy(); + } + else + dialog.destroy(); + }); + } + ); + }); + let exportColorPresetButton = new Gtk.Button({ + label: _("Export Theme Preset"), + hexpand: true, + vexpand: true, + }); + exportColorPresetButton.connect('clicked', ()=> { + let dialog = new ExportColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + this.selectedThemes = dialog.selectedThemes; + this._showFileChooser( + _('Export Theme Preset'), + { action: Gtk.FileChooserAction.SAVE }, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + for(let i = 0; i" + _('ArcMenu Settings Window Size') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsSizeHeaderLabel); + + let settingsSizeFrame = new PW.FrameBox(); + let settingsWidthRow = new PW.FrameBoxRow(); + let settingsWidthLabel = new Gtk.Label({ + label: _('Window Width'), + xalign:0, + hexpand: false, + }); + let settingsWidthScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 850, upper: 1800, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsWidthScale.set_value(this._settings.get_int("settings-width")); + settingsWidthScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-width", widget.get_value()) + }); + settingsWidthRow.add(settingsWidthLabel); + settingsWidthRow.add(settingsWidthScale); + settingsSizeFrame.add(settingsWidthRow); + + let settingsHeightRow = new PW.FrameBoxRow(); + let settingsHeightLabel = new Gtk.Label({ + label: _('Window Height'), + xalign:0, + hexpand: false, + }); + let settingsHeightScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: 1600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsHeightScale.set_value(this._settings.get_int("settings-height")); + settingsHeightScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-height", widget.get_value()) + }); + settingsHeightRow.add(settingsHeightLabel); + settingsHeightRow.add(settingsHeightScale); + settingsSizeFrame.add(settingsHeightRow); + + this.mainBox.append(settingsSizeFrame); + + let resetSettingsButton = new Gtk.Button({ + valign: Gtk.Align.END, + halign: Gtk.Align.START, + vexpand: true, + hexpand: false, + label: _("Reset all Settings"), + }); + let context = resetSettingsButton.get_style_context(); + context.add_class('suggested-action'); + resetSettingsButton.connect('clicked', (widget) => { + let dialog = new Gtk.MessageDialog({ + text: "" + _("Restore Default Settings?") + '\n' + _("All ArcMenu settings will be reset to the default value."), + use_markup: true, + buttons: Gtk.ButtonsType.YES_NO, + message_type: Gtk.MessageType.WARNING, + transient_for: this.get_root(), + modal: true + }); + dialog.connect('response', (widget, response) => { + if(response == Gtk.ResponseType.YES){ + GLib.spawn_command_line_sync('dconf reset -f /org/gnome/shell/extensions/arcmenu/'); + let children = [...parentBox.settingsFrameStack]; + for(let child of children){ + parentBox.settingsFrameStack.remove(child); + } + parentBox.populateSettingsFrameStack(); + } + dialog.destroy(); + }); + dialog.show(); + }); + + this.mainBox.append(resetSettingsButton); + } + _showFileChooser(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog({ + title: _(title), + transient_for: this.get_root(), + modal: true, + action: params.action, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + try { + acceptHandler(dialog.get_file().get_path()); + } catch(e) { + log('error from ArcMenu filechooser: ' + e); + } + } + dialog.destroy(); + }); + + dialog.show(); + } + }); + function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + return main; + }; + +var AboutPage = GObject.registerClass( + class Arc_Menu_AboutPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_start: 24, + margin_end: 24, + spacing: 0, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let releaseVersion; + if(Me.metadata.version) + releaseVersion = Me.metadata.version; + else + releaseVersion = 'unknown'; + + let commitVersion; + if(Me.metadata.commit) + commitVersion = Me.metadata.commit; + + let projectUrl = Me.metadata.url; + + let arcMenuImage = new Gtk.Image({ + margin_bottom: 5, + icon_name: 'arc-menu-logo', + pixel_size: 100, + }); + let arcMenuImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_top: 10, + margin_bottom: 10, + hexpand: false, + vexpand: false + }); + arcMenuImageBox.append(arcMenuImage); + + let extensionInfoFrame = new PW.FrameBox(); + + let arcMenuVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let versionText = new Gtk.Label({ + label: _('ArcMenu Version'), + }); + let versionInfo = new Gtk.Label({ + label: releaseVersion + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + arcMenuVersionRow.add(versionText); + arcMenuVersionRow.add(versionInfo); + extensionInfoFrame.add(arcMenuVersionRow); + + let commitRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let commitText = new Gtk.Label({ + label: _('Git Commit'), + }); + let commitInfo = new Gtk.Label({ + label: commitVersion ? commitVersion : '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + commitRow.add(commitText); + commitRow.add(commitInfo); + if(commitVersion){ + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(commitRow); + } + + let gnomeVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let gnomeVersionText = new Gtk.Label({ + label: _('GNOME Version'), + }); + let gnomeVersionInfo = new Gtk.Label({ + label: imports.misc.config.PACKAGE_VERSION + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + gnomeVersionRow.add(gnomeVersionText); + gnomeVersionRow.add(gnomeVersionInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(gnomeVersionRow); + + let osRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let osText = new Gtk.Label({ + label: _('OS'), + }); + let osInfoText; + let name = GLib.get_os_info("NAME"); + let prettyName = GLib.get_os_info("PRETTY_NAME"); + if(prettyName) + osInfoText = prettyName; + else + osInfoText = name; + let versionID = GLib.get_os_info("VERSION_ID"); + if(versionID) + osInfoText += "; Version ID: " + versionID; + let buildID = GLib.get_os_info("BUILD_ID"); + if(buildID) + osInfoText += "; " + "Build ID: " +buildID; + + let osInfo = new Gtk.Label({ + label: osInfoText, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + osRow.add(osText); + osRow.add(osInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(osRow); + + let windowingRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let windowingText = new Gtk.Label({ + label: _('Session Type'), + }); + let windowingLabel; + if(Me.metadata.isWayland) + windowingLabel = "Wayland"; + else + windowingLabel = "X11"; + + let windowingInfo = new Gtk.Label({ + label: windowingLabel, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + windowingRow.add(windowingText); + windowingRow.add(windowingInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(windowingRow); + + let arcMenuInfoBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + vexpand: false + }); + let arcMenuLabel = new Gtk.Label({ + label: '' + _('ArcMenu') + '', + use_markup: true, + vexpand: true, + valign: Gtk.Align.FILL + }); + + let projectDescriptionLabel = new Gtk.Label({ + label: _('Application Menu Extension for GNOME'), + hexpand: false, + vexpand: false, + margin_bottom: 5 + }); + let linksBox = new Gtk.Box({ + hexpand: false, + vexpand: false, + valign: Gtk.Align.END, + halign: Gtk.Align.CENTER, + margin_top: 0, + margin_bottom: 0, + margin_start: 0, + margin_end: 0, + spacing: 0, + }); + + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/donate-icon.svg', 150, 50); + let donateImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let donateLinkButton = new Gtk.LinkButton({ + child: donateImage, + uri: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url', + }); + + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/gitlab-icon.svg', 150, 50); + let gitlabImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let projectLinkButton = new Gtk.LinkButton({ + child: gitlabImage, + uri: projectUrl, + }); + + linksBox.append(projectLinkButton); + linksBox.append(donateLinkButton); + + this.creditsScrollWindow = new Gtk.ScrolledWindow({ + margin_top: 10, + margin_bottom: 0, + hexpand: false, + }); + this.creditsScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.creditsScrollWindow.set_max_content_height(200); + this.creditsScrollWindow.set_min_content_height(200); + this.creditsFrame = new PW.Notebook(); + this.creditsFrame.scrollable = true; + let developersPage = new PW.NotebookPage(_("Developers")); + this.creditsFrame.append_page(developersPage); + let translatorsPage = new PW.NotebookPage(_("Translators")); + this.creditsFrame.append_page(translatorsPage); + let contributorsPage = new PW.NotebookPage(_("Contributors")); + this.creditsFrame.append_page(contributorsPage ); + let artworkPage = new PW.NotebookPage(_("Artwork")); + this.creditsFrame.append_page(artworkPage); + this.creditsScrollWindow.set_child(this.creditsFrame); + let creditsLabel = new Gtk.Label({ + label: _(Constants.DEVELOPERS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + developersPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.TRANSLATORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + translatorsPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.CONTRIBUTORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + contributorsPage.append(creditsLabel); + contributorsPage.hexpand = false; + creditsLabel = new Gtk.Label({ + label: _(Constants.ARTWORK), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + artworkPage.append(creditsLabel); + arcMenuImageBox.append(arcMenuLabel); + arcMenuImageBox.append(projectDescriptionLabel); + + let gnuSofwareLabel = new Gtk.Label({ + label: _(Constants.GNU_SOFTWARE), + use_markup: true, + justify: Gtk.Justification.CENTER + }); + let gnuSofwareLabelBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + valign: Gtk.Align.END, + vexpand: true, + margin_top: 5, + margin_bottom: 10 + }); + gnuSofwareLabelBox.append(gnuSofwareLabel); + + this.mainBox.append(arcMenuImageBox); + this.mainBox.append(arcMenuInfoBox); + this.mainBox.append(extensionInfoFrame); + + this.mainBox.append(this.creditsScrollWindow) + this.mainBox.append(gnuSofwareLabelBox); + this.mainBox.append(linksBox); + } +}); + +function createSeparator(){ + let separatorRow = new Gtk.ListBoxRow({ + selectable: false, + activatable: false + }); + separatorRow.set_child(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + return separatorRow; +} + +var ArcMenuPreferencesWidget = GObject.registerClass( +class Arc_Menu_ArcMenuPreferencesWidget extends Gtk.Box { + _init() { + super._init(); + + this.leftHeaderBox = new Gtk.Box({ + hexpand: true, + visible: true + }); + + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.backButton = new Gtk.Button({ + child: new Gtk.Image({icon_name: 'go-previous-symbolic'}), + visible: true + }); + this.backButton.connect("clicked", () => { + this.leftHeaderBox.remove(this.backButton); + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + }); + + this.settingsFrameStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.CROSSFADE + }); + + this.settingsListStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let mainStackListBox = new PW.StackListBox(this, {width_request: 215}); + + let mainStackBox = mainStackListBox.scrollWindow; + mainStackListBox.addRow("General", _("General"), 'homescreen-symbolic'); + mainStackListBox.addRow("MenuLayout", _("Menu Layout"), 'menu-layouts-symbolic') + mainStackListBox.addRow("MenuTheme", _("Menu Theme"), 'menu-theme-symbolic'); + mainStackListBox.addRow("MenuSettingsGeneral", _("Customize Menu"), 'menu-settings-symbolic', "MenuSettings"); + mainStackListBox.addRow("ButtonAppearance", _("Button Appearance"), 'arc-menu-symbolic') + mainStackListBox.addRow("Misc", _("Misc"), 'misc-symbolic') + mainStackListBox.addRow("About", _("About"), 'info-circle-symbolic'); + mainStackListBox.setSeparatorIndices([1, 4, 5]); + + let menuSettingsStackListBox = new PW.StackListBox(this, {width_request: 215}); + let menuSettingsListBox = menuSettingsStackListBox.scrollWindow; + menuSettingsStackListBox.addRow("MenuSettingsGeneral", _("Menu Settings"), 'menu-settings-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPinnedApps", _("Pinned Apps"), 'pinned-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutDirectories", _("Directory Shortcuts"), 'folder-documents-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutApplications", _("Application Shortcuts"), 'preferences-desktop-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPowerOptions", _("Power Options"), 'gnome-power-manager-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsSearchOptions", _("Search Options"), 'preferences-system-search-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsCategories", _("Extra Categories"), 'categories-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsNewApps", _("New Apps Tracker"), 'preferences-system-notifications-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsFineTune", _("Fine-Tune"), 'fine-tune-symbolic'); + menuSettingsStackListBox.setSeparatorIndices([1, 4, 8]); + + this.settingsListStack.add_named(mainStackBox, "Main"); + this.settingsListStack.add_named(menuSettingsListBox, "MenuSettings"); + + let sidebar = new Gtk.StackSidebar(); + sidebar.set_stack(this.settingsListStack); + this.append(this.settingsListStack); + this.append(sidebar); + + this.append(this.settingsFrameStack); + this.populateSettingsFrameStack(); + } + + populateSettingsFrameStack(){ + this.settingsFrameStack.add_named(new GeneralPage(this._settings), "General"); + this.menuLayoutPage = new MenuLayoutPage(this._settings); + this.settingsFrameStack.add_named(this.menuLayoutPage, "MenuLayout"); + this.settingsFrameStack.add_named(new MenuThemePage(this._settings), "MenuTheme"); + + this.settingsFrameStack.add_named(new MenuSettingsGeneralPage(this._settings), "MenuSettingsGeneral"); + this.settingsFrameStack.add_named(new MenuSettingsPinnedAppsPage(this._settings), "MenuSettingsPinnedApps"); + + let menuSettingsPinnedAppsPage = this.settingsFrameStack.get_child_by_name("MenuSettingsPinnedApps"); + + if(this.pinnedAppsChangedID){ + this._settings.disconnect(this.pinnedAppsChangedID); + this.pinnedAppsChangedID = null; + } + this.pinnedAppsChangedID = this._settings.connect("changed::pinned-app-list", () =>{ + menuSettingsPinnedAppsPage.frame.remove_all_children(); + menuSettingsPinnedAppsPage._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + menuSettingsPinnedAppsPage.frame.show(); + }); + + this.settingsFrameStack.add_named(new MenuSettingsShortcutDirectoriesPage(this._settings), "MenuSettingsShortcutDirectories"); + this.settingsFrameStack.add_named(new MenuSettingsShortcutApplicationsPage(this._settings), "MenuSettingsShortcutApplications"); + this.settingsFrameStack.add_named(new MenuSettingsPowerOptionsPage(this._settings), "MenuSettingsPowerOptions"); + this.settingsFrameStack.add_named(new MenuSettingsSearchOptionsPage(this._settings), "MenuSettingsSearchOptions"); + this.settingsFrameStack.add_named(new MenuSettingsCategoriesPage(this._settings, "extra-categories"), "MenuSettingsCategories"); + this.settingsFrameStack.add_named(new MenuSettingsNewAppsPage(this._settings), "MenuSettingsNewApps"); + this.settingsFrameStack.add_named(new MenuSettingsFineTunePage(this._settings), "MenuSettingsFineTune"); + this.settingsFrameStack.add_named(new ButtonAppearancePage(this._settings), "ButtonAppearance"); + this.settingsFrameStack.add_named(new MiscPage(this._settings, this), "Misc"); + this.settingsFrameStack.add_named(new AboutPage(this._settings), "About"); + + this.show(); + + if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MAIN){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.CUSTOMIZE_MENU){ + this.settingsListStack.set_visible_child_name("MenuSettings"); + this.settingsListStack.get_child_by_name('MenuSettings').listBox.selectRowAtIndex(0); + if(!this.backButton.get_parent()) + this.leftHeaderBox.append(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MENU_LAYOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.BUTTON_APPEARANCE){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(4); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.LAYOUT_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayLayoutTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.RUNNER_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayRunnerTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.ABOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(6); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + this._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.MAIN); + } +}); + +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +function buildPrefsWidget() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); + if(!iconTheme.get_search_path().includes(Me.path + "/media/icons/prefs_icons")) + iconTheme.add_search_path(Me.path + "/media/icons/prefs_icons"); + let widget = new ArcMenuPreferencesWidget(); + widget.connect("realize", () => { + let window = widget.get_root(); + + window.default_width = this._settings.get_int('settings-width'); + window.default_height = this._settings.get_int('settings-height'); + + window.set_title(_("ArcMenu Settings")); + window.get_titlebar().pack_start(widget.leftHeaderBox); + }); + + widget.show(); + return widget; +} + +function checkIfValidShortcut(frameRow, label, icon){ + if(frameRow._cmd.endsWith(".desktop") && !Gio.DesktopAppInfo.new(frameRow._cmd)){ + icon.icon_name = 'warning-symbolic'; + label.label = "" + _("Invalid Shortcut") + " "+ _(label.label); + } +} + +function getIconPath(listing){ + let path, icon; + + if(listing[2]=="ArcMenu_Home") + path = GLib.get_home_dir(); + else if(listing[2].startsWith("ArcMenu_")){ + let string = listing[2]; + path = string.replace("ArcMenu_",''); + if(path === "Documents") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + else if(path === "Downloads") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + else if(path === "Music") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC); + else if(path === "Pictures") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); + else if(path === "Videos") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS); + else + path = null; + } + else if(listing[1] == listing[2]) + path = listing[2]; + else if(listing[1] == "ArcMenu_Folder"){ + path = listing[2]; + } + else + path = null; + + if(path){ + let file = Gio.File.new_for_path(path); + try { + let info = file.query_info('standard::symbolic-icon', 0, null); + icon = info.get_symbolic_icon(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!file.is_native()) { + icon = new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + icon = new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + return icon.to_string(); + } + else{ + if(listing[2]=="ArcMenu_Network") + return 'network-workgroup-symbolic'; + else if(listing[2]=="ArcMenu_Computer") + return 'drive-harddisk-symbolic'; + else + return listing[1]; + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js new file mode 100644 index 0000000..0700025 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js @@ -0,0 +1,793 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var Notebook = GObject.registerClass(class Arc_Menu_Notebook extends Gtk.Notebook{ + _init() { + super._init({ + margin_start: 0, + margin_end: 0 + }); + } + + append_page(notebookPage) { + Gtk.Notebook.prototype.append_page.call( + this, + notebookPage, + notebookPage.getTitleLabel() + ); + } +}); + +var NotebookPage = GObject.registerClass(class Arc_Menu_NotebookPage extends Gtk.Box { + _init(title) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + homogeneous: false + }); + this._title = new Gtk.Label({ + label: "" + title + "", + use_markup: true, + xalign: 0 + }); + } + + getTitleLabel() { + return this._title; + } +}); + +var Button = GObject.registerClass(class Arc_Menu_Button extends Gtk.Button { + _init(params) { + super._init(); + this._params = params; + this.halign = Gtk.Align.END; + this.valign = Gtk.Align.CENTER; + this.box = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 5 + }); + this.set_child(this.box); + + if (this._params.icon_name) { + let image = new Gtk.Image({ + icon_name: this._params.icon_name, + halign: Gtk.Align.CENTER + }); + this.box.append(image); + } + if (this._params.tooltip_text){ + this.set_tooltip_text(this._params.tooltip_text); + } + if (this._params.title){ + let label = new Gtk.Label({ + label: _(this._params.title), + use_markup: true, + xalign: 0 + }); + if(this._params.icon_first) + this.box.append(label); + else + this.box.prepend(label); + } + } +}); + +var DialogWindow = GObject.registerClass(class Arc_Menu_DialogWindow extends Gtk.Dialog { + _init(title, parent) { + super._init({ + title: title, + transient_for: parent.get_root(), + modal: true + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + vbox.insert_after(this.get_content_area(), null); + this._createLayout(vbox); + } + + _createLayout(vbox) { + throw "Not implemented!"; + } +}); + +var MessageDialog = GObject.registerClass(class Arc_Menu_MessageDialog extends Gtk.MessageDialog { + _init(params) { + super._init({ + transient_for: params.transient_for, + modal: true, + buttons: params.buttons + }); + this.set_size_request(300, 50); + this.grid = new Gtk.Grid({ + row_spacing: 10, + column_spacing: 24, + margin_top: 24, + margin_bottom: 0, + margin_start: 24, + margin_end: 24, + hexpand: false, + halign: Gtk.Align.CENTER + }); + this.grid.insert_after(this.get_content_area(), null); + let text = new Gtk.Label({ + label: "" + _(params.text) + "", + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(text, 1, 0, 1, 1); + + if(params.secondaryText){ + let secondayText = new Gtk.Label({ + label: _(params.secondaryText), + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(secondayText, 1, 1, 1, 1); + } + + if(params.iconName){ + let image = new Gtk.Image({ + icon_name: params.iconName, + pixel_size: 48 + }); + this.grid.attach(image, 0, 0, 1, 2); + } + } +}); + +var FrameBox = GObject.registerClass(class Arc_Menu_FrameBox extends Gtk.Frame { + _init(params) { + super._init(params); + this._listBox = new Gtk.ListBox(); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.count = 0; + this.children = []; + Gtk.Frame.prototype.set_child.call(this, this._listBox); + } + + add(boxRow) { + this._listBox.append(boxRow); + this.children.push(boxRow); + this.count++; + } + show() { + this._listBox.show(); + super.show(); + } + length() { + return this._listBox.length; + } + remove(boxRow){ + if(boxRow){ + this._listBox.remove(boxRow); + this.children = this.children.filter(e => e !== boxRow) + this.count = this.count -1; + } + } + removeChildrenAfterIndex(index){ + let childrenCount = this.count; + for(let i = childrenCount - 1; i > index; i--){ + let child = this._listBox.get_row_at_index(i); + if(child) this.remove(child); + } + this._listBox.show(); + } + remove_all_children() { + for(let i = 0; i < this.children.length; i++){ + let child = this.children[i]; + this._listBox.remove(child); + } + this.children = []; + this.count = 0; + this._listBox.show(); + } + get_index(index){ + return this._listBox.get_row_at_index(index); + } + insert(row, pos){ + this._listBox.insert(row, pos); + this.children.push(row); + this.count++; + } +}); + +var FrameBoxRow = GObject.registerClass(class Arc_Menu_FrameBoxRow extends Gtk.ListBoxRow { + _init(params) { + super._init(params); + this.selectable = false; + this.activatable = false; + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var FrameBoxDragRow = GObject.registerClass(class Arc_Menu_FrameBoxDragRow extends Gtk.ListBoxRow { + _init(scrolledWindow) { + super._init(); + + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + + let dragSource = new Gtk.DragSource({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dragSource); + + let dropTarget = new Gtk.DropTargetAsync({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dropTarget); + + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + dragSource.connect("drag-begin", (self, gdkDrag) => { + //get listbox parent + let listBox = self.get_widget().get_parent(); + //get widgets parent - the listBoxDragRow + listBox.dragRow = this; + + let alloc = self.get_widget().get_allocation(); + let dragWidget = self.get_widget().createDragRow(alloc); + listBox.dragWidget = dragWidget; + + let icon = Gtk.DragIcon.get_for_drag(gdkDrag); + icon.set_child(dragWidget); + + gdkDrag.set_hotspot(listBox.dragX, listBox.dragY); + }); + + dragSource.connect("prepare", (self, x, y) => { + //get listbox parent + this.set_state_flags(Gtk.StateFlags.NORMAL, true); + let listBox = self.get_widget().get_parent(); + //store drag start cursor location + listBox.dragX = x; + listBox.dragY = y; + return new Gdk.ContentProvider(Arc_Menu_FrameBoxDragRow); + }); + + dragSource.connect("drag-end", (self, gdkDrag, deleteData)=> { + deleteData = true; + let listBox = self.get_widget().get_parent(); + listBox.dragWidget = null; + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drag-enter", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + let widget = self.get_widget(); + + listBox.startIndex = widget.get_index(); + listBox.drag_highlight_row(widget); + + if(!scrolledWindow) + return true; + + let height = widget.get_height(); + let scrollHeight = scrolledWindow.get_height(); + let widgetLoc = widget.get_index() * height; + let value = scrolledWindow.vadjustment.value; + + if((widgetLoc + (height * 4)) > (value + scrollHeight)) + scrolledWindow.vadjustment.value += height; + else if((widgetLoc - (height * 2)) < value) + scrolledWindow.vadjustment.value -= height; + }); + + dropTarget.connect("drag-leave", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drop", (self, gdkDrop, x, y, selection, info, time)=> { + //get listbox parent + let listBox = this.get_parent(); + let index = this.get_index(); + if(index === listBox.dragRow.get_index()){ + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + } + listBox.remove(listBox.dragRow); + listBox.show(); + listBox.insert(listBox.dragRow, index); + this.resetButton?.set_sensitive(true); + this.saveButton.set_sensitive(true); + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + }); + } + + createDragRow(alloc){ + let dragWidget = new Gtk.ListBox(); + dragWidget.set_size_request(alloc.width, alloc.height); + + let dragRow = new FrameBoxRow(); + dragWidget.append(dragRow); + dragWidget.drag_highlight_row(dragRow); + + let image = new Gtk.Image( { + gicon: this._gicon, + pixel_size: 22 + }); + + let imageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: true, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + imageBox.append(dragImage); + imageBox.append(image); + + dragRow.add(imageBox); + + let label = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true, + label: _(this._name) + }); + dragRow.add(label); + let grid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }) + let editButton = new Button({ + icon_name: 'view-more-symbolic' + }); + grid.attach(editButton, 0, 0, 1, 1); + + if(this.hasSwitch){ + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + active: this.switchActive + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(modifyButton, 0, 0, 1, 1); + } + if(this.hasEditButton){ + let editButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(editButton, 0, 0, 1, 1); + } + dragRow.add(grid); + + return dragWidget; + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var EditEntriesBox = GObject.registerClass({ + Signals: { + 'modify': {}, + 'change': {}, + 'move-up': {}, + 'move-down': {}, + 'delete': {}, + }, +}, class Arc_Menu_EditEntriesBox extends Gtk.Grid{ + _init(params){ + super._init({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + let editPopover = new Gtk.Popover(); + let frameRow = params.frameRow; + let frame = params.frame; + let buttons = params.buttons; + + let modifyButton, deleteButton, changeButton; + + if(params.modifyButton){ + modifyButton = new Gtk.Button({ + label: _("Modify"), + has_frame: false + }); + modifyButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('modify'); + }); + } + + if(params.changeButton){ + changeButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + changeButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('change'); + }); + } + + let editButton = new Gtk.MenuButton({ + icon_name: 'view-more-symbolic', + popover: editPopover, + }); + + this.attach(editButton, 0, 0, 1, 1); + + let editPopoverBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + + editPopover.set_child(editPopoverBox); + + let moveUpButton = new Gtk.Button({ + label: _("Move Up"), + has_frame: false + }); + moveUpButton.connect('clicked', ()=> { + this.emit('move-up'); + let index = frameRow.get_index(); + if(index > 0){ + frame.remove(frameRow); + frame.insert(frameRow, index - 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + let moveDownButton = new Gtk.Button({ + label: _("Move Down"), + has_frame: false + }); + moveDownButton.connect('clicked', ()=> { + this.emit('move-down'); + let index = frameRow.get_index(); + if(index + 1 < frame.count) { + frame.remove(frameRow); + frame.insert(frameRow, index + 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + if(params.deleteButton){ + deleteButton = new Gtk.Button({ + label: _("Delete"), + has_frame: false, + }); + deleteButton.connect('clicked', ()=> { + this.emit('delete'); + frame.remove(frameRow); + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + } + + if(params.changeButton){ + this.insert_column(0); + this.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + this.insert_column(0); + this.attach(changeButton, 0, 0, 1, 1); + } + + if(params.modifyButton){ + editPopoverBox.append(modifyButton); + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + } + + editPopoverBox.append(moveUpButton); + editPopoverBox.append(moveDownButton); + + if(params.deleteButton){ + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + editPopoverBox.append(deleteButton); + } + } +}); + +var StackListBox = GObject.registerClass(class Arc_Menu_StackListBox extends Gtk.ListBox{ + _init(widget, params){ + super._init(params); + this.valign = Gtk.Align.FILL; + this.vexpand = true; + this.hexpand = false; + this.settingsFrameStack = widget.settingsFrameStack; + this.settingsListStack = widget.settingsListStack + this.connect("row-selected", (self, row) => { + if(row){ + let stackName = row.stackName; + this.settingsFrameStack.set_visible_child_name(stackName); + if(row.nextPage){ + if(widget.backButton.get_parent()) + widget.leftHeaderBox.remove(widget.backButton); + widget.leftHeaderBox.prepend(widget.backButton); + this.settingsListStack.set_visible_child_name(row.nextPage); + this.settingsListStack.get_child_by_name(row.nextPage).listBox.selectFirstRow(); + } + } + }); + this.scrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.scrollWindow.set_child(this); + this.scrollWindow.listBox = this; + } + + getRowAtIndex(index){ + return this.get_row_at_index(index).get_children()[0]; + } + + getSelectedRow(){ + return this.get_selected_row().get_children()[0]; + } + + selectFirstRow(){ + this.select_row(this.get_row_at_index(0)); + } + + selectRowAtIndex(index){ + this.select_row(this.get_row_at_index(index)); + } + + addRow(name, translateableName, iconName, nextPage){ + let row1 = new Gtk.ListBoxRow(); + this.append(row1); + + let row = new Gtk.Grid({ + margin_top: 12, + margin_bottom: 12, + margin_start: 12, + margin_end: 12, + column_spacing: 10 + }); + row1.set_child(row); + row1.stackName = name; + row1.translateableName = translateableName; + + let image = new Gtk.Image({ + icon_name: iconName + }); + + let label = new Gtk.Label({ + label: translateableName, + halign: Gtk.Align.START, + }); + row.attach(image, 0, 0, 1, 1); + row.attach(label, 1, 0, 1, 1); + + if(nextPage){ + row1.nextPage = nextPage; + let image2 = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + hexpand: true + }); + row.attach(image2, 2, 0, 1, 1); + } + } + + setSeparatorIndices(indexArray){ + this.set_header_func((_row, _before) =>{ + for(let i = 0; i < indexArray.length; i++){ + if(_row.get_index() === indexArray[i]){ + let sep = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL); + sep.show(); + _row.set_header(sep); + + } + } + }); + } +}); + +var TileGrid = GObject.registerClass(class Arc_Menu_TileGrid extends Gtk.FlowBox{ + _init(maxColumns) { + super._init({ + row_spacing: 5, + column_spacing: 5, + vexpand: true, + hexpand: true, + valign: Gtk.Align.CENTER, + halign: Gtk.Align.CENTER, + max_children_per_line: maxColumns, + homogeneous: true, + selection_mode: Gtk.SelectionMode.NONE + }); + } +}); + +var IconGrid = GObject.registerClass(class Arc_Menu_IconGrid extends Gtk.FlowBox{ + _init() { + super._init({ + max_children_per_line: 7, + row_spacing: 10, + column_spacing: 10, + vexpand: true, + hexpand: false, + valign: Gtk.Align.START, + halign: Gtk.Align.CENTER, + homogeneous: true, + selection_mode: Gtk.SelectionMode.SINGLE + }); + this.childrenCount = 0; + } + + add(widget){ + this.insert(widget, -1); + this.childrenCount++; + } +}); + +var Tile = GObject.registerClass(class Arc_Menu_Tile extends FrameBox{ + _init(name, file, width, height, layout) { + super._init({ + hexpand: true, + vexpand: false, + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER + }); + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.orientation = Gtk.Orientation.VERTICAL, + this.activatable = true; + this.name = name; + this.layout = layout; + this._image = new Gtk.Image({ + + gicon: Gio.icon_new_for_string(file), + pixel_size: width + }); + this._label = new Gtk.Label({ label: _(this.name) }); + + this.box._grid.attach(this._image, 0, 0, 1, 1); + this.box._grid.attach(this._label, 0, 1, 1, 1); + this._listBox.append(this.box); + } +}); + +var LayoutTile = GObject.registerClass(class Arc_Menu_LayoutTile extends FrameBox{ + _init(name, file, layout) { + super._init({ + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER, + hexpand: true, + vexpand: false + }); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.name = name; + this.layout = layout.MENU_TYPE; + + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.column_spacing = 0; + + this._image = new Gtk.Image({ + hexpand: false, + halign: Gtk.Align.START, + gicon: Gio.icon_new_for_string(file), + pixel_size: 46 + }); + + let titleLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", layout.TITLE).format(layout.TITLE) + "", + use_markup: true, + hexpand: true, + halign: Gtk.Align.CENTER, + vexpand: true, + valign: Gtk.Align.CENTER, + wrap: true, + }) + + let goNextImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + hexpand: false, + vexpand: false, + }) + + this.box._grid.attach(this._image, 0, 0, 1, 2); + this.box._grid.attach(titleLabel, 1, 0, 1, 1); + this.box._grid.attach(goNextImage, 2, 0, 1, 2); + + this._listBox.append(this.box); + } +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js new file mode 100644 index 0000000..eb51dff --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js @@ -0,0 +1,111 @@ +const { Gtk, Gio, GLib } = imports.gi; +const ExtensionUtils = imports.misc.extensionUtils; +const Main = imports.ui.main; + +const LogEnabled = false; + +var isCanceled = false; +var currentQueries = []; + +var RecentFilesManager = class Arc_Menu_RecentFilesManager { + constructor() { + this._settings = ExtensionUtils.getSettings(); + this._recentManager = new Gtk.RecentManager(); + } + + filterRecentFiles(callback){ + isCanceled = false; + this._recentManager.get_items().sort((a, b) => b.get_modified() - a.get_modified()) + .forEach(item => { + this.queryFileExists(item) + .then(validFile => { + this.debugLog("Valid file - " + validFile.get_display_name()); + if(!isCanceled) + callback(validFile); + }) + .catch(err =>{ + this.debugLog(err); + }); + }); + } + + queryFileExists(item) { + return new Promise((resolve, reject) => { + let file = Gio.File.new_for_uri(item.get_uri()); + let cancellable = new Gio.Cancellable(); + + if(file === null) + reject("Recent file is null. Rejected."); + + //Create and store queryInfo to cancel any active queries when needed + let queryInfo = { + timeOutID: null, + cancellable, + reject, + item + }; + + currentQueries.push(queryInfo); + + file.query_info_async('standard::type,standard::is-hidden', 0, 0, cancellable, (source, res) => { + try { + let fileInfo = source.query_info_finish(res); + this.removeQueryInfoFromList(queryInfo); + if (fileInfo) { + let isHidden = fileInfo.get_attribute_boolean("standard::is-hidden"); + let showHidden = this._settings.get_boolean('show-hidden-recent-files'); + if(isHidden && !showHidden) + reject(item.get_display_name() + " is hidden. Rejected.") + resolve(item); + } + } + catch (err) { + if (err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + this.debugLog("Cancel Called: " + item.get_display_name()); + + this.removeQueryInfoFromList(queryInfo); + reject(err); + } + }); + }); + } + + removeQueryInfoFromList(queryInfo){ + let queryIndex = currentQueries.indexOf(queryInfo); + if(queryIndex !== -1) + currentQueries.splice(queryIndex, 1); + } + + cancelCurrentQueries(){ + if(currentQueries.length === 0) + return; + isCanceled = true; + this.debugLog("Canceling " + currentQueries.length + " queries...") + for(let queryInfo of currentQueries){ + this.debugLog("Cancel query - " + queryInfo.item.get_display_name()); + queryInfo.cancellable.cancel(); + queryInfo.cancellable = null; + queryInfo.reject("Query Canceled"); + } + currentQueries = null; + currentQueries = []; + this.debugLog("Cancel Finished"); + } + + debugLog(message){ + if (!LogEnabled) + return; + else log(message); + } + + getRecentManager(){ + return this._recentManager; + } + + destroy(){ + this.cancelCurrentQueries(); + this._settings = null; + this._recentManager = null; + } +} + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled new file mode 100644 index 0000000..473fe73 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml new file mode 100644 index 0000000..9638cb6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 50 + Menu position alignment + Menu position alignment 0 = Left, 50 = Center, 100 = Right + + + 'Default' + menu layout + Menu Layout + + + 'Off' + Force the menu to a specific location + Force the menu to a specific location + + + false + disable hotkey on key release + disable hotkey on key release. + + + false + show ArcMenu on primary monitor when using hotkey + show ArcMenu on primary monitor when using hotkey. + + + false + show standalone Runner menu on primary monitor when using hotkey + show standalone Runner menu monitor when using hotkey. + + + 875 + ArcMenu Settings Width + ArcMenu Settings Width. + + + 725 + ArcMenu Settings Height + ArcMenu Settings Height. + + + [true, false, false] + Keeps track of available placement for ArcMenu. [Main Panel, Dash to Panel, Dash to Dock] + false = not avaliable, true = avaliable + + + "Panel" + Embed ArcMenu button into Dash instead of panel + Embed ArcMenu button into Dash instead of panel + + + 'Left' + Raven layout position. 'Left' or 'Right' side of screen + Raven layout position. 'Left' or 'Right' side of screen. + + + true + Enable Weather Widget raven layout + Enable Weather Widget raven layout. + + + true + Enable Clocks Widget raven layout + Enable Clocks Widget raven layout. + + + false + Enable Weather Widget Unity layout + Enable Weather Widget Unity layout. + + + false + Enable Clocks Widget Unity layout + Enable Clocks Widget Unity layout. + + + false + Enable Category Sub Menus + Enable Category Sub Menus. + + + 'Full_Color' + Category icon type. Full_Color or Symbolic + Category icon type. Full_Color or Symbolic + + + 'Symbolic' + Shortcut icon type. Full_Color or Symbolic + Shortcut icon type. Full_Color or Symbolic + + + false + disable the fade effect on scrollviews + ddisable the fade effect on scrollviews (may help improve performace) + + + false + Show a larger icon and extra app details + Show a larger icon and extra app details. + + + 5 + The amount of search results to display. + The amount of search results to display. + + + false + Highlight search results terms + Highlight search results terms. + + + false + Show search result description label + Show search result description label. + + + false + Show custom search provider - open windows + Show custom search provider - open windows. + + + false + Show custom search provider - recent files + Show custom search provider - recent files. + + + false + Show hidden recent files + Show hidden recent files. + + + false + Activate Categories on Hover + Activate Categories on Hover. + + + false + disable recently installed apps + disable recently installed apps. + + + false + disable tooltips + disable tooltips. + + + true + Separate All Programs by a Character Listing + Separate All Programs by a Character Listing. + + + true + Multi-lined labels for large icon application grid layouts + Multi-lined labels for large icon application grid layouts. + + + 'Pinned_Apps' + Set ArcMenu Layout Default View + Set ArcMenu Layout Default View. + + + 'Categories_List' + Set Tognee Layout Default View + Set Tognee Layout Default View. + + + true + Set Unity layout to display "Home Screen" as default + Set Unity layout to display "Home Screen" as default. False = Show all Apps + + + false + Remove the themes menu arrow and displacement + Remove the themes menu arrow and displacement + + + false + Remove border around the searchbox + Remove border around the searchbox + + + false + Disable the user avatar icon from the menu + Disable the user avatar icon from the menu + + + false + Enable an Activitities Overview Shortcut + Enable an Activitities Overview Shortcut + + + 'Bottom' + Searchbar location for layouts with default searchbar on bottom + Searchbar location for layouts with default searchbar on bottom + + + 'Top' + Searchbar location for layouts with default searchbar on top + Searchbar location for layouts with default searchbar on top + + + false + Flip menu horizontally + Flip menu horizontally + + + false + Windows layout - disable frequent apps + Windows layout - disable frequent apps + + + false + Windows layout - disable pinned apps + Windows layout - disable pinned apps + + + false + GNOME Dash Layout - Show Applications + GNOME Dash Layout - Show Applications + + + "rgb(61, 174, 235)" + Plasma Selected Item Color + Plasma Selected Item Color. + + + "rgba(245, 245, 245, .05)" + Plasma Selected Item Background Color + Plasma Selected Item Background Color. + + + true + Plasma Menu Hover to activate item + Plasma Menu Hover to activate item. + + + false + Runner layout - show frequent apps + Runner layout - show frequent apps + + + false + Runner layout - use current shell theme gap + Runner layout - use current shell theme gap + + + 400 + Runner layout - menu height + Runner layout - menu height + + + 500 + Runner layout - menu width + Runner layout - menu width + + + 0 + Runner layout - font size + Runner layout - font size + + + false + Eleven Layout - disable frequent apps + Eleven Layout - disable frequent apps + + + false + Used to reload theme + Used to reload theme. + + + false + Enable a vertical separator + Enable a vertical separator. + + + "rgb(32,32,32)" + Separator Color + Separator Color. + + + "rgba(53,53,53,0.987)" + Menu Background Color + Menu Background Color. + + + "rgb(223,223,223)" + Menu Foreground Color + Menu Foreground Color. + + + "rgb(32,32,32)" + Border Color + Border Color. + + + "rgb(21,83,158)" + Highlight/Active Menu Item Background Color + Highlight/Active Menu Item Background Color. + + + "rgba(255,255,255,1)" + Highlight/Active Menu Item Foreground Color + Highlight/Active Menu Item Foreground Color. + + + 9 + Menu font size + Menu font size. + + + 1 + Menu border size + Menu border size. + + + 5 + Menu corner radius + Menu corner radius. + + + 24 + Menu margin + Menu margin. + + + 12 + Menu arrow size + Menu arrow size. + + + 550 + Menu Height + Menu Height. + + + 290 + Menu width + Menu width. + + + 0 + Menu Width Adjustement. + Menu Width Adjustement. 0 Default. A negative value decreses the default width, positive increases width. + + + 205 + Right Panel width + Right Panel width. + + + 0 + Gap Adjustment + Gap Adjustment + + + "rgb(41, 165, 249)" + Recently Installed Application Inidcator Color + Recently Installed Application Inidcator Color.. + + + "rgba(196, 196, 196, 0.3)" + Recently Installed Application Inidcator Text Background Color + Recently Installed Application Inidcator Text Background Color.. + + + false + Enable Custom ArcMenu Theme + Enable Custom ArcMenu Theme. + + + false + Enable Custom ArcMenu Layout + Enable Custom ArcMenu Layout. + + + false + Show External Devices + Show External Devices. + + + false + Show Bookmarks + Show Bookmarks. + + + [(0, true), (1, true), (2, true), (3, true), (4, false), (5, false), (6, false)] + Power Options + See Constants.js PowerOptions + + + false + Display on all monitors + Display the menu on all monitors when using Dash to Panel. + + + 'Default' + Activities hotcorner action + Activities hotcorner action. + + + false + Override action of activities hot corner + Override action of activities hot corner. + + + false + Show/Hide Activities Button in panel + Show/Hide Activities Button in panel. + + + "sh -c 'notify-send \"$(date)\"'" + Custom hot corner terminal command + Custom hot corner terminal command. + + + 'Undefined' + Set a hotkey to open ArcMenu + Set a hotkey to open ArcMenu. + + + ["<Super>x"] + Custom keybind to open ArcMenu + Custom keybind to open ArcMenu. + + + false + Enable a standalone Runner menu. + Enable a standalone Runner menu. + + + 'Custom' + Set a hotkey to open the standalone Runner menu. + Set a hotkey to open the standalone Runner menu. + + + ["<Alt>1"] + Keybinding to open the standalone runner menu + Keybinding to open the standalone runner menu. + + + 'Left' + The menu position in the panel + The menu position in the panel. + + + 'Top' + Runner Menu Position + Runner Menu Position. + + + 'Icon' + Appearance of the menu button. + Appearance of the menu button. + + + 'Circular' + Appearance of the avatar icon. + Appearance of the avatar icon. + + + false + Enables the default menu button arrow. + Enables the default menu button arrow. + + + 'Default' + Size of the menu items icon. + Size of the menu items icon. Includes all application items, category items, search results. + + + 'Default' + Size of the menu grid icons. + Size of the menu grid icon. + + + 'Default' + Size of the button items in ArcMenu. + Size of the button items in ArcMenu. Includes all buttons inside the menu + + + 'Default' + Size of misc items in ArcMenu. + Size of misc items in ArcMenu. Includes searchbox icons, back menu item, all applications menu item, usermenu item. + + + 'Default' + Size of quicklink items in ArcMenu. + Size of quicklink items in ArcMenu. Includes places, shortcuts, external devices, bookmarks. + + + 'Applications' + Text of the menu button. + Text of the menu button. + + + 'Arc_Menu_Icon' + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + '' + File path of the custom icon for the menu button. + File path of the custom icon for the menu button. + + + 20 + Size of the icon in percentage. + Size of the icon in percentage. + + + -1 + Menu Button Padding. + Menu Button Padding. + + + 0 + Menu button position offset for main panel + Menu button position offset for main panel + + + false + Override border radius styling of the menu button + Override border radius of the menu button. + + + 0 + The border radius size of the menu button + The border radius size of the menu button. + + + 'rgb(240,240,240)' + Color for the menu button icon + Color for the menu button icon. + + + false + Allows changing the menu button icon color + Allows changing the menu button icon color. + + + 'rgb(240,240,240)' + Active color for the menu button icon + Active color for the menu button icon. + + + false + Allows changing the menu button icon active color + Allows changing the menu button icon active color. + + + 'rgb(214,214,214)' + Hover color for the menu button icon + Hover color for the menu button icon. + + + false + Allows changing the menu button icon hover color + Allows changing the menu button icon hover color. + + + 'rgba(238,238,236,0.1)' + Hover background color for the menu button icon + Hover background color for the menu button icon. + + + false + Allows changing the menu button hover background color + Allows changing the menu button hover background color. + + + 'rgba(238,238,236,0.18)' + Active background color for the menu button icon + Active background color for the menu button icon. + + + false + Allows changing the menu button active background color + Allows changing the menu button active background color. + + + [(0, true), (1, true), (2, false), (3, false), (4, false)] + Array of extra categories. See Constants.js - Categories + Array of extra categories. See Constants.js - Categories + + + [(0, false), (1, false), (2, false), (3, false), (4, false)] + Array of extra categories links for ArcMenu layout. See Constants.js - Categories + Array of extra categories for ArcMenu layout. See Constants.js - Categories + + + 'Bottom' + Display extra categories quick links on ArcMenu Layout home page + Display extra categories quick links on ArcMenu Layout home page + + + [] + List of recently installed apps + List of recently installed apps + + + [ "ArcMenu_WebBrowser","WebBrowser", "WebBrowser", + "Files", "", "org.gnome.Nautilus.desktop", + "Terminal", "", "org.gnome.Terminal.desktop", + "ArcMenu Settings", "ArcMenu_ArcMenuIcon", "gnome-extensions prefs arcmenu@arcmenu.com" + ] + + List of Apps Pinned to Menu + List of Apps Pinned to Menu + + + false + Toggle for enabling custom shortcuts. + Toggle for enabling custom shortcuts. + + + [["Home","ArcMenu_Home", "ArcMenu_Home"], ["Documents","ArcMenu_Documents", "ArcMenu_Documents"],["Downloads","ArcMenu_Downloads", "ArcMenu_Downloads"], + ["Music","ArcMenu_Music", "ArcMenu_Music"],["Pictures","ArcMenu_Pictures", "ArcMenu_Pictures"],["Videos","ArcMenu_Videos", "ArcMenu_Videos"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [["Software","system-software-install-symbolic", "ArcMenu_Software"], ["Settings","preferences-system-symbolic", "gnome-control-center.desktop"], + ["Tweaks","org.gnome.tweaks-symbolic", "org.gnome.tweaks.desktop"],["Terminal","utilities-terminal-symbolic", "org.gnome.Terminal.desktop"], + ["Activities Overview", "view-fullscreen-symbolic", "ArcMenu_ActivitiesOverview"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [] + List of Unity Layout Pinned Apps + List of Uniity Layout Pinned Apps + + + 5 + Index of Unity Layout Pinned App Separator + Index of Unity Layout Pinned App Separator, 0 = none + + + ["Software","system-software-install-symbolic", "ArcMenu_Software", "Settings","preferences-system-symbolic", "gnome-control-center.desktop"] + List of Brisk Layout Shortcuts + List of Brisk Layout Shortcuts + + + [] + List of Mint Layout Pinned Apps + List of Mint Layout Pinned Apps + + + 5 + Index of Mint Layout Pinned App Separator + Index of Mint Layout Pinned App Separator, 0 = none + + + [['ArcMenu Style', 'rgba(53,53,53,0.987)', 'rgb(223,223,223)', 'rgb(32,32,32)', 'rgb(21,83,158)', 'rgba(255,255,255,1)', 'rgb(32,32,32)', '9', '1', '5', '12', '24', 'false'], + ['Simply Dark', 'rgba(28, 28, 28, 0.98)', 'rgba(211, 218, 227, 1)', 'rgb(63,62,64)', 'rgba(238, 238, 236, 0.1)', 'rgba(255,255,255,1)', 'rgb(63,62,64)', '9', '0', '0', '0', '0', 'false'], + ['Dark Blue Theme', 'rgb(25,31,34)', 'rgb(189,230,251)', 'rgb(41,50,55)', 'rgb(41,50,55)', 'rgba(255,255,255,1)', 'rgb(41,50,55)', '9', '1', '5', '12', '24', 'true'], + ['Light Blue Theme', 'rgb(255,255,255)', 'rgb(51,51,51)', 'rgb(235,235,235)', 'rgba(189,230,251,0.9)', 'rgba(89,89,89,1)', 'rgba(189,230,251,0.9)', '9', '1', '5', '12', '24', 'true']] + List of color-themes + List of color themes. + + + + 0 + Handles which page to open in ArcMenu Settings + See Constants.js PrefsVisiblePage + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/search.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/search.js new file mode 100644 index 0000000..9085c77 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/search.js @@ -0,0 +1,872 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from GNOME Shell search.js file + * (https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/search.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Clutter, Gio, GLib, GObject, Shell, St } = imports.gi; +const AppDisplay = imports.ui.appDisplay; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const RemoteSearch = imports.ui.remoteSearch; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const { OpenWindowSearchProvider } = Me.imports.searchProviders.openWindows; +const { RecentFilesSearchProvider } = Me.imports.searchProviders.recentFiles; + +const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers'; + +var ListSearchResult = GObject.registerClass(class Arc_Menu_ListSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']); + + super._init(menulayout, app, Constants.DisplayType.LIST, metaInfo) + + this.app = app; + let layoutProperties = this._menuLayout.layoutProperties; + this.searchType = layoutProperties.SearchDisplayType; + this.metaInfo = metaInfo; + this.provider = provider; + this._settings = this._menuLayout._settings; + this.resultsView = resultsView; + this.layout = this._settings.get_enum('menu-layout'); + + if(this.provider.id === 'org.gnome.Nautilus.desktop' || this.provider.id === 'arcmenu.recent-files') + this._path = this.metaInfo['description']; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.metaInfo['description'] && this.provider.appInfo.get_id() === 'org.gnome.Calculator.desktop' && !showSearchResultDescriptions) + this.label.text = this.metaInfo['name'] + " " + this.metaInfo['description']; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var AppSearchResult = GObject.registerClass(class Arc_Menu_AppSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']) || appSys.lookup_app(provider.id); + let displayType = menulayout.layoutProperties.SearchDisplayType; + super._init(menulayout, app, displayType, metaInfo); + this.app = app; + this.provider = provider; + this.metaInfo = metaInfo; + this.resultsView = resultsView; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.descriptionLabel.text.split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var SearchResultsBase = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResultsBase extends St.BoxLayout { + _init(provider, resultsView) { + super._init({ vertical: true }); + this.provider = provider; + this.resultsView = resultsView; + this._menuLayout = resultsView._menuLayout; + this._terms = []; + + this._resultDisplayBin = new St.Bin({ + x_expand: true, + y_expand: true + }); + + this.add_child(this._resultDisplayBin); + + this._resultDisplays = {}; + this._clipboard = St.Clipboard.get_default(); + + this._cancellable = new Gio.Cancellable(); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + this._terms = []; + } + + _createResultDisplay(meta) { + if (this.provider.createResultObject) + return this.provider.createResultObject(meta, this.resultsView); + + return null; + } + + clear() { + this._cancellable.cancel(); + for (let resultId in this._resultDisplays) + this._resultDisplays[resultId].destroy(); + this._resultDisplays = {}; + this._clearResultDisplay(); + this.hide(); + } + + _setMoreCount(count) { + } + + _ensureResultActors(results, callback) { + let metasNeeded = results.filter( + resultId => this._resultDisplays[resultId] === undefined + ); + + if (metasNeeded.length === 0) { + callback(true); + } else { + this._cancellable.cancel(); + this._cancellable.reset(); + + this.provider.getResultMetas(metasNeeded, metas => { + if (this._cancellable.is_cancelled()) { + if (metas.length > 0) + log(`Search provider ${this.provider.id} returned results after the request was canceled`); + callback(false); + return; + } + if (metas.length != metasNeeded.length) { + log('Wrong number of result metas returned by search provider ' + this.provider.id + + ': expected ' + metasNeeded.length + ' but got ' + metas.length); + callback(false); + return; + } + if (metas.some(meta => !meta.name || !meta.id)) { + log('Invalid result meta returned from search provider ' + this.provider.id); + callback(false); + return; + } + + metasNeeded.forEach((resultId, i) => { + let meta = metas[i]; + let display = this._createResultDisplay(meta); + this._resultDisplays[resultId] = display; + }); + callback(true); + }, this._cancellable); + } + } + + updateSearch(providerResults, terms, callback) { + this._terms = terms; + if (providerResults.length == 0) { + this._clearResultDisplay(); + this.hide(); + callback(); + } else { + let maxResults = this._getMaxDisplayedResults(); + let results = this.provider.filterResults(providerResults, maxResults); + let moreCount = Math.max(providerResults.length - results.length, 0); + + this._ensureResultActors(results, successful => { + if (!successful) { + this._clearResultDisplay(); + callback(); + return; + } + + // To avoid CSS transitions causing flickering when + // the first search result stays the same, we hide the + // content while filling in the results. + this.hide(); + this._clearResultDisplay(); + results.forEach(resultId => { + this._addItem(this._resultDisplays[resultId]); + }); + + this._setMoreCount(this.provider.canLaunchSearch ? moreCount : 0); + this.show(); + callback(); + }); + } + } +}); + +var ListSearchResults = GObject.registerClass( +class ArcMenu_ListSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._menuLayout = resultsView._menuLayout; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._container = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + x_expand: true, + y_expand: true, + }); + + if(this.searchType === Constants.DisplayType.GRID){ + this.add_style_class_name('margin-box'); + } + + this.providerInfo = new ArcSearchProviderInfo(provider, this._menuLayout); + this.providerInfo.connect('activate', () => { + if (provider.canLaunchSearch) { + provider.launchSearch(this._terms); + this._menuLayout.arcMenu.toggle(); + } + }); + + this._container.add_child(this.providerInfo); + + this._content = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + + this._container.add_child(this._content); + this._resultDisplayBin.set_child(this._container); + } + + _setMoreCount(count) { + this.providerInfo.setMoreCount(count); + } + + _getMaxDisplayedResults() { + return this._settings.get_int('max-search-results'); + } + + _clearResultDisplay() { + this._content.remove_all_children(); + } + + _createResultDisplay(meta) { + return super._createResultDisplay(meta, this.resultsView) || + new ListSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + if(display.get_parent()) + display.get_parent().remove_child(display); + this._content.add_child(display); + } + + getFirstResult() { + if (this._content.get_n_children() > 0) + return this._content.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var AppSearchResults = GObject.registerClass( +class ArcMenu_AppSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._parentContainer = resultsView; + this._menuLayout = resultsView._menuLayout; + this._settings = this._menuLayout._settings; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this.layout = this._menuLayout._settings.get_enum('menu-layout'); + + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + + this.rtl = this._menuLayout.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.ColumnSpacing : 0, + row_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.RowSpacing : 0, + }); + this._grid = new St.Widget({ + x_expand: true, + x_align: this.searchType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this._grid); + + if(this.searchType === Constants.DisplayType.GRID){ + let spacing = this.layoutProperties.ColumnSpacing; + + this._grid.style = "padding: 0px 0px 10px 0px; spacing: " + spacing + "px;"; + this._resultDisplayBin.x_align = Clutter.ActorAlign.CENTER; + } + + this._resultDisplayBin.set_child(this._grid); + } + + _getMaxDisplayedResults() { + let maxDisplayedResults; + if(this.searchType === Constants.DisplayType.GRID) + maxDisplayedResults = this._menuLayout.getColumnsFromGridIconSizeSetting(); + else + maxDisplayedResults = this._settings.get_int('max-search-results'); + return maxDisplayedResults; + } + + _clearResultDisplay() { + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + this._grid.remove_all_children(); + } + + _createResultDisplay(meta) { + return new AppSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + const GridColumns = this.searchType === Constants.DisplayType.LIST ? 1 : this._menuLayout.getColumnsFromGridIconSizeSetting(); + if(!this.rtl && (this.itemCount % GridColumns === 0)){ + this.gridTop++; + this.gridLeft = 0; + } + else if(this.rtl && (this.gridLeft === 0)){ + this.gridTop++; + this.gridLeft = GridColumns; + } + this._grid.layout_manager.attach(display, this.gridLeft, this.gridTop, 1, 1); + display.gridLocation = [this.gridLeft, this.gridTop]; + + if(!this.rtl) + this.gridLeft++; + else if(this.rtl) + this.gridLeft--; + this.itemCount++; + } + + getFirstResult() { + if (this._grid.get_n_children() > 0) + return this._grid.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var SearchResults = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'have-results': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResults extends St.BoxLayout { + _init(menuLayout) { + super._init({ + vertical: true, + y_expand: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + this._menuLayout = menuLayout; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._content = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL + }); + + this.add_child(this._content); + + this._statusText = new St.Label(); + this._statusBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true, + y_expand: true + }); + + if(menuLayout._settings.get_boolean('enable-custom-arc-menu')) + this._statusText.style_class = 'arc-menu-status-text'; + else + this._statusText.style_class = ''; + + this.add_child(this._statusBin); + this._statusBin.set_child(this._statusText); + + this._highlightDefault = true; + this._defaultResult = null; + this._startingSearch = false; + + this._terms = []; + this._results = {}; + + this._providers = []; + + this._highlightRegex = null; + + this.recentFilesManager = new RecentFilesManager(); + + this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA }); + this.disabledID = this._searchSettings.connect('changed::disabled', this._reloadRemoteProviders.bind(this)); + this.enabledID = this._searchSettings.connect('changed::enabled', this._reloadRemoteProviders.bind(this)); + this.disablExternalID = this._searchSettings.connect('changed::disable-external', this._reloadRemoteProviders.bind(this)); + this.sortOrderID = this._searchSettings.connect('changed::sort-order', this._reloadRemoteProviders.bind(this)); + + this._searchTimeoutId = null; + this._cancellable = new Gio.Cancellable(); + + this._registerProvider(new AppDisplay.AppSearchProvider()); + + this.installChangedID = appSys.connect('installed-changed', this._reloadRemoteProviders.bind(this)); + + this._reloadRemoteProviders(); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + get terms() { + return this._terms; + } + + setStyle(style){ + if(this._statusText){ + this._statusText.style_class = style; + } + } + + _onDestroy(){ + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + if(this.disabledID){ + this._searchSettings.disconnect(this.disabledID); + this.disabledID = null; + } + if(this.enabledID){ + this._searchSettings.disconnect(this.enabledID); + this.enabledID = null; + } + if(this.disablExternalID){ + this._searchSettings.disconnect(this.disablExternalID); + this.disablExternalID = null; + } + if(this.sortOrderID){ + this._searchSettings.disconnect(this.sortOrderID); + this.sortOrderID = null; + } + if(this.installChangedID){ + appSys.disconnect(this.installChangedID); + this.installChangedID = null; + } + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + + this._content.destroy_all_children(); + } + + _reloadRemoteProviders() { + let currentTerms = this._terms; + //cancel any active search + if (this._terms.length !== 0) + this._reset(); + + this._oldProviders = null; + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + if(this._settings.get_boolean('search-provider-open-windows')) + this._registerProvider(new OpenWindowSearchProvider()); + if(this._settings.get_boolean('search-provider-recent-files')) + this._registerProvider(new RecentFilesSearchProvider(this.recentFilesManager)); + + RemoteSearch.loadRemoteSearchProviders(this._searchSettings, providers => { + providers.forEach(this._registerProvider.bind(this)); + }); + + //restart any active search + if(currentTerms.length > 0) + this.setTerms(currentTerms); + } + + _registerProvider(provider) { + provider.searchInProgress = false; + this._providers.push(provider); + this._ensureProviderDisplay(provider); + } + + _unregisterProvider(provider) { + let index = this._providers.indexOf(provider); + this._providers.splice(index, 1); + + if (provider.display){ + provider.display.destroy(); + } + } + + _gotResults(results, provider) { + this._results[provider.id] = results; + this._updateResults(provider, results); + } + + _clearSearchTimeout() { + if (this._searchTimeoutId) { + GLib.source_remove(this._searchTimeoutId); + this._searchTimeoutId = null; + } + } + + _reset() { + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + + this._updateSearchProgress(); + } + + _doSearch() { + this._startingSearch = false; + + let previousResults = this._results; + this._results = {}; + + this._providers.forEach(provider => { + provider.searchInProgress = true; + + let previousProviderResults = previousResults[provider.id]; + if (this._isSubSearch && previousProviderResults) + provider.getSubsearchResultSet(previousProviderResults, + this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + else + provider.getInitialResultSet(this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + }); + + this._updateSearchProgress(); + + this._clearSearchTimeout(); + } + + _onSearchTimeout() { + this._searchTimeoutId = null; + this._doSearch(); + return GLib.SOURCE_REMOVE; + } + + setTerms(terms) { + // Check for the case of making a duplicate previous search before + // setting state of the current search or cancelling the search. + // This will prevent incorrect state being as a result of a duplicate + // search while the previous search is still active. + let searchString = terms.join(' '); + let previousSearchString = this._terms.join(' '); + if (searchString == previousSearchString) + return; + + this._startingSearch = true; + + this.recentFilesManager.cancelCurrentQueries(); + + this._cancellable.cancel(); + this._cancellable.reset(); + + if (terms.length == 0) { + this._reset(); + return; + } + + let isSubSearch = false; + if (this._terms.length > 0) + isSubSearch = searchString.indexOf(previousSearchString) == 0; + + this._terms = terms; + this._isSubSearch = isSubSearch; + this._updateSearchProgress(); + + if (this._searchTimeoutId === null) + this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, this._onSearchTimeout.bind(this)); + + + + const escapedTerms = terms + .map(term => Shell.util_regex_escape(term)) + .filter(term => term.length > 0); + + if (escapedTerms.length === 0) + return; + + this._highlightRegex = new RegExp('(%s)'.format( + escapedTerms.join('|')), 'gi'); + + this.emit('terms-changed'); + } + + _ensureProviderDisplay(provider) { + if (provider.display) + return; + + let providerDisplay; + if (provider.appInfo) + providerDisplay = new ListSearchResults(provider, this); + else + providerDisplay = new AppSearchResults(provider, this); + providerDisplay.hide(); + this._content.add_child(providerDisplay); + provider.display = providerDisplay; + } + + _clearDisplay() { + this._providers.forEach(provider => { + provider.display.clear(); + }); + } + + _maybeSetInitialSelection() { + let newDefaultResult = null; + + let providers = this._providers; + for (let i = 0; i < providers.length; i++) { + let provider = providers[i]; + let display = provider.display; + + if (!display.visible) + continue; + + let firstResult = display.getFirstResult(); + if (firstResult) { + newDefaultResult = firstResult; + break; // select this one! + } + } + + if (newDefaultResult !== this._defaultResult) { + this._setSelected(this._defaultResult, false); + this._setSelected(newDefaultResult, this._highlightDefault); + + this._defaultResult = newDefaultResult; + } + } + + get searchInProgress() { + if (this._startingSearch) + return true; + + return this._providers.some(p => p.searchInProgress); + } + + _updateSearchProgress() { + let haveResults = this._providers.some(provider => { + let display = provider.display; + return (display.getFirstResult() != null); + }); + + this._statusBin.visible = !haveResults; + if (haveResults) + this.emit("have-results") + else if (!haveResults) { + if (this.searchInProgress) + this._statusText.set_text(_("Searching...")); + else + this._statusText.set_text(_("No results.")); + + this.emit("no-results") + } + } + + _updateResults(provider, results) { + let terms = this._terms; + let display = provider.display; + display.updateSearch(results, terms, () => { + provider.searchInProgress = false; + + this._maybeSetInitialSelection(); + this._updateSearchProgress(); + }); + } + + highlightDefault(highlight) { + this._highlightDefault = highlight; + this._setSelected(this._defaultResult, highlight); + } + + getTopResult(){ + return this._defaultResult; + } + + getProviders(){ + return this._providers; + } + + setProvider(providerID){ + if(!this._oldProviders) + this._oldProviders = this._providers; + this._clearDisplay(); + this._providers = this._oldProviders; + if(providerID === Constants.CategoryType.ALL_PROGRAMS){ + this._providers = this._providers.filter(p => (p.appInfo ? false : true)); + } + else if(providerID !== Constants.CategoryType.SEARCH_RESULTS){ + this._providers = this._providers.filter(p => (p.appInfo ? p.appInfo.get_id() : p) === providerID); + } + } + + _setSelected(result, selected) { + if(!result) + return; + + if(selected) + result.add_style_pseudo_class('active'); + else + result.remove_style_pseudo_class('active'); + } + + hasActiveResult(){ + return (this._defaultResult ? true : false) && this._highlightDefault; + } + + highlightTerms(text) { + if (!this._highlightRegex) + return GLib.markup_escape_text(text, -1); + + let escaped = []; + let lastMatchEnd = 0; + let match; + while ((match = this._highlightRegex.exec(text))) { + if (match.index > lastMatchEnd) { + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd, match.index), -1); + escaped.push(unmatched); + } + let matched = GLib.markup_escape_text(match[0], -1); + escaped.push('%s'.format(matched)); + lastMatchEnd = match.index + match[0].length; + } + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd), -1); + escaped.push(unmatched); + + return escaped.join(''); + } +}); + +var ArcSearchProviderInfo = GObject.registerClass(class Arc_Menu_ArcSearchProviderInfo extends MW.ArcMenuPopupBaseMenuItem{ + _init(provider, menuLayout) { + super._init(menuLayout); + this.provider = provider; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this.description = this.provider.appInfo.get_description(); + if(this.description) + this.description = this.description.split('\n')[0]; + + this.label = new St.Label({ + text: provider.appInfo.get_name(), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + style: 'text-align: left;' + }); + + this.label.style = 'font-weight: bold;'; + this.style = "padding: 10px 0px;"; + this.add_child(this.label); + + this._moreText = ""; + } + + setMoreCount(count) { + this._moreText = ngettext("%d more", "%d more", count).format(count); + + if(count > 0) + this.label.text = this.provider.appInfo.get_name() + " (" + this._moreText + ")"; + else + this.label.text = this.provider.appInfo.get_name(); + } +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js new file mode 100644 index 0000000..933a1e6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js @@ -0,0 +1,93 @@ +const { Meta, Gio, St, Shell } = imports.gi; + +const Main = imports.ui.main; +const { getWindows } = imports.ui.altTab; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(app, size) { + return app + ? app.create_icon_texture(size) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var OpenWindowSearchProvider = class { + constructor() { + this.id = 'arcmenu.open-windows'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + + this._appWindows = []; + this._windowTracker = Shell.WindowTracker.get_default(); + + this.appInfo = { + get_description: () => _('List of open windows across all workspaces'), + get_name: () => _('Open Windows'), + get_id: () => 'arcmenu.open-windows', + get_icon: () => Gio.icon_new_for_string('focus-windows-symbolic'), + } + } + + getResultMetas(winIds, callback) { + const metas = winIds.map(winId => { + const aw = this._getAppWindow(winId); + return aw ? { + id: winId, + name: aw.window.title ?? aw.app.get_name(), + description: aw.window.get_workspace() ? _("'%s' on Workspace %d").format(aw.app.get_name(), aw.window.get_workspace().index() + 1) : aw.app.get_name(), + createIcon: (size) => createIcon(aw.app, size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this._appWindows = getWindows(null).map(window => { + return { + window, + app: this._windowTracker.get_window_app(window), + } + }); + + callback(this._getFilteredWindowIds(terms, this._appWindows)); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const appWindows = previousResults.map(winId => this._getAppWindow(winId)).filter(aw => aw !== undefined); + callback(this._getFilteredWindowIds(terms, appWindows)); + } + + activateResult(winId, _terms) { + const window = this._getAppWindow(winId)?.window; + if (window) + Main.activateWindow(window); + } + + launchSearch() { + + } + + _getFilteredWindowIds(terms, appWindows) { + terms = terms.map(term => term.toLowerCase()); + appWindows = appWindows.filter(aw => { + const title = aw.window.title?.toLowerCase(); + const appName = aw.app.get_name()?.toLowerCase(); + const appDescription = aw.app.get_description()?.toLowerCase(); + return terms.some(term => title?.includes(term) || appName?.includes(term) || appDescription?.includes(term)); + }); + + return appWindows.map(aw => aw.window.get_id().toString()); + } + + _getAppWindow(winId) { + winId = typeof winId === "string" ? parseInt(winId) : winId; + return this._appWindows.find(aw => aw.window.get_id() === winId); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js new file mode 100644 index 0000000..fb595e4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js @@ -0,0 +1,100 @@ +const { Meta, Gtk, Gio, GLib, St, Shell } = imports.gi; + +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(mimeType, size) { + let symbolicIcon = mimeType ? Gio.content_type_get_symbolic_icon(mimeType)?.to_string() : null; + return symbolicIcon + ? new St.Icon({ gicon: Gio.icon_new_for_string(symbolicIcon), icon_size: size }) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var RecentFilesSearchProvider = class { + constructor(recentFilesManager) { + this.id = 'arcmenu.recent-files'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + this.recentFilesManager = recentFilesManager; + this._recentFiles = []; + + this.appInfo = { + get_description: () => _('Recent Files'), + get_name: () => _('Recent Files'), + get_id: () => 'arcmenu.recent-files', + get_icon: () => Gio.icon_new_for_string('document-open-recent-symbolic'), + } + } + + getResultMetas(fileUris, callback) { + const metas = fileUris.map(fileUri => { + const rf = this._getRecentFile(fileUri); + const file = Gio.File.new_for_uri(rf.get_uri()); + return rf ? { + id: fileUri, + name: rf.get_display_name(), + description: file.get_parent()?.get_path(), // can be null + createIcon: (size) => createIcon(rf.get_mime_type(), size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this.recentFilesManager.cancelCurrentQueries(); + this._recentFiles = []; + this.recentFilesManager.filterRecentFiles(recentFile => { + this._recentFiles.push(recentFile); + callback(this._getFilteredFileUris(terms, this._recentFiles)); + }); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const recentFiles = previousResults.map(fileUri => this._getRecentFile(fileUri)).filter(rf => rf !== undefined); + callback(this._getFilteredFileUris(terms, recentFiles)); + } + + activateResult(fileUri, _terms) { + const recentFile = this._getRecentFile(fileUri); + if (recentFile){ + let context = global.create_app_launch_context(0, -1); + + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(recentFile.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(recentFile.get_display_name()), e.message); + reject(e); + } + }); + }); + } + } + + launchSearch() { + } + + _getFilteredFileUris(terms, recentFiles) { + terms = terms.map(term => term.toLowerCase()); + recentFiles = recentFiles.filter(rf => { + const fileName = rf.get_display_name()?.toLowerCase(); + return terms.some(term => fileName?.includes(term)); + }); + + return recentFiles.map(rf => rf.get_uri()); + } + + _getRecentFile(fileUri) { + return this._recentFiles.find(rf => rf.get_uri() === fileUri); + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js new file mode 100644 index 0000000..6c0613d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var StandaloneRunner = class Arc_Menu_StandaloneRunner{ + constructor(settings) { + this._settings = settings; + + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this.dummyWidget, 0.5, St.Side.TOP, this); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(Main.panel); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + let rect = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryMonitor.index); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + this.rise; + this.dummyWidget.set_position(positionX, positionY); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.subMenuManager._changeMenu = (menu) => {}; + } + + initiate(){ + this.initiateRecentlyInstalledApps(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._forcedMenuLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._forcedMenuLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(this.MenuLayout) + this.MenuLayout.updateStyle(); + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + if(!this.arcMenu.isOpen){ + this.MenuLayout.updateLocation(); + this.arcMenu.toggle(); + if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else + return null; + } + + destroy(){ + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.dummyWidget){ + Main.uiGroup.remove_child(this.dummyWidget); + this.dummyWidget.destroy(); + } + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + } + } +}; + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide, standaloneRunner) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this.standaloneRunner = standaloneRunner; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this.standaloneRunner.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this.standaloneRunner.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this.standaloneRunner.contextMenuManager.activeMenu) + this.standaloneRunner.contextMenuManager.activeMenu.toggle(); + if(this.standaloneRunner.subMenuManager.activeMenu) + this.standaloneRunner.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/utils.js b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/utils.js new file mode 100644 index 0000000..92207b5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/arcmenu@arcmenu.com/utils.js @@ -0,0 +1,687 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Constants = Me.imports.constants; +const {Gio, GLib} = imports.gi; + +const PowerManagerInterface = ` + + + + + + + + + + + + + + +`; +const PowerManager = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface); + +function canHibernate(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHibernate = needsAuth || result[0] === 'yes'; + asyncCallback(canHibernate, needsAuth); + } + }); +} + +function activateHibernate(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hibernate Error!"), _("System unable to hibernate.")); + else{ + proxy.HibernateRemote(true); + } + }); +} + +function canHybridSleep(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHybridSleep = needsAuth || result[0] === 'yes'; + asyncCallback(canHybridSleep, needsAuth); + } + }); +} + +function activateHybridSleep(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hybrid Sleep Error!"), _("System unable to hybrid sleep.")); + else{ + proxy.HybridSleepRemote(true); + } + }); +} + +function getMenuLayout(menuButton, layout, isStandaloneRunner){ + let MenuLayout = Me.imports.menulayouts; + switch(layout){ + case Constants.MenuLayout.ARCMENU: + return new MenuLayout.arcmenu.createMenu(menuButton); + case Constants.MenuLayout.BRISK: + return new MenuLayout.brisk.createMenu(menuButton); + case Constants.MenuLayout.WHISKER: + return new MenuLayout.whisker.createMenu(menuButton); + case Constants.MenuLayout.GNOME_MENU: + return new MenuLayout.gnomemenu.createMenu(menuButton); + case Constants.MenuLayout.MINT: + return new MenuLayout.mint.createMenu(menuButton); + case Constants.MenuLayout.GNOME_OVERVIEW: + return null; + case Constants.MenuLayout.ELEMENTARY: + return new MenuLayout.elementary.createMenu(menuButton); + case Constants.MenuLayout.REDMOND: + return new MenuLayout.redmond.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE: + return new MenuLayout.simple.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE_2: + return new MenuLayout.simple2.createMenu(menuButton); + case Constants.MenuLayout.UNITY: + return new MenuLayout.unity.createMenu(menuButton); + case Constants.MenuLayout.BUDGIE: + return new MenuLayout.budgie.createMenu(menuButton); + case Constants.MenuLayout.INSIDER: + return new MenuLayout.insider.createMenu(menuButton); + case Constants.MenuLayout.RUNNER: + return new MenuLayout.runner.createMenu(menuButton, isStandaloneRunner); + case Constants.MenuLayout.CHROMEBOOK: + return new MenuLayout.chromebook.createMenu(menuButton); + case Constants.MenuLayout.RAVEN: + return new MenuLayout.raven.createMenu(menuButton); + case Constants.MenuLayout.TOGNEE: + return new MenuLayout.tognee.createMenu(menuButton); + case Constants.MenuLayout.PLASMA: + return new MenuLayout.plasma.createMenu(menuButton); + case Constants.MenuLayout.WINDOWS: + return new MenuLayout.windows.createMenu(menuButton); + case Constants.MenuLayout.LAUNCHER: + return new MenuLayout.launcher.createMenu(menuButton); + case Constants.MenuLayout.ELEVEN: + return new MenuLayout.eleven.createMenu(menuButton); + case Constants.MenuLayout.AZ: + return new MenuLayout.az.createMenu(menuButton); + default: + return new MenuLayout.arcmenu.createMenu(menuButton); + } +} + +function getSettings(schema, extensionUUID) { + let extension = imports.ui.main.extensionManager.lookup(extensionUUID); + + if (!extension) + throw new Error('ArcMenu - getSettings() unable to find extension'); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Expect USER extensions to have a schemas/ subfolder, otherwise assume a + // SYSTEM extension that has been installed in the same prefix as the shell + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error(`Schema ${schema} could not be found for extension ${extension.metadata.uuid}. Please check your installation`); + + return new Gio.Settings({ settings_schema: schemaObj }); +} + +function convertToGridLayout(item){ + const Clutter = imports.gi.Clutter; + const settings = item._settings; + const layoutProperties = item._menuLayout.layoutProperties; + + let icon = item._icon ? item._icon : item._iconBin; + + item.vertical = true; + if(item._ornamentLabel) + item.remove_child(item._ornamentLabel); + + item.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + item.label.x_align = item.label.y_align = Clutter.ActorAlign.CENTER; + item.label.y_expand = true; + + icon.y_align = Clutter.ActorAlign.CENTER; + icon.y_expand = true; + if(settings.get_boolean('multi-lined-labels')){ + icon.y_align = Clutter.ActorAlign.TOP; + icon.y_expand = false; + + let clutterText = item.label.get_clutter_text(); + clutterText.set({ + line_wrap: true, + line_wrap_mode: imports.gi.Pango.WrapMode.WORD_CHAR, + }); + } + + if(item._indicator){ + item.remove_child(item._indicator); + item.insert_child_at_index(item._indicator, 0); + item._indicator.x_align = Clutter.ActorAlign.CENTER; + item._indicator.y_align = Clutter.ActorAlign.START; + item._indicator.y_expand = false; + } + + const iconSizeEnum = settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = layoutProperties.DefaultIconGridStyle; + + iconSize = getGridIconStyle(iconSizeEnum, defaultIconStyle); + item.name = iconSize; +} + +function getIconSize(iconSizeEnum, defaultIconSize){ + const IconSizeEnum = iconSizeEnum; + let iconSize = defaultIconSize; + if(IconSizeEnum === Constants.IconSize.DEFAULT) + iconSize = defaultIconSize; + else if(IconSizeEnum === Constants.IconSize.EXTRA_SMALL) + iconSize = Constants.EXTRA_SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.SMALL) + iconSize = Constants.SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.MEDIUM) + iconSize = Constants.MEDIUM_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.LARGE) + iconSize = Constants.LARGE_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.EXTRA_LARGE) + iconSize = Constants.EXTRA_LARGE_ICON_SIZE; + + return iconSize; +} + +function getGridIconSize(iconSizeEnum, defaultIconStyle){ + let iconSize; + if(iconSizeEnum === Constants.GridIconSize.DEFAULT){ + Constants.GridIconInfo.forEach((info) => { + if(info.NAME === defaultIconStyle){ + iconSize = info.ICON_SIZE; + } + }); + } + else + iconSize = Constants.GridIconInfo[iconSizeEnum - 1].ICON_SIZE; + + return iconSize; +} + +function getGridIconStyle(iconSizeEnum, defaultIconStyle){ + const IconSizeEnum = iconSizeEnum; + let iconStyle = defaultIconStyle; + if(IconSizeEnum === Constants.GridIconSize.DEFAULT) + iconStyle = defaultIconStyle; + else if(IconSizeEnum === Constants.GridIconSize.SMALL) + iconStyle = 'SmallIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM) + iconStyle = 'MediumIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE) + iconStyle = 'LargeIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.SMALL_RECT) + iconStyle = 'SmallRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM_RECT) + iconStyle = 'MediumRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE_RECT) + iconStyle = 'LargeRectIconGrid'; + + return iconStyle; +} + +function getCategoryDetails(currentCategory, categoryIconType){ + let name, gicon, iconName, fallbackIconName; + for(let entry of Constants.Categories){ + if(entry.CATEGORY === currentCategory){ + name = entry.NAME; + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + iconName = entry.FULL_COLOR_ICON; + else + iconName = entry.ICON; + return [name, gicon, iconName, fallbackIconName]; + } + } + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + name = _("Home Screen"); + gicon = Gio.icon_new_for_string(Me.path + '/media/icons/menu_icons/homescreen-symbolic.svg'); + return [name, gicon, iconName, fallbackIconName]; + } + else{ + name = currentCategory.get_name(); + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + gicon = currentCategory.get_icon() ? currentCategory.get_icon() : null; + else + iconName = currentCategory.get_icon().to_string() + "-symbolic"; + fallbackIconName = currentCategory.get_icon() ? currentCategory.get_icon().to_string() : null; + return [name, gicon, iconName, fallbackIconName]; + } +} + +function activateCategory(currentCategory, menuLayout, menuItem, extraParams = false){ + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + menuLayout.activeCategory = _("Pinned Apps"); + menuLayout.displayPinnedApps(); + } + else if(currentCategory === Constants.CategoryType.PINNED_APPS) + menuLayout.displayPinnedApps(); + else if(currentCategory === Constants.CategoryType.FREQUENT_APPS){ + menuLayout.setFrequentAppsList(menuItem); + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + } + else if(currentCategory === Constants.CategoryType.ALL_PROGRAMS) + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + else if(currentCategory === Constants.CategoryType.RECENT_FILES) + menuLayout.displayRecentFiles(); + else + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + + menuLayout.activeCategoryType = currentCategory; +} + +function getMenuButtonIcon(settings, path){ + let iconType = settings.get_enum('menu-button-icon'); + + if(iconType === Constants.MenuIcon.CUSTOM){ + if(path && GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else if(iconType === Constants.MenuIcon.DISTRO_ICON){ + let iconEnum = settings.get_int('distro-icon'); + path = Me.path + Constants.DistroIcons[iconEnum].PATH; + if(Constants.DistroIcons[iconEnum].PATH === 'start-here-symbolic') + return 'start-here-symbolic'; + else if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else{ + let iconEnum = settings.get_int('arc-menu-icon'); + path = Me.path + Constants.MenuIcons[iconEnum].PATH; + if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + + global.log("ArcMenu Error - Failed to set menu button icon. Set to System Default."); + return 'start-here-symbolic'; +} + +function findSoftwareManager(){ + let softwareManager = null; + let appSys = imports.gi.Shell.AppSystem.get_default(); + + for(let softwareManagerID of Constants.SoftwareManagerIDs){ + if(appSys.lookup_app(softwareManagerID)){ + softwareManager = softwareManagerID; + break; + } + } + + return softwareManager; +} + +function createXpmImage(color1, color2, color3, color4){ + let width = 42; + let height = 14; + let colors = 5; + let xpm = [width + " " + height + " " + colors + " " + 1, "1 c " + rgbStringToHex(color1), "2 c " + rgbStringToHex(color2), + "3 c " + rgbStringToHex(color3), "4 c " + rgbStringToHex(color4), "x c #AAAAAA"]; + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + for(let i = 0; i < height - 2; i++) + xpm.push("x1111111111222222222233333333334444444444x"); + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + return xpm; +} + +function areaOfTriangle(p1, p2, p3){ + return Math.abs((p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1])) / 2.0); +} + +function ensureActorVisibleInScrollView(actor) { + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2; + + let parent = actor.get_parent(); + while (!(parent instanceof imports.gi.St.ScrollView)) { + if (!parent) + return; + + box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + parent = parent.get_parent(); + } + + let adjustment = parent.vscroll.adjustment; + let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values(); + + let offset = 0; + let vfade = parent.get_effect("fade"); + if (vfade) + offset = vfade.fade_margins.top; + + if (y1 < value + offset) + value = Math.max(0, y1 - offset); + else if (y2 > value + pageSize - offset) + value = Math.min(upper, y2 + offset - pageSize); + else + return; + adjustment.set_value(value); +} + +function getArraysEqual(a, b) { + if(a instanceof Array && b instanceof Array){ + if (a.length !== b.length) + return false; + for(let i = 0; i < a.length; i++) + if (!getArraysEqual(a[i], b[i])) + return false; + return true; + } + else + return a === b; +} + +function createTooltip(button, widget, titleLabel, description, displayType){ + let lbl = titleLabel.clutter_text; + lbl.get_allocation_box(); + let isEllipsized = lbl.get_layout().is_ellipsized(); + if(displayType !== Constants.DisplayType.BUTTON && (isEllipsized || description)){ + let titleText, descriptionText; + if(isEllipsized && description){ + titleText = titleLabel.text.replace(/\n/g, " "); + descriptionText = description; + } + else if(isEllipsized && !description) + titleText = titleLabel.text.replace(/\n/g, " "); + else if(!isEllipsized && description) + descriptionText = description; + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, descriptionText); + widget.tooltip._onHover(); + } + else if(displayType === Constants.DisplayType.BUTTON){ + let titleText = titleLabel.text.replace(/\n/g, " "); + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, null); + widget.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + widget.tooltip._onHover(); + } +} + +function getDashToPanelPosition(settings, index){ + var positions = null; + var side; + + try{ + positions = JSON.parse(settings.get_string('panel-positions')) + } catch(e){ + log('Error parsing Dash to Panel positions: ' + e.message); + } + + if(!positions) + side = settings.get_string('panel-position'); + else{ + side = positions[index]; + } + + if (side === 'TOP') + return imports.gi.St.Side.TOP; + else if (side === 'RIGHT') + return imports.gi.St.Side.RIGHT; + else if (side === 'BOTTOM') + return imports.gi.St.Side.BOTTOM; + else if (side === 'LEFT') + return imports.gi.St.Side.LEFT; + else + return imports.gi.St.Side.BOTTOM; +} + +function getStylesheet(){ + let stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + + if(!stylesheet.query_exists(null)){ + GLib.spawn_command_line_sync("mkdir " + GLib.get_home_dir() + "/.local/share/arcmenu"); + GLib.spawn_command_line_sync("touch " + GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + } + + return stylesheet; +} + +function rgbStringToHex(colorString) { + let [r, g, b, a_] = parseRgbString(colorString) + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); +} + +function clutterColorToRGBA(color) { + return `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`; +} + +function parseRgbString(colorString){ + if(colorString.includes('rgba')) + colorString = colorString.replace('rgba(',''); + if(colorString.includes('rgb')) + colorString = colorString.replace('rgb(',''); + colorString = colorString.replace(')',''); + let rgbaColor = colorString.split(","); + + let r = parseFloat(rgbaColor[0]); + let g = parseFloat(rgbaColor[1]); + let b = parseFloat(rgbaColor[2]); + let a; + if(rgbaColor[3] != undefined) + a = parseFloat(rgbaColor[3]); + else + a = 1; + return [r, g, b, a]; +} + +function modifyColorLuminance(colorString, luminanceFactor, overrideAlpha){ + let Clutter = imports.gi.Clutter; + let color = Clutter.color_from_string(colorString)[1]; + let [hue, lum, sat] = color.to_hls(); + let modifiedLum = lum; + + if(lum >= .85) //if lum is too light, force darken + modifiedLum = Math.min((1 - Math.abs(luminanceFactor)) * modifiedLum, 1); + else if(lum <= .15) //if lum is too dark, force lighten + modifiedLum = Math.max((1 - Math.abs(luminanceFactor)) * modifiedLum, 0); + else if(luminanceFactor >= 0) //otherwise, darken or lighten based on luminanceFactor + modifiedLum = Math.min((1 + luminanceFactor) * modifiedLum, 1); + else + modifiedLum = Math.max((1 + luminanceFactor) * modifiedLum, 0); + + let alpha = (color.alpha / 255).toPrecision(3); + if(overrideAlpha) + alpha = overrideAlpha; + + let modifiedColor = Clutter.color_from_hls(hue, modifiedLum, sat); + + return `rgba(${modifiedColor.red}, ${modifiedColor.green}, ${modifiedColor.blue}, ${alpha})` +} + +function createStylesheet(settings){ + let customarcMenu = settings.get_boolean('enable-custom-arc-menu'); + let separatorColor = settings.get_string('separator-color'); + let menuColor = settings.get_string('menu-color'); + let menuForegroundColor = settings.get_string('menu-foreground-color'); + let borderColor = settings.get_string('border-color'); + let highlightColor = settings.get_string('highlight-color'); + let highlightForegroundColor = settings.get_string('highlight-foreground-color'); + let fontSize = settings.get_int('menu-font-size'); + let borderSize = settings.get_int('menu-border-size'); + let cornerRadius = settings.get_int('menu-corner-radius'); + let menuMargin = settings.get_int('menu-margin'); + let menuArrowSize = settings.get_int('menu-arrow-size'); + let leftPanelWidth = settings.get_int('menu-width'); + let leftPanelWidthSmall = settings.get_int('menu-width') - 65; + let rightPanelWidth = settings.get_int('right-panel-width'); + let rightPanelWidthPlus45 = settings.get_int('right-panel-width') + 45; + let rightPanelWidthPlus70 = settings.get_int('right-panel-width') + 70; + let avatarStyle = settings.get_enum('avatar-style'); + let avatarRadius = avatarStyle == 0 ? 999 : 0; + let menuButtonColor = settings.get_string('menu-button-color'); + let menuButtonHoverColor = settings.get_string('menu-button-hover-color'); + let menuButtonActiveColor = settings.get_string('menu-button-active-color'); + let menuButtonHoverBackgroundcolor = settings.get_string('menu-button-hover-backgroundcolor'); + let menuButtonActiveBackgroundcolor = settings.get_string('menu-button-active-backgroundcolor'); + let gapAdjustment = settings.get_int('gap-adjustment'); + let indicatorColor = settings.get_string('indicator-color'); + let indicatorTextBackgroundColor = settings.get_string('indicator-text-color'); + let plasmaSelectedItemColor = settings.get_string('plasma-selected-color'); + let plasmaSelectedItemBackgroundColor = settings.get_string('plasma-selected-background-color'); + let plasmaSearchBarTop = settings.get_enum('searchbar-default-top-location'); + let menuButtonBorderRadius = settings.get_int('menu-button-border-radius'); + let tooltipStyle, separatorColorStyle = "\n", smallButtonHoverStyle = "\n"; + let plasmaButtonStyle = plasmaSearchBarTop === Constants.SearchbarLocation.TOP ? 'border-top-width: 2px;' : 'border-bottom-width: 2px;'; + if(customarcMenu){ + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\nbox-shadow: 0 0 1px 0px " + separatorColor + ";\nfont-size:" + fontSize + "pt;\npadding: 3px 8px;\nmin-height: 0px;" + + "\ncolor:" + menuForegroundColor+ ";\nbackground-color:" + modifyColorLuminance(menuColor, 0.05, 1) + ";\nmax-width:550px;\n}\n\n"; + separatorColorStyle = ".separator-color-style{\nbackground-color: " + separatorColor + ";\n}\n\n"; + smallButtonHoverStyle = ".arc-menu .popup-menu-item .arcmenu-small-button.selected{\nbackground-color: " + modifyColorLuminance(highlightColor, -0.25) + "\n}\n\n"; + } + else + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\npadding: 3px 8px;\nmax-width:550px;\nmin-height: 0px;\n}\n\n"; + + let menuButtonStyle = ''; + if(settings.get_boolean('override-menu-button-color')) + menuButtonStyle += ".arc-menu-icon, .arc-menu-text, .arc-menu-arrow{\ncolor: " + menuButtonColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover{\nbackground-color: " + menuButtonHoverBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover .arc-menu-icon, .arc-menu-panel-menu:hover .arc-menu-text" + +", .arc-menu-panel-menu:hover .arc-menu-arrow{\ncolor: " + menuButtonHoverColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-color')) + menuButtonStyle += ".arc-menu-icon:active, .arc-menu-text:active, .arc-menu-arrow:active{\ncolor: " + menuButtonActiveColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:active{\nbackground-color: " + menuButtonActiveBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('menu-button-override-border-radius')){ + let border = menuButtonBorderRadius === 0 ? 1 : 3; + menuButtonStyle += ".arc-menu-panel-menu{\nborder-radius: " + menuButtonBorderRadius + "px;\nborder: " + border + "px solid transparent;\n}\n\n"; + } + + let iconGridStyle = "\ntext-align: center;\n border-radius: 8px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n"; + + let stylesheetCSS = "#arc-search{\nwidth: " + leftPanelWidth + "px;\n}\n\n" + +".arc-menu-status-text{\ncolor:" + menuForegroundColor + ";\nfont-size:" + fontSize + "pt;\n}\n\n" + +".search-statustext{\nfont-size:11pt;\n}\n\n" + + +"#ExtraLargeIconGrid{\nwidth: 150px;\n height: 150px;" + iconGridStyle + "}\n\n" + + +"#LargeIconGrid{\nwidth: 95px;\n height: 95px;" + iconGridStyle + "}\n\n" + + +"#MediumIconGrid{\nwidth: 87px;\n height: 87px;" + iconGridStyle + "}\n\n" + + +"#SmallIconGrid{\nwidth: 80px;\n height: 80px;" + iconGridStyle + "}\n\n" + + +"#LargeRectIconGrid{\nwidth: 95px;\n height: 85px;" + iconGridStyle + "}\n\n" + + +"#MediumRectIconGrid{\nwidth: 92px;\n height: 78px;" + iconGridStyle + "}\n\n" + + +"#SmallRectIconGrid{\nwidth: 85px;\n height: 70px;" + iconGridStyle + "}\n\n" + + +".left-panel{\nwidth:" + leftPanelWidth + "px;\n}\n\n" + +".left-panel-small{\nwidth:" + leftPanelWidthSmall + "px;\n}\n\n" + +".right-panel{\nwidth:" + rightPanelWidth + "px;\n}\n\n" + +".right-panel-plus45{\nwidth:" + rightPanelWidthPlus45 + "px;\n}\n\n" + +".right-panel-plus70{\nwidth:" + rightPanelWidthPlus70 + "px;\n}\n\n" + +".default-search-entry{\nmax-width: 17.667em;\n}\n\n" + +".arc-search-entry{\nmax-width: 17.667em;\nfont-size:" + fontSize + "pt;\nborder-color:" + separatorColor + ";\nborder-width: 1px;\n" + +"color:" + menuForegroundColor + ";\nbackground-color:" + modifyColorLuminance(menuColor, -0.1, 1) + ";\n}\n\n" + +".arc-search-entry:focus{\nborder-color:" + highlightColor + ";\nborder-width: 1px;\nbox-shadow: inset 0 0 0 1px " + modifyColorLuminance(highlightColor, 0.05) + ";\n}\n\n" + +".arc-search-entry StLabel.hint-text{\ncolor: " + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +"#ArcSearchEntry{\nmin-height: 0px;\nborder-radius: 8px;\nborder-width: 1px;\npadding: 7px 9px;\n}\n\n" + +"#ArcSearchEntryRound{\nmin-height: 0px;\nborder-radius: 18px;\nborder-width: 1px;\npadding: 7px 12px;\n}\n\n" + + menuButtonStyle + +".symbolic-icons{\n-st-icon-style: symbolic;\n}\n\n" + +".regular-icons{\n-st-icon-style: regular;\n}\n\n" + +".arcmenu-menu-item{\nborder-radius: 8px;\n}\n\n" + +".margin-box{\nmargin: 0px 4px;\n}\n\n" + +"#arc-menu-launcher-button{\nmax-width: 90px;\nborder-radius: 0px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\nborder-color: transparent;\nborder-bottom-width: 3px;\n}\n\n" + +"#arc-menu-launcher-button.active-item, #arc-menu-launcher-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + +"\nborder-color: " + plasmaSelectedItemColor + ";\nborder-bottom-width: 3px;\n}\n\n" + + +"#arc-menu-plasma-button{\nwidth: 90px;\n height: 65px;\nborder-radius: 8px;\n text-align: center;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n\n" + plasmaButtonStyle + ";\nborder-color: transparent;\n}\n\n" + +"#arc-menu-plasma-button:active-item, .arc-menu-plasma-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + + plasmaButtonStyle + "\nborder-color: " + plasmaSelectedItemColor + ";\n}\n\n" + + +"StScrollView .small-vfade{\n-st-vfade-offset: 44px;\n}\n\n" + + +".arc-menu-button{\n-st-icon-style: symbolic;\nborder-width: 1px;\nborder-radius: 8px;\npadding: 8px;\n}\n\n" + +".arcmenu-small-button{\n-st-icon-style: symbolic;\nborder-radius: 8px;\npadding: 3px 8px;\n}\n\n" + +smallButtonHoverStyle + + +".arc-menu-menu-item-indicator{\ncolor: " + indicatorColor + ";\n}\n\n" + +".arc-menu-menu-item-text-indicator{\nbackground-color: " + indicatorTextBackgroundColor + ";\n}\n\n" + + +tooltipStyle + + +".arc-menu{\n-boxpointer-gap: " + gapAdjustment + "px;\nmin-width: 15em;\ncolor: #D3DAE3;\nborder-image: none;\n" + +"box-shadow: none;\nfont-size:" + fontSize + "pt;\n}\n\n" + +".arc-menu .popup-sub-menu{\npadding-bottom: 1px;\nbackground-color: " + modifyColorLuminance(menuColor, 0.04) + ";\n}\n\n" + +".arc-menu .popup-menu-item{\nspacing: 6px; \nborder: none;\ncolor:" + menuForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:active{\nbackground-color:" + modifyColorLuminance(highlightColor, -0.15) + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item.selected{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:checked{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:insensitive{\ncolor:" + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +".arc-menu-boxpointer{ \n-arrow-border-radius:" + cornerRadius + "px;\n" + +"-arrow-background-color:" + menuColor + ";\n" + +"-arrow-border-color:" + borderColor + ";\n" + +"-arrow-border-width:" + borderSize + "px;\n" + +"-arrow-base:" + menuMargin + "px;\n" + +"-arrow-rise:" + menuArrowSize + "px;\n}\n\n" + +".arc-menu .popup-menu-content{\npadding: 16px 0px;\nmargin: 0;\nbackground-color: transparent;\nborder-radius: 0px;\nbox-shadow: 0;\n}\n\n" + + +".arcmenu-separator{\npadding: 0px;\nheight: 1px;\nmargin: 0px 20px;\n}\n\n" + + separatorColorStyle + +".menu-user-avatar{\nbackground-size: contain;\nborder-radius: " + avatarRadius + "px;\n}\n\n"; + + let stylesheet = getStylesheet(); + if(stylesheet){ + try{ + stylesheet.replace_contents(stylesheetCSS, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + } + catch(e){ + global.log("ArcMenu Error - Failed to update stylesheet. " + e.message); + } + } + else + global.log("ArcMenu Error - Failed to find stylesheet."); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/appfolders.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/appfolders.js new file mode 100644 index 0000000..9548559 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/appfolders.js @@ -0,0 +1,225 @@ +'use strict'; + +const { Shell, GLib, Clutter } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const transparent = Clutter.Color.from_pixel(0x00000000); +const FOLDER_DIALOG_ANIMATION_TIME = 200; +const FRAME_UPDATE_PERIOD = 16; + +let original_zoomAndFadeIn = null; +let original_zoomAndFadeOut = null; +let sigma = 30; +let brightness = 0.6; + +let _zoomAndFadeIn = function () { + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.child.set({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + }); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + effect.sigma = 0; + Utils.ease_property(effect, 'sigma', 0, sigma, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + effect.brightness = 1.0; + Utils.ease_property(effect, 'brightness', 1.0, brightness, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + + this._needsZoomAndFade = false; + + if (this._sourceMappedId === 0) { + this._sourceMappedId = this._source.connect( + 'notify::mapped', this._zoomAndFadeOut.bind(this)); + } +} + +let _zoomAndFadeOut = function () { + if (!this._isOpen) + return; + + if (!this._source.mapped) { + this.hide(); + return; + } + + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + Utils.ease_property(effect, 'sigma', effect.sigma, 0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + Utils.ease_property(effect, 'brightness', effect.brightness, 1.0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this.child.set({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + }); + this.hide(); + + this._popdownCallbacks.forEach(func => func()); + this._popdownCallbacks = []; + }, + }); + + this._needsZoomAndFade = false; +} + + +var AppFoldersBlur = class AppFoldersBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + } + + enable() { + this._log("blurring appfolders"); + + if (Main.overview._overview.controls._appDisplay._folderIcons.length > 0) { + this.blur_appfolders(); + } + this.connections.connect(Main.overview._overview.controls._appDisplay, 'view-loaded', () => { + this.blur_appfolders(); + }) + } + + blur_appfolders() { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + icon._ensureFolderDialog(); + + if (original_zoomAndFadeIn == null) { + original_zoomAndFadeIn = icon._dialog._zoomAndFadeIn; + } + if (original_zoomAndFadeOut == null) { + original_zoomAndFadeOut = icon._dialog._zoomAndFadeOut; + } + + let effect = new Shell.BlurEffect({ + name: "appfolder-blur", + sigma: sigma, + brightness: brightness, + mode: 1 + }); + icon._dialog.remove_effect_by_name("appfolder-blur"); + icon._dialog.add_effect(effect); + + // HACK + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("appfolders hack level 1"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("appfolders hack level 2"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + icon._dialog._viewBox.set_style_class_name('app-folder-dialog transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + + icon._dialog._zoomAndFadeIn = _zoomAndFadeIn; + icon._dialog._zoomAndFadeOut = _zoomAndFadeOut; + }); + } + + set_sigma(s) { + sigma = s; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + set_brightness(b) { + brightness = b; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + disable() { + this._log("removing blur from appfolders"); + + if (original_zoomAndFadeIn != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeIn = original_zoomAndFadeIn; + }); + } + if (original_zoomAndFadeOut != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeOut = original_zoomAndFadeOut; + }); + } + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) { + icon._dialog.remove_effect_by_name("appfolder-blur") + icon._dialog._viewBox.remove_style_class_name('transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + } + }); + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/applications.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/applications.js new file mode 100644 index 0000000..e044464 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/applications.js @@ -0,0 +1,274 @@ +'use strict'; + +const { Shell, Clutter, Meta, GLib } = imports.gi; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; +const BlurMode = Shell.BlurMode; + +var ApplicationsBlur = class ApplicationsBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + + this.windowMap = new Map(); + this.blurActorMap = new Map(); + } + + enable() { + this._log("blurring applications..."); + + // iterate through existing windows and add blur as needed + for (let workspace = 0; workspace < global.workspace_manager.get_n_workspaces(); ++workspace) { + let metaWorkspace = global.workspace_manager.get_workspace_by_index(workspace); + let windows = metaWorkspace.list_windows(); + windows.forEach((meta_window) => { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + }) + } + + // blur every new window + this.connections.connect(global.display, 'window-created', (meta_display, meta_window) => { + this._log("window created"); + if (meta_window) { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + } + }); + + // workaround for blur being in front of target windows + this.connections.connect(global.display, 'notify::focus-window', () => { + if (this.blurActorMap.size > 0) { + let callbackId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + this.blurActorMap.forEach((blurActor, pid) => { + let actor = this.windowMap.get(pid).get_compositor_private(); + if (actor !== null && actor.get_parent() === blurActor.get_parent()) { + global.window_group.set_child_below_sibling(blurActor, actor); + } + }) + }) + } + }) + } + + // Blurs and add the needed signals to every new tracked window + track_new(window_actor, meta_window) { + // TODO change the pid to a more unique one, to prevent collisions? + let pid = Date.now(); + + window_actor['blur_provider_pid'] = pid; + meta_window['blur_provider_pid'] = pid; + + // remove the blur when the window is destroyed + this.connections.connect(window_actor, 'destroy', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (this.blurActorMap.has(pid)) { + this.remove_blur(pid) + } + }); + + // update the blur when the mutter-hint is changed + this.connections.connect(meta_window, 'notify::mutter-hints', (meta_window) => { + this._log("mutter-hint changed"); + let pid = meta_window.blur_provider_pid; + let window_actor = meta_window.get_compositor_private(); + this.update_blur(window_actor, meta_window, pid) + }); + + this.update_blur(window_actor, meta_window, pid); + } + + // This method is basically a catch-all for blurring windows. It handles the decisions + // to call different methods that handle removing, setting, and updating blur + update_blur(window_actor, meta_window, pid) { + let mutter_hint = meta_window.get_mutter_hints(); + + // check if the window wants blur and update it accordingly + if (mutter_hint != null && mutter_hint.includes("blur-provider")) { + // get blur effect parameters + let sigma = this.parse_sigma_value(mutter_hint); + let brightness = this.prefs.BRIGHTNESS.get(); + + // if the provided sigma value is incorrect + if (sigma == null || sigma < 0 || sigma > 111) { + this._log("sigma value is null or outside of range (0-111), defaulting to extension setting") + sigma = this.prefs.SIGMA.get(); + } + + // check wether the actor is already blurred and act consequently + if (this.blurActorMap.has(pid)) { + if (sigma == 0) { + // actor already blurred, should not be anymore + this.remove_blur(pid); + } else { + // actor already blurred, update it + this.update_blur_effect( + this.blurActorMap.get(pid), + sigma, + brightness + ); + } + } else if (sigma != 0) { + // actor not blurred, blur it + this.set_blur( + pid, + window_actor, + meta_window, + this.create_blur_effect(sigma, brightness) + ) + } + } else if (this.blurActorMap.has(pid)) { + // remove blur if the mutter_hint no longer contains our blur-provider value + this.remove_blur(pid); + } + } + + // Returns a new blur effect + create_blur_effect(sigma, brightness) { + return new Shell.BlurEffect({ + sigma: sigma, + brightness: brightness, + mode: BlurMode.BACKGROUND + }); + } + + // Add the blur effect to the actor + set_blur(pid, window_actor, meta_window, blurEffect) { + let blurActor = this.create_blur_actor(meta_window, window_actor, blurEffect); + + // if hacks are selected, force the repaint the window to prevent artifacts + if (this.prefs.HACKS_LEVEL.get() >= 1) { + this._log("applications hack level 1 or 2"); + this.paint_signals.disconnect_all(); + this.paint_signals.connect(blurActor, blurEffect); + } else { + this.paint_signals.disconnect_all(); + } + + global.window_group.insert_child_below(blurActor, window_actor); + + // registed the blur actor/effect + blurActor['blur_provider_pid'] = pid; + this.blurActorMap.set(pid, blurActor); + this.windowMap.set(pid, meta_window); + + // hide if window become invisible + this.connections.connect(window_actor, 'notify::visible', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (window_actor.visible) { + this.blurActorMap.get(pid).show(); + } else { + this.blurActorMap.get(pid).hide(); + } + }); + } + + // Returns a new already blurred widget, configured to follow the size and + // position of its target window + create_blur_actor(meta_window, window_actor, blurEffect) { + // create the constraints in size and position to its target window + let frame = meta_window.get_frame_rect(); + let buffer = meta_window.get_buffer_rect(); + + const offsetX = frame.x - buffer.x; + const offsetY = frame.y - buffer.y; + const offsetWidth = buffer.width - frame.width; + const offsetHeight = buffer.height - frame.height; + + let constraintPosX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.X, + offset: offsetX + }); + let constraintPosY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.Y, + offset: offsetY + }); + + let constraintSizeX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.WIDTH, + offset: -offsetWidth + }); + let constraintSizeY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.HEIGHT, + offset: -offsetHeight + }); + + // create the actor and add the constraints + let blurActor = new Clutter.Actor(); + blurActor.add_constraint(constraintPosX); + blurActor.add_constraint(constraintPosY); + blurActor.add_constraint(constraintSizeX); + blurActor.add_constraint(constraintSizeY); + + // add the effect + blurActor.add_effect_with_name('blur-effect', blurEffect); + + return blurActor; + } + + // Updates the blur effect by overwriting its sigma and brightness values + update_blur_effect(blur_actor, sigma, brightness) { + let effect = blur_actor.get_effect('blur-effect'); + effect.sigma = sigma; + effect.brightness = brightness; + } + + // Removes the blur actor from the shell and unregister it + remove_blur(pid) { + // global.window_group is null when restarting the shell, causing an innocent crash crash + if (global.window_group == null) + return + + global.window_group.remove_actor(this.blurActorMap.get(pid)); + this.blurActorMap.delete(pid); + this.windowMap.delete(pid); + } + + // When given the xprop property, returns either a valid sigma value between 0 and 111 + // or null if the parsing is incorrect + parse_sigma_value(property) { + let result = property.match("(blur-provider=)(\\d{1,3})") + if (result == null) { + return null; + } else { + return result[2]; + } + } + + disable() { + this._log("removing blur from applications..."); + + this.blurActorMap.forEach(((value, key) => { + this.remove_blur(key) + })); + this.connections.disconnect_all(); + this.paint_signals.disconnect_all(); + } + + // Updates each blur effect to use new sigma value + set_sigma(s) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_sigma(s) + }) + } + + // Updates each blur effect to use new brightness value + set_brightness(b) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_brightness(b) + }) + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/connections.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/connections.js new file mode 100644 index 0000000..3517a27 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/connections.js @@ -0,0 +1,81 @@ +'use strict'; + +const GObject = imports.gi.GObject; + + +var Connections = class Connections { + constructor() { + this.buffer = []; + } + + process_connection(actor, id) { + let infos = { + actor: actor, + id: id + }; + + if (actor.connect && (!(actor instanceof GObject.Object) || GObject.signal_lookup('destroy', actor))) { + let destroy_id = actor.connect('destroy', () => { + actor.disconnect(id); + actor.disconnect(destroy_id); + + let index = this.buffer.indexOf(infos); + if (index >= 0) { + this.buffer.splice(index, 1) + } + }) + } + + this.buffer.push(infos) + } + + connect(actor, signal, handler) { + let id = actor.connect(signal, handler); + this.process_connection(actor, id); + } + + connect_after(actor, signal, handler) { + let id = actor.connect_after(signal, handler); + + this.process_connection(actor, id); + } + + disconnect_all_for(actor) { + let actor_connections = [] + + this.buffer.forEach((infos) => { + if (infos.actor == actor) { + actor_connections.push(infos) + } + }); + + actor_connections.forEach((connection) => { + // disconnect + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + + // remove from buffer + let index = this.buffer.indexOf(connection); + this.buffer.splice(index, 1); + }) + } + + disconnect_all() { + this.buffer.forEach((connection) => { + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + }) + this.buffer = []; + } + + // no need to check if DEBUG here, the log function is only used on error + _log(str) { + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash.js new file mode 100644 index 0000000..650bf69 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash.js @@ -0,0 +1,51 @@ +'use strict'; + +const { St, Shell, Meta } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; + + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring dash"); + this.update(); + } + + update() { + if (Main.overview.dash.constructor.name == "Dash") { + Main.overview.dash.get_child_at_index(0).style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + // set search entry the same opacity as the dash + Main.overview._overview._controls._searchEntry.style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + disable() { + this._log("removing blur from dash"); + + if (Main.overview.dash.constructor.name == "Dash") { + if (Main.screenShield && !Main.screenShield.locked) { + try { + Main.overview.dash.get_child_at_index(0).style = null; + } catch (e) { + this._log(e); + } + } + } + Main.overview._overview._controls._searchEntry.style = null; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js new file mode 100644 index 0000000..166f147 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js @@ -0,0 +1,235 @@ +'use strict'; + +const { St, Shell, GLib } = imports.gi; +const Main = imports.ui.main; +const Signals = imports.signals; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +// This type of object is created for every dash found, and talks to the main DashBlur thanks +// to signals. This allows to dynamically track the created dashes for each screen. +class DashInfos { + constructor(dash_blur, dash, dash_box, background_parent, effect, prefs) { + // the parent DashBlur object, to communicate + this.dash_blur = dash_blur; + // the blurred dash + this.dash = dash; + // the actually blurred box + this.dash_box = dash_box; + this.background_parent = background_parent; + this.effect = effect; + this.prefs = prefs; + + dash_blur.connections.connect(dash_blur, 'remove-dashes', () => { + this._log("removing blur from dash"); + this.dash.get_parent().remove_child(this.background_parent); + this.dash.remove_style_class_name('blurred-dash'); + }); + + dash_blur.connections.connect(dash_blur, 'update-sigma', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'update-brightness', () => { + this.effect.brightness = this.dash_blur.brightness; + }); + + dash_blur.connections.connect(dash_blur, 'show', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'hide', () => { + this.effect.sigma = 0; + }); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.dashes = []; + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.sigma = prefs.SIGMA.get(); + this.brightness = prefs.BRIGHTNESS.get(); + } + + enable() { + this.connections.connect(Main.uiGroup, 'actor-added', (_, actor) => { + if ((actor.get_name() == "dashtodockContainer") && (actor.constructor.name == 'DashToDock')) + this.try_blur(actor); + }); + + this.blur_existing_dashes(); + } + + // Finds all existing dashes on every monitor, and call `try_blur` on them + // We cannot only blur `Main.overview.dash`, as there could be multiple screens + blur_existing_dashes() { + this._log("searching for dash"); + // blur every dash found + Main.uiGroup.get_children().filter((child) => { + // filter by name + return (child.get_name() == "dashtodockContainer") && (child.constructor.name == 'DashToDock') + }).forEach(this.try_blur.bind(this)); + } + + // Tries to blur the dash contained in the given actor + try_blur(dash_container) { + let dash_box = dash_container._slider.get_child(); + // verify that we did not already blur that dash + if (!dash_box.get_children().some((c) => { + return c.get_name() == "dash-blurred-background-parent" + })) { + // finally blur the dash + this._log("dash to dock found, blurring it"); + let dash = dash_box.get_children().find(c => { return c.get_name() == 'dash' }) + this.dashes.push(this.blur_dash_from(dash, dash_container)); + } + } + + // Blurs the dash and returns a `DashInfos` containing its informations + blur_dash_from(dash, dash_container) { + // the effect to be applied + let effect = new Shell.BlurEffect({ + brightness: this.brightness, + sigma: this.sigma, + mode: 1 + }); + + // dash background parent, not visible + let background_parent = new St.Widget({ + name: 'dash-blurred-background-parent', + style_class: 'dash-blurred-background-parent', + width: 0, + height: 0 + }); + + // dash background widget + let background = new St.Widget({ + name: 'dash-blurred-background', + style_class: 'dash-blurred-background', + x: 0, + y: dash_container._slider.y, + width: dash.width, + height: dash.height, + }); + + // updates size and position on change + this.connections.connect(dash_container._slider, 'notify::y', _ => { + background.y = dash_container._slider.y; + }); + this.connections.connect(dash, 'notify::width', _ => { + background.width = dash.width; + }); + this.connections.connect(dash, 'notify::height', _ => { + background.height = dash.height; + }); + + + // HACK + { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the dash buttons to cause artefacts on the dash itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("dash hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { + effect.queue_repaint() + }; + + dash._box.get_children().forEach((icon) => { + try { + let zone = icon.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._box, 'actor-added', (_, actor) => { + try { + let zone = actor.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._showAppsIcon, 'enter-event', rp); + this.connections.connect(dash._showAppsIcon, 'leave-event', rp); + this.connections.connect(dash._showAppsIcon, 'button-press-event', rp); + + this.connections.connect(dash, 'leave-event', rp); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("dash hack level 2"); + + this.paint_signals.connect(background, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + + // add the widget to the dash + background.add_effect(effect); + background_parent.add_child(background); + dash.get_parent().insert_child_at_index(background_parent, 0); + + // remove background color + dash.set_style_class_name('blurred-dash'); + + // returns infos + return new DashInfos(this, dash, dash._background, background_parent, effect, this.prefs); + } + + set_sigma(sigma) { + this.sigma = sigma; + this.emit('update-sigma', true); + } + + set_brightness(brightness) { + this.brightness = brightness; + this.emit('update-brightness', true); + } + + disable() { + this._log("removing blur from dashes"); + + this.emit('remove-dashes', true); + + this.dashes = []; + this.connections.disconnect_all(); + } + + show() { + this.emit('show', true); + } + hide() { + this.emit('hide', true); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +Signals.addSignalMethods(DashBlur.prototype); \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/extension.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/extension.js new file mode 100644 index 0000000..4d5c4c9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/extension.js @@ -0,0 +1,224 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const Settings = Me.imports.settings; +const Connections = Me.imports.connections; + +const Panel = Me.imports.panel; +const Dash = Me.imports.dash; +const Overview = Me.imports.overview; +const DashToDock = Me.imports.dash_to_dock; +const Lockscreen = Me.imports.lockscreen; +const AppFolders = Me.imports.appfolders; +const WindowList = Me.imports.window_list; +const Applications = Me.imports.applications; + + +class Extension { + constructor() { } + + enable() { + this._prefs = new Settings.Prefs; + + this._log("enabling extension..."); + this._connections = []; + + this._panel_blur = new Panel.PanelBlur(new Connections.Connections, this._prefs); + this._dash_blur = new Dash.DashBlur(new Connections.Connections, this._prefs); + this._dash_to_dock_blur = new DashToDock.DashBlur(new Connections.Connections, this._prefs); + this._overview_blur = new Overview.OverviewBlur(new Connections.Connections, this._prefs); + this._lockscreen_blur = new Lockscreen.LockscreenBlur(new Connections.Connections, this._prefs); + this._appfolders_blur = new AppFolders.AppFoldersBlur(new Connections.Connections, this._prefs); + this._window_list_blur = new WindowList.WindowListBlur(new Connections.Connections, this._prefs); + this._applications_blur = new Applications.ApplicationsBlur(new Connections.Connections, this._prefs); + + + this._connections.push(this._panel_blur.connections, this._dash_blur.connections, + this._dash_to_dock_blur.connections, this._overview_blur.connections, + this._lockscreen_blur.connections, this._appfolders_blur.connections, + this._window_list_blur.connections, this._applications_blur.connections); + + this._connect_to_settings(); + + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } + + this._update_sigma(); + this._update_brightness(); + + this._log("extension enabled."); + } + + disable() { + this._log("disabling extension..."); + + this._panel_blur.disable(); + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + this._overview_blur.disable(); + this._lockscreen_blur.disable(); + this._appfolders_blur.disable(); + this._window_list_blur.disable(); + this._applications_blur.disable(); + + this._panel_blur = null; + this._dash_blur = null; + this._dash_to_dock_blur = null; + this._overview_blur = null; + this._lockscreen_blur = null; + this._appfolders_blur = null; + this._window_list_blur = null; + this._applications_blur = null; + + this._disconnect_settings(); + + // in theory, this shouldn't be needed if we switch to making modules responsible for disconnecting their own + // signals. For now, I will leave this small bit of code in. Calling disable on all modules has already + // done the same thing + this._connections.forEach((connections) => { + connections.disconnect_all(); + }) + this._connections = []; + + this._log("extension disabled."); + + this._prefs = null; + } + + _connect_to_settings() { + this._prefs.SIGMA.changed(() => { + this._update_sigma(); + }); + this._prefs.BRIGHTNESS.changed(() => { + this._update_brightness(); + }); + + this._prefs.BLUR_DASH.changed(() => { + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } else { + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + } + }); + this._prefs.BLUR_PANEL.changed(() => { + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } else { + this._panel_blur.disable(); + } + }); + this._prefs.BLUR_OVERVIEW.changed(() => { + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } else { + this._overview_blur.disable(); + } + }); + this._prefs.BLUR_LOCKSCREEN.changed(() => { + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } else { + this._lockscreen_blur.disable(); + } + }); + this._prefs.BLUR_APPFOLDERS.changed(() => { + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } else { + this._appfolders_blur.disable(); + } + }); + this._prefs.BLUR_WINDOW_LIST.changed(() => { + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } else { + this._window_list_blur.disable(); + } + }); + this._prefs.BLUR_APPLICATIONS.changed(() => { + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } else { + this._applications_blur.disable(); + } + }) + this._prefs.DASH_OPACITY.changed(() => { + this._dash_blur.update(); + }); + this._prefs.APPFOLDER_DIALOG_OPACITY.changed(() => { + this._appfolders_blur.blur_appfolders(); + }); + this._prefs.STATIC_BLUR.changed(() => { + this._panel_blur.change_blur_type(); + }); + this._prefs.HIDETOPBAR.changed(() => { + this._panel_blur.connect_to_overview(); + }); + } + + _disconnect_settings() { + this._prefs.SIGMA.disconnect(); + this._prefs.BRIGHTNESS.disconnect(); + } + + _update_sigma() { + let sigma = this._prefs.SIGMA.get(); + + this._panel_blur.set_sigma(sigma); + this._dash_to_dock_blur.set_sigma(sigma); + this._overview_blur.set_sigma(sigma); + this._lockscreen_blur.set_sigma(sigma); + this._appfolders_blur.set_sigma(sigma); + this._window_list_blur.set_sigma(sigma); + this._applications_blur.set_sigma(sigma); + } + + _update_brightness() { + let brightness = this._prefs.BRIGHTNESS.get(); + + this._panel_blur.set_brightness(brightness); + this._dash_to_dock_blur.set_brightness(brightness); + this._overview_blur.set_brightness(brightness); + this._lockscreen_blur.set_brightness(brightness); + this._appfolders_blur.set_brightness(brightness); + this._window_list_blur.set_brightness(brightness); + this._applications_blur.set_brightness(brightness); + } + + _log(str) { + if (this._prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + + +// Called on gnome-shell loading, even if extension is deactivated +function init() { + return new Extension(); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/lockscreen.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/lockscreen.js new file mode 100644 index 0000000..e6d39b5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/lockscreen.js @@ -0,0 +1,64 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; +const Background = imports.ui.background; + +let sigma = 30; +let brightness = 0.6; + +const original_createBackground = imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects; + + +var LockscreenBlur = class LockscreenBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring lockscreen"); + + this.update_lockscreen(); + } + + update_lockscreen() { + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = this._createBackground; + } + + _createBackground() { + for (const widget of this._backgroundGroup) { + const effect = widget.get_effect('blur'); + + if (effect) { + effect.set({ + brightness: brightness, + sigma: sigma, + }); + } + } + } + + set_sigma(s) { + sigma = s; + this.update_lockscreen(); + } + + set_brightness(b) { + brightness = b; + this.update_lockscreen(); + } + + disable() { + this._log("removing blur from lockscreen"); + + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = original_createBackground; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/metadata.json b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/metadata.json new file mode 100644 index 0000000..820fa02 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/metadata.json @@ -0,0 +1,12 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.", + "name": "Blur my Shell", + "shell-version": [ + "40", + "41" + ], + "url": "https://github.com/aunetx/gnome-shell-extension-blur-my-shell", + "uuid": "blur-my-shell@aunetx", + "version": 29 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/overview.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/overview.js new file mode 100644 index 0000000..ffd86f9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/overview.js @@ -0,0 +1,161 @@ +'use strict'; + +const { Shell, Gio, Meta } = imports.gi; +const Main = imports.ui.main; +const WorkspaceAnimationController = imports.ui.workspaceAnimation.WorkspaceAnimationController; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; + + +var OverviewBlur = class OverviewBlur { + constructor(connections, prefs) { + this.connections = connections; + this.effects = []; + this.prefs = prefs; + this._workspace_switch_bg_actors = []; + } + + enable() { + this._log("blurring overview"); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this._log("updated background"); + this.update_backgrounds(); + }); + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this._log("changed monitors"); + this.update_backgrounds(); + } + }); + + // add css class names, to change folders and workspace-switch background + Main.uiGroup.add_style_class_name("blurred-overview"); + + // update background on extension activation + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + this.update_backgrounds(); + } catch (error) { this._log(`could not blur overview: ${error}`); } + + // store original methods for restoring them on disable() + this._origPrepareSwitch = WorkspaceAnimationController.prototype._prepareWorkspaceSwitch; + this._origFinishSwitch = WorkspaceAnimationController.prototype._finishWorkspaceSwitch; + + const outerThis = this; + + // create blurred background actors for each monitor during a workspace switch + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = function (...params) { + outerThis._log("prepare workspace switch"); + outerThis._origPrepareSwitch.apply(this, params); + + Main.layoutManager.monitors.forEach(monitor => { + if (!(Meta.prefs_get_workspaces_only_on_primary() && (monitor != Main.layoutManager.primaryMonitor))) { + const bg_actor = outerThis.create_background_actor(monitor); + Main.uiGroup.insert_child_above(bg_actor, global.window_group); + + // store the actors so that we can delete them later + outerThis._workspace_switch_bg_actors.push(bg_actor); + } + }); + }; + + // remove the workspace-switch actors when the switch is done + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = function (...params) { + outerThis._log("finish workspace switch"); + outerThis._origFinishSwitch.apply(this, params); + + outerThis._workspace_switch_bg_actors.forEach(actor => { + actor.destroy(); + }); + outerThis._workspace_switch_bg_actors = []; + }; + } + + update_backgrounds() { + // remove every old background + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + actor.destroy(); + } + }); + this.effects = []; + + // add new backgrounds + Main.layoutManager.monitors.forEach(monitor => { + const bg_actor = this.create_background_actor(monitor); + Main.layoutManager.overviewGroup.insert_child_at_index(bg_actor, monitor.index); + }); + } + + create_background_actor(monitor) { + let bg_actor = new Meta.BackgroundActor; + + let background = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - monitor.index - 1); + + if (!background) { + this._log("could not get background for overview"); + return bg_actor; + } + + bg_actor.set_content(background.get_content()); + + let effect = new Shell.BlurEffect({ + brightness: this.prefs.BRIGHTNESS.get(), + sigma: this.prefs.SIGMA.get(), + mode: 0 + }); + bg_actor.add_effect(effect); + this.effects.push(effect); + + bg_actor.set_x(monitor.x); + bg_actor.set_y(monitor.y); + + return bg_actor; + } + + set_sigma(s) { + this.effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.effects.forEach(effect => { + effect.brightness = b; + }); + } + + disable() { + this._log("removing blur from overview"); + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + } + }); + Main.uiGroup.remove_style_class_name("blurred-overview"); + + this.effects = []; + this.connections.disconnect_all(); + + // restore original behavior + if (this._origPrepareSwitch) { + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = this._origPrepareSwitch; + } + + if (this._origFinishSwitch) { + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = this._origFinishSwitch; + } + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/paint_signals.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/paint_signals.js new file mode 100644 index 0000000..0c3dc4f --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/paint_signals.js @@ -0,0 +1,59 @@ +'use strict' + +const { GObject, Clutter } = imports.gi; + + +var PaintSignals = class PaintSignals { + constructor(connections) { + this.buffer = []; + this.connections = connections + } + + connect(actor, blur_effect) { + let paint_effect = new EmitPaintSignal(); + let infos = { + actor: actor, + paint_effect: paint_effect + }; + let counter = 0; + + actor.add_effect(paint_effect); + this.connections.connect(paint_effect, 'update-blur', () => { + try { + // checking if blur_effect.queue_repaint() has been recently called + if (counter === 0) { + counter = 2; + blur_effect.queue_repaint(); + } + else counter--; + } catch (e) { } + }); + + this.buffer.push(infos) + } + + disconnect_all() { + this.buffer.forEach((infos) => { + this.connections.disconnect_all_for(infos.paint_effect); + infos.actor.remove_effect(infos.paint_effect); + }); + + this.buffer = [] + } +} + +var EmitPaintSignal = GObject.registerClass({ + GTypeName: 'EmitPaintSignal', + Signals: { + 'update-blur': { + param_types: [] + }, + } +}, + class EmitPaintSignal extends Clutter.Effect { + vfunc_paint(node, paint_context, paint_flags) { + this.emit("update-blur"); + super.vfunc_paint(node, paint_context, paint_flags); + } + } +); \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/panel.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/panel.js new file mode 100644 index 0000000..930ca4d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/panel.js @@ -0,0 +1,245 @@ +'use strict'; + +const { St, Shell, Meta, Gio, GLib } = imports.gi; +const Main = imports.ui.main; +const Config = imports.misc.config; +const backgroundSettings = new Gio.Settings({ schema: 'org.gnome.desktop.background' }) + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.'); + + +var PanelBlur = class PanelBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + this.effect = new Shell.BlurEffect({ + brightness: prefs.BRIGHTNESS.get(), + sigma: prefs.SIGMA.get(), + mode: prefs.STATIC_BLUR.get() ? 0 : 1 + }); + this.background_parent = new St.Widget({ + name: 'topbar-blurred-background-parent', + style_class: 'topbar-blurred-background-parent', + x: this.monitor.x, + y: this.monitor.y, + width: this.monitor.width, + height: 0, + }); + this.background = prefs.STATIC_BLUR.get() ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.background_parent.add_child(this.background); + } + + enable() { + this._log("blurring top panel"); + + if (GS_MAJOR < 42) { + // hide corners, can't style them + Main.panel._leftCorner.hide(); + Main.panel._rightCorner.hide(); + this.connections.connect(Main.panel._leftCorner, 'show', () => { Main.panel._leftCorner.hide(); }); + this.connections.connect(Main.panel._rightCorner, 'show', () => { Main.panel._rightCorner.hide(); }); + } + + // insert background parent + let children = Main.layoutManager.panelBox.get_children(); + for (let i = 0; i < children.length; ++i) + if (children[i].name == 'topbar-blurred-background-parent') + Main.layoutManager.panelBox.remove_child(children[i]); + Main.layoutManager.panelBox.insert_child_at_index(this.background_parent, 0); + + // remove background + Main.panel.add_style_class_name('transparent-panel'); + + // perform updates + this.change_blur_type(); + Utils.setTimeout(() => { this.change_blur_type() }, 500); + + // connect to panel size change + this.connections.connect(Main.panel, 'notify::height', () => { + this.update_size(this.prefs.STATIC_BLUR.get()); + }); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + }) + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + this.update_size(this.prefs.STATIC_BLUR.get()); + } + }); + + this.connect_to_overview(); + } + + change_blur_type() { + let is_static = this.prefs.STATIC_BLUR.get(); + + // reset widgets to right state + this.background_parent.remove_child(this.background); + this.background.remove_effect(this.effect); + this.background = is_static ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.effect.set_mode(is_static ? 0 : 1); + this.background.add_effect(this.effect); + this.background_parent.add_child(this.background); + + // perform updates + this.update_wallpaper(is_static); + this.update_size(is_static); + + // HACK + if (!is_static) { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("panel hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { this.effect.queue_repaint() }; + + this.connections.connect(Main.panel, 'enter-event', rp); + this.connections.connect(Main.panel, 'leave-event', rp); + this.connections.connect(Main.panel, 'button-press-event', rp); + + Main.panel.get_children().forEach(child => { + this.connections.connect(child, 'enter-event', rp); + this.connections.connect(child, 'leave-event', rp); + this.connections.connect(child, 'button-press-event', rp); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("panel hack level 2"); + this.paint_signals.disconnect_all(); + + this.paint_signals.connect(this.background, this.effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + } + + update_wallpaper(is_static) { + // if static blur, get right wallpaper and update blur with it + if (is_static) { + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + let bg = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - this.monitor.index - 1); + this.background.set_content(bg.get_content()); + } catch (error) { this._log(`could not blur panel: ${error}`) } + } + } + + update_size(is_static) { + this.background_parent.width = Main.panel.width; + this.background.width = Main.panel.width; + let panel_box = Main.layoutManager.panelBox; + this.background.height = panel_box.height; + let clip_box = panel_box.get_parent(); + if (is_static) { + this.background.set_clip( + clip_box.x, + clip_box.y, + panel_box.width, + panel_box.height + ); + this.background.x = -clip_box.x; + this.background.y = -clip_box.y; + } + } + + // returns either the primary monitor, or a dummy one if none is connected + get monitor() { + if (Main.layoutManager.primaryMonitor != null) { + return Main.layoutManager.primaryMonitor + } else { + return { x: 0, y: 0, width: 0, index: 0 } + } + } + + // connect when overview if opened/closed to hide/show the blur in consequence + // if HIDETOPBAR set, we need just to hide the blur when showing appgrid (so no shadow is cropped) + connect_to_overview() { + this.connections.disconnect_all_for(Main.overview._overview._controls._appDisplay); + this.connections.disconnect_all_for(Main.overview); + + if (!this.prefs.HIDETOPBAR.get()) { + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } else { + this.connections.connect(Main.overview._overview._controls._appDisplay, 'show', () => { + this.hide(); + }); + this.connections.connect(Main.overview._overview._controls._appDisplay, 'hide', () => { + this.show(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + } + + set_sigma(s) { + this.effect.sigma = s; + } + + set_brightness(b) { + this.effect.brightness = b; + } + + disable() { + this._log("removing blur from top panel"); + Main.panel.remove_style_class_name('transparent-panel'); + + if (GS_MAJOR < 42) { + Main.panel._leftCorner.show(); + Main.panel._rightCorner.show(); + } + + try { + Main.layoutManager.panelBox.remove_child(this.background_parent); + } catch (e) { } + + this.connections.disconnect_all(); + } + + show() { + this.background_parent.show(); + } + hide() { + this.background_parent.hide(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.js new file mode 100644 index 0000000..b8c1c41 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.js @@ -0,0 +1,187 @@ +'use strict'; + +const { GObject, Gtk } = imports.gi; + +const ExtensionUtils = imports.misc.extensionUtils; +const Extension = ExtensionUtils.getCurrentExtension(); +let Settings = Extension.imports.settings; +let config = new Settings.Prefs(); + + +const BlurMyShellPrefsWidget = GObject.registerClass({ + GTypeName: 'BlurMyShellPrefsWidget', + Template: Extension.dir.get_child('prefs.ui').get_uri(), + InternalChildren: [ + 'sigma_scale', + 'brightness_scale', + 'blur_dash', + 'blur_panel', + 'blur_overview', + 'blur_applications', + 'blur_lockscreen', + 'blur_appfolders', + 'blur_window_list', + 'hacks_level0', + 'hacks_level1', + 'hacks_level2', + 'dash_opacity_scale', + 'appfolder_dialog_opacity_scale', + 'static_blur', + 'hidetopbar', + 'debug_mode' + ], +}, class BlurMyShellPrefsWidget extends Gtk.Box { + _init(params = {}) { + super._init(params); + + // ! sigma + this._sigma_scale.set_value(config.SIGMA.get()); + + // ! brightness + this._brightness_scale.set_value(config.BRIGHTNESS.get()); + + // ! blur dash + this._blur_dash.set_active(config.BLUR_DASH.get()); + + // ! blur panel + this._blur_panel.set_active(config.BLUR_PANEL.get()); + + // ! blur overview + this._blur_overview.set_active(config.BLUR_OVERVIEW.get()); + + // ! blur applications + this._blur_applications.set_active(config.BLUR_APPLICATIONS.get()); + + // ! blur lockscreen + this._blur_lockscreen.set_active(config.BLUR_LOCKSCREEN.get()); + + // ! blur appfolders + this._blur_appfolders.set_active(config.BLUR_APPFOLDERS.get()); + + // ! blur window list + this._blur_window_list.set_active(config.BLUR_WINDOW_LIST.get()); + + // ! dash hacks + if (config.HACKS_LEVEL.get() == 0) { + this._hacks_level0.set_active(true); + } else if (config.HACKS_LEVEL.get() == 1) { + this._hacks_level1.set_active(true); + } else if (config.HACKS_LEVEL.get() == 2) { + this._hacks_level2.set_active(true); + } else { + this._log(`hack level out-of-bound: ${hack_level}, defaulting to 1.`); + this._hacks_level0.set_active(true); + } + + // ! dash opacity + this._dash_opacity_scale.set_value(config.DASH_OPACITY.get()); + + // ! appfolder dialog opacity + this._appfolder_dialog_opacity_scale.set_value(config.APPFOLDER_DIALOG_OPACITY.get()); + + // ! static panel blur + this._static_blur.set_active(config.STATIC_BLUR.get()); + + // ! hidetopbar compatibility + this._hidetopbar.set_active(config.HIDETOPBAR.get()); + + // ! debug mode + this._debug_mode.set_active(config.DEBUG.get()); + } + + sigma_changed(w) { + let value = w.get_value(); + config.SIGMA.set(value); + } + + brightness_changed(w) { + let value = w.get_value(); + config.BRIGHTNESS.set(value); + } + + blur_dash_toggled(w) { + let value = w.get_active(); + config.BLUR_DASH.set(value); + } + + blur_panel_toggled(w) { + let value = w.get_active(); + config.BLUR_PANEL.set(value); + } + + blur_overview_toggled(w) { + let value = w.get_active(); + config.BLUR_OVERVIEW.set(value); + } + + blur_applications_toggled(w) { + let value = w.get_active(); + config.BLUR_APPLICATIONS.set(value); + } + + blur_lockscreen_toggled(w) { + let value = w.get_active(); + config.BLUR_LOCKSCREEN.set(value); + } + + blur_appfolders_toggled(w) { + let value = w.get_active(); + config.BLUR_APPFOLDERS.set(value); + } + + blur_window_list_toggled(w) { + let value = w.get_active(); + config.BLUR_WINDOW_LIST.set(value); + } + + hacks_level0_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(0) } + } + + hacks_level1_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(1) } + } + + hacks_level2_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(2) } + } + + dash_opacity_changed(w) { + let value = w.get_value(); + config.DASH_OPACITY.set(value); + } + + appfolder_dialog_opacity_changed(w) { + let value = w.get_value(); + config.APPFOLDER_DIALOG_OPACITY.set(value); + } + + static_blur_toggled(w) { + let value = w.get_active(); + config.STATIC_BLUR.set(value); + } + + hidetopbar_toggled(w) { + let value = w.get_active(); + config.HIDETOPBAR.set(value); + } + + debug_mode_toggled(w) { + let value = w.get_active(); + config.DEBUG.set(value); + } + + _log(str) { + if (config.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +}); + +function init() { } + +function buildPrefsWidget() { + return new BlurMyShellPrefsWidget(); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.ui b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.ui new file mode 100644 index 0000000..a5d30c7 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/prefs.ui @@ -0,0 +1,410 @@ + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled new file mode 100644 index 0000000..ca00e0c Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml new file mode 100644 index 0000000..4417dce --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml @@ -0,0 +1,95 @@ + + + + + + 30 + Global sigma (gaussian blur radius) to use + + + + + 0.6 + Global brightness to use + + + + + true + Boolean, whether to blur the dash or not + + + + + true + Boolean, whether to blur the panel or not + + + + + true + Boolean, whether to blur the overview or not + + + + + true + Boolean, whether to blur lockscreen or not + + + + + true + Boolean, whether to blur appfolders or not + + + + + true + Boolean, whether to blur window list extension or not + + + + + false + Boolean, whether to blur applications that request it or not + + + + + 1 + Level of hacks to use (from 0 to 2) + + + + + 0.12 + Opacity of dash to use + + + + + 0.12 + Opacity of appfolder dialog to use + + + + + true + Boolean, whether to have a static blur on panel or a dynamic one + + + + + false + Boolean, whether to try compatibility with hidetopbar@mathieu.bidon.ca or not + + + + + false + Boolean, set to true to activate debug mode (more verbose journalctl logs) + + + + \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/settings.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/settings.js new file mode 100644 index 0000000..69a0093 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/settings.js @@ -0,0 +1,274 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Extension = imports.misc.extensionUtils.getCurrentExtension(); + +const SCHEMA_PATH = 'org.gnome.shell.extensions.blur-my-shell'; + +function get_local_gsettings(schema_path) { + const GioSSS = Gio.SettingsSchemaSource; + let schemaDir = Extension.dir.get_child('schemas'); + let schemaSource = GioSSS.get_default(); + + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory( + schemaDir.get_path(), + schemaSource, + false); + } + + let schemaObj = schemaSource.lookup(schema_path, true); + if (!schemaObj) { + throw new Error( + `Schema ${schema_path} could not be found for extension ${Extension.metadata.uuid}` + ); + } + return new Gio.Settings({ + settings_schema: schemaObj + }); +}; + +var Prefs = class Prefs { + constructor() { + var settings = this.settings = get_local_gsettings(SCHEMA_PATH); + this.SIGMA = { + key: 'sigma', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BRIGHTNESS = { + key: 'brightness', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BLUR_DASH = { + key: 'blur-dash', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_PANEL = { + key: 'blur-panel', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_OVERVIEW = { + key: 'blur-overview', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_LOCKSCREEN = { + key: 'blur-lockscreen', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPLICATIONS = { + key: 'blur-applications', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPFOLDERS = { + key: 'blur-appfolders', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_WINDOW_LIST = { + key: 'blur-window-list', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HACKS_LEVEL = { + key: 'hacks-level', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.DASH_OPACITY = { + key: 'dash-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.APPFOLDER_DIALOG_OPACITY = { + key: 'appfolder-dialog-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.STATIC_BLUR = { + key: 'static-blur', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HIDETOPBAR = { + key: 'hidetopbar', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.DEBUG = { + key: 'debug', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + } +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/stylesheet.css b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/stylesheet.css new file mode 100644 index 0000000..a094537 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/stylesheet.css @@ -0,0 +1,436 @@ +#panel.transparent-panel { + background: transparent; + transition-duration: 500ms; +} + +.blurred-overview .app-folder { + background-color: rgba(0, 0, 0, 0.12); +} + + +.blurred-overview .workspace-animation { + background-color: transparent !important; +} + +.transparent-app-folder-dialogs .edit-folder-button { + background: transparent; + border-radius: 19px; +} + +.blurred-dash .dash-background { + background: transparent; +} + +/* +! TRANSPARENT APPFOLDER DIALOGS + +python generator: + +```py +for e in range(0,101):print(".transparent-app-folder-dialogs-"+str(e)+"\n{background-color: rgba(0, 0, 0, "+str(round(e/100,2))+");}") +``` +*/ + +.transparent-app-folder-dialogs-0 { + background-color: rgba(0, 0, 0, 0.0); +} + +.transparent-app-folder-dialogs-1 { + background-color: rgba(0, 0, 0, 0.01); +} + +.transparent-app-folder-dialogs-2 { + background-color: rgba(0, 0, 0, 0.02); +} + +.transparent-app-folder-dialogs-3 { + background-color: rgba(0, 0, 0, 0.03); +} + +.transparent-app-folder-dialogs-4 { + background-color: rgba(0, 0, 0, 0.04); +} + +.transparent-app-folder-dialogs-5 { + background-color: rgba(0, 0, 0, 0.05); +} + +.transparent-app-folder-dialogs-6 { + background-color: rgba(0, 0, 0, 0.06); +} + +.transparent-app-folder-dialogs-7 { + background-color: rgba(0, 0, 0, 0.07); +} + +.transparent-app-folder-dialogs-8 { + background-color: rgba(0, 0, 0, 0.08); +} + +.transparent-app-folder-dialogs-9 { + background-color: rgba(0, 0, 0, 0.09); +} + +.transparent-app-folder-dialogs-10 { + background-color: rgba(0, 0, 0, 0.1); +} + +.transparent-app-folder-dialogs-11 { + background-color: rgba(0, 0, 0, 0.11); +} + +.transparent-app-folder-dialogs-12 { + background-color: rgba(0, 0, 0, 0.12); +} + +.transparent-app-folder-dialogs-13 { + background-color: rgba(0, 0, 0, 0.13); +} + +.transparent-app-folder-dialogs-14 { + background-color: rgba(0, 0, 0, 0.14); +} + +.transparent-app-folder-dialogs-15 { + background-color: rgba(0, 0, 0, 0.15); +} + +.transparent-app-folder-dialogs-16 { + background-color: rgba(0, 0, 0, 0.16); +} + +.transparent-app-folder-dialogs-17 { + background-color: rgba(0, 0, 0, 0.17); +} + +.transparent-app-folder-dialogs-18 { + background-color: rgba(0, 0, 0, 0.18); +} + +.transparent-app-folder-dialogs-19 { + background-color: rgba(0, 0, 0, 0.19); +} + +.transparent-app-folder-dialogs-20 { + background-color: rgba(0, 0, 0, 0.2); +} + +.transparent-app-folder-dialogs-21 { + background-color: rgba(0, 0, 0, 0.21); +} + +.transparent-app-folder-dialogs-22 { + background-color: rgba(0, 0, 0, 0.22); +} + +.transparent-app-folder-dialogs-23 { + background-color: rgba(0, 0, 0, 0.23); +} + +.transparent-app-folder-dialogs-24 { + background-color: rgba(0, 0, 0, 0.24); +} + +.transparent-app-folder-dialogs-25 { + background-color: rgba(0, 0, 0, 0.25); +} + +.transparent-app-folder-dialogs-26 { + background-color: rgba(0, 0, 0, 0.26); +} + +.transparent-app-folder-dialogs-27 { + background-color: rgba(0, 0, 0, 0.27); +} + +.transparent-app-folder-dialogs-28 { + background-color: rgba(0, 0, 0, 0.28); +} + +.transparent-app-folder-dialogs-29 { + background-color: rgba(0, 0, 0, 0.29); +} + +.transparent-app-folder-dialogs-30 { + background-color: rgba(0, 0, 0, 0.3); +} + +.transparent-app-folder-dialogs-31 { + background-color: rgba(0, 0, 0, 0.31); +} + +.transparent-app-folder-dialogs-32 { + background-color: rgba(0, 0, 0, 0.32); +} + +.transparent-app-folder-dialogs-33 { + background-color: rgba(0, 0, 0, 0.33); +} + +.transparent-app-folder-dialogs-34 { + background-color: rgba(0, 0, 0, 0.34); +} + +.transparent-app-folder-dialogs-35 { + background-color: rgba(0, 0, 0, 0.35); +} + +.transparent-app-folder-dialogs-36 { + background-color: rgba(0, 0, 0, 0.36); +} + +.transparent-app-folder-dialogs-37 { + background-color: rgba(0, 0, 0, 0.37); +} + +.transparent-app-folder-dialogs-38 { + background-color: rgba(0, 0, 0, 0.38); +} + +.transparent-app-folder-dialogs-39 { + background-color: rgba(0, 0, 0, 0.39); +} + +.transparent-app-folder-dialogs-40 { + background-color: rgba(0, 0, 0, 0.4); +} + +.transparent-app-folder-dialogs-41 { + background-color: rgba(0, 0, 0, 0.41); +} + +.transparent-app-folder-dialogs-42 { + background-color: rgba(0, 0, 0, 0.42); +} + +.transparent-app-folder-dialogs-43 { + background-color: rgba(0, 0, 0, 0.43); +} + +.transparent-app-folder-dialogs-44 { + background-color: rgba(0, 0, 0, 0.44); +} + +.transparent-app-folder-dialogs-45 { + background-color: rgba(0, 0, 0, 0.45); +} + +.transparent-app-folder-dialogs-46 { + background-color: rgba(0, 0, 0, 0.46); +} + +.transparent-app-folder-dialogs-47 { + background-color: rgba(0, 0, 0, 0.47); +} + +.transparent-app-folder-dialogs-48 { + background-color: rgba(0, 0, 0, 0.48); +} + +.transparent-app-folder-dialogs-49 { + background-color: rgba(0, 0, 0, 0.49); +} + +.transparent-app-folder-dialogs-50 { + background-color: rgba(0, 0, 0, 0.5); +} + +.transparent-app-folder-dialogs-51 { + background-color: rgba(0, 0, 0, 0.51); +} + +.transparent-app-folder-dialogs-52 { + background-color: rgba(0, 0, 0, 0.52); +} + +.transparent-app-folder-dialogs-53 { + background-color: rgba(0, 0, 0, 0.53); +} + +.transparent-app-folder-dialogs-54 { + background-color: rgba(0, 0, 0, 0.54); +} + +.transparent-app-folder-dialogs-55 { + background-color: rgba(0, 0, 0, 0.55); +} + +.transparent-app-folder-dialogs-56 { + background-color: rgba(0, 0, 0, 0.56); +} + +.transparent-app-folder-dialogs-57 { + background-color: rgba(0, 0, 0, 0.57); +} + +.transparent-app-folder-dialogs-58 { + background-color: rgba(0, 0, 0, 0.58); +} + +.transparent-app-folder-dialogs-59 { + background-color: rgba(0, 0, 0, 0.59); +} + +.transparent-app-folder-dialogs-60 { + background-color: rgba(0, 0, 0, 0.6); +} + +.transparent-app-folder-dialogs-61 { + background-color: rgba(0, 0, 0, 0.61); +} + +.transparent-app-folder-dialogs-62 { + background-color: rgba(0, 0, 0, 0.62); +} + +.transparent-app-folder-dialogs-63 { + background-color: rgba(0, 0, 0, 0.63); +} + +.transparent-app-folder-dialogs-64 { + background-color: rgba(0, 0, 0, 0.64); +} + +.transparent-app-folder-dialogs-65 { + background-color: rgba(0, 0, 0, 0.65); +} + +.transparent-app-folder-dialogs-66 { + background-color: rgba(0, 0, 0, 0.66); +} + +.transparent-app-folder-dialogs-67 { + background-color: rgba(0, 0, 0, 0.67); +} + +.transparent-app-folder-dialogs-68 { + background-color: rgba(0, 0, 0, 0.68); +} + +.transparent-app-folder-dialogs-69 { + background-color: rgba(0, 0, 0, 0.69); +} + +.transparent-app-folder-dialogs-70 { + background-color: rgba(0, 0, 0, 0.7); +} + +.transparent-app-folder-dialogs-71 { + background-color: rgba(0, 0, 0, 0.71); +} + +.transparent-app-folder-dialogs-72 { + background-color: rgba(0, 0, 0, 0.72); +} + +.transparent-app-folder-dialogs-73 { + background-color: rgba(0, 0, 0, 0.73); +} + +.transparent-app-folder-dialogs-74 { + background-color: rgba(0, 0, 0, 0.74); +} + +.transparent-app-folder-dialogs-75 { + background-color: rgba(0, 0, 0, 0.75); +} + +.transparent-app-folder-dialogs-76 { + background-color: rgba(0, 0, 0, 0.76); +} + +.transparent-app-folder-dialogs-77 { + background-color: rgba(0, 0, 0, 0.77); +} + +.transparent-app-folder-dialogs-78 { + background-color: rgba(0, 0, 0, 0.78); +} + +.transparent-app-folder-dialogs-79 { + background-color: rgba(0, 0, 0, 0.79); +} + +.transparent-app-folder-dialogs-80 { + background-color: rgba(0, 0, 0, 0.8); +} + +.transparent-app-folder-dialogs-81 { + background-color: rgba(0, 0, 0, 0.81); +} + +.transparent-app-folder-dialogs-82 { + background-color: rgba(0, 0, 0, 0.82); +} + +.transparent-app-folder-dialogs-83 { + background-color: rgba(0, 0, 0, 0.83); +} + +.transparent-app-folder-dialogs-84 { + background-color: rgba(0, 0, 0, 0.84); +} + +.transparent-app-folder-dialogs-85 { + background-color: rgba(0, 0, 0, 0.85); +} + +.transparent-app-folder-dialogs-86 { + background-color: rgba(0, 0, 0, 0.86); +} + +.transparent-app-folder-dialogs-87 { + background-color: rgba(0, 0, 0, 0.87); +} + +.transparent-app-folder-dialogs-88 { + background-color: rgba(0, 0, 0, 0.88); +} + +.transparent-app-folder-dialogs-89 { + background-color: rgba(0, 0, 0, 0.89); +} + +.transparent-app-folder-dialogs-90 { + background-color: rgba(0, 0, 0, 0.9); +} + +.transparent-app-folder-dialogs-91 { + background-color: rgba(0, 0, 0, 0.91); +} + +.transparent-app-folder-dialogs-92 { + background-color: rgba(0, 0, 0, 0.92); +} + +.transparent-app-folder-dialogs-93 { + background-color: rgba(0, 0, 0, 0.93); +} + +.transparent-app-folder-dialogs-94 { + background-color: rgba(0, 0, 0, 0.94); +} + +.transparent-app-folder-dialogs-95 { + background-color: rgba(0, 0, 0, 0.95); +} + +.transparent-app-folder-dialogs-96 { + background-color: rgba(0, 0, 0, 0.96); +} + +.transparent-app-folder-dialogs-97 { + background-color: rgba(0, 0, 0, 0.97); +} + +.transparent-app-folder-dialogs-98 { + background-color: rgba(0, 0, 0, 0.98); +} + +.transparent-app-folder-dialogs-99 { + background-color: rgba(0, 0, 0, 0.99); +} + +.transparent-app-folder-dialogs-100 { + background-color: rgba(0, 0, 0, 1.0); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/utilities.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/utilities.js new file mode 100644 index 0000000..5dbc319 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/utilities.js @@ -0,0 +1,39 @@ +'use strict' + +const GLib = imports.gi.GLib; + +let clearTimeout, clearInterval; +clearInterval = clearTimeout = GLib.Source.remove; + +var setTimeout = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_REMOVE; + }); +}; + +var setInterval = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_CONTINUE; + }); +}; + +var easeOutQuad = function(t, begin, end, duration) { + t /= duration + return begin + (t * (2 - t) * (end - begin)) +}; + +var ease_property = function(object, property, begin, end, duration, update) { + let start = Date.now(); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, update, () => { + let time = Date.now() - start; + if (time < duration) { + object[property] = easeOutQuad(time, begin, end, duration); + return GLib.SOURCE_CONTINUE; + } else { + object[property] = end; + return GLib.SOURCE_REMOVE; + } + }); +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/window_list.js b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/window_list.js new file mode 100644 index 0000000..ca8708d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/blur-my-shell@aunetx/window_list.js @@ -0,0 +1,128 @@ +'use strict'; + +const { St, Shell, Meta, Gio } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + + +var WindowListBlur = class WindowListBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.blur_effects = []; + } + + enable() { + this._log("blurring window list"); + + // add the blur if window-list found + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_blur(child)); + + // listen to new actors in `Main.layoutManager.uiGroup` and blur if window-list + this.connections.connect(Main.layoutManager.uiGroup, 'actor-added', (_, child) => this.try_blur(child)); + + // connect to overview + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + + try_blur(child) { + if (child.constructor.name == "WindowList" && child.style != "background:transparent;") { + this._log("found window list to blur"); + + child.style = "background:transparent;"; + let effect = new Shell.BlurEffect({ + name: 'window-list-blur', + sigma: this.prefs.SIGMA.get(), + brightness: this.prefs.BRIGHTNESS.get(), + mode: 1 + }); + child.add_effect(effect); + this.blur_effects.push(effect); + + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("window list hack level 1"); + + child._windowList.get_children().forEach(child => { + this.connections.connect(child, 'button-press-event', () => { effect.queue_repaint(); }); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("window list hack level 2"); + + this.paint_signals.connect(child, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + child._windowList.get_children().forEach(window => this.blur_window_button(window)); + this.connections.connect(child._windowList, 'actor-added', (_, window) => { + this.blur_window_button(window); + }) + } + } + + blur_window_button(window) { + window.get_child_at_index(0).style = "box-shadow:none;background-color:rgba(0,0,0,0.2);border-radius:5px;"; + } + + try_remove_blur(child) { + if (child.constructor.name == "WindowList" && child.style == "background:transparent;") { + child.style = null; + child.remove_effect_by_name('window-list-blur'); + + child._windowList.get_children().forEach(child => { + child.get_child_at_index(0).style = null; + }); + } + } + + set_sigma(s) { + this.blur_effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.blur_effects.forEach(effect => { + effect.brightness = b; + }); + } + + hide() { + this.set_sigma(0); + } + + show() { + this.set_sigma(this.prefs.SIGMA.get()); + } + + disable() { + this._log("removing blur from window list"); + + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_remove_blur(child)) + + this.blur_effects = []; + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING new file mode 100644 index 0000000..8d61b15 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/README.md b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/README.md new file mode 100644 index 0000000..5000de1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/README.md @@ -0,0 +1,189 @@ +

+ +

+

+ + + + +

+ +![](media/design/png/dtp-main-p2.png) + +### Introduction + +Dash to Panel is an icon taskbar for Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications. + +Beyond that, just about every aspect of the panel is fully customizable. From positioning and scaling panel elements to running indicators to multi-monitor display, to window previews and even intellihide, Dash to Panel has everything you need to make your workspace feel like home. + +### Features + +|Customizable appearance| +|:-----:| +|![screenshot](media/design/gif/customizable.gif)| +|Hide & show panel elements and set their positions, sizes & colors| + +## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Customizable running indicators
MetroCiliora/Dashes
CilioraSquares/Segmented
DashesDots/Solid
Set position, style, weight & color of running indicators to easily and quickly identify focused and unfocused applications
+ +## + +|Live Previews on Hover| +|:-----:| +|![screenshot](media/design/gif/previews.gif)| +|Hover over the launcher icon for an open application to get a live window preview| + +## +|Launch by Number| +|:-----:| +|![](media/design/png/indicators-num.png.png)| +|Optionally launch your favorite applications via keyboard| + +## + +|Panel Intellihide| +|:-----:| +|![Intellihide](media/design/gif/Intellihide.gif)| +|Hide and reveal the panel according to your set preferences| + +## +|Additional Features|Feature Implemented| +|:-----|:-----:| +|Add "Show Desktop" button to panel|![](media/design/png/done.png)| +|Isolate running apps by workspaces and/or monitors|![](media/design/png/done.png)| +|Custom click behaviors (launch new window, cycle open windows, minimize, etc)|![](media/design/png/done.png)| +|Integrate native Gnome appMenu into right-click secondary menu|![](media/design/png/done.png)| +|Multi-monitor support|![](media/design/png/done.png)| +|Dynamic transparency|![](media/design/png/done.png)| +|Ungroup application windows|![](media/design/png/done.png)| +|Export and import settings|![](media/design/png/done.png)| +## + +### Installation + +**To install the most recent official release: +[Visit Dash-to-Panel at GNOME Extensions](https://extensions.gnome.org/extension/1160/dash-to-panel/)** + +To install a development version from source, please see the [Installation wiki page](https://github.com/jderose9/dash-to-panel/wiki/Installation). + +## +### FAQ + +How do I customize the panel? [See the Wiki](https://github.com/home-sweet-gnome/dash-to-panel/wiki/Enable-and-Customize#customize-it) + +How do I embed my bottom left notification drawer into the panel like a system tray? [Top Icons Plus](https://extensions.gnome.org/extension/2311/topicons-plus) or [(K)StatusNotifierItem/AppIndicator Support](https://extensions.gnome.org/extension/615/appindicator-support) + +How do I add a traditional start menu? [Arc Menu](https://extensions.gnome.org/extension/3628/arcmenu/) + +How do I disable the hot corner? [No Topleft Hot Corner](https://extensions.gnome.org/extension/118/no-topleft-hot-corner) + +How do I move the notifications to somewhere other than the top center? [Panel OSD](https://extensions.gnome.org/extension/708/panel-osd) + +How do I display Minimize & Maximize buttons? In the Tweak Tool application, turn on `Windows > Titlebar Buttons > Minimize & Maximize`. + +How do I reset the extension to its default settings? `dconf reset -f /org/gnome/shell/extensions/dash-to-panel/`. + +## +### Themes +While this extension works well with most popular Gnome Shell themes, the following themes are known to have explicitly added custom styles for this extension: +- [Ciliora Tertia](https://github.com/zagortenay333/ciliora-tertia-shell) / [Ciliora Secunda](https://github.com/zagortenay333/ciliora-secunda-shell) +- [Plano](https://github.com/lassekongo83/plano-theme) + + +## +### Compatibility + +This extension has been tested with Gnome 3.18+. + +This extension manipulates the Gnome Main Panel, aka Top Bar. So, most other extensions which operate on the top bar should be compatible. + +## +### Volunteers needed! + +This extension could be even better with your help! Any items in the issue tracker labelled `help wanted` or `good first issue` are up for grabs. For more info, see the [Contributing wiki page](https://github.com/jderose9/dash-to-panel/wiki/Contributing). + +## +### Credits + +This extension is developed and maintained by [@jderose9](https://github.com/jderose9) and [@charlesg99](https://github.com/charlesg99). + +Significant portions of code in this extension were derived from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html). + +Additional credits: This extension leverages the work for [ZorinOS Taskbar](https://github.com/ZorinOS/zorin-taskbar) (used in [ZorinOS](https://zorinos.com/)) to show window previews and allow the dash from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html) to be embedded in the Gnome main panel. +Code to set anchor position taken from [Thoma5/gnome-shell-extension-bottompanel](https://github.com/Thoma5/gnome-shell-extension-bottompanel). +Pattern for moving panel contents based on [Frippery Move Clock](http://frippery.org/extensions/) by R M Yorston. +Ideas for recursing child actors and assigning inline styles are based on code from the extension [StatusAreaHorizontalSpacing](https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension). +## + +#### Thanks to the following people for contributing via pull requests: + +- @franglais125 for launching apps by number (w/ overlay), bug fixes, and issue support +- @LinxGem33 and @sbarrett322 for artwork, logos, screenshots and design effort +- @dziku1337 for peek mode in window previews +- @robrobinbin for configuring appMenu on/off in the panel +- @MartinPL for toggling favorites on/off in panel +- @jackwickham for thumbnail middle and right click actions +- @abakkk for centering the taskbar icons in the panel, and animated taskbar hovering +- @quasoft for changing of font weight of ungrouped application titles +- @jordanribera for using icon's dominant color as running indicator color +- @tper0700 for dynamically building context menu based on system capabilities +- @levacic for configurable minimized application title font color +- @l3nn4rt for toggling workspace switch popup +- @hlechner for adjustable show desktop line color and window preview icon size +- @ArtyomZorin for animated urgent icons +- @jvpessoa10 for additional click window cycle options +- @marksvc for assigning percent of display for panel length +- @philippun1 for GNOME 40 support :rocket: + +#### Bug Fixes: +@imrvelj, @Teslator, @bil-elmoussaoui, @brandon-schumann, @sw9, @rockon999 , @lexruee, @3v1n0, @freeroot, @moqmar, @ArtyomZorin, @lkc0987, @saibotk, @vanillajonathan, @Zkdc, @leebickmtu, @l3nn4rt, @Melix19, @Aikatsui, @melix99, @kyrillzorin, @oneshadab, , @CorvetteCole + +#### Documentation Improvements: +@BoQsc, @zakkak, @dandv + +#### Translations: +@frnogueira / @victorwpbastos (pt_BR), @zeten30 (cs), @franglais125 / @calotam / @oeramirez (es), @LaurentTreguier / @SolarLiner (fr), @elsieholmes (uk), @hosiet (zh\_CN), @jonnius / @linuxr01 (de), @urbalazs / @pappfer (hu), @crayxt (kk), @pkomur / @MartinPL / @alex4401 (pl), @AlexGluck / @GoodNike / @rjapolov / @vantu5z (ru), @sicklylife-jp / @ryonakano (ja), @oltulu / @TeknoMobil / @daenney (tr), @sbadux / @kowalski7cc / @l3nn4rt (it), @OriginCode / @pan93412 (zh\_TW), @ojn (sv), @frandieguez (gl) + + +## +### License & Terms ![](media/design/png/copyleft-16.png) + +Dash to Panel is available under the terms of the GPL-v2 or later license See [`COPYING`](https://github.com/jderose9/dash-to-panel/blob/master/COPYING) for details. + +![](https://img.shields.io/badge/Language-JavaScript-yellow.svg) ![](https://img.shields.io/badge/Licence-GPL--2.0-blue.svg) diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui new file mode 100644 index 0000000..ed7ef90 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui @@ -0,0 +1,7508 @@ + + + + + + True + False + vertical + 1 + 1 + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animation type + 0 + + + + + True + False + center + + Simple + Ripple + Plank + + + + + + + + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 24 + 32 + + + True + False + 12 + Duration + True + 0 + end + + 0 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_duration_adjustment + 0 + 0 + right + True + + 0 + 1 + + + + + + True + False + Rotation + 0 + end + + 1 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_rotation_adjustment + 0 + 0 + right + True + + 1 + 1 + + + + + + True + False + Travel + 0 + end + + 2 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_travel_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + Zoom + 0 + end + + 3 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_zoom_adjustment + 0 + 0 + right + True + + 3 + 1 + + + + + + True + False + Convexity + 0 + end + + 4 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_convexity_adjustment + 1 + 1 + right + True + + 4 + 1 + + + + + + True + False + Extent + 0 + end + + 5 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_extent_adjustment + 0 + 0 + right + True + + 5 + 1 + + + + + + + + + + 100 + 1 + 10 + + + 0 + 300 + 1 + 5 + + + -30 + 30 + 1 + 5 + + + 0 + 100 + 1 + 5 + + + 100 + 250 + 1 + 5 + + + 0 + 3 + 0.1 + 1 + + + 1 + 10 + 0.1 + 1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + True + Nothing yet! + True + + + + + + + + + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + When set to minimize, double clicking minimizes all the windows of the application. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Toggle single / Cycle multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Shift+Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + + + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Integrate <i>AppMenu</i> items + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + <i>Show Details</i> menu item + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 1 + 5 + + + 5 + 1 + 5 + + + 50 + 9999 + 25 + 100 + + + 5 + 100 + 5 + 5 + + + True + False + 12 + 12 + vertical + 1 + 1 + + + True + False + 12 + 12 + 12 + 12 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Highlight focused application + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 8 + + + True + False + True + Icon dominant color + 0 + + 0 + 0 + + + + + + True + True + end + center + + + + + True + False + True + Custom color + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + Highlight opacity + 0 + + 2 + 0 + + + + + + True + True + end + 5 + focus_highlight_opacity_adjustment + 5 + + 2 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator size (px) + 0 + + 0 + 0 + + + + + + True + True + end + 0 + dot_size_adjustment + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator color - Icon Dominant + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + vertical + + + True + False + + + True + False + True + Indicator color - Override Theme + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + True + False + vertical + + + True + False + 12 + + + True + False + True + Use different for unfocused + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + + + + + + + + + + + 6 + 24 + 1 + 100 + + + 1000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + group_apps_label_font_size_adjustment + True + + 0 + 1 + + + + + + True + False + True + Font size (px) of the application titles (default is 14) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font weight of application titles + 0 + + 0 + 0 + + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the minimized application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Maximum width (px) of the application titles (default is 160) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + group_apps_label_max_width_adjustment + True + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use a fixed width for the application titles + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display running indicators on unfocused applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use the favorite icons as application launchers + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 2000 + 10 + 100 + + + 10 + 4000 + 10 + 100 + + + 10000 + 10 + 100 + + + 1 + 9990 + 10 + 100 + + + 1 + 5000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + True + + + True + False + True + Only hide the panel when it is obstructed by windows + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + The panel hides from + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Require pressure at the edge of the screen to reveal the panel + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + Required pressure threshold (px) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_threshold_adjustment + True + + 0 + 1 + + + + + + True + False + True + Required pressure timeout (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_time_adjustment + True + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Allow the panel to be revealed while in fullscreen mode + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Only hide secondary panels (requires multi-monitors option) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>i + + 0 + 1 + 2 + + + + + + True + False + True + Keyboard shortcut to reveal and hold the panel + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Hide and reveal animation duration (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_animation_time_adjustment + True + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before hiding the panel (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_close_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before enabling intellihide on start (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_enable_hide_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + + + + + 9999 + 25 + 100 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 255 + 10 + 25 + + + 1000 + 10 + 50 + + + 50 + 500 + 10 + 50 + + + 100 + 5 + 10 + + + 50 + 1 + 5 + + + 100 + 800 + 10 + 50 + + + 9999 + 25 + 100 + + + 6 + 24 + 1 + 100 + + + 8 + 48 + 1 + 100 + + + True + True + 460 + 480 + + + True + False + True + True + natural + natural + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + preview_timeout_adjustment + True + + 0 + 1 + + + + + + True + False + True + Time (ms) before showing (400 is default) + True + 0 + + 0 + 0 + + + + + + True + False + True + Animation time (ms) + 0 + + 2 + 0 + + + + + + True + True + end + 4 + 0 + preview_animation_time_adjustment + True + + 2 + 1 + + + + + + True + False + vertical + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + + + True + True + False + 12 + 4 + + + 4 + True + False + start + 4 + Immediate on application icon click + True + + + + + + 1 + 0 + + + + + + True + True + end + center + 4 + 25 + leave_timeout_adjustment + True + 25 + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Middle click on the preview to close the window + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + 0 + 0 + 2 + + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + 2 + 0 + + + + + + True + False + True + Window previews padding (px) + True + 0 + + 3 + 0 + + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + 3 + 1 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 1 + 1 + + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + 1 + 0 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 2 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use custom opacity for the previews background + True + 0 + + 0 + 0 + + + + + + True + False + True + If disabled, the previews background have the same opacity as the panel + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + center + 5 + preview_opacity_adjustment + 5 + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + + + True + False + end + 32 + + + Bottom + True + True + False + center + center + True + + + + + + Top + True + True + False + center + center + preview_title_position_bottom_button + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 32 + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + 4 + 6 + preview_custom_icon_size_adjustment + True + 6 + + + + 0 + 1 + + + + + + True + False + True + Icon size (px) of the window preview + True + 0 + + 1 + 0 + + + + + + True + False + True + If disabled, the previews icon size will be based on headerbar size + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + True + end + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + 0 + 1 + + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + 0 + 0 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + 0 + 0 + + + + + + True + False + end + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + 3 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + 4 + 0 + 2 + + + + + + + + + + True + True + 6 + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + peek_mode_opacity_adjustment + True + + 0 + 1 + + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 3 + 0 + 2 + + + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_icon_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_panel_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show popup when changing workspace + True + 0 + + 0 + 0 + + + + + + True + False + True + This affects workspace popup when scrolling on the panel only. + True + 0 + + + 1 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + + + + + + + 10000 + 250 + 1000 + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Super + Super + Alt + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys prefix + 0 + + 0 + 0 + + + + + + True + False + Hotkeys will either be Super+Number or Super+Alt+Num + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Never + Show temporarily + Always visible + + + 0 + 1 + 2 + + + + + + True + False + True + Number overlay + 0 + + 0 + 0 + + + + + + True + False + Temporarily show the application numbers over the icons when using the hotkeys. + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + shortcut_time_adjustment + + 0 + 1 + + + + + + True + False + True + Hide timeout (ms) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>q + + 0 + 1 + 2 + + + + + + True + False + True + Shortcut to show the overlay for 2 seconds + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show window previews on hotkey + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show previews when the application have multiple instances + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + end + center + + Number row + Numeric keypad + Both + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys are activated with + 0 + + 0 + 0 + + + + + + True + False + Select which keyboard number keys are used to activate the hotkeys + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + 100 + 1 + 10 + + + True + False + vertical + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Current Show Applications icon + True + 0 + + 0 + 0 + + + + + + 32 + 32 + True + False + end + gtk-missing-image + 32 + + 0 + 1 + + + + + + 140 + True + + 1 + 1 + + + + + + True + False + True + Custom Show Applications image icon + True + 0 + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + 0 + show_applications_side_padding_adjustment + + 0 + 1 + + + + + + True + False + True + Show Applications icon side padding (px) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Override escape key and return to desktop + True + 0 + + 0 + 0 + + + + + + + + + + 5000 + 10 + 100 + + + 5000 + 10 + 100 + + + 1 + 40 + 1 + 10 + + + True + False + vertical + + + True + False + none + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_width_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Override Show Desktop line color + 0 + + 1 + 0 + + + + + + True + False + 12 + end + + + True + True + True + end + True + + + + + True + True + end + center + + + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Reveal the desktop when hovering the Show Desktop button + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 4 + + + True + False + True + Delay before revealing the desktop (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_delay_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Fade duration (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_time_adjustment + True + 1 + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 2000 + 1 + 10 + + + 200 + 1 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + + + True + False + True + The panel background opacity is affected by + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_distance_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Change opacity when a window gets closer than (px) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + + + True + False + 12 + Change opacity to (%) + True + 0 + + + + + True + True + end + 0 + trans_opacity_min_adjustment + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_anim_time_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Opacity change animation duration (ms) + True + 0 + + 0 + 0 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + True + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + 32 + + + True + False + True + Display the main panel on + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Display panels on all monitors + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Panel Intellihide + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + True + False + True + Hide and reveal the panel according to preferences + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + + + True + False + True + Order and positions on monitor + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + Apply changes to all monitors + True + True + False + 12 + 4 + 4 + + 1 + 0 + 2 + + + + + + True + False + 6 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 6 + 6 + 12 + 32 + + + True + True + baseline + True + panel_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + Panel thickness (default is 48) + 0 + + 1 + 0 + + + + + + True + False + Panel length (%) (default is 100) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + panel_length_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + center + + Start + Middle + End + + + 3 + 1 + + + + + + True + False + Anchor + 0 + + 3 + 0 + + + + + + True + False + True + Panel screen position + 0 + + 0 + 0 + + + + + + True + False + 32 + + + Bottom + True + True + False + center + center + + True + + + + + + Top + True + True + False + center + center + + position_bottom_button + + + + + + Left + True + True + False + center + center + + position_bottom_button + + + + + + Right + True + True + False + center + center + + position_bottom_button + + + + 0 + 1 + + + + + + + 1 + 0 + + + + + + + + + + 2 + 0 + 2 + + + + + + + + True + False + 6 + none + + + + + + + + + + + + + + + + True + False + Position + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + App Icon Margin (default is 8) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_margin_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 32 + + + True + False + App Icon Padding (default is 4) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator position + 0 + + + + + True + False + 32 + + + Bottom + True + True + False + center + True + + + + + + Top + True + True + False + center + dots_bottom_button + + + + + + Left + True + True + False + center + dots_bottom_button + + + + + + Right + True + True + False + center + dots_bottom_button + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Focused app) + 0 + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Unfocused apps) + 0 + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background color + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + end + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background opacity + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Panel background opacity (%) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + 0 + trans_opacity_adjustment + + 0 + 1 + + + + + + True + False + True + vertical + + + True + False + True + Dynamic background opacity + True + 0 + + + + + True + False + True + Change opacity when a window gets close to the panel + True + 40 + 0 + + + + + 1 + 0 + + + + + + True + False + end + center + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme gradient + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Gradient top color and opacity (%) + 0 + + 0 + 0 + + + + + + True + False + True + Gradient bottom color and opacity (%) + 0 + + 1 + 0 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity1_adjustment + + + + 0 + 1 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity2_adjustment + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animate hovering app icons + 0 + + 2 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 2 + 1 + + + + + + + + + + + + + + + + + + True + False + Style + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Show favorite applications + 0 + + 0 + 0 + + + + + + True + False + True + Show running applications + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show favorite applications on secondary panels + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show <i>AppMenu</i> button + True + 0 + + 0 + 0 + + + + + + True + False + True + Top Bar > Show App Menu must be enabled in Tweak Tool + True + True + 0 + + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + True + False + True + Show window previews on hover + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show tooltip on hover + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Isolate Workspaces + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Isolate monitors + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Click empty space to close overview + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Disable show overview on startup + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Ungroup applications + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + + + + + + + + + + + + True + False + Behavior + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behaviour when clicking on the icon of a running application. + True + 0 + + + 1 + 0 + + + + + + True + False + True + Click action + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + center + + Cycle windows + minimize + Cycle through windows + Toggle single / Preview multiple + Toggle windows + Raise windows + Launch new instance + + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + False + 0 + + + True + False + 12 + 12 + 12 + 12 + 16 + 6 + + + True + False + vertical + + + True + False + True + Scroll panel action + 0 + + + + + True + False + True + Behavior when mouse scrolling over the panel. + True + 0 + + + + + 0 + 0 + + + + + + True + False + vertical + + + True + False + True + Scroll icon action + 0 + + + + + True + False + True + Behavior when mouse scrolling over an application icon. + True + 0 + + + + + 1 + 0 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + True + False + center + True + + Do nothing + Switch workspace + Cycle windows + Change volume + + + 0 + 2 + + + + + + True + False + center + True + + Do nothing + Cycle windows + Same as panel + + + 1 + 2 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 1 + 1 + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl. + True + True + 0 + + + 1 + 0 + + + + + + True + False + True + Use hotkeys to activate apps + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + True + False + Action + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + True + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + Tray Font Size (0 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_size_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + LeftBox Font Size (0 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + leftbox_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + Tray Item Padding (-1 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + Status Icon Padding (-1 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + statusicon_padding_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + LeftBox Padding (-1 = theme default) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + leftbox_padding_adjustment + 0 + 0 + right + True + + + 2 + 1 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Animate switching applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Animate launching new windows + 0 + + 1 + 0 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Keep original gnome-shell dash (overview) + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Force Activities hot corner on primary monitor + 0 + + 3 + 0 + + + + + + True + True + end + center + + 3 + 1 + + + + + + True + False + True + Activate panel menu buttons (e.g. date menu) on click only + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + False + True + Keep original gnome-shell top panel + 0 + + 1 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 20 + 32 + + + True + False + True + App icon secondary (right-click) menu + 0 + + 0 + 0 + + + + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + + + + + + + + + + + + Advanced Options + False + True + True + start + + + + + + + + + True + False + center + Fine-Tune + + + + + + + False + 24 + 24 + 24 + 24 + True + True + vertical + 5 + + + True + False + vertical + + + True + False + <b>Dash-to-Panel</b> + True + + + + + True + False + center + + + True + False + end + version: + + + + + True + False + start + ... + + + + + + + GitHub + True + True + True + center + https://github.com/jderose9/dash-to-panel + + + + + + + False + 20 + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + 12 + True + Use the buttons below to create a settings file from your current preferences that can be imported on a different machine. + True + 0 + + + 1 + 0 + 2 + + + + + + True + False + start + Export and import settings + + 0 + 0 + 2 + + + + + + Export to file + True + True + True + + 2 + 0 + + + + + + Import from file + True + True + True + + 2 + 1 + + + + + + + + + + + + + + + + + True + True + end + <span size="small">This program comes with ABSOLUTELY NO WARRANTY. See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span> + True + center + True + + + + + + + + + True + False + About + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js new file mode 100644 index 0000000..e79eae8 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js @@ -0,0 +1,1964 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const Config = imports.misc.config; +const AppDisplay = imports.ui.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Taskbar = Me.imports.taskbar; +const Progress = Me.imports.progress; +const _ = imports.gettext.domain(Utils.TRANSLATION_DOMAIN).gettext; + +//timeout names +const T1 = 'setStyleTimeout'; +const T2 = 'mouseScrollTimeout'; +const T3 = 'showDotsTimeout'; +const T4 = 'overviewWindowDragEndTimeout'; +const T5 = 'switchWorkspaceTimeout'; +const T6 = 'displayProperIndicatorTimeout'; + +//right padding defined for .overview-label in stylesheet.css +const TITLE_RIGHT_PADDING = 8; + +let LABEL_GAP = 5; +let MAX_INDICATORS = 4; +var DEFAULT_PADDING_SIZE = 4; + +let DOT_STYLE = { + DOTS: "DOTS", + SQUARES: "SQUARES", + DASHES: "DASHES", + SEGMENTED: "SEGMENTED", + CILIORA: "CILIORA", + METRO: "METRO", + SOLID: "SOLID" +} + +let DOT_POSITION = { + TOP: "TOP", + BOTTOM: "BOTTOM", + LEFT: 'LEFT', + RIGHT: 'RIGHT' +} + +let recentlyClickedAppLoopId = 0; +let recentlyClickedApp = null; +let recentlyClickedAppWindows = null; +let recentlyClickedAppIndex = 0; +let recentlyClickedAppMonitorIndex; + +let tracker = Shell.WindowTracker.get_default(); +let menuRedisplayFunc = !!(AppDisplay.AppMenu || AppDisplay.AppIconMenu).prototype._rebuildMenu ? '_rebuildMenu' : '_redisplay'; + +/** + * Extend AppIcon + * + * - Apply a css class based on the number of windows of each application (#N); + * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); + * a class of the form "running#N" is applied to the AppWellIcon actor. + * like the original .running one. + * - add a .focused style to the focused app + * - Customize click actions. + * - Update minimization animation target + * + */ + +var taskbarAppIcon = Utils.defineClass({ + Name: 'DashToPanel.TaskbarAppIcon', + Extends: AppDisplay.AppIcon, + ParentConstrParams: [[0, 'app'], [2]], + + _init: function(appInfo, panel, iconParams, previewMenu, iconAnimator) { + this.dtpPanel = panel; + this._nWindows = 0; + this.window = appInfo.window; + this.isLauncher = appInfo.isLauncher; + this._previewMenu = previewMenu; + this.iconAnimator = iconAnimator; + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + // Fix touchscreen issues before the listener is added by the parent constructor. + this._onTouchEvent = function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) { + // Open the popup menu on long press. + this._setPopupTimeout(); + } else if (this._menuTimeoutId != 0 && (event.type() == Clutter.EventType.TOUCH_END || event.type() == Clutter.EventType.TOUCH_CANCEL)) { + // Activate/launch the application. + this.activate(1); + this._removeMenuTimeout(); + } + // Disable dragging via touch screen as it's buggy as hell. Not perfect for tablet users, but the alternative is way worse. + // Also, EVENT_PROPAGATE launches applications twice with this solution, so this.activate(1) above must only be called if there's already a window. + return Clutter.EVENT_STOP; + }; + // Hack for missing TOUCH_END event. + this._onLeaveEvent = function(actor, event) { + this.actor.fake_release(); + if (this._menuTimeoutId != 0) this.activate(1); // Activate/launch the application if TOUCH_END didn't fire. + this._removeMenuTimeout(); + }; + + this.callParent('_init', appInfo.app, iconParams); + + Utils.wrapActor(this.icon); + Utils.wrapActor(this); + + this._dot.set_width(0); + this._isGroupApps = Me.settings.get_boolean('group-apps'); + + this._container = new St.Widget({ style_class: 'dtp-container', layout_manager: new Clutter.BinLayout() }); + this._dotsContainer = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._dtpIconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(), style: getIconContainerStyle(panel.checkIfVertical()) }); + + this.actor.remove_actor(this._iconContainer); + + this._dtpIconContainer.add_child(this._iconContainer); + + if (appInfo.window) { + let box = new St.BoxLayout(); + + this._windowTitle = new St.Label({ + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.START, + style_class: 'overview-label' + }); + + this._updateWindowTitle(); + this._updateWindowTitleStyle(); + + this._scaleFactorChangedId = Utils.getStageTheme().connect('changed', () => this._updateWindowTitleStyle()); + + box.add_child(this._dtpIconContainer); + box.add_child(this._windowTitle); + + this._dotsContainer.add_child(box); + } else { + this._dotsContainer.add_child(this._dtpIconContainer); + } + + this._container.add_child(this._dotsContainer); + this.actor.set_child(this._container); + + if (panel.checkIfVertical()) { + this.actor.set_width(panel.geom.w); + } + + // Monitor windows-changes instead of app state. + // Keep using the same Id and function callback (that is extended) + if(this._stateChangedId > 0) { + this.app.disconnect(this._stateChangedId); + this._stateChangedId = 0; + } + + this._onAnimateAppiconHoverChanged(); + this._setAppIconPadding(); + this._showDots(); + + this._focusWindowChangedId = global.display.connect('notify::focus-window', + Lang.bind(this, this._onFocusAppChanged)); + + this._windowEnteredMonitorId = this._windowLeftMonitorId = 0; + this._stateChangedId = this.app.connect('windows-changed', Lang.bind(this, this.onWindowsChanged)); + + if (!this.window) { + if (Me.settings.get_boolean('isolate-monitors')) { + this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this)); + this._windowLeftMonitorId = Utils.DisplayWrapper.getScreen().connect('window-left-monitor', this.onWindowEnteredOrLeft.bind(this)); + } + + this._titleWindowChangeId = 0; + this._minimizedWindowChangeId = 0; + } else { + this._titleWindowChangeId = this.window.connect('notify::title', + Lang.bind(this, this._updateWindowTitle)); + + this._minimizedWindowChangeId = this.window.connect('notify::minimized', + Lang.bind(this, this._updateWindowTitleStyle)); + } + + this._scrollEventId = this.actor.connect('scroll-event', this._onMouseScroll.bind(this)); + + this._overviewWindowDragEndId = Main.overview.connect('window-drag-end', + Lang.bind(this, this._onOverviewWindowDragEnd)); + + this._switchWorkspaceId = global.window_manager.connect('switch-workspace', + Lang.bind(this, this._onSwitchWorkspace)); + + this._hoverChangeId = this.actor.connect('notify::hover', () => this._onAppIconHoverChanged()); + + this._dtpSettingsSignalIds = [ + Me.settings.connect('changed::animate-appicon-hover', Lang.bind(this, this._onAnimateAppiconHoverChanged)), + Me.settings.connect('changed::dot-position', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-size', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-focused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-unfocused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-override', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-different', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-color', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-opacity', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::group-apps-label-font-size', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-weight', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color-minimized', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-max-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-use-fixed-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-underline-unfocused', Lang.bind(this, this._settingsChangeRefresh)) + ] + + this.forcedOverview = false; + + this._progressIndicator = new Progress.ProgressIndicator(this, panel.progressManager); + + this._numberOverlay(); + }, + + getDragActor: function() { + return this.app.create_icon_texture(this.dtpPanel.taskbar.iconSize); + }, + + // Used by TaskbarItemContainer to animate appIcons on hover + getCloneButton: function() { + // The source of the clone is this._container, + // using this.actor directly would break DnD style. + let clone = new Clutter.Clone({ + source: this.actor.child, + x: this.actor.child.x, y: this.actor.child.y, + width: this.actor.child.width, height: this.actor.child.height, + pivot_point: new Utils.getPoint({ x: 0.5, y: 0.5 }), + opacity: 255, + reactive: false, + x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER, + }); + + // "clone" of this.actor + return new St.Button({ + child: clone, + x: this.actor.x, y: this.actor.y, + width: this.actor.width, height: this.actor.height, + reactive: false, + }); + }, + + shouldShowTooltip: function() { + if (!Me.settings.get_boolean('show-tooltip') || + (!this.isLauncher && Me.settings.get_boolean("show-window-previews") && + this.getAppIconInterestingWindows().length > 0)) { + return false; + } else { + return this.actor.hover && !this.window && + (!this._menu || !this._menu.isOpen) && + (this._previewMenu.getCurrentAppIcon() !== this); + } + }, + + _onAppIconHoverChanged: function() { + if (!Me.settings.get_boolean('show-window-previews') || + (!this.window && !this._nWindows)) { + return; + } + + if (this.actor.hover) { + this._previewMenu.requestOpen(this); + } else { + this._previewMenu.requestClose(); + } + }, + + _onDestroy: function() { + this.callParent('_onDestroy'); + this._destroyed = true; + + this._timeoutsHandler.destroy(); + + this._previewMenu.close(true); + + // Disconect global signals + // stateChangedId is already handled by parent) + + if(this._overviewWindowDragEndId) + Main.overview.disconnect(this._overviewWindowDragEndId); + + if(this._focusWindowChangedId) + global.display.disconnect(this._focusWindowChangedId); + + if(this._titleWindowChangeId) + this.window.disconnect(this._titleWindowChangeId); + + if(this._minimizedWindowChangeId) + this.window.disconnect(this._minimizedWindowChangeId); + + if (this._windowEnteredMonitorId) { + Utils.DisplayWrapper.getScreen().disconnect(this._windowEnteredMonitorId); + Utils.DisplayWrapper.getScreen().disconnect(this._windowLeftMonitorId); + } + + if(this._switchWorkspaceId) + global.window_manager.disconnect(this._switchWorkspaceId); + + if(this._scaleFactorChangedId) + Utils.getStageTheme().disconnect(this._scaleFactorChangedId); + + if (this._hoverChangeId) { + this.actor.disconnect(this._hoverChangeId); + } + + if (this._scrollEventId) { + this.actor.disconnect(this._scrollEventId); + } + + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + }, + + onWindowsChanged: function() { + this._updateWindows(); + this.updateIcon(); + }, + + onWindowEnteredOrLeft: function() { + if (this._checkIfFocusedApp()) { + this._updateWindows(); + this._displayProperIndicator(); + } + }, + + updateTitleStyle: function() { + this._updateWindowTitleStyle(); + }, + + // Update indicator and target for minimization animation + updateIcon: function() { + + // If (for unknown reason) the actor is not on the stage the reported size + // and position are random values, which might exceeds the integer range + // resulting in an error when assigned to the a rect. This is a more like + // a workaround to prevent flooding the system with errors. + if (this.actor.get_stage() == null) + return; + + let rect = new Meta.Rectangle(); + + [rect.x, rect.y] = this.actor.get_transformed_position(); + [rect.width, rect.height] = this.actor.get_transformed_size(); + + let windows = this.window ? [this.window] : this.getAppIconInterestingWindows(true); + windows.forEach(function(w) { + w.set_icon_geometry(rect); + }); + }, + + _onAnimateAppiconHoverChanged: function() { + if (Me.settings.get_boolean('animate-appicon-hover')) { + this._container.add_style_class_name('animate-appicon-hover'); + + // Workaround to prevent scaled icon from being ugly when it is animated on hover. + // It increases the "resolution" of the icon without changing the icon size. + this.icon.createIcon = (iconSize) => this.app.create_icon_texture(2 * iconSize); + this._iconIconBinActorAddedId = this.icon._iconBin.connect('actor-added', () => { + if (this.icon._iconBin.child.mapped) { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + } else { + let iconMappedId = this.icon._iconBin.child.connect('notify::mapped', () => { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + this.icon._iconBin.child.disconnect(iconMappedId); + }); + } + }); + if (this.icon._iconBin.child) + this.icon._createIconTexture(this.icon.iconSize); + } else { + this._container.remove_style_class_name('animate-appicon-hover'); + + if (this._iconIconBinActorAddedId) { + this.icon._iconBin.disconnect(this._iconIconBinActorAddedId); + this._iconIconBinActorAddedId = 0; + this.icon.createIcon = Lang.bind(this, this._createIcon); + } + } + }, + + _onMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-icon-action'); + + if (scrollAction === 'PASS_THROUGH') { + return this.dtpPanel._onPanelMouseScroll(actor, event); + } else if (scrollAction === 'NOTHING' || (!this.window && !this._nWindows)) { + return; + } + + let direction = Utils.getMouseScrollDirection(event); + + if (direction && !this._timeoutsHandler.getId(T2)) { + this._timeoutsHandler.add([T2, Me.settings.get_int('scroll-icon-delay'), () => {}]); + + let windows = this.getAppIconInterestingWindows(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + Utils.activateSiblingWindow(windows, direction, this.window); + } + }, + + _showDots: function() { + // Just update style if dots already exist + if (this._focusedDots && this._unfocusedDots) { + this._updateWindows(); + return; + } + + if (!this._isGroupApps) { + this._focusedDots = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + visible: false + }); + + let mappedId = this.actor.connect('notify::mapped', () => { + this._displayProperIndicator(); + this.actor.disconnect(mappedId); + }); + } else { + this._focusedDots = new St.DrawingArea(), + this._unfocusedDots = new St.DrawingArea(); + this._focusedDots._tweeningToSize = null, + this._unfocusedDots._tweeningToSize = null; + + this._focusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._focusedDots, Me.settings.get_string('dot-style-focused'), true); + this._displayProperIndicator(); + })); + + this._unfocusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._unfocusedDots, Me.settings.get_string('dot-style-unfocused'), false); + this._displayProperIndicator(); + })); + + this._dotsContainer.add_child(this._unfocusedDots); + + this._updateWindows(); + + this._timeoutsHandler.add([T3, 0, () => { + this._resetDots(); + this._displayProperIndicator(); + }]); + } + + this._dotsContainer.add_child(this._focusedDots); + }, + + _resetDots: function() { + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + [this._focusedDots, this._unfocusedDots].forEach(d => { + d._tweeningToSize = null; + d.set_size(-1, -1); + d.x_expand = d.y_expand = false; + + d[isHorizontalDots ? 'width' : 'height'] = 1; + d[(isHorizontalDots ? 'y' : 'x') + '_expand'] = true; + }); + }, + + _settingsChangeRefresh: function() { + if (this._isGroupApps) { + this._updateWindows(); + this._resetDots(); + this._focusedDots.queue_repaint(); + this._unfocusedDots.queue_repaint(); + } + + this._displayProperIndicator(true); + }, + + _updateWindowTitleStyle: function() { + if (this._windowTitle) { + let useFixedWidth = Me.settings.get_boolean('group-apps-use-fixed-width'); + let variableWidth = !useFixedWidth || this.dtpPanel.checkIfVertical() || this.dtpPanel.taskbar.fullScrollView; + let fontWeight = Me.settings.get_string('group-apps-label-font-weight'); + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let fontColor = this.window.minimized ? + Me.settings.get_string('group-apps-label-font-color-minimized') : + Me.settings.get_string('group-apps-label-font-color'); + let scaleFactor = Utils.getScaleFactor(); + let maxLabelWidth = Me.settings.get_int('group-apps-label-max-width') * scaleFactor; + + this._windowTitle[(maxLabelWidth > 0 ? 'show' : 'hide')](); + + this._windowTitle.clutter_text.natural_width = useFixedWidth ? maxLabelWidth : 0; + this._windowTitle.clutter_text.natural_width_set = useFixedWidth; + this._windowTitle.set_width(variableWidth ? -1 : maxLabelWidth + TITLE_RIGHT_PADDING * scaleFactor); + + this._windowTitle.set_style('font-size: ' + Me.settings.get_int('group-apps-label-font-size') * fontScale + 'px;' + + 'font-weight: ' + fontWeight + ';' + + (useFixedWidth ? '' : 'max-width: ' + maxLabelWidth + 'px;') + + 'color: ' + fontColor); + } + }, + + _updateWindowTitle: function() { + if (this._windowTitle.text != this.window.title) { + this._windowTitle.text = (this.window.title ? this.window.title : this.app.get_name()).replace(/\r?\n|\r/g, '').trim(); + + if (this._focusedDots) { + this._displayProperIndicator(); + } + } + }, + + _setIconStyle: function(isFocused) { + let inlineStyle = 'margin: 0;'; + + if(Me.settings.get_boolean('focus-highlight') && + this._checkIfFocusedApp() && !this.isLauncher && + (!this.window || isFocused) && !this._isThemeProvidingIndicator() && this._checkIfMonitorHasFocus()) { + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let isWide = this._isWideDotStyle(focusedDotStyle); + let pos = Me.settings.get_string('dot-position'); + let highlightMargin = isWide ? Me.settings.get_int('dot-size') : 0; + + if(!this.window) { + let containerWidth = this._dtpIconContainer.get_width() / Utils.getScaleFactor();; + let backgroundSize = containerWidth + "px " + + (containerWidth - (pos == DOT_POSITION.BOTTOM ? highlightMargin : 0)) + "px;"; + + if (focusedDotStyle == DOT_STYLE.CILIORA || focusedDotStyle == DOT_STYLE.SEGMENTED) + highlightMargin += 1; + + if (this._nWindows > 1 && focusedDotStyle == DOT_STYLE.METRO) { + let bgSvg = '/img/highlight_stacked_bg'; + + if (pos == DOT_POSITION.LEFT || pos == DOT_POSITION.RIGHT) { + bgSvg += (this.dtpPanel.checkIfVertical() ? '_2' : '_3'); + } + + inlineStyle += "background-image: url('" + Me.path + bgSvg + ".svg');" + + "background-position: 0 " + (pos == DOT_POSITION.TOP ? highlightMargin : 0) + "px;" + + "background-size: " + backgroundSize; + } + } + + let highlightColor = this._getFocusHighlightColor(); + inlineStyle += "background-color: " + cssHexTocssRgba(highlightColor, Me.settings.get_int('focus-highlight-opacity') * 0.01); + } + + if(this._dotsContainer.get_style() != inlineStyle && this._dotsContainer.mapped) { + if (!this._isGroupApps) { + //when the apps are ungrouped, set the style synchronously so the icons don't jump around on taskbar redraw + this._dotsContainer.set_style(inlineStyle); + } else if (!this._timeoutsHandler.getId(T1)) { + //graphical glitches if i dont set this on a timeout + this._timeoutsHandler.add([T1, 0, () => this._dotsContainer.set_style(inlineStyle)]); + } + } + }, + + _checkIfFocusedApp: function() { + return tracker.focus_app == this.app; + }, + + _checkIfMonitorHasFocus: function() { + return global.display.focus_window && + (!Me.settings.get_boolean('multi-monitors') || // only check same monitor index if multi window is enabled. + !Me.settings.get_boolean('isolate-monitors') || + global.display.focus_window.get_monitor() === this.dtpPanel.monitor.index); + }, + + _setAppIconPadding: function() { + let padding = getIconPadding(this.dtpPanel.monitor.index); + let margin = Me.settings.get_int('appicon-margin'); + + this.actor.set_style('padding:' + (this.dtpPanel.checkIfVertical() ? margin + 'px 0' : '0 ' + margin + 'px;')); + this._iconContainer.set_style('padding: ' + padding + 'px;'); + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + + if (this._draggable) { + this._draggable.fakeRelease(); + } + + if (this.isDragged) { + return; + } + + if (!this._menu) { + this._menu = new taskbarSecondaryMenu(this, this.dtpPanel); + this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { + this.activateWindow(window, Me.settings); + })); + this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + + this._menuManager.addMenu(this._menu); + } + + this.emit('menu-state-changed', true); + + this._previewMenu.close(true); + + this.actor.set_hover(true); + this._menu.actor.add_style_class_name('dashtopanelSecondaryMenu'); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + _onFocusAppChanged: function(windowTracker) { + this._displayProperIndicator(true); + }, + + _onOverviewWindowDragEnd: function(windowTracker) { + this._timeoutsHandler.add([T4, 0, () => this._displayProperIndicator()]); + }, + + _onSwitchWorkspace: function(windowTracker) { + if (this._isGroupApps) { + this._timeoutsHandler.add([T5, 0, () => this._displayProperIndicator(true)]); + } else { + this._displayProperIndicator(); + } + }, + + _displayProperIndicator: function (force) { + let isFocused = this._isFocusedWindow(); + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + this._setIconStyle(isFocused); + + if(!this._isGroupApps) { + if (this.window && (Me.settings.get_boolean('group-apps-underline-unfocused') || isFocused)) { + let align = Clutter.ActorAlign[position == DOT_POSITION.TOP || position == DOT_POSITION.LEFT ? 'START' : 'END']; + + this._focusedDots.set_size(0, 0); + this._focusedDots[isHorizontalDots ? 'height' : 'width'] = this._getRunningIndicatorSize(); + + this._focusedDots.y_align = this._focusedDots.x_align = Clutter.ActorAlign.FILL; + this._focusedDots[(isHorizontalDots ? 'y' : 'x') + '_align'] = align; + this._focusedDots.background_color = this._getRunningIndicatorColor(isFocused); + this._focusedDots.show(); + } else if (this._focusedDots.visible) { + this._focusedDots.hide(); + } + } else { + let sizeProp = isHorizontalDots ? 'width' : 'height'; + let containerSize = this._container[sizeProp]; + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let unfocusedDotStyle = Me.settings.get_string('dot-style-unfocused'); + let focusedIsWide = this._isWideDotStyle(focusedDotStyle); + let unfocusedIsWide = this._isWideDotStyle(unfocusedDotStyle); + + let newFocusedDotsSize = 0; + let newFocusedDotsOpacity = 0; + let newUnfocusedDotsSize = 0; + let newUnfocusedDotsOpacity = 0; + + isFocused = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + this._timeoutsHandler.add([T6, 0, () => { + if (!this._destroyed) { + if(isFocused) + this.actor.add_style_class_name('focused'); + else + this.actor.remove_style_class_name('focused'); + } + }]); + + if(focusedIsWide) { + newFocusedDotsSize = (isFocused && this._nWindows > 0) ? containerSize : 0; + newFocusedDotsOpacity = 255; + } else { + newFocusedDotsSize = containerSize; + newFocusedDotsOpacity = (isFocused && this._nWindows > 0) ? 255 : 0; + } + + if(unfocusedIsWide) { + newUnfocusedDotsSize = (!isFocused && this._nWindows > 0) ? containerSize : 0; + newUnfocusedDotsOpacity = 255; + } else { + newUnfocusedDotsSize = containerSize; + newUnfocusedDotsOpacity = (!isFocused && this._nWindows > 0) ? 255 : 0; + } + + // Only animate if... + // animation is enabled in settings + // AND (going from a wide style to a narrow style indicator or vice-versa + // OR going from an open app to a closed app or vice versa) + if(Me.settings.get_boolean('animate-app-switch') && + ((focusedIsWide != unfocusedIsWide) || + (this._focusedDots[sizeProp] != newUnfocusedDotsSize || this._unfocusedDots[sizeProp] != newFocusedDotsSize))) { + this._animateDotDisplay(this._focusedDots, newFocusedDotsSize, this._unfocusedDots, newUnfocusedDotsOpacity, force, sizeProp); + this._animateDotDisplay(this._unfocusedDots, newUnfocusedDotsSize, this._focusedDots, newFocusedDotsOpacity, force, sizeProp); + } else { + this._focusedDots.opacity = newFocusedDotsOpacity; + this._unfocusedDots.opacity = newUnfocusedDotsOpacity; + this._focusedDots[sizeProp] = newFocusedDotsSize; + this._unfocusedDots[sizeProp] = newUnfocusedDotsSize; + } + } + }, + + _animateDotDisplay: function (dots, newSize, otherDots, newOtherOpacity, force, sizeProp) { + if((dots[sizeProp] != newSize && dots._tweeningToSize !== newSize) || force) { + let tweenOpts = { + time: Taskbar.DASH_ANIMATION_TIME, + transition: 'easeInOutCubic', + onComplete: Lang.bind(this, function() { + if(newOtherOpacity > 0) + otherDots.opacity = newOtherOpacity; + dots._tweeningToSize = null; + }) + }; + + if(newOtherOpacity == 0) + otherDots.opacity = newOtherOpacity; + + tweenOpts[sizeProp] = newSize; + dots._tweeningToSize = newSize; + + Utils.animate(dots, tweenOpts); + } + }, + + _isFocusedWindow: function() { + let focusedWindow = global.display.focus_window; + + while (focusedWindow) { + if (focusedWindow == this.window) { + return true; + } + + focusedWindow = focusedWindow.get_transient_for(); + } + + return false; + }, + + _isWideDotStyle: function(dotStyle) { + return dotStyle == DOT_STYLE.SEGMENTED || + dotStyle == DOT_STYLE.CILIORA || + dotStyle == DOT_STYLE.METRO || + dotStyle == DOT_STYLE.SOLID; + }, + + _isThemeProvidingIndicator: function () { + // This is an attempt to determine if the theme is providing their own + // running indicator by way of a border image on the icon, for example in + // the theme Ciliora + return (this.icon.actor.get_stage() && + this.icon.actor.get_theme_node().get_border_image()); + }, + + activate: function(button, handleAsGrouped) { + let event = Clutter.get_current_event(); + let modifiers = event ? event.get_state() : 0; + + // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.) + modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK); + + // We don't change the CTRL-click behaviour: in such case we just chain + // up the parent method and return. + if (modifiers & Clutter.ModifierType.CONTROL_MASK) { + // Keep default behaviour: launch new window + // By calling the parent method I make it compatible + // with other extensions tweaking ctrl + click + this.callParent('activate', button); + return; + } + + // We check what type of click we have and if the modifier SHIFT is + // being used. We then define what buttonAction should be for this + // event. + let buttonAction = 0; + if (button && button == 2 ) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-middle-click-action'); + else + buttonAction = Me.settings.get_string('middle-click-action'); + } + else if (button && button == 1) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-click-action'); + else + buttonAction = Me.settings.get_string('click-action'); + } + + let appCount = this.getAppIconInterestingWindows().length; + let previewedAppIcon = this._previewMenu.getCurrentAppIcon(); + this._previewMenu.close(Me.settings.get_boolean('window-preview-hide-immediate-click')); + + // We check if the app is running, and that the # of windows is > 0 in + // case we use workspace isolation, + let appIsRunning = this.app.state == Shell.AppState.RUNNING && appCount > 0; + + // We customize the action only when the application is already running + if (appIsRunning && !this.isLauncher) { + if (this.window && !handleAsGrouped) { + //ungrouped applications behaviors + switch (buttonAction) { + case 'RAISE': case 'CYCLE': case 'CYCLE-MIN': case 'MINIMIZE': case 'TOGGLE-SHOWPREVIEW': case 'TOGGLE-CYCLE': + if (!Main.overview._shown && + (buttonAction == 'MINIMIZE' || buttonAction == 'TOGGLE-SHOWPREVIEW' || buttonAction == 'TOGGLE-CYCLE' || buttonAction == 'CYCLE-MIN') && + (this._isFocusedWindow() || (buttonAction == 'MINIMIZE' && (button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK)))) { + this.window.minimize(); + } else { + Main.activateWindow(this.window); + } + + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "QUIT": + this.window.delete(global.get_current_time()); + break; + } + } else { + //grouped application behaviors + let monitor = this.dtpPanel.monitor; + let appHasFocus = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + switch (buttonAction) { + case "RAISE": + activateAllWindows(this.app, monitor); + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "MINIMIZE": + // In overview just activate the app, unless the acion is explicitely + // requested with a keyboard modifier + if (!Main.overview._shown || modifiers){ + // If we have button=2 or a modifier, allow minimization even if + // the app is not focused + if (appHasFocus || button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) { + // minimize all windows on double click and always in the case of primary click without + // additional modifiers + let all_windows = (button == 1 && ! modifiers) || event.get_click_count() > 1; + minimizeWindow(this.app, all_windows, monitor); + } + else + activateAllWindows(this.app, monitor); + } + else + this.app.activate(); + break; + + case "CYCLE": + if (!Main.overview._shown){ + if (appHasFocus) + cycleThroughWindows(this.app, false, false, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "CYCLE-MIN": + if (!Main.overview._shown){ + if (appHasFocus || (recentlyClickedApp == this.app && recentlyClickedAppWindows[recentlyClickedAppIndex % recentlyClickedAppWindows.length] == "MINIMIZE")) + cycleThroughWindows(this.app, false, true, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "TOGGLE-SHOWPREVIEW": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + if (event.get_click_count() > 1) { + // minimize all windows if double clicked + minimizeWindow(this.app, true, monitor); + } else if (previewedAppIcon != this) { + this._previewMenu.open(this); + } + + this.emit('sync-tooltip'); + } + } + else + this.app.activate(); + break; + case "TOGGLE-CYCLE": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + cycleThroughWindows(this.app, false, false, monitor); + } + } + else + this.app.activate(); + break; + case "QUIT": + closeAllWindows(this.app, monitor); + break; + } + } + } + else { + this._launchNewInstance(); + } + + Main.overview.hide(); + }, + + _launchNewInstance: function() { + if (this.app.can_open_new_window()) { + let appActions = this.app.get_app_info().list_actions(); + let newWindowIndex = appActions.indexOf('new-window'); + + if(Me.settings.get_boolean('animate-window-launch')) { + this.animateLaunch(); + } + + if (newWindowIndex < 0) { + this.app.open_new_window(-1); + } else { + this.app.launch_action(appActions[newWindowIndex], global.get_current_time(), -1); + } + } else { + let windows = this.window ? [this.window] : this.app.get_windows(); + + if (windows.length) { + Main.activateWindow(windows[0]); + } else { + this.app.activate(); + } + } + }, + + _updateWindows: function() { + let windows = [this.window]; + + if (!this.window) { + windows = this.getAppIconInterestingWindows(); + + this._nWindows = windows.length; + + for (let i = 1; i <= MAX_INDICATORS; i++){ + let className = 'running'+i; + if(i != this._nWindows) + this.actor.remove_style_class_name(className); + else + this.actor.add_style_class_name(className); + } + } + + this._previewMenu.update(this, windows); + }, + + _getRunningIndicatorCount: function() { + return Math.min(this._nWindows, MAX_INDICATORS); + }, + + _getRunningIndicatorSize: function() { + return Me.settings.get_int('dot-size') * Utils.getScaleFactor(); + }, + + _getRunningIndicatorColor: function(isFocused) { + let color; + const fallbackColor = new Clutter.Color({ red: 82, green: 148, blue: 226, alpha: 255 }); + + if (Me.settings.get_boolean('dot-color-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) { + color = Clutter.color_from_string(palette.original)[1]; + } else { // unable to determine color, fall back to theme + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + } else if(Me.settings.get_boolean('dot-color-override')) { + let dotColorSettingPrefix = 'dot-color-'; + + if(!isFocused && Me.settings.get_boolean('dot-color-unfocused-different')) + dotColorSettingPrefix = 'dot-color-unfocused-'; + + color = Clutter.color_from_string(Me.settings.get_string(dotColorSettingPrefix + (this._getRunningIndicatorCount() || 1) ))[1]; + } else { + // Re-use the style - background color, and border width and color - + // of the default dot + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + + return color; + }, + + _getFocusHighlightColor: function() { + if (Me.settings.get_boolean('focus-highlight-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) return palette.original; + } + return Me.settings.get_string('focus-highlight-color'); + }, + + _drawRunningIndicator: function(area, type, isFocused) { + let n = this._getRunningIndicatorCount(); + + if (!n) { + return; + } + + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + let bodyColor = this._getRunningIndicatorColor(isFocused); + let [areaWidth, areaHeight] = area.get_surface_size(); + let cr = area.get_context(); + let size = this._getRunningIndicatorSize(); + + let areaSize = areaWidth; + let startX = 0; + let startY = 0; + + if (isHorizontalDots) { + if (position == DOT_POSITION.BOTTOM) { + startY = areaHeight - size; + } + } else { + areaSize = areaHeight; + + if (position == DOT_POSITION.RIGHT) { + startX = areaWidth - size; + } + } + + if (type == DOT_STYLE.SOLID || type == DOT_STYLE.METRO) { + if (type == DOT_STYLE.SOLID || n <= 1) { + cr.translate(startX, startY); + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [areaSize, size] : [size, areaSize])); + cr.fill(); + } else { + let blackenedLength = (1 / 48) * areaSize; // need to scale with the SVG for the stacked highlight + let darkenedLength = isFocused ? (2 / 48) * areaSize : (10 / 48) * areaSize; + let blackenedColor = bodyColor.shade(.3); + let darkenedColor = bodyColor.shade(.7); + let solidDarkLength = areaSize - darkenedLength; + let solidLength = solidDarkLength - blackenedLength; + + cr.translate(startX, startY); + + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [solidLength, size] : [size, solidLength])); + cr.fill(); + Clutter.cairo_set_source_color(cr, blackenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidLength, 0, 1, size] : [0, solidLength, size, 1]); + cr.fill(); + Clutter.cairo_set_source_color(cr, darkenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidDarkLength, 0, darkenedLength, size] : [0, solidDarkLength, size, darkenedLength]); + cr.fill(); + } + } else { + let spacing = Math.ceil(areaSize / 18); // separation between the indicators + let length; + let dist; + let indicatorSize; + let translate; + let preDraw = () => {}; + let draw; + let drawDash = (i, dashLength) => { + dist = i * dashLength + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0, dashLength, size] : [0, dist, size, dashLength])); + }; + + switch (type) { + case DOT_STYLE.CILIORA: + spacing = size; + length = areaSize - (size * (n - 1)) - (spacing * (n - 1)); + translate = () => cr.translate(startX, startY); + preDraw = () => { + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [length, size] : [size, length])); + }; + draw = i => { + dist = length + (i * spacing) + ((i - 1) * size); + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DOTS: + let radius = size / 2; + + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = (2 * i + 1) * radius + i * spacing; + cr.arc.apply(cr, (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI])); + }; + break; + case DOT_STYLE.SQUARES: + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = i * size + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DASHES: + length = Math.floor(areaSize / 4) - spacing; + translate = () => { + indicatorSize = Math.floor((areaSize - n * length - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => drawDash(i, length); + break; + case DOT_STYLE.SEGMENTED: + length = Math.ceil((areaSize - ((n - 1) * spacing)) / n); + translate = () => cr.translate(startX, startY); + draw = i => drawDash(i, length); + break; + } + + translate(); + + Clutter.cairo_set_source_color(cr, bodyColor); + preDraw(); + for (let i = 0; i < n; i++) { + cr.newSubPath(); + draw(i); + } + cr.fill(); + } + + cr.$dispose(); + }, + + _numberOverlay: function() { + // Add label for a Hot-Key visual aid + this._numberOverlayLabel = new St.Label({ style_class: 'badge' }); + this._numberOverlayBin = new St.Bin({ + child: this._numberOverlayLabel, y: 2 + }); + this._numberOverlayLabel.add_style_class_name('number-overlay'); + this._numberOverlayOrder = -1; + this._numberOverlayBin.hide(); + + this._dtpIconContainer.add_child(this._numberOverlayBin); + }, + + updateHotkeyNumberOverlay: function() { + this.updateNumberOverlay(this._numberOverlayBin, true); + }, + + updateNumberOverlay: function(bin, fixedSize) { + // We apply an overall scale factor that might come from a HiDPI monitor. + // Clutter dimensions are in physical pixels, but CSS measures are in logical + // pixels, so make sure to consider the scale. + // Set the font size to something smaller than the whole icon so it is + // still visible. The border radius is large to make the shape circular + let [minWidth, natWidth] = this._dtpIconContainer.get_preferred_width(-1); + let font_size = Math.round(Math.max(12, 0.3 * natWidth) / Utils.getScaleFactor()); + let size = Math.round(font_size * 1.3); + let label = bin.child; + let style = 'font-size: ' + font_size + 'px;' + + 'border-radius: ' + this.icon.iconSize + 'px;' + + 'height: ' + size +'px;'; + + if (fixedSize || label.get_text().length == 1) { + style += 'width: ' + size + 'px;'; + } else { + style += 'padding: 0 2px;'; + } + + bin.x = fixedSize ? natWidth - size - 2 : 2; + label.set_style(style); + }, + + setNumberOverlay: function(number) { + this._numberOverlayOrder = number; + this._numberOverlayLabel.set_text(number.toString()); + }, + + toggleNumberOverlay: function(activate) { + if (activate && this._numberOverlayOrder > -1) + this._numberOverlayBin.show(); + else + this._numberOverlayBin.hide(); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + this._previewMenu.close(true); + } + + return DND.DragMotionResult.CONTINUE; + }, + + // Disable all DnD methods on gnome-shell 3.34 + _onDragBegin: function() {}, + _onDragEnd: function() {}, + acceptDrop: function() { return false; }, + + getAppIconInterestingWindows: function(isolateMonitors) { + return getInterestingWindows(this.app, this.dtpPanel.monitor, isolateMonitors); + } +}); +taskbarAppIcon.prototype.scaleAndFade = taskbarAppIcon.prototype.undoScaleAndFade = () => {}; + +function minimizeWindow(app, param, monitor){ + // Param true make all app windows minimize + let windows = getInterestingWindows(app, monitor); + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + for (let i = 0; i < windows.length; i++) { + let w = windows[i]; + if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()){ + w.minimize(); + // Just minimize one window. By specification it should be the + // focused window on the current workspace. + if(!param) + break; + } + } +} + +/* + * By default only non minimized windows are activated. + * This activates all windows in the current workspace. + */ +function activateAllWindows(app, monitor){ + + // First activate first window so workspace is switched if needed, + // then activate all other app windows in the current workspace. + let windows = getInterestingWindows(app, monitor); + let w = windows[0]; + Main.activateWindow(w); + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + + if (windows.length <= 0) + return; + + for (let i = windows.length - 1; i >= 0; i--){ + if (windows[i].get_workspace().index() == activeWorkspace){ + Main.activateWindow(windows[i]); + } + } +} + +function activateFirstWindow(app, monitor){ + + let windows = getInterestingWindows(app, monitor); + Main.activateWindow(windows[0]); +} + +function cycleThroughWindows(app, reversed, shouldMinimize, monitor) { + // Store for a little amount of time last clicked app and its windows + // since the order changes upon window interaction + let MEMORY_TIME=3000; + + let app_windows = getInterestingWindows(app, monitor); + + if(shouldMinimize) + app_windows.push("MINIMIZE"); + + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); + + // If there isn't already a list of windows for the current app, + // or the stored list is outdated, use the current windows list. + if (!recentlyClickedApp || + recentlyClickedApp.get_id() != app.get_id() || + recentlyClickedAppWindows.length != app_windows.length || + recentlyClickedAppMonitorIndex != monitor.index) { + recentlyClickedApp = app; + recentlyClickedAppWindows = app_windows; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = monitor.index; + } + + if (reversed) { + recentlyClickedAppIndex--; + if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1; + } else { + recentlyClickedAppIndex++; + } + let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; + + if(recentlyClickedAppWindows[index] === "MINIMIZE") + minimizeWindow(app, true, monitor); + else + Main.activateWindow(recentlyClickedAppWindows[index]); +} + +function resetRecentlyClickedApp() { + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId=0; + recentlyClickedApp =null; + recentlyClickedAppWindows = null; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = null; + + return false; +} + +function closeAllWindows(app, monitor) { + let windows = getInterestingWindows(app, monitor); + for (let i = 0; i < windows.length; i++) + windows[i].delete(global.get_current_time()); +} + +// Filter out unnecessary windows, for instance +// nautilus desktop window. +function getInterestingWindows(app, monitor, isolateMonitors) { + let windows = app.get_windows().filter(function(w) { + return !w.skip_taskbar; + }); + + // When using workspace or monitor isolation, we filter out windows + // that are not in the current workspace or on the same monitor as the appicon + if (Me.settings.get_boolean('isolate-workspaces')) + windows = windows.filter(function(w) { + return w.get_workspace().index() == Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + }); + + if (monitor && Me.settings.get_boolean('multi-monitors') && (isolateMonitors || Me.settings.get_boolean('isolate-monitors'))) { + windows = windows.filter(function(w) { + return w.get_monitor() == monitor.index; + }); + } + + return windows; +} + +function cssHexTocssRgba(cssHex, opacity) { + var bigint = parseInt(cssHex.slice(1), 16); + var r = (bigint >> 16) & 255; + var g = (bigint >> 8) & 255; + var b = bigint & 255; + + return 'rgba(' + [r, g, b].join(',') + ',' + opacity + ')'; +} + +function getIconPadding(monitorIndex) { + let panelSize = PanelSettings.getPanelSize(Me.settings, monitorIndex); + let padding = Me.settings.get_int('appicon-padding'); + let availSize = panelSize - Taskbar.MIN_ICON_SIZE - panelSize % 2; + + if (padding * 2 > availSize) { + padding = availSize * .5; + } + + return padding; +} + +/** + * Extend AppMenu (AppIconMenu for pre gnome 41) + * + * - set popup arrow side based on taskbar orientation + * - Add close windows option based on quitfromdash extension + * (https://github.com/deuill/shell-extension-quitfromdash) + */ + +var taskbarSecondaryMenu = Utils.defineClass({ + Name: 'DashToPanel.SecondaryMenu', + Extends: (AppDisplay.AppMenu || AppDisplay.AppIconMenu), + ParentConstrParams: [[0]], + + _init: function(source, panel) { + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later + this.callParent('_init', source); + + let side = panel.getPosition(); + // Change the initialized side where required. + this._arrowSide = side; + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + }, + + // helper function for the quit windows abilities + _closeWindowInstance: function(metaWindow) { + metaWindow.delete(global.get_current_time()); + }, + + _dtpRedisplay: function(parentFunc) { + this.callParent(parentFunc); + + // Remove "Show Details" menu item + if(!Me.settings.get_boolean('secondarymenu-contains-showdetails')) { + let existingMenuItems = this._getMenuItems(); + for(let idx in existingMenuItems) { + if(existingMenuItems[idx].actor.label_actor.text == _("Show Details")) { + this.box.remove_child(existingMenuItems[idx].actor); + if(existingMenuItems[idx-1] instanceof PopupMenu.PopupSeparatorMenuItem) + this.box.remove_child(existingMenuItems[idx-1].actor); + break; + } + } + } + + // prepend items from the appMenu (for native gnome apps) + if(Me.settings.get_boolean('secondarymenu-contains-appmenu')) { + let appMenu = this._source.app.menu; + if(appMenu) { + let remoteMenu = new imports.ui.remoteMenu.RemoteMenu(this._source.actor, this._source.app.menu, this._source.app.action_group); + let appMenuItems = remoteMenu._getMenuItems(); + for(var i = 0, l = appMenuItems.length || 0; i < l; ++i) { + let menuItem = appMenuItems[i]; + let labelText = menuItem.actor.label_actor.text; + if(labelText == _("New Window") || labelText == _("Quit")) + continue; + + if(menuItem instanceof PopupMenu.PopupSeparatorMenuItem) + continue; + + // this ends up getting called multiple times, and bombing due to the signal id's being invalid + // on a 2nd pass. disconnect the base handler and attach our own that wraps the id's in if statements + menuItem.disconnect(menuItem._popupMenuDestroyId) + menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) { + if(menuItem._popupMenuDestroyId) { + menuItem.disconnect(menuItem._popupMenuDestroyId); + menuItem._popupMenuDestroyId = 0; + } + if(menuItem._activateId) { + menuItem.disconnect(menuItem._activateId); + menuItem._activateId = 0; + } + if(menuItem._activeChangeId) { + menuItem.disconnect(menuItem._activeChangeId); + menuItem._activeChangeId = 0; + } + if(menuItem._sensitiveChangeId) { + menuItem.disconnect(menuItem._sensitiveChangeId); + menuItem._sensitiveChangeId = 0; + } + this.disconnect(menuItem._parentSensitiveChangeId); + if (menuItem == this._activeMenuItem) + this._activeMenuItem = null; + })); + + menuItem.actor.get_parent().remove_child(menuItem.actor); + if(menuItem instanceof PopupMenu.PopupSubMenuMenuItem) { + let newSubMenuMenuItem = new PopupMenu.PopupSubMenuMenuItem(labelText); + let appSubMenuItems = menuItem.menu._getMenuItems(); + for(let appSubMenuIdx in appSubMenuItems){ + let subMenuItem = appSubMenuItems[appSubMenuIdx]; + subMenuItem.actor.get_parent().remove_child(subMenuItem.actor); + newSubMenuMenuItem.menu.addMenuItem(subMenuItem); + } + this.addMenuItem(newSubMenuMenuItem, i); + } else + this.addMenuItem(menuItem, i); + } + + if(i > 0) { + let separator = new PopupMenu.PopupSeparatorMenuItem(); + this.addMenuItem(separator, i); + } + } + } + + // quit menu + let app = this._source.app; + let window = this._source.window; + let count = window ? 1 : getInterestingWindows(app).length; + if ( count > 0) { + this._appendSeparator(); + let quitFromTaskbarMenuText = ""; + if (count == 1) + quitFromTaskbarMenuText = _("Quit"); + else + quitFromTaskbarMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + + this._quitfromTaskbarMenuItem = this._appendMenuItem(quitFromTaskbarMenuText); + this._quitfromTaskbarMenuItem.connect('activate', Lang.bind(this, function() { + let app = this._source.app; + let windows = window ? [window] : app.get_windows(); + for (i = 0; i < windows.length; i++) { + this._closeWindowInstance(windows[i]) + } + })); + } + } +}); +Signals.addSignalMethods(taskbarSecondaryMenu.prototype); +adjustMenuRedisplay(taskbarSecondaryMenu.prototype); + +/** + * This function is used for extendDashItemContainer + */ +function ItemShowLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.allocation.x2 - this.allocation.x1; + let itemHeight = this.allocation.y2 - this.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let position = this._dtpPanel.getPosition(); + let labelOffset = node.get_length('-x-offset'); + + // From TaskbarItemContainer + if (this._getIconAnimationOffset) + labelOffset += this._getIconAnimationOffset(); + + let xOffset = Math.floor((itemWidth - labelWidth) / 2); + let x = stageX + xOffset + let y = stageY + (itemHeight - labelHeight) * .5; + + switch(position) { + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + break; + case St.Side.BOTTOM: + y = stageY - labelHeight - labelOffset; + break; + case St.Side.LEFT: + x = stageX + labelOffset + itemWidth; + break; + case St.Side.RIGHT: + x = stageX - labelWidth - labelOffset; + break; + } + + // keep the label inside the screen border + // Only needed for the x coordinate. + + // Leave a few pixel gap + let gap = LABEL_GAP; + let monitor = Main.layoutManager.findMonitorForActor(this); + if ( x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if ( x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth -( monitor.x + monitor.width) + gap; + + this.label.set_position(Math.round(x), Math.round(y)); + + let duration = Dash.DASH_ITEM_LABEL_SHOW_TIME; + + if (duration > 1) { + duration /= 1000; + } + + Utils.animate(this.label, { + opacity: 255, + time: duration, + transition: 'easeOutQuad', + }); +}; + +/** + * A wrapper class around the ShowAppsIcon class. + * + * - Pass settings to the constructor + * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class) + * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class) + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon + * use of this class in place of the original showAppsButton. + * + */ +var ShowAppsIconWrapper = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconWrapper', + + _init: function(dtpPanel) { + this.realShowAppsIcon = new Dash.ShowAppsIcon(); + + Utils.wrapActor(this.realShowAppsIcon); + Utils.wrapActor(this.realShowAppsIcon.toggleButton); + + /* the variable equivalent to toggleButton has a different name in the appIcon class + (actor): duplicate reference to easily reuse appIcon methods */ + this.actor = this.realShowAppsIcon.toggleButton; + this.realShowAppsIcon.show(false); + + // Re-use appIcon methods + this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; + this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; + this._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; + + // No action on clicked (showing of the appsview is controlled elsewhere) + this._onClicked = Lang.bind(this, function(actor, button) { + this._removeMenuTimeout(); + }); + + this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); + this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent)); + this.actor.connect('clicked', Lang.bind(this, this._onClicked)); + this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu)); + + this._menu = null; + this._menuManager = new PopupMenu.PopupMenuManager(this.actor); + this._menuTimeoutId = 0; + + this.realShowAppsIcon._dtpPanel = dtpPanel; + Taskbar.extendDashItemContainer(this.realShowAppsIcon); + + let customIconPath = Me.settings.get_string('show-apps-icon-file'); + + this.realShowAppsIcon.icon.createIcon = function(size) { + this._iconActor = new St.Icon({ icon_name: 'view' + (Config.PACKAGE_VERSION < '3.20' ? '' : '-app') + '-grid-symbolic', + icon_size: size, + style_class: 'show-apps-icon', + track_hover: true }); + + if (customIconPath) { + this._iconActor.gicon = new Gio.FileIcon({ file: Gio.File.new_for_path(customIconPath) }); + } + + return this._iconActor; + }; + + this._changedShowAppsIconId = Me.settings.connect('changed::show-apps-icon-file', () => { + customIconPath = Me.settings.get_string('show-apps-icon-file'); + this.realShowAppsIcon.icon._createIconTexture(this.realShowAppsIcon.icon.iconSize); + }); + + this._changedAppIconPaddingId = Me.settings.connect('changed::appicon-padding', () => this.setShowAppsPadding()); + this._changedAppIconSidePaddingId = Me.settings.connect('changed::show-apps-icon-side-padding', () => this.setShowAppsPadding()); + + this.setShowAppsPadding(); + }, + + _onButtonPress: function(_actor, event) { + let button = event.get_button(); + if (button == 1) { + this._setPopupTimeout(); + } else if (button == 3) { + this.popupMenu(); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + }, + + _onLeaveEvent: function(_actor, _event) { + this.actor.fake_release(); + this._removeMenuTimeout(); + }, + + _onTouchEvent: function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) + this._setPopupTimeout(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMenuPoppedDown: function() { + this._menu.sourceActor = this.actor; + this.actor.sync_hover(); + this.emit('menu-state-changed', false); + }, + + setShowAppsPadding: function() { + let padding = getIconPadding(this.realShowAppsIcon._dtpPanel.monitor.index); + let sidePadding = Me.settings.get_int('show-apps-icon-side-padding'); + let isVertical = this.realShowAppsIcon._dtpPanel.checkIfVertical(); + + this.actor.set_style('padding:' + (padding + (isVertical ? sidePadding : 0)) + 'px ' + (padding + (isVertical ? 0 : sidePadding)) + 'px;'); + }, + + createMenu: function() { + if (!this._menu) { + this._menu = new MyShowAppsIconMenu(this.actor, this.realShowAppsIcon._dtpPanel); + this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function() { + this._menu.close(); + })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + this._menuManager.addMenu(this._menu); + } + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + this.createMenu(this.actor); + + //this.emit('menu-state-changed', true); + + this.actor.set_hover(true); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + shouldShowTooltip: function() { + return Me.settings.get_boolean('show-tooltip') && + (this.actor.hover && (!this._menu || !this._menu.isOpen)); + }, + + destroy: function() { + Me.settings.disconnect(this._changedShowAppsIconId); + Me.settings.disconnect(this._changedAppIconSidePaddingId); + Me.settings.disconnect(this._changedAppIconPaddingId); + + this.realShowAppsIcon.destroy(); + } +}); +Signals.addSignalMethods(ShowAppsIconWrapper.prototype); + +/** + * A menu for the showAppsIcon + */ +var MyShowAppsIconMenu = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconMenu', + Extends: taskbarSecondaryMenu, + ParentConstrParams: [[0], [1]], + + _dtpRedisplay: function() { + this.removeAll(); + + // Only add menu entries for commands that exist in path + function _appendItem(obj, info) { + if (Utils.checkIfCommandExists(info.cmd[0])) { + let item = obj._appendMenuItem(_(info.title)); + + item.connect('activate', function() { + Util.spawn(info.cmd); + }); + return item; + } + + return null; + } + + function _appendList(obj, commandList, titleList) { + if (commandList.length != titleList.length) { + return; + } + + for (var entry = 0; entry < commandList.length; entry++) { + _appendItem(obj, { + title: titleList[entry], + cmd: commandList[entry].split(' ') + }); + } + } + + if (this.sourceActor != Main.layoutManager.dummyCursor) { + _appendItem(this, { + title: 'Power options', + cmd: ['gnome-control-center', 'power'] + }); + + _appendItem(this, { + title: 'Event logs', + cmd: ['gnome-logs'] + }); + + _appendItem(this, { + title: 'System', + cmd: ['gnome-control-center', 'info-overview'] + }); + + _appendItem(this, { + title: 'Device Management', + cmd: ['gnome-control-center', 'display'] + }); + + _appendItem(this, { + title: 'Disk Management', + cmd: ['gnome-disks'] + }); + + _appendList( + this, + Me.settings.get_strv('show-apps-button-context-menu-commands'), + Me.settings.get_strv('show-apps-button-context-menu-titles') + ) + + this._appendSeparator(); + } + + _appendItem(this, { + title: 'Terminal', + cmd: ['gnome-terminal'] + }); + + _appendItem(this, { + title: 'System monitor', + cmd: ['gnome-system-monitor'] + }); + + _appendItem(this, { + title: 'Files', + cmd: ['nautilus'] + }); + + _appendItem(this, { + title: 'Extensions', + cmd: ['gnome-shell-extension-prefs'] + }); + + _appendItem(this, { + title: 'Settings', + cmd: ['gnome-control-center', 'wifi'] + }); + + _appendList( + this, + Me.settings.get_strv('panel-context-menu-commands'), + Me.settings.get_strv('panel-context-menu-titles') + ) + + this._appendSeparator(); + + let lockTaskbarMenuItem = this._appendMenuItem(Me.settings.get_boolean('taskbar-locked') ? _('Unlock taskbar') : _('Lock taskbar')); + lockTaskbarMenuItem.connect('activate', () => { + Me.settings.set_boolean('taskbar-locked', !Me.settings.get_boolean('taskbar-locked')); + }); + + let settingsMenuItem = this._appendMenuItem(_('Dash to Panel Settings')); + settingsMenuItem.connect('activate', function () { + let command = ["gnome-shell-extension-prefs"]; + + if (Config.PACKAGE_VERSION > '3.36') { + command = ["gnome-extensions", "prefs"]; + } + + Util.spawn(command.concat([Me.metadata.uuid])); + }); + + if(this._source._dtpPanel) { + this._appendSeparator(); + let item = this._appendMenuItem(this._source._dtpPanel._restoreWindowList ? _('Restore Windows') : _('Show Desktop')); + item.connect('activate', Lang.bind(this._source._dtpPanel, this._source._dtpPanel._onShowDesktopButtonPress)); + } + } +}); +adjustMenuRedisplay(MyShowAppsIconMenu.prototype); + +function adjustMenuRedisplay(menuProto) { + menuProto[menuRedisplayFunc] = function() { this._dtpRedisplay(menuRedisplayFunc) }; +} + +var getIconContainerStyle = function(isVertical) { + let style = 'padding: '; + + if (Me.settings.get_boolean('group-apps')) { + style += (isVertical ? '0;' : '0 ' + DEFAULT_PADDING_SIZE + 'px;'); + } else { + style += (isVertical ? '' : '0 ') + DEFAULT_PADDING_SIZE + 'px;'; + } + + return style; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js new file mode 100644 index 0000000..57d2f13 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js @@ -0,0 +1,89 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // Check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) + Gettext.bindtextdomain(domain, localeDir.get_path()); + else + Gettext.bindtextdomain(domain, Config.LOCALEDIR); +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + else + schemaSource = GioSSS.get_default(); + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error('Schema ' + schema + ' could not be found for extension ' + + extension.metadata.uuid + '. Please check your installation.'); + + return new Gio.Settings({ + settings_schema: schemaObj + }); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js new file mode 100644 index 0000000..7ab80f2 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js @@ -0,0 +1,149 @@ +/* + * Dash-To-Panel extension for Gnome 3 + * Copyright 2016 Jason DeRose (jderose9) and Charles Gagnon (charlesg99) + * + * 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 2 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 . + * + */ + + +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Lang = imports.lang; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const ExtensionUtils = imports.misc.extensionUtils; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + +const Me = ExtensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const PanelManager = Me.imports.panelManager; +const Utils = Me.imports.utils; + +const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +let panelManager; +let extensionChangedHandler; +let disabledUbuntuDock; +let extensionSystem = (Main.extensionManager || imports.ui.extensionSystem); + +function init() { + this._realHasOverview = Main.sessionMode.hasOverview; + + Convenience.initTranslations(Utils.TRANSLATION_DOMAIN); + + //create an object that persists until gnome-shell is restarted, even if the extension is disabled + Me.persistentStorage = {}; +} + +function enable() { + // The Ubuntu Dock extension might get enabled after this extension + extensionChangedHandler = extensionSystem.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === UBUNTU_DOCK_UUID && extension.state === 1) { + _enable(); + } + }); + + //create a global object that can emit signals and conveniently expose functionalities to other extensions + global.dashToPanel = {}; + Signals.addSignalMethods(global.dashToPanel); + + _enable(); +} + +function _enable() { + let ubuntuDock = Main.extensionManager ? + Main.extensionManager.lookup(UBUNTU_DOCK_UUID) : //gnome-shell >= 3.33.4 + ExtensionUtils.extensions[UBUNTU_DOCK_UUID]; + + if (ubuntuDock && ubuntuDock.stateObj && ubuntuDock.stateObj.dockManager) { + // Disable Ubuntu Dock + let extensionOrder = (extensionSystem.extensionOrder || extensionSystem._extensionOrder); + + Utils.getStageTheme().get_theme().unload_stylesheet(ubuntuDock.stylesheet); + ubuntuDock.stateObj.disable(); + disabledUbuntuDock = true; + ubuntuDock.state = 2; //ExtensionState.DISABLED + extensionOrder.splice(extensionOrder.indexOf(UBUNTU_DOCK_UUID), 1); + + //reset to prevent conflicts with the ubuntu-dock + if (panelManager) { + disable(true); + } + } + + if (panelManager) return; //already initialized + + Me.settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + Me.desktopSettings = Convenience.getSettings('org.gnome.desktop.interface'); + + Main.layoutManager.startInOverview = !Me.settings.get_boolean('hide-overview-on-startup'); + + if (Me.settings.get_boolean('hide-overview-on-startup') && Main.layoutManager._startingUp) { + Main.sessionMode.hasOverview = false; + Main.layoutManager.connect('startup-complete', () => { + Main.sessionMode.hasOverview = this._realHasOverview + }); + } + + panelManager = new PanelManager.dtpPanelManager(); + + panelManager.enable(); + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(this, function() { + if(Me.settings.get_boolean('show-appmenu')) + Main.wm._toggleAppMenu(); + else + panelManager.primaryPanel.taskbar.popupFocusedAppSecondaryMenu(); + }), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); +} + +function disable(reset) { + panelManager.disable(); + Me.settings.run_dispose(); + Me.desktopSettings.run_dispose(); + + delete Me.settings; + panelManager = null; + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(Main.wm, Main.wm._toggleAppMenu), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); + + if (!reset) { + extensionSystem.disconnect(extensionChangedHandler); + delete global.dashToPanel; + + // Re-enable Ubuntu Dock if it was disabled by dash to panel + if (disabledUbuntuDock && Main.sessionMode.allowExtensions) { + (extensionSystem._callExtensionEnable || extensionSystem.enableExtension).call(extensionSystem, UBUNTU_DOCK_UUID); + } + } + + Main.sessionMode.hasOverview = this._realHasOverview; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg new file mode 100644 index 0000000..977146b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg new file mode 100644 index 0000000..47aa802 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg new file mode 100644 index 0000000..80420fd --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js new file mode 100644 index 0000000..8fb1e97 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js @@ -0,0 +1,401 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +var GrabHelper = imports.ui.grabHelper; +const Layout = imports.ui.layout; +const Main = imports.ui.main; +const OverviewControls = imports.ui.overviewControls; +const PointerWatcher = imports.ui.pointerWatcher; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +//timeout intervals +const CHECK_POINTER_MS = 200; +const CHECK_GRAB_MS = 400; +const POST_ANIMATE_MS = 50; +const MIN_UPDATE_MS = 250; + +//timeout names +const T1 = 'checkGrabTimeout'; +const T2 = 'limitUpdateTimeout'; +const T3 = 'postAnimateTimeout'; +const T4 = 'panelBoxClipTimeout'; + +var SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1); + +var Hold = { + NONE: 0, + TEMPORARY: 1, + PERMANENT: 2 +}; + +var Intellihide = Utils.defineClass({ + Name: 'DashToPanel.Intellihide', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._panelBox = dtpPanel.panelBox; + this._panelManager = dtpPanel.panelManager; + this._proximityManager = this._panelManager.proximityManager; + this._holdStatus = Hold.NONE; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._intellihideChangedId = Me.settings.connect('changed::intellihide', () => this._changeEnabledStatus()); + this._intellihideOnlySecondaryChangedId = Me.settings.connect('changed::intellihide-only-secondary', () => this._changeEnabledStatus()); + + this.enabled = false; + this._changeEnabledStatus(); + }, + + enable: function() { + this.enabled = true; + this._monitor = this._dtpPanel.monitor; + this._animationDestination = -1; + this._pendingUpdate = false; + this._hoveredOut = false; + this._windowOverlap = false; + this._translationProp = 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y'); + + this._panelBox.translation_y = 0; + this._panelBox.translation_x = 0; + + this._setTrackPanel(true); + this._bindGeneralSignals(); + + if (Me.settings.get_boolean('intellihide-hide-from-windows')) { + this._proximityWatchId = this._proximityManager.createWatch( + this._panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('intellihide-behaviour')], + 0, 0, + overlap => { + this._windowOverlap = overlap; + this._queueUpdatePanelPosition(); + } + ); + } + + this._setRevealMechanism(); + this._queueUpdatePanelPosition(); + }, + + disable: function(reset) { + if (this._proximityWatchId) { + this._proximityManager.removeWatch(this._proximityWatchId); + } + + this._setTrackPanel(false); + + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + + this._removeRevealMechanism(); + + this._revealPanel(!reset); + + this.enabled = false; + }, + + destroy: function() { + Me.settings.disconnect(this._intellihideChangedId); + Me.settings.disconnect(this._intellihideOnlySecondaryChangedId); + + if (this.enabled) { + this.disable(); + } + }, + + toggle: function() { + this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](Hold.PERMANENT); + }, + + revealAndHold: function(holdStatus) { + if (this.enabled && !this._holdStatus) { + this._revealPanel(); + } + + this._holdStatus |= holdStatus; + }, + + release: function(holdStatus) { + this._holdStatus -= holdStatus; + + if (this.enabled && !this._holdStatus) { + this._queueUpdatePanelPosition(); + } + }, + + reset: function() { + this.disable(true); + this.enable(); + }, + + _changeEnabledStatus: function() { + let intellihide = Me.settings.get_boolean('intellihide'); + let onlySecondary = Me.settings.get_boolean('intellihide-only-secondary'); + let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary); + + if (this.enabled !== enabled) { + this[enabled ? 'enable' : 'disable'](); + } + }, + + _bindGeneralSignals: function() { + this._signalsHandler.add( + [ + this._dtpPanel.taskbar, + 'menu-closed', + () => this._panelBox.sync_hover() + ], + [ + Me.settings, + [ + 'changed::intellihide-use-pressure', + 'changed::intellihide-hide-from-windows', + 'changed::intellihide-behaviour', + 'changed::intellihide-pressure-threshold', + 'changed::intellihide-pressure-time' + ], + () => this.reset() + ], + [ + this._panelBox, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._dtpPanel.taskbar.previewMenu, + 'open-state-changed', + () => this._queueUpdatePanelPosition() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._queueUpdatePanelPosition() + ] + ); + }, + + _onHoverChanged: function() { + this._hoveredOut = !this._panelBox.hover; + this._queueUpdatePanelPosition(); + }, + + _setTrackPanel: function(enable) { + let trackedIndex = Main.layoutManager._findActor(this._panelBox); + let actorData = Main.layoutManager._trackedActors[trackedIndex] + + actorData.affectsStruts = !enable; + actorData.trackFullscreen = !enable; + + this._panelBox.track_hover = enable; + this._panelBox.reactive = enable; + this._panelBox.visible = enable ? enable : this._panelBox.visible; + + Main.layoutManager._queueUpdateRegions(); + }, + + _setRevealMechanism: function() { + if (global.display.supports_extended_barriers() && Me.settings.get_boolean('intellihide-use-pressure')) { + this._edgeBarrier = this._createBarrier(); + this._pressureBarrier = new Layout.PressureBarrier( + Me.settings.get_int('intellihide-pressure-threshold'), + Me.settings.get_int('intellihide-pressure-time'), + Shell.ActionMode.NORMAL + ); + this._pressureBarrier.addBarrier(this._edgeBarrier); + this._signalsHandler.add([this._pressureBarrier, 'trigger', () => this._queueUpdatePanelPosition(true)]); + } else { + this._pointerWatch = PointerWatcher.getPointerWatcher() + .addWatch(CHECK_POINTER_MS, (x, y) => this._checkMousePointer(x, y)); + } + }, + + _removeRevealMechanism: function() { + if (this._pointerWatch) { + PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch); + } + + if (this._pressureBarrier) { + this._pressureBarrier.destroy(); + this._edgeBarrier.destroy(); + } + }, + + _createBarrier: function() { + let position = this._dtpPanel.geom.position; + let opts = { display: global.display }; + + if (this._dtpPanel.checkIfVertical()) { + opts.y1 = this._monitor.y; + opts.y2 = this._monitor.y + this._monitor.height; + opts.x1 = opts.x2 = this._monitor.x; + } else { + opts.x1 = this._monitor.x; + opts.x2 = this._monitor.x + this._monitor.width; + opts.y1 = opts.y2 = this._monitor.y; + } + + if (position == St.Side.TOP) { + opts.directions = Meta.BarrierDirection.POSITIVE_Y; + } else if (position == St.Side.BOTTOM) { + opts.y1 = opts.y2 = opts.y1 + this._monitor.height; + opts.directions = Meta.BarrierDirection.NEGATIVE_Y; + } else if (position == St.Side.LEFT) { + opts.directions = Meta.BarrierDirection.POSITIVE_X; + } else { + opts.x1 = opts.x2 = opts.x1 + this._monitor.width; + opts.directions = Meta.BarrierDirection.NEGATIVE_X; + } + + return new Meta.Barrier(opts); + }, + + _checkMousePointer: function(x, y) { + let position = this._dtpPanel.geom.position; + + if (!this._panelBox.hover && !Main.overview.visible && + ((position == St.Side.TOP && y <= this._monitor.y + 1) || + (position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - 1) || + (position == St.Side.LEFT && x <= this._monitor.x + 1) || + (position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - 1)) && + ((x >= this._monitor.x && x < this._monitor.x + this._monitor.width) && + (y >= this._monitor.y && y < this._monitor.y + this._monitor.height))) { + this._queueUpdatePanelPosition(true); + } + }, + + _queueUpdatePanelPosition: function(fromRevealMechanism) { + if (!fromRevealMechanism && this._timeoutsHandler.getId(T2) && !Main.overview.visible) { + //unless this is a mouse interaction or entering/leaving the overview, limit the number + //of updates, but remember to update again when the limit timeout is reached + this._pendingUpdate = true; + } else if (!this._holdStatus) { + this._checkIfShouldBeVisible(fromRevealMechanism) ? this._revealPanel() : this._hidePanel(); + this._timeoutsHandler.add([T2, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + } + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdatePanelPosition(); + } + }, + + _checkIfShouldBeVisible: function(fromRevealMechanism) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || + this._panelBox.get_hover() || this._checkIfGrab()) { + return true; + } + + if (fromRevealMechanism) { + let mouseBtnIsPressed = global.get_pointer()[2] & Clutter.ModifierType.BUTTON1_MASK; + + //the user is trying to reveal the panel + if (this._monitor.inFullscreen && !mouseBtnIsPressed) { + return Me.settings.get_boolean('intellihide-show-in-fullscreen'); + } + + return !mouseBtnIsPressed; + } + + if (!Me.settings.get_boolean('intellihide-hide-from-windows')) { + return this._panelBox.hover; + } + + return !this._windowOverlap; + }, + + _checkIfGrab: function() { + if (GrabHelper._grabHelperStack.some(gh => gh._owner == this._dtpPanel.panel.actor)) { + //there currently is a grab on a child of the panel, check again soon to catch its release + this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]); + + return true; + } + }, + + _revealPanel: function(immediate) { + if (!this._panelBox.visible) { + this._panelBox.visible = true; + this._dtpPanel.taskbar._shownInitially = false; + } + + this._animatePanel(0, immediate); + }, + + _hidePanel: function(immediate) { + let position = this._dtpPanel.geom.position; + let size = this._panelBox[position == St.Side.LEFT || position == St.Side.RIGHT ? 'width' : 'height']; + let coefficient = position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1; + + this._animatePanel(size * coefficient, immediate); + }, + + _animatePanel: function(destination, immediate) { + let animating = Utils.isAnimating(this._panelBox, this._translationProp); + + if (!((animating && destination === this._animationDestination) || + (!animating && destination === this._panelBox[this._translationProp]))) { + //the panel isn't already at, or animating to the asked destination + if (animating) { + Utils.stopAnimations(this._panelBox); + } + + this._animationDestination = destination; + + if (immediate) { + this._panelBox[this._translationProp] = destination; + this._panelBox.visible = !destination; + } else { + let tweenOpts = { + //when entering/leaving the overview, use its animation time instead of the one from the settings + time: Main.overview.visible ? + SIDE_CONTROLS_ANIMATION_TIME : + Me.settings.get_int('intellihide-animation-time') * 0.001, + //only delay the animation when hiding the panel after the user hovered out + delay: destination != 0 && this._hoveredOut ? Me.settings.get_int('intellihide-close-delay') * 0.001 : 0, + transition: 'easeOutQuad', + onComplete: () => { + this._panelBox.visible = !destination; + Main.layoutManager._queueUpdateRegions(); + this._timeoutsHandler.add([T3, POST_ANIMATE_MS, () => this._queueUpdatePanelPosition()]); + } + }; + + tweenOpts[this._translationProp] = destination; + Utils.animate(this._panelBox, tweenOpts); + } + } + + this._hoveredOut = false; + }, +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8425f68 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..86da090 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..7a5af2f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..70da5fa Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..f52e89a Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2fd26da Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..c467e93 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bd1a46 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..84eac31 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..99b526b Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8ae66e3 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..0d64932 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..e7cacbb Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bc58a5 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2993304 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..26ed613 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..ed1cc6d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json new file mode 100644 index 0000000..4b11eea --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json @@ -0,0 +1,13 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "An icon taskbar for the Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications.\n\nFor a more traditional experience, you may also want to use Tweak Tool to enable Windows > Titlebar Buttons > Minimize & Maximize.\n\nFor the best support, please report any issues on Github. Dash-to-panel is developed and maintained by @jderose9 and @charlesg99.", + "extension-id": "dash-to-panel", + "gettext-domain": "dash-to-panel", + "name": "Dash to Panel", + "shell-version": [ + "40" + ], + "url": "https://github.com/home-sweet-gnome/dash-to-panel", + "uuid": "dash-to-panel@jderose9.github.com", + "version": 44 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js new file mode 100644 index 0000000..57600a5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js @@ -0,0 +1,708 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Intellihide = Me.imports.intellihide; +const Utils = Me.imports.utils; + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Lang = imports.lang; +const Main = imports.ui.main; +const Shell = imports.gi.Shell; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; +const Mainloop = imports.mainloop; +const IconGrid = imports.ui.iconGrid; +const OverviewControls = imports.ui.overviewControls; +const Workspace = imports.ui.workspace; +const St = imports.gi.St; +const WorkspaceThumbnail = imports.ui.workspaceThumbnail; + +const Meta = imports.gi.Meta; + +const GS_HOTKEYS_KEY = 'switch-to-application-'; +const BACKGROUND_MARGIN = 12; +const SMALL_WORKSPACE_RATIO = 0.15; +const DASH_MAX_HEIGHT_RATIO = 0.15; + + +//timeout names +const T1 = 'swipeEndTimeout'; + +var dtpOverview = Utils.defineClass({ + Name: 'DashToPanel.Overview', + + _init: function() { + this._numHotkeys = 10; + this._timeoutsHandler = new Utils.TimeoutsHandler(); + }, + + enable : function(panel) { + this._panel = panel; + this.taskbar = panel.taskbar; + + this._injectionsHandler = new Utils.InjectionsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._optionalWorkspaceIsolation(); + this._optionalHotKeys(); + this._optionalNumberOverlay(); + this._optionalClickToExit(); + this._toggleDash(); + this._hookupAllocation(); + + this._signalsHandler.add([ + Me.settings, + 'changed::stockgs-keep-dash', + () => this._toggleDash() + ]); + + }, + + disable: function () { + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', Workspace.WorkspaceBackground.prototype.vfunc_allocate); + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', OverviewControls.ControlsManagerLayout.prototype.vfunc_allocate); + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = this._oldComputeWorkspacesBoxForState; + + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); + + this._toggleDash(true); + + // Remove key bindings + this._disableHotKeys(); + this._disableExtraShortcut(); + this._disableClickToExit(); + }, + + _toggleDash: function(visible) { + // To hide the dash, set its width to 1, so it's almost not taken into account by code + // calculaing the reserved space in the overview. The reason to keep it at 1 is + // to allow its visibility change to trigger an allocaion of the appGrid which + // in turn is triggergin the appsIcon spring animation, required when no other + // actors has this effect, i.e in horizontal mode and without the workspaceThumnails + // 1 static workspace only) + + if (visible === undefined) { + visible = Me.settings.get_boolean('stockgs-keep-dash'); + } + + let visibilityFunc = visible ? 'show' : 'hide'; + let width = visible ? -1 : 1; + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + + overviewControls.dash.actor[visibilityFunc](); + overviewControls.dash.actor.set_width(width); + + // This force the recalculation of the icon size + overviewControls.dash._maxHeight = -1; + }, + + /** + * Isolate overview to open new windows for inactive apps + */ + _optionalWorkspaceIsolation: function() { + let label = 'optionalWorkspaceIsolation'; + + this._signalsHandler.add([ + Me.settings, + 'changed::isolate-workspaces', + Lang.bind(this, function() { + this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons()); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + else + Lang.bind(this, disable)(); + }) + ]); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + + function enable() { + this._injectionsHandler.removeWithLabel(label); + + this._injectionsHandler.addWithLabel(label, [ + Shell.App.prototype, + 'activate', + IsolatedOverview + ]); + + this._signalsHandler.removeWithLabel(label); + + this._signalsHandler.addWithLabel(label, [ + global.window_manager, + 'switch-workspace', + () => this._panel.panelManager.allPanels.forEach(p => p.taskbar.handleIsolatedWorkspaceSwitch()) + ]); + } + + function disable() { + this._signalsHandler.removeWithLabel(label); + this._injectionsHandler.removeWithLabel(label); + } + + function IsolatedOverview() { + // These lines take care of Nautilus for icons on Desktop + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = this.get_windows().filter(w => w.get_workspace().index() == activeWorkspace.index()); + + if (windows.length > 0 && + (!(windows.length == 1 && windows[0].skip_taskbar) || + this.is_on_workspace(activeWorkspace))) + return Main.activateWindow(windows[0]); + + return this.open_new_window(-1); + } + }, + + // Hotkeys + _activateApp: function(appIndex) { + let seenApps = {}; + let apps = []; + + this.taskbar._getAppIcons().forEach(function(appIcon) { + if (!seenApps[appIcon.app]) { + apps.push(appIcon); + } + + seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1; + }); + + this._showOverlay(); + + if (appIndex < apps.length) { + let appIcon = apps[appIndex]; + let seenAppCount = seenApps[appIcon.app]; + let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows; + + if (Me.settings.get_boolean('shortcut-previews') && windowCount > 1 && + !(Clutter.get_current_event().get_state() & ~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.MOD4_MASK))) { //ignore the alt (MOD1_MASK) and super key (MOD4_MASK) + if (this._hotkeyPreviewCycleInfo && this._hotkeyPreviewCycleInfo.appIcon != appIcon) { + this._endHotkeyPreviewCycle(); + } + + if (!this._hotkeyPreviewCycleInfo) { + this._hotkeyPreviewCycleInfo = { + appIcon: appIcon, + currentWindow: appIcon.window, + keyFocusOutId: appIcon.actor.connect('key-focus-out', () => appIcon.actor.grab_key_focus()), + capturedEventId: global.stage.connect('captured-event', (actor, e) => { + if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)) { + this._endHotkeyPreviewCycle(true); + } + + return Clutter.EVENT_PROPAGATE; + }) + }; + + appIcon._hotkeysCycle = appIcon.window; + appIcon.window = null; + appIcon._previewMenu.open(appIcon); + appIcon.actor.grab_key_focus(); + } + + appIcon._previewMenu.focusNext(); + } else { + // Activate with button = 1, i.e. same as left click + let button = 1; + this._endHotkeyPreviewCycle(); + appIcon.activate(button, true); + } + } + }, + + _endHotkeyPreviewCycle: function(focusWindow) { + if (this._hotkeyPreviewCycleInfo) { + global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId); + this._hotkeyPreviewCycleInfo.appIcon.actor.disconnect(this._hotkeyPreviewCycleInfo.keyFocusOutId); + + if (focusWindow) { + this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused(); + } + + this._hotkeyPreviewCycleInfo.appIcon.window = this._hotkeyPreviewCycleInfo.currentWindow; + delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle; + this._hotkeyPreviewCycleInfo = 0; + } + }, + + _optionalHotKeys: function() { + this._hotKeysEnabled = false; + if (Me.settings.get_boolean('hot-keys')) + this._enableHotKeys(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys')) + Lang.bind(this, this._enableHotKeys)(); + else + Lang.bind(this, this._disableHotKeys)(); + }) + ]); + }, + + _resetHotkeys: function() { + this._disableHotKeys(); + this._enableHotKeys(); + }, + + _enableHotKeys: function() { + if (this._hotKeysEnabled) + return; + + //3.32 introduced app hotkeys, disable them to prevent conflicts + if (Main.wm._switchToApplication) { + for (let i = 1; i < 10; ++i) { + Utils.removeKeybinding(GS_HOTKEYS_KEY + i); + } + } + + // Setup keyboard bindings for taskbar elements + let shortcutNumKeys = Me.settings.get_string('shortcut-num-keys'); + let bothNumKeys = shortcutNumKeys == 'BOTH'; + let keys = []; + + if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') { + keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'); // Regular numbers + } + + if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') { + keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-'); // Key-pad numbers + } + + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + let appNum = i; + + Utils.addKeybinding(key + (i + 1), Me.settings, () => this._activateApp(appNum)); + } + }, this); + + this._hotKeysEnabled = true; + + if (Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + }, + + _disableHotKeys: function() { + if (!this._hotKeysEnabled) + return; + + let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-', // Regular numbers + 'app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-']; // Key-pad numbers + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + Utils.removeKeybinding(key + (i + 1)); + } + }, this); + + if (Main.wm._switchToApplication) { + let gsSettings = new Gio.Settings({ schema_id: imports.ui.windowManager.SHELL_KEYBINDINGS_SCHEMA }); + + for (let i = 1; i < 10; ++i) { + Utils.addKeybinding(GS_HOTKEYS_KEY + i, gsSettings, Main.wm._switchToApplication.bind(Main.wm)); + } + } + + this._hotKeysEnabled = false; + + this.taskbar.toggleNumberOverlay(false); + }, + + _optionalNumberOverlay: function() { + // Enable extra shortcut + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, this._checkHotkeysOptions) + ], [ + Me.settings, + 'changed::hotkeys-overlay-combo', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys') && Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + else + this.taskbar.toggleNumberOverlay(false); + }) + ], [ + Me.settings, + 'changed::shortcut-num-keys', + () => this._resetHotkeys() + ]); + }, + + _checkHotkeysOptions: function() { + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + else + this._disableExtraShortcut(); + }, + + _enableExtraShortcut: function() { + Utils.addKeybinding('shortcut', Me.settings, () => this._showOverlay(true)); + }, + + _disableExtraShortcut: function() { + Utils.removeKeybinding('shortcut'); + }, + + _showOverlay: function(overlayFromShortcut) { + //wait for intellihide timeout initialization + if (!this._panel.intellihide) { + return; + } + + // Restart the counting if the shortcut is pressed again + if (this._numberOverlayTimeoutId) { + Mainloop.source_remove(this._numberOverlayTimeoutId); + this._numberOverlayTimeoutId = 0; + } + + let hotkey_option = Me.settings.get_string('hotkeys-overlay-combo'); + + if (hotkey_option === 'NEVER') + return; + + if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut) + this.taskbar.toggleNumberOverlay(true); + + this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY); + + let timeout = Me.settings.get_int('overlay-timeout'); + + if (overlayFromShortcut) { + timeout = Me.settings.get_int('shortcut-timeout'); + } + + // Hide the overlay/dock after the timeout + this._numberOverlayTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, function() { + this._numberOverlayTimeoutId = 0; + + if (hotkey_option != 'ALWAYS') { + this.taskbar.toggleNumberOverlay(false); + } + + this._panel.intellihide.release(Intellihide.Hold.TEMPORARY); + })); + }, + + _optionalClickToExit: function() { + this._clickToExitEnabled = false; + if (Me.settings.get_boolean('overview-click-to-exit')) + this._enableClickToExit(); + + this._signalsHandler.add([ + Me.settings, + 'changed::overview-click-to-exit', + Lang.bind(this, function() { + if (Me.settings.get_boolean('overview-click-to-exit')) + Lang.bind(this, this._enableClickToExit)(); + else + Lang.bind(this, this._disableClickToExit)(); + }) + ]); + }, + + _enableClickToExit: function() { + if (this._clickToExitEnabled) + return; + + let view = imports.ui.appDisplay; + this._oldOverviewReactive = Main.overview._overview.reactive + + Main.overview._overview.reactive = true; + + this._clickAction = new Clutter.ClickAction(); + this._clickAction.connect('clicked', () => { + + if (this._swiping) + return Clutter.EVENT_PROPAGATE; + + let [x, y] = global.get_pointer(); + let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); + + Main.overview.toggle(); + }); + Main.overview._overview.add_action(this._clickAction); + + this._clickToExitEnabled = true; + }, + + _disableClickToExit: function () { + if (!this._clickToExitEnabled) + return; + + Main.overview._overview.remove_action(this._clickAction); + Main.overview._overview.reactive = this._oldOverviewReactive; + + this._signalsHandler.removeWithLabel('clickToExit'); + + this._clickToExitEnabled = false; + }, + + _onSwipeBegin: function() { + this._swiping = true; + return true; + }, + + _onSwipeEnd: function() { + this._timeoutsHandler.add([ + T1, + 0, + () => this._swiping = false + ]); + return true; + }, + + _hookupAllocation: function() { + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', function vfunc_allocate(container, box) { + const childBox = new Clutter.ActorBox(); + + const { spacing } = this; + + let startY = 0; + let startX = 0; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) { + startY = Main.layoutManager.panelBox.height; + box.y1 += startY; + } + + const panel = global.dashToPanel.panels[0]; + if(panel) { + switch (panel.getPosition()) { + case St.Side.TOP: + startY = panel.panelBox.height; + box.y1 += startY; + break; + case St.Side.LEFT: + startX = panel.panelBox.width; + box.x1 += startX; + break; + case St.Side.RIGHT: + box.x2 -= panel.panelBox.width; + break; + + } + } + + + const [width, height] = box.get_size(); + let availableHeight = height; + + // Search entry + let [searchHeight] = this._searchEntry.get_preferred_height(width); + childBox.set_origin(startX, startY); + childBox.set_size(width, searchHeight); + this._searchEntry.allocate(childBox); + + availableHeight -= searchHeight + spacing; + + // Dash + const maxDashHeight = Math.round(box.get_height() * DASH_MAX_HEIGHT_RATIO); + this._dash.setMaxSize(width, maxDashHeight); + + let [, dashHeight] = this._dash.get_preferred_height(width); + if (Me.settings.get_boolean('stockgs-keep-dash')) + dashHeight = Math.min(dashHeight, maxDashHeight); + else + dashHeight = spacing*5; // todo: determine proper spacing for window labels on maximized windows on workspace display + childBox.set_origin(startX, startY + height - dashHeight); + childBox.set_size(width, dashHeight); + this._dash.allocate(childBox); + + availableHeight -= dashHeight + spacing; + + // Workspace Thumbnails + let thumbnailsHeight = 0; + if (this._workspacesThumbnails.visible) { + const { expandFraction } = this._workspacesThumbnails; + [thumbnailsHeight] = + this._workspacesThumbnails.get_preferred_height(width); + thumbnailsHeight = Math.min( + thumbnailsHeight * expandFraction, + height * WorkspaceThumbnail.MAX_THUMBNAIL_SCALE); + childBox.set_origin(startX, startY + searchHeight + spacing); + childBox.set_size(width, thumbnailsHeight); + this._workspacesThumbnails.allocate(childBox); + } + + // Workspaces + let params = [box, startX, startY, searchHeight, dashHeight, thumbnailsHeight]; + const transitionParams = this._stateAdjustment.getStateTransitionParams(); + + // Update cached boxes + for (const state of Object.values(OverviewControls.ControlsState)) { + this._cachedWorkspaceBoxes.set( + state, this._computeWorkspacesBoxForState(state, ...params)); + } + + let workspacesBox; + if (!transitionParams.transitioning) { + workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); + } else { + const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); + const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); + workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._workspacesDisplay.allocate(workspacesBox); + + // AppDisplay + if (this._appDisplay.visible) { + const workspaceAppGridBox = + this._cachedWorkspaceBoxes.get(OverviewControls.ControlsState.APP_GRID); + + if (Config.PACKAGE_VERSION > '40.3') { + const monitor = Main.layoutManager.findMonitorForActor(this._container); + const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); + const workAreaBox = new Clutter.ActorBox(); + + workAreaBox.set_origin(startX, startY); + workAreaBox.set_size(workArea.width, workArea.height); + + params = [workAreaBox, searchHeight, dashHeight, workspaceAppGridBox] + } else { + params = [box, startX, searchHeight, dashHeight, workspaceAppGridBox]; + } + + let appDisplayBox; + if (!transitionParams.transitioning) { + appDisplayBox = + this._getAppDisplayBoxForState(transitionParams.currentState, ...params); + } else { + const initialBox = + this._getAppDisplayBoxForState(transitionParams.initialState, ...params); + const finalBox = + this._getAppDisplayBoxForState(transitionParams.finalState, ...params); + + appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._appDisplay.allocate(appDisplayBox); + } + + // Search + childBox.set_origin(0, startY + searchHeight + spacing); + childBox.set_size(width, availableHeight); + + this._searchController.allocate(childBox); + + this._runPostAllocation(); + }); + + this._oldComputeWorkspacesBoxForState = OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState; + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = function _computeWorkspacesBoxForState(state, box, startX, startY, searchHeight, dashHeight, thumbnailsHeight) { + const workspaceBox = box.copy(); + const [width, height] = workspaceBox.get_size(); + const { spacing } = this; + const { expandFraction } = this._workspacesThumbnails; + + switch (state) { + case OverviewControls.ControlsState.HIDDEN: + break; + case OverviewControls.ControlsState.WINDOW_PICKER: + workspaceBox.set_origin(startX, + startY + searchHeight + spacing + + thumbnailsHeight + spacing * expandFraction); + workspaceBox.set_size(width, + height - + dashHeight - spacing - + searchHeight - spacing - + thumbnailsHeight - spacing * expandFraction); + break; + case OverviewControls.ControlsState.APP_GRID: + workspaceBox.set_origin(startX, startY + searchHeight + spacing); + workspaceBox.set_size( + width, + Math.round(height * SMALL_WORKSPACE_RATIO)); + break; + } + + return workspaceBox; + } + + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', function vfunc_allocate(box) { + const [width, height] = box.get_size(); + const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const scaledHeight = height - (BACKGROUND_MARGIN * 2 * scaleFactor); + const scaledWidth = (scaledHeight / height) * width; + + const scaledBox = box.copy(); + scaledBox.set_origin( + box.x1 + (width - scaledWidth) / 2, + box.y1 + (height - scaledHeight) / 2); + scaledBox.set_size(scaledWidth, scaledHeight); + + const progress = this._stateAdjustment.value; + + if (progress === 1) + box = scaledBox; + else if (progress !== 0) + box = box.interpolate(scaledBox, progress); + + this.set_allocation(box); + + const themeNode = this.get_theme_node(); + const contentBox = themeNode.get_content_box(box); + + this._bin.allocate(contentBox); + + + const [contentWidth, contentHeight] = contentBox.get_size(); + const monitor = Main.layoutManager.monitors[this._monitorIndex]; + let xOff = (contentWidth / this._workarea.width) * + (this._workarea.x - monitor.x); + let yOff = (contentHeight / this._workarea.height) * + (this._workarea.y - monitor.y); + + let startX = -xOff; + let startY = -yOff; + const panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == this._monitorIndex); + switch (panel.getPosition()) { + case St.Side.TOP: + yOff += panel.panelBox.height; + startY -= panel.panelBox.height; + break; + case St.Side.BOTTOM: + yOff += panel.panelBox.height; + break; + case St.Side.RIGHT: + xOff += panel.panelBox.width; + break; + } + contentBox.set_origin(startX, startY); + contentBox.set_size(xOff + contentWidth, yOff + contentHeight); + this._backgroundGroup.allocate(contentBox); + }); + + } +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js new file mode 100644 index 0000000..5e0b5f9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js @@ -0,0 +1,1512 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gtk = imports.gi.Gtk; +const Gi = imports._gi; +const AppIcons = Me.imports.appIcons; +const Utils = Me.imports.utils; +const Taskbar = Me.imports.taskbar; +const Pos = Me.imports.panelPositions; +const PanelSettings = Me.imports.panelSettings; +const PanelStyle = Me.imports.panelStyle; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Dash = imports.ui.dash; +const CtrlAltTab = imports.ui.ctrlAltTab; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const St = imports.gi.St; +const GLib = imports.gi.GLib; +const Meta = imports.gi.Meta; +const Pango = imports.gi.Pango; +const DND = imports.ui.dnd; +const Shell = imports.gi.Shell; +const PopupMenu = imports.ui.popupMenu; +const IconGrid = imports.ui.iconGrid; +const DateMenu = imports.ui.dateMenu; +const Volume = imports.ui.status.volume; +const Progress = Me.imports.progress; + +const Intellihide = Me.imports.intellihide; +const Transparency = Me.imports.transparency; +const _ = imports.gettext.domain(Me.imports.utils.TRANSLATION_DOMAIN).gettext; + +let tracker = Shell.WindowTracker.get_default(); +var panelBoxes = ['_leftBox', '_centerBox', '_rightBox']; + +//timeout names +const T1 = 'startDynamicTransparencyTimeout'; +const T2 = 'startIntellihideTimeout'; +const T3 = 'allocationThrottleTimeout'; +const T4 = 'showDesktopTimeout'; +const T5 = 'trackerFocusAppTimeout'; +const T6 = 'scrollPanelDelayTimeout'; +const T7 = 'waitPanelBoxAllocation'; + +var dtpPanel = Utils.defineClass({ + Name: 'DashToPanel-Panel', + Extends: St.Widget, + + _init: function(panelManager, monitor, panelBox, isStandalone) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this.panelManager = panelManager; + this.panelStyle = new PanelStyle.dtpPanelStyle(); + + this.monitor = monitor; + this.panelBox = panelBox; + + // when the original gnome-shell top panel is kept, all panels are "standalone", + // so in this case use isPrimary to get the panel on the primary dtp monitor, which + // might be different from the system's primary monitor. + this.isStandalone = isStandalone; + this.isPrimary = !isStandalone || (Me.settings.get_boolean('stockgs-keep-top-panel') && + monitor == panelManager.dtpPrimaryMonitor); + + this._sessionStyle = null; + this._unmappedButtons = []; + this._elementGroups = []; + this.cornerSize = 0; + + let position = this.getPosition(); + + if (isStandalone) { + this.panel = new dtpSecondaryPanel({ name: 'panel', reactive: true }); + this.statusArea = this.panel.statusArea = {}; + + Utils.wrapActor(this.panel); + + //next 3 functions are needed by other extensions to add elements to the secondary panel + this.panel.addToStatusArea = function(role, indicator, position, box) { + return Main.panel.addToStatusArea.call(this, role, indicator, position, box); + }; + + this.panel._addToPanelBox = function(role, indicator, position, box) { + Main.panel._addToPanelBox.call(this, role, indicator, position, box); + }; + + this.panel._onMenuSet = function(indicator) { + Main.panel._onMenuSet.call(this, indicator); + }; + + this._leftBox = this.panel._leftBox = new St.BoxLayout({ name: 'panelLeft' }); + this._centerBox = this.panel._centerBox = new St.BoxLayout({ name: 'panelCenter' }); + this._rightBox = this.panel._rightBox = new St.BoxLayout({ name: 'panelRight' }); + + this.menuManager = this.panel.menuManager = new PopupMenu.PopupMenuManager(this.panel); + + this._setPanelMenu('aggregateMenu', dtpSecondaryAggregateMenu, this.panel.actor); + this._setPanelMenu('dateMenu', DateMenu.DateMenuButton, this.panel.actor); + this._setPanelMenu('activities', Panel.ActivitiesButton, this.panel.actor); + + this.panel.add_child(this._leftBox); + this.panel.add_child(this._centerBox); + this.panel.add_child(this._rightBox); + } else { + this.panel = Main.panel; + this.statusArea = Main.panel.statusArea; + this.menuManager = Main.panel.menuManager; + + panelBoxes.forEach(p => this[p] = Main.panel[p]); + + ['activities', 'aggregateMenu', 'dateMenu'].forEach(b => { + let container = this.statusArea[b].container; + let parent = container.get_parent(); + + container._dtpOriginalParent = parent; + parent ? parent.remove_child(container) : null; + this.panel.actor.add_child(container); + }); + } + + // Create a wrapper around the real showAppsIcon in order to add a popupMenu. Most of + // its behavior is handled by the taskbar, but its positioning is done at the panel level + this.showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this); + this.panel.actor.add_child(this.showAppsIconWrapper.realShowAppsIcon); + + this.panel.actor._delegate = this; + + Utils.wrapActor(this.statusArea.activities); + + this.add_child(this.panel.actor); + + if (Main.panel._onButtonPress || Main.panel._tryDragWindow) { + this._signalsHandler.add([ + this.panel.actor, + [ + 'button-press-event', + 'touch-event' + ], + this._onButtonPress.bind(this) + ]); + } + + if (Main.panel._onKeyPress) { + this._signalsHandler.add([this.panel.actor, 'key-press-event', Main.panel._onKeyPress.bind(this)]); + } + + Main.ctrlAltTabManager.addGroup(this, _("Top Bar")+" "+ monitor.index, 'focus-top-bar-symbolic', + { sortGroup: CtrlAltTab.SortGroup.TOP }); + }, + + enable : function() { + let position = this.getPosition(); + + if (this.statusArea.aggregateMenu) { + Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll = 1; + } + + this.geom = this.getGeometry(); + + // The overview uses the panel height as a margin by way of a "ghost" transparent Clone + // This pushes everything down, which isn't desired when the panel is moved to the bottom + // I'm adding a 2nd ghost panel and will resize the top or bottom ghost depending on the panel position + this._myPanelGhost = new Clutter.Actor({ + x: this.geom.x, + y: this.geom.y , + reactive: false, + opacity: 0 + }); + + let isTop = this.geom.position == St.Side.TOP; + + if (isTop) { + this.panel._leftCorner = this.panel._leftCorner || new Panel.PanelCorner(St.Side.LEFT); + this.panel._rightCorner = this.panel._rightCorner || new Panel.PanelCorner(St.Side.RIGHT); + + Main.overview._overview.insert_child_at_index(this._myPanelGhost, 0); + } else { + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + Main.overview._overview.add_actor(this._myPanelGhost); + } + + if (this.panel._leftCorner) { + Utils.wrapActor(this.panel._leftCorner); + Utils.wrapActor(this.panel._rightCorner); + + if (isTop) { + if (this.isStandalone) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + } else if (Config.PACKAGE_VERSION >= '3.32') { + this.panel.actor.remove_child(this.panel._leftCorner.actor); + this.panel.actor.remove_child(this.panel._rightCorner.actor); + } + } + + this._setPanelPosition(); + + if (!this.isStandalone) { + if (this.panel.vfunc_allocate) { + this._panelConnectId = 0; + Utils.hookVfunc(this.panel.__proto__, 'allocate', (box, flags) => this._mainPanelAllocate(0, box, flags)); + } else { + this._panelConnectId = this.panel.actor.connect('allocate', (actor, box, flags) => this._mainPanelAllocate(actor, box, flags)); + } + + // remove the extra space before the clock when the message-indicator is displayed + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', () => [0,0]); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', () => [0,0]); + } + } + + if (!DateMenu.IndicatorPad && this.statusArea.dateMenu) { + //3.36 switched to a size constraint applied on an anonymous child + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints = indicatorPad.get_constraints(); + indicatorPad.clear_constraints(); + } + + // The main panel's connection to the "allocate" signal is competing with this extension + // trying to move the centerBox over to the right, creating a never-ending cycle. + // Since we don't have the ID to disconnect that handler, wrap the allocate() function + // it calls instead. If the call didn't originate from this file, ignore it. + panelBoxes.forEach(b => { + this[b].allocate = (box, flags, isFromDashToPanel) => { + if (isFromDashToPanel) { + Utils.allocate(this[b], box, flags, true); + } + } + }); + + this.menuManager._oldChangeMenu = this.menuManager._changeMenu; + this.menuManager._changeMenu = (menu) => { + if (!Me.settings.get_boolean('stockgs-panelbtn-click-only')) { + this.menuManager._oldChangeMenu(menu); + } + }; + + this.dynamicTransparency = new Transparency.DynamicTransparency(this); + + this.taskbar = new Taskbar.taskbar(this); + + this.panel.actor.add_child(this.taskbar.actor); + + this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')); + this._setShowDesktopButton(true); + + this._setAllocationMap(); + + this.panel.actor.add_style_class_name('dashtopanelMainPanel ' + this.getOrientation()); + + this._setPanelGhostSize(); + + this._timeoutsHandler.add([T2, Me.settings.get_int('intellihide-enable-start-delay'), () => this.intellihide = new Intellihide.Intellihide(this)]); + + this._signalsHandler.add( + // this is to catch changes to the theme or window scale factor + [ + Utils.getStageTheme(), + 'changed', + () => (this._resetGeometry(), this._setShowDesktopButtonStyle()), + ], + [ + // sync hover after a popupmenu is closed + this.taskbar, + 'menu-closed', + Lang.bind(this, function(){this.panel.actor.sync_hover();}) + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._adjustForOverview() + ], + [ + Main.overview, + 'hidden', + () => { + if (this.isPrimary) { + //reset the primary monitor when exiting the overview + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this.statusArea.activities.actor, + 'captured-event', + (actor, e) => { + // todo this is not being called right now, so the overview is not shown on the correct monitor + if (e.type() == Clutter.EventType.BUTTON_PRESS || e.type() == Clutter.EventType.TOUCH_BEGIN) { + //temporarily use as primary the monitor on which the activities btn was clicked + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this._centerBox, + 'actor-added', + () => this._onBoxActorAdded(this._centerBox) + ], + [ + this._rightBox, + 'actor-added', + () => this._onBoxActorAdded(this._rightBox) + ], + [ + this.panel.actor, + 'scroll-event', + this._onPanelMouseScroll.bind(this) + ], + [ + Main.layoutManager, + 'startup-complete', + () => this._resetGeometry() + ] + ); + + this._bindSettingsChanges(); + + this.panelStyle.enable(this); + + if (this.checkIfVertical()) { + this._signalsHandler.add([ + this.panelBox, + 'notify::visible', + () => { + if (this.panelBox.visible) { + this._refreshVerticalAlloc(); + } + } + ]); + + this._setSearchEntryOffset(this.geom.w); + + if (this.statusArea.dateMenu) { + this._formatVerticalClock(); + + this._signalsHandler.add([ + this.statusArea.dateMenu._clock, + 'notify::clock', + () => this._formatVerticalClock() + ]); + } + } + + // Since we are usually visible but not usually changing, make sure + // most repaint requests don't actually require us to repaint anything. + // This saves significant CPU when repainting the screen. + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._initProgressManager(); + }, + + disable: function () { + this.panelStyle.disable(); + + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + this._disablePanelCornerSignals(); + + this.panel.actor.remove_child(this.taskbar.actor); + this._setAppmenuVisible(false); + + if (this.intellihide) { + this.intellihide.destroy(); + } + + this.dynamicTransparency.destroy(); + + this.progressManager.destroy(); + + this.taskbar.destroy(); + this.showAppsIconWrapper.destroy(); + + this.menuManager._changeMenu = this.menuManager._oldChangeMenu; + + this._myPanelGhost.get_parent().remove_actor(this._myPanelGhost); + this._setSearchEntryOffset(0); + + panelBoxes.forEach(b => delete this[b].allocate); + this._unmappedButtons.forEach(a => this._disconnectVisibleId(a)); + + if (this._dateMenuIndicatorPadContraints && this.statusArea.dateMenu) { + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints.forEach(c => indicatorPad.add_constraint(c)); + } + + this._setVertical(this.panel.actor, false); + + if (!this.isStandalone) { + this.statusArea.dateMenu._clockDisplay.text = this.statusArea.dateMenu._clock.clock; + + ['vertical', 'horizontal', 'dashtopanelMainPanel'].forEach(c => this.panel.actor.remove_style_class_name(c)); + + if (!Main.sessionMode.isLocked) { + [['activities', 0], ['aggregateMenu', -1], ['dateMenu', 0]].forEach(b => { + let container = this.statusArea[b[0]].container; + let originalParent = container._dtpOriginalParent; + + this.panel.actor.remove_child(container); + originalParent ? originalParent.insert_child_at_index(container, b[1]) : null; + delete container._dtpOriginalParent; + }); + } + + if (!this.panel._leftCorner.actor.mapped) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + + this._setShowDesktopButton(false); + + delete Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll; + + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_width); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_height); + } + + if (this._panelConnectId) { + this.panel.actor.disconnect(this._panelConnectId); + } else { + Utils.hookVfunc(this.panel.__proto__, 'allocate', this.panel.__proto__.vfunc_allocate); + } + + this.panel.actor._delegate = this.panel; + } else { + this._removePanelMenu('dateMenu'); + this._removePanelMenu('aggregateMenu'); + this._removePanelMenu('activities'); + } + + Main.ctrlAltTabManager.removeGroup(this); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + + // open overview so they can choose a window for focusing + // and ultimately dropping dragged item onto + if(Main.overview.shouldToggleByCornerOrButton()) + Main.overview.show(); + } + + return DND.DragMotionResult.CONTINUE; + }, + + getPosition: function() { + let position = PanelSettings.getPanelPosition(Me.settings, this.monitor.index); + + if (position == Pos.TOP) { + return St.Side.TOP; + } else if (position == Pos.RIGHT) { + return St.Side.RIGHT; + } else if (position == Pos.BOTTOM) { + return St.Side.BOTTOM; + } + + return St.Side.LEFT; + }, + + checkIfVertical: function() { + let position = this.getPosition(); + + return (position == St.Side.LEFT || position == St.Side.RIGHT); + }, + + getOrientation: function() { + return (this.checkIfVertical() ? 'vertical' : 'horizontal'); + }, + + updateElementPositions: function() { + let panelPositions = this.panelManager.panelsElementPositions[this.monitor.index] || Pos.defaults; + + this._updateGroupedElements(panelPositions); + + this._disablePanelCornerSignals(); + + if (this.getPosition() == St.Side.TOP) { + let visibleElements = panelPositions.filter(pp => pp.visible); + let connectCorner = (corner, button) => { + corner._button = button; + corner._buttonStyleChangedSignalId = button.connect('style-changed', () => { + corner.set_style_pseudo_class(button.get_style_pseudo_class()); + }); + } + + if (visibleElements[0].element == Pos.ACTIVITIES_BTN) { + connectCorner(this.panel._leftCorner, this.statusArea.activities); + } + + if (visibleElements[visibleElements.length - 1].element == Pos.SYSTEM_MENU) { + connectCorner(this.panel._rightCorner, this.statusArea.aggregateMenu); + } + } + + this.panel.actor.hide(); + this.panel.actor.show(); + }, + + _updateGroupedElements: function(panelPositions) { + let previousPosition = 0; + let previousCenteredPosition = 0; + let currentGroup = -1; + + this._elementGroups = []; + + panelPositions.forEach(pos => { + let allocationMap = this.allocationMap[pos.element]; + + if (allocationMap.actor) { + allocationMap.actor.visible = pos.visible; + + if (!pos.visible) { + return; + } + + let currentPosition = pos.position; + let isCentered = Pos.checkIfCentered(currentPosition); + + if (currentPosition == Pos.STACKED_TL && previousPosition == Pos.STACKED_BR) { + currentPosition = Pos.STACKED_BR; + } + + if (!previousPosition || + (previousPosition == Pos.STACKED_TL && currentPosition != Pos.STACKED_TL) || + (previousPosition != Pos.STACKED_BR && currentPosition == Pos.STACKED_BR) || + (isCentered && previousPosition != currentPosition && previousPosition != Pos.STACKED_BR)) { + this._elementGroups[++currentGroup] = { elements: [], index: this._elementGroups.length, expandableIndex: -1 }; + previousCenteredPosition = 0; + } + + if (pos.element == Pos.TASKBAR) { + this._elementGroups[currentGroup].expandableIndex = this._elementGroups[currentGroup].elements.length; + } + + if (isCentered && !this._elementGroups[currentGroup].isCentered) { + this._elementGroups[currentGroup].isCentered = 1; + previousCenteredPosition = currentPosition; + } + + this._elementGroups[currentGroup].position = previousCenteredPosition || currentPosition; + this._elementGroups[currentGroup].elements.push(allocationMap); + + allocationMap.position = currentPosition; + previousPosition = currentPosition; + } + }); + }, + + _disablePanelCornerSignals: function() { + if (this.panel._rightCorner && this.panel._rightCorner._buttonStyleChangedSignalId) { + this.panel._rightCorner._button.disconnect(this.panel._rightCorner._buttonStyleChangedSignalId); + delete this.panel._rightCorner._buttonStyleChangedSignalId; + } + + if (this.panel._leftCorner && this.panel._leftCorner._buttonStyleChangedSignalId) { + this.panel._leftCorner._button.disconnect(this.panel._leftCorner._buttonStyleChangedSignalId); + delete this.panel._leftCorner._buttonStyleChangedSignalId; + } + }, + + _bindSettingsChanges: function() { + let isVertical = this.checkIfVertical(); + + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::group-apps' + ], + () => this._resetGeometry() + ], + [ + Me.settings, + [ + 'changed::appicon-margin', + 'changed::appicon-padding' + ], + () => this.taskbar.resetAppIcons() + ], + [ + Me.settings, + 'changed::show-appmenu', + () => this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')) + ], + [ + Me.settings, + [ + 'changed::showdesktop-button-width', + 'changed::trans-use-custom-bg', + 'changed::desktop-line-use-custom-color', + 'changed::desktop-line-custom-color', + 'changed::trans-bg-color' + ], + () => this._setShowDesktopButtonStyle() + ], + [ + Me.desktopSettings, + 'changed::clock-format', + () => { + this._clockFormat = null; + + if (isVertical) { + this._formatVerticalClock(); + } + } + ], + [ + Me.settings, + 'changed::progress-show-bar', + () => this._initProgressManager() + ], + [ + Me.settings, + 'changed::progress-show-count', + () => this._initProgressManager() + ] + ); + + if (isVertical) { + this._signalsHandler.add([Me.settings, 'changed::group-apps-label-max-width', () => this._resetGeometry()]); + } + }, + + _setPanelMenu: function(propName, constr, container) { + if (!this.statusArea[propName]) { + this.statusArea[propName] = this._getPanelMenu(propName, constr); + this.menuManager.addMenu(this.statusArea[propName].menu); + container.insert_child_at_index(this.statusArea[propName].container, 0); + } + }, + + _removePanelMenu: function(propName) { + if (this.statusArea[propName]) { + let parent = this.statusArea[propName].container.get_parent(); + + if (parent) { + parent.remove_actor(this.statusArea[propName].container); + } + + //calling this.statusArea[propName].destroy(); is buggy for now, gnome-shell never + //destroys those panel menus... + //since we can't destroy the menu (hence properly disconnect its signals), let's + //store it so the next time a panel needs one of its kind, we can reuse it instead + //of creating a new one + let panelMenu = this.statusArea[propName]; + + this.menuManager.removeMenu(panelMenu.menu); + Me.persistentStorage[propName].push(panelMenu); + this.statusArea[propName] = null; + } + }, + + _getPanelMenu: function(propName, constr) { + Me.persistentStorage[propName] = Me.persistentStorage[propName] || []; + + if (!Me.persistentStorage[propName].length) { + Me.persistentStorage[propName].push(new constr()); + } + + return Me.persistentStorage[propName].pop(); + }, + + _setPanelGhostSize: function() { + this._myPanelGhost.set_size(this.width, this.checkIfVertical() ? 1 : this.height); + }, + + _setSearchEntryOffset: function(offset) { + if (this.isPrimary) { + //In the overview, when the panel is vertical the search-entry is the only element + //that doesn't natively take into account the size of a side dock, as it is always + //centered relatively to the monitor. This looks misaligned, adjust it here so it + //is centered like the rest of the overview elements. + let paddingSide = this.getPosition() == St.Side.LEFT ? 'left' : 'right'; + let scaleFactor = Utils.getScaleFactor(); + let style = offset ? 'padding-' + paddingSide + ':' + (offset / scaleFactor) + 'px;' : null; + let searchEntry = Main.overview._overview._controls._searchEntry; + searchEntry.get_parent().set_style(style); + } + }, + + _adjustForOverview: function() { + let isFocusedMonitor = this.panelManager.checkIfFocusedMonitor(this.monitor); + let isOverview = !!Main.overview.visibleTarget; + let isOverviewFocusedMonitor = isOverview && isFocusedMonitor; + let isShown = !isOverview || isOverviewFocusedMonitor; + + this.panelBox[isShown ? 'show' : 'hide'](); + + if (isOverview) { + this._myPanelGhost[isOverviewFocusedMonitor ? 'show' : 'hide'](); + + if (isOverviewFocusedMonitor) { + Utils.getPanelGhost().set_size(1, this.geom.position == St.Side.TOP ? 0 : 32); + } + } + }, + + _resetGeometry: function() { + this.geom = this.getGeometry(); + this._setPanelGhostSize(); + this._setPanelPosition(); + this.taskbar.resetAppIcons(true); + this.dynamicTransparency.updateExternalStyle(); + + if (this.intellihide && this.intellihide.enabled) { + this.intellihide.reset(); + } + + if (this.checkIfVertical()) { + this.showAppsIconWrapper.realShowAppsIcon.toggleButton.set_width(this.geom.w); + this._refreshVerticalAlloc(); + this._setSearchEntryOffset(this.geom.w); + } + }, + + getGeometry: function() { + let scaleFactor = Utils.getScaleFactor(); + let panelBoxTheme = this.panelBox.get_theme_node(); + let lrPadding = panelBoxTheme.get_padding(St.Side.RIGHT) + panelBoxTheme.get_padding(St.Side.LEFT); + let topPadding = panelBoxTheme.get_padding(St.Side.TOP); + let tbPadding = topPadding + panelBoxTheme.get_padding(St.Side.BOTTOM); + let position = this.getPosition(); + let length = PanelSettings.getPanelLength(Me.settings, this.monitor.index) / 100; + let anchor = PanelSettings.getPanelAnchor(Me.settings, this.monitor.index); + let anchorPlaceOnMonitor = 0; + let gsTopPanelOffset = 0; + let x = 0, y = 0; + let w = 0, h = 0; + + const panelSize = PanelSettings.getPanelSize(Me.settings, this.monitor.index); + this.dtpSize = panelSize * scaleFactor; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.primaryMonitor == this.monitor) { + gsTopPanelOffset = Main.layoutManager.panelBox.height - topPadding; + } + + if (this.checkIfVertical()) { + if (!Me.settings.get_boolean('group-apps')) { + // add window title width and side padding of _dtpIconContainer when vertical + this.dtpSize += Me.settings.get_int('group-apps-label-max-width') + AppIcons.DEFAULT_PADDING_SIZE * 2 / scaleFactor; + } + + this.sizeFunc = 'get_preferred_height', + this.fixedCoord = { c1: 'x1', c2: 'x2' }, + this.varCoord = { c1: 'y1', c2: 'y2' }; + + w = this.dtpSize; + h = this.monitor.height * length - tbPadding - gsTopPanelOffset; + } else { + this.sizeFunc = 'get_preferred_width'; + this.fixedCoord = { c1: 'y1', c2: 'y2' }; + this.varCoord = { c1: 'x1', c2: 'x2' }; + + w = this.monitor.width * length - lrPadding; + h = this.dtpSize; + } + + if (position == St.Side.TOP || position == St.Side.LEFT) { + x = this.monitor.x; + y = this.monitor.y + gsTopPanelOffset; + } else if (position == St.Side.RIGHT) { + x = this.monitor.x + this.monitor.width - this.dtpSize - lrPadding; + y = this.monitor.y + gsTopPanelOffset; + } else { //BOTTOM + x = this.monitor.x; + y = this.monitor.y + this.monitor.height - this.dtpSize - tbPadding; + } + + if (this.checkIfVertical()) { + let viewHeight = this.monitor.height - gsTopPanelOffset; + + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (viewHeight - h) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = viewHeight - h; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + y = y + anchorPlaceOnMonitor; + } else { + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (this.monitor.width - w) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = this.monitor.width - w; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + x = x + anchorPlaceOnMonitor; + } + + return { + x: x, y: y, + w: w, h: h, + lrPadding: lrPadding, + tbPadding: tbPadding, + position: position + }; + }, + + _setAllocationMap: function() { + this.allocationMap = {}; + let setMap = (name, actor, isBox) => this.allocationMap[name] = { + actor: actor, + isBox: isBox || 0, + box: new Clutter.ActorBox() + }; + + setMap(Pos.SHOW_APPS_BTN, this.showAppsIconWrapper.realShowAppsIcon); + setMap(Pos.ACTIVITIES_BTN, this.statusArea.activities ? this.statusArea.activities.container : 0); + setMap(Pos.LEFT_BOX, this._leftBox, 1); + setMap(Pos.TASKBAR, this.taskbar.actor); + setMap(Pos.CENTER_BOX, this._centerBox, 1); + setMap(Pos.DATE_MENU, this.statusArea.dateMenu.container); + setMap(Pos.SYSTEM_MENU, this.statusArea.aggregateMenu.container); + setMap(Pos.RIGHT_BOX, this._rightBox, 1); + setMap(Pos.DESKTOP_BTN, this._showDesktopButton); + }, + + _mainPanelAllocate: function(actor, box, flags) { + Utils.setAllocation(this.panel.actor, box, flags); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + + let fixed = 0; + let centeredMonitorGroup; + let panelAlloc = new Clutter.ActorBox({ x1: 0, y1: 0, x2: this.geom.w, y2: this.geom.h }); + let assignGroupSize = (group, update) => { + group.size = 0; + group.tlOffset = 0; + group.brOffset = 0; + + group.elements.forEach(element => { + if (!update) { + element.box[this.fixedCoord.c1] = panelAlloc[this.fixedCoord.c1]; + element.box[this.fixedCoord.c2] = panelAlloc[this.fixedCoord.c2]; + element.natSize = element.actor[this.sizeFunc](-1)[1]; + } + + if (!group.isCentered || Pos.checkIfCentered(element.position)) { + group.size += element.natSize; + } else if (element.position == Pos.STACKED_TL) {  + group.tlOffset += element.natSize; + } else { // Pos.STACKED_BR + group.brOffset += element.natSize; + } + }); + + if (group.isCentered) { + group.size += Math.max(group.tlOffset, group.brOffset) * 2; + group.tlOffset = Math.max(group.tlOffset - group.brOffset, 0); + } + }; + let allocateGroup = (group, tlLimit, brLimit) => { + let startPosition = tlLimit; + let currentPosition = 0; + + if (group.expandableIndex >= 0) { + let availableSize = brLimit - tlLimit; + let expandable = group.elements[group.expandableIndex]; + let i = 0; + let l = this._elementGroups.length; + let tlSize = 0; + let brSize = 0; + + if (centeredMonitorGroup && (centeredMonitorGroup != group || expandable.position != Pos.CENTERED_MONITOR)) { + if (centeredMonitorGroup.index < group.index || (centeredMonitorGroup == group && expandable.position == Pos.STACKED_TL)) { + i = centeredMonitorGroup.index; + } else { + l = centeredMonitorGroup.index; + } + } + + for (; i < l; ++i) { + let refGroup = this._elementGroups[i]; + + if (i < group.index && (!refGroup.fixed || refGroup[this.varCoord.c2] > tlLimit)) { + tlSize += refGroup.size; + } else if (i > group.index && (!refGroup.fixed || refGroup[this.varCoord.c1] < brLimit)) { + brSize += refGroup.size; + } + } + + if (group.isCentered) { + availableSize -= Math.max(tlSize, brSize) * 2; + } else { + availableSize -= tlSize + brSize; + } + + if (availableSize < group.size) { + expandable.natSize -= (group.size - availableSize) * (group.isCentered && !Pos.checkIfCentered(expandable.position) ? .5 : 1); + assignGroupSize(group, true); + } + } + + if (group.isCentered) { + startPosition = tlLimit + (brLimit - tlLimit - group.size) * .5; + } else if (group.position == Pos.STACKED_BR) { + startPosition = brLimit - group.size; + } + + currentPosition = group.tlOffset + startPosition; + + group.elements.forEach(element => { + element.box[this.varCoord.c1] = Math.round(currentPosition); + element.box[this.varCoord.c2] = Math.round((currentPosition += element.natSize)); + + if (element.isBox) { + return element.actor.allocate(element.box, flags, true); + } + + Utils.allocate(element.actor, element.box, flags, false); + }); + + group[this.varCoord.c1] = startPosition; + group[this.varCoord.c2] = currentPosition; + group.fixed = 1; + ++fixed; + }; + + Utils.allocate(this.panel.actor, panelAlloc, flags); + + this._elementGroups.forEach(group => { + group.fixed = 0; + + assignGroupSize(group); + + if (group.position == Pos.CENTERED_MONITOR) { + centeredMonitorGroup = group; + } + }); + + if (centeredMonitorGroup) { + allocateGroup(centeredMonitorGroup, panelAlloc[this.varCoord.c1], panelAlloc[this.varCoord.c2]); + } + + let iterations = 0; //failsafe + while (fixed < this._elementGroups.length && ++iterations < 10) { + for (let i = 0, l = this._elementGroups.length; i < l; ++i) { + let group = this._elementGroups[i]; + + if (group.fixed) { + continue; + } + + let prevGroup = this._elementGroups[i - 1]; + let nextGroup = this._elementGroups[i + 1]; + let prevLimit = prevGroup && prevGroup.fixed ? prevGroup[this.varCoord.c2] : + centeredMonitorGroup && group.index > centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c2] : panelAlloc[this.varCoord.c1]; + let nextLimit = nextGroup && nextGroup.fixed ? nextGroup[this.varCoord.c1] : + centeredMonitorGroup && group.index < centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c1] : panelAlloc[this.varCoord.c2]; + + if (group.position == Pos.STACKED_TL) { + allocateGroup(group, panelAlloc[this.varCoord.c1], nextLimit); + } else if (group.position == Pos.STACKED_BR) { + allocateGroup(group, prevLimit, panelAlloc[this.varCoord.c2]); + } else if ((!prevGroup || prevGroup.fixed) && (!nextGroup || nextGroup.fixed)) { // CENTERED + allocateGroup(group, prevLimit, nextLimit); + } + } + } + + if (this.geom.position == St.Side.TOP) { + let childBoxLeftCorner = new Clutter.ActorBox(); + let childBoxRightCorner = new Clutter.ActorBox(); + let currentCornerSize = this.cornerSize; + let panelAllocFixedSize = box[this.fixedCoord.c2] - box[this.fixedCoord.c1]; + + [ , this.cornerSize] = this.panel._leftCorner.actor[this.sizeFunc](-1); + childBoxLeftCorner[this.varCoord.c1] = 0; + childBoxLeftCorner[this.varCoord.c2] = this.cornerSize; + childBoxLeftCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxLeftCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + childBoxRightCorner[this.varCoord.c1] = box[this.varCoord.c2] - this.cornerSize; + childBoxRightCorner[this.varCoord.c2] = box[this.varCoord.c2]; + childBoxRightCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxRightCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + Utils.allocate(this.panel._leftCorner.actor, childBoxLeftCorner, flags); + Utils.allocate(this.panel._rightCorner.actor, childBoxRightCorner, flags); + + if (this.cornerSize != currentCornerSize) { + this._setPanelClip(); + } + } + }, + + _setPanelPosition: function() { + let clipContainer = this.panelBox.get_parent(); + + this.set_size(this.geom.w, this.geom.h); + clipContainer.set_position(this.geom.x, this.geom.y); + + this._setVertical(this.panel.actor, this.checkIfVertical()); + + // styles for theming + Object.keys(St.Side).forEach(p => { + let cssName = 'dashtopanel' + p.charAt(0) + p.slice(1).toLowerCase(); + + this.panel.actor[(St.Side[p] == this.geom.position ? 'add' : 'remove') + '_style_class_name'](cssName); + }); + + this._setPanelClip(clipContainer); + + Main.layoutManager._updateHotCorners(); + Main.layoutManager._updatePanelBarrier(this); + }, + + _setPanelClip: function(clipContainer) { + clipContainer = clipContainer || this.panelBox.get_parent(); + this._timeoutsHandler.add([T7, 0, () => Utils.setClip(clipContainer, clipContainer.x, clipContainer.y, this.panelBox.width, this.panelBox.height + this.cornerSize)]); + }, + + _onButtonPress: function(actor, event) { + let type = event.type(); + let isPress = type == Clutter.EventType.BUTTON_PRESS; + let button = isPress ? event.get_button() : -1; + let [stageX, stageY] = event.get_coords(); + + if (button == 3 && global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, stageX, stageY) == this.panel.actor) { + //right click on an empty part of the panel, temporarily borrow and display the showapps context menu + Main.layoutManager.setDummyCursorGeometry(stageX, stageY, 0, 0); + + this.showAppsIconWrapper.createMenu(); + this.showAppsIconWrapper._menu.sourceActor = Main.layoutManager.dummyCursor; + this.showAppsIconWrapper.popupMenu(); + + return Clutter.EVENT_STOP; + } else if (Main.modalCount > 0 || event.get_source() != actor || + (!isPress && type != Clutter.EventType.TOUCH_BEGIN) || + (isPress && button != 1)) { + return Clutter.EVENT_PROPAGATE; + } + + let params = this.checkIfVertical() ? [stageY, 'y', 'height'] : [stageX, 'x', 'width']; + let dragWindow = this._getDraggableWindowForPosition.apply(this, params.concat(['maximized_' + this.getOrientation() + 'ly'])); + + if (!dragWindow) + return Clutter.EVENT_PROPAGATE; + + global.display.begin_grab_op(dragWindow, + Meta.GrabOp.MOVING, + false, /* pointer grab */ + true, /* frame action */ + button, + event.get_state(), + event.get_time(), + stageX, stageY); + + return Clutter.EVENT_STOP; + }, + + _getDraggableWindowForPosition: function(stageCoord, coord, dimension, maximizedProp) { + let workspace = Utils.getCurrentWorkspace(); + let allWindowsByStacking = global.display.sort_windows_by_stacking( + workspace.list_windows() + ).reverse(); + + return Utils.find(allWindowsByStacking, metaWindow => { + let rect = metaWindow.get_frame_rect(); + + return metaWindow.get_monitor() == this.monitor.index && + metaWindow.showing_on_its_workspace() && + metaWindow.get_window_type() != Meta.WindowType.DESKTOP && + metaWindow[maximizedProp] && + stageCoord > rect[coord] && stageCoord < rect[coord] + rect[dimension]; + }); + }, + + _onBoxActorAdded: function(box) { + if (this.checkIfVertical()) { + this._setVertical(box, true); + } + }, + + _refreshVerticalAlloc: function() { + this._setVertical(this._centerBox, true); + this._setVertical(this._rightBox, true); + this._formatVerticalClock(); + }, + + _setVertical: function(actor, isVertical) { + let _set = (actor, isVertical) => { + if (!actor || actor instanceof Dash.DashItemContainer || actor instanceof Taskbar.TaskbarItemContainer) { + return; + } + + if (actor instanceof St.BoxLayout) { + actor.vertical = isVertical; + } else if ((actor._delegate || actor) instanceof PanelMenu.ButtonBox && actor != this.statusArea.appMenu) { + let child = actor.get_first_child(); + + if (isVertical && !actor.visible && !actor._dtpVisibleId) { + this._unmappedButtons.push(actor); + actor._dtpVisibleId = actor.connect('notify::visible', () => { + this._disconnectVisibleId(actor); + this._refreshVerticalAlloc(); + }); + actor._dtpDestroyId = actor.connect('destroy', () => this._disconnectVisibleId(actor)); + } + + if (child) { + let [, natWidth] = actor.get_preferred_width(-1); + + child.x_align = Clutter.ActorAlign[isVertical ? 'CENTER' : 'START']; + actor.set_width(isVertical ? this.dtpSize : -1); + isVertical = isVertical && (natWidth > this.dtpSize); + actor[(isVertical ? 'add' : 'remove') + '_style_class_name']('vertical'); + } + } + + actor.get_children().forEach(c => _set(c, isVertical)); + }; + + _set(actor, false); + _set(actor, isVertical); + }, + + _disconnectVisibleId: function(actor) { + actor.disconnect(actor._dtpVisibleId); + actor.disconnect(actor._dtpDestroyId); + + delete actor._dtpVisibleId; + delete actor._dtpDestroyId; + + this._unmappedButtons.splice(this._unmappedButtons.indexOf(actor), 1); + }, + + _setAppmenuVisible: function(isVisible) { + let parent; + let appMenu = this.statusArea.appMenu; + + if(appMenu) + parent = appMenu.container.get_parent(); + + if (parent) { + parent.remove_child(appMenu.container); + } + + if (isVisible && appMenu) { + this._leftBox.insert_child_above(appMenu.container, null); + } + }, + + _formatVerticalClock: function() { + // https://github.com/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-wall-clock.c#L310 + if (this.statusArea.dateMenu) { + let datetime = this.statusArea.dateMenu._clock.clock; + let datetimeParts = datetime.split(' '); + let time = datetimeParts[1]; + let clockText = this.statusArea.dateMenu._clockDisplay.clutter_text; + let setClockText = text => { + let stacks = text instanceof Array; + let separator = '\n‧‧\n'; + + clockText.set_text((stacks ? text.join(separator) : text).trim()); + clockText.set_use_markup(stacks); + clockText.get_allocation_box(); + + return !clockText.get_layout().is_ellipsized(); + }; + + if (clockText.ellipsize == Pango.EllipsizeMode.NONE) { + //on gnome-shell 3.36.4, the clockdisplay isn't ellipsize anymore, so set it back + clockText.ellipsize = Pango.EllipsizeMode.END; + } + + if (!time) { + datetimeParts = datetime.split(' '); + time = datetimeParts.pop(); + datetimeParts = [datetimeParts.join(' '), time]; + } + + if (!setClockText(datetime) && + !setClockText(datetimeParts) && + !setClockText(time)) { + let timeParts = time.split('∶'); + + if (!this._clockFormat) { + this._clockFormat = Me.desktopSettings.get_string('clock-format'); + } + + if (this._clockFormat == '12h') { + timeParts.push.apply(timeParts, timeParts.pop().split(' ')); + } + + setClockText(timeParts); + } + } + }, + + _setShowDesktopButton: function (add) { + if (add) { + if(this._showDesktopButton) + return; + + this._showDesktopButton = new St.Bin({ style_class: 'showdesktop-button', + reactive: true, + can_focus: true, + // x_fill: true, + // y_fill: true, + track_hover: true }); + + this._setShowDesktopButtonStyle(); + + this._showDesktopButton.connect('button-press-event', () => this._onShowDesktopButtonPress()); + this._showDesktopButton.connect('enter-event', () => { + this._showDesktopButton.add_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + this._timeoutsHandler.add([T4, Me.settings.get_int('show-showdesktop-delay'), () => { + this._hiddenDesktopWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + this._toggleWorkspaceWindows(true, this._hiddenDesktopWorkspace); + }]); + } + }); + + this._showDesktopButton.connect('leave-event', () => { + this._showDesktopButton.remove_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + if (this._timeoutsHandler.getId(T4)) { + this._timeoutsHandler.remove(T4); + } else if (this._hiddenDesktopWorkspace) { + this._toggleWorkspaceWindows(false, this._hiddenDesktopWorkspace); + } +  } + }); + + this.panel.actor.add_child(this._showDesktopButton); + } else { + if(!this._showDesktopButton) + return; + + this.panel.actor.remove_child(this._showDesktopButton); + this._showDesktopButton.destroy(); + this._showDesktopButton = null; + } + }, + + _setShowDesktopButtonStyle: function() { + let rgb = this._getBackgroundBrightness() ? "rgba(55, 55, 55, .2)" : "rgba(200, 200, 200, .2)"; + + let isLineCustom = Me.settings.get_boolean('desktop-line-use-custom-color'); + rgb = isLineCustom ? Me.settings.get_string('desktop-line-custom-color') : rgb; + + if (this._showDesktopButton) { + let buttonSize = Me.settings.get_int('showdesktop-button-width') + 'px;'; + let isVertical = this.checkIfVertical(); + + let sytle = "border: 0 solid " + rgb + ";"; + sytle += isVertical ? 'border-top-width:1px;height:' + buttonSize : 'border-left-width:1px;width:' + buttonSize; + + this._showDesktopButton.set_style(sytle); + this._showDesktopButton[(isVertical ? 'x' : 'y') + '_expand'] = true; + } + }, + + // _getBackgroundBrightness: return true if panel has a bright background color + _getBackgroundBrightness: function() { + return Utils.checkIfColorIsBright(this.dynamicTransparency.backgroundColorRgb); + }, + + _toggleWorkspaceWindows: function(hide, workspace) { + let time = Me.settings.get_int('show-showdesktop-time') * .001; + + workspace.list_windows().forEach(w => { + if (!w.minimized) { + let tweenOpts = { + opacity: hide ? 0 : 255, + time: time, + transition: 'easeOutQuad' + }; + + Utils.animateWindowOpacity(w.get_compositor_private(), tweenOpts); + } + }); + }, + + _onShowDesktopButtonPress: function() { + let label = 'trackerFocusApp'; + + this._signalsHandler.removeWithLabel(label); + this._timeoutsHandler.remove(T5); + + if(this._restoreWindowList && this._restoreWindowList.length) { + this._timeoutsHandler.remove(T4); + + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows(); + this._restoreWindowList.forEach(function(w) { + if(windows.indexOf(w) > -1) + Main.activateWindow(w); + }); + this._restoreWindowList = null; + } else { + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows().filter(function (w) { + return w.showing_on_its_workspace() && !w.skip_taskbar; + }); + windows = global.display.sort_windows_by_stacking(windows); + + windows.forEach(function(w) { + w.minimize(); + }); + + this._restoreWindowList = windows; + + this._timeoutsHandler.add([T5, 20, () => this._signalsHandler.addWithLabel( + label, + [ + tracker, + 'notify::focus-app', + () => this._restoreWindowList = null + ] + )]); + } + + Main.overview.hide(); + }, + + _onPanelMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-panel-action'); + let direction = Utils.getMouseScrollDirection(event); + + if (!this._checkIfIgnoredScrollSource(event.get_source()) && !this._timeoutsHandler.getId(T6)) { + if (direction && scrollAction === 'SWITCH_WORKSPACE') { + let args = [global.display]; + + //adjust for horizontal workspaces + if (Utils.DisplayWrapper.getWorkspaceManager().layout_rows === 1) { + direction = direction == 'up' ? 'left' : 'right'; + } + + //gnome-shell < 3.30 needs an additional "screen" param + global.screen ? args.push(global.screen) : 0; + + let showWsPopup = Me.settings.get_boolean('scroll-panel-show-ws-popup'); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = { display: () => {} }; + Main.wm._showWorkspaceSwitcher.apply(Main.wm, args.concat([0, { get_name: () => 'switch---' + direction }])); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = null; + } else if (direction && scrollAction === 'CYCLE_WINDOWS') { + let windows = this.taskbar.getAppInfos().reduce((ws, appInfo) => ws.concat(appInfo.windows), []); + + Utils.activateSiblingWindow(windows, direction); + } else if (scrollAction === 'CHANGE_VOLUME' && !event.is_pointer_emulated()) { + var proto = Volume.Indicator.prototype; + var func = proto._handleScrollEvent || proto.vfunc_scroll_event || proto._onScrollEvent; + + func.call(Main.panel.statusArea.aggregateMenu._volume, 0, event); + } else { + return; + } + + var scrollDelay = Me.settings.get_int('scroll-panel-delay'); + + if (scrollDelay) { + this._timeoutsHandler.add([T6, scrollDelay, () => {}]); + } + } + }, + + _checkIfIgnoredScrollSource: function(source) { + let ignoredConstr = ['WorkspaceIndicator']; + + return source.get_parent()._dtpIgnoreScroll || ignoredConstr.indexOf(source.constructor.name) >= 0; + }, + + _initProgressManager: function() { + if(!this.progressManager && (Me.settings.get_boolean('progress-show-bar') || Me.settings.get_boolean('progress-show-count'))) + this.progressManager = new Progress.ProgressManager(); + }, +}); + +var dtpSecondaryPanel = Utils.defineClass({ + Name: 'DashToPanel-SecondaryPanel', + Extends: St.Widget, + + _init: function(params) { + this.callParent('_init', params); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + } +}); + +var dtpSecondaryAggregateMenu = Utils.defineClass({ + Name: 'DashToPanel-SecondaryAggregateMenu', + Extends: PanelMenu.Button, + + _init: function() { + this.callParent('_init', 0.0, C_("System menu in the top bar", "System"), false); + + Utils.wrapActor(this); + + this.menu.actor.add_style_class_name('aggregate-menu'); + + let menuLayout = new Panel.AggregateLayout(); + this.menu.box.set_layout_manager(menuLayout); + + this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' }); + this.actor.add_child(this._indicators); + + this._power = new imports.ui.status.power.Indicator(); + this._volume = new imports.ui.status.volume.Indicator(); + this._brightness = new imports.ui.status.brightness.Indicator(); + this._system = new imports.ui.status.system.Indicator(); + + if (Config.PACKAGE_VERSION >= '3.28') { + this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._thunderbolt)); + } + + if (Config.PACKAGE_VERSION < '3.37') { + this._screencast = new imports.ui.status.screencast.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._screencast)); + } + + if (Config.PACKAGE_VERSION >= '3.24') { + this._nightLight = new imports.ui.status.nightLight.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._nightLight)); + } + + if (Config.HAVE_NETWORKMANAGER && Config.PACKAGE_VERSION >= '3.24') { + this._network = new imports.ui.status.network.NMApplet(); + this._indicators.add_child(Utils.getIndicators(this._network)); + } + + if (Config.HAVE_BLUETOOTH) { + this._bluetooth = new imports.ui.status.bluetooth.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._bluetooth)); + } + + this._indicators.add_child(Utils.getIndicators(this._volume)); + this._indicators.add_child(Utils.getIndicators(this._power)); + + this.menu.addMenuItem(this._volume.menu); + this._volume._volumeMenu._readOutput(); + this._volume._volumeMenu._readInput(); + + this.menu.addMenuItem(this._brightness.menu); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + if (this._network) { + this.menu.addMenuItem(this._network.menu); + } + + if (this._bluetooth) { + this.menu.addMenuItem(this._bluetooth.menu); + } + + this.menu.addMenuItem(this._power.menu); + this._power._sync(); + + if (this._nightLight) { + this.menu.addMenuItem(this._nightLight.menu); + } + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(this._system.menu); + + menuLayout.addSizeChild(this._power.menu.actor); + menuLayout.addSizeChild(this._system.menu.actor); + }, +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js new file mode 100644 index 0000000..d572d8b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js @@ -0,0 +1,789 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Overview = Me.imports.overview; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Proximity = Me.imports.proximity; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +const Config = imports.misc.config; +const Lang = imports.lang; +const Gi = imports._gi; +const GLib = imports.gi.GLib; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +const AppDisplay = imports.ui.appDisplay; +const BoxPointer = imports.ui.boxpointer; +const Dash = imports.ui.dash; +const IconGrid = imports.ui.iconGrid; +const LookingGlass = imports.ui.lookingGlass; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const Layout = imports.ui.layout; +const WM = imports.ui.windowManager; +const WorkspacesView = imports.ui.workspacesView; + +var dtpPanelManager = Utils.defineClass({ + Name: 'DashToPanel.PanelManager', + + _init: function() { + this.overview = new Overview.dtpOverview(); + this.panelsElementPositions = {}; + + this._saveMonitors(); + + Utils.getAppDisplayViews().forEach(v => { + Utils.wrapActor(v.view); + Utils.wrapActor(v.view._grid); + }); + }, + + enable: function(reset) { + let dtpPrimaryIndex = Me.settings.get_int('primary-monitor'); + + this.dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex] || Main.layoutManager.primaryMonitor; + this.proximityManager = new Proximity.ProximityManager(); + + this._oldGetShowAppsButton = imports.ui.main.overview.dash.showAppsButton; + + Utils.wrapActor(Main.panel); + Utils.wrapActor(Main.overview.dash || 0); + + this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel')); + this.allPanels = [ this.primaryPanel ]; + + this.overview.enable(this.primaryPanel); + + if (Me.settings.get_boolean('multi-monitors')) { + Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => { + this.allPanels.push(this._createPanel(m, true)); + }); + } + + global.dashToPanel.panels = this.allPanels; + global.dashToPanel.emit('panels-created'); + + this.allPanels.forEach(p => { + let panelPosition = p.getPosition(); + let leftOrRight = (panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT); + + p.panelBox.set_size( + leftOrRight ? -1 : p.geom.w + p.geom.lrPadding, + leftOrRight ? p.geom.h + p.geom.tbPadding : -1 + ); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => this._adjustPanelMenuButton(pmb, p.monitor, panelPosition)); + + p.taskbar.iconAnimator.start(); + }); + + //in 3.32, BoxPointer now inherits St.Widget + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + let panelManager = this; + + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', function(forWidth) { + let alloc = { min_size: 0, natural_size: 0 }; + + [alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth); + + return panelManager._getBoxPointerPreferredHeight(this, alloc); + }); + } + + this._updatePanelElementPositions(); + this.setFocusedMonitor(this.dtpPrimaryMonitor); + + if (this.primaryPanel.checkIfVertical()) { + Main.wm._getPositionForDirection = newGetPositionForDirection; + } + + if (reset) return; + + if (Config.PACKAGE_VERSION > '3.35.1') { + this._oldDoSpringAnimation = AppDisplay.BaseAppView.prototype._doSpringAnimation; + AppDisplay.BaseAppView.prototype._doSpringAnimation = newDoSpringAnimation; + } + + this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier; + Main.layoutManager._updatePanelBarrier = (panel) => { + let panelUpdates = panel ? [panel] : this.allPanels; + + panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p)); + }; + Main.layoutManager._updatePanelBarrier(); + + this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners; + Main.layoutManager._updateHotCorners = Lang.bind(Main.layoutManager, newUpdateHotCorners); + Main.layoutManager._updateHotCorners(); + + this._forceHotCornerId = Me.settings.connect('changed::stockgs-force-hotcorner', () => Main.layoutManager._updateHotCorners()); + + if (Main.layoutManager._interfaceSettings) { + this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners()); + } + + Main.overview.getShowAppsButton = this._newGetShowAppsButton.bind(this); + + this._needsDashItemContainerAllocate = !Dash.DashItemContainer.prototype.hasOwnProperty('vfunc_allocate'); + + if (this._needsDashItemContainerAllocate) { + Utils.hookVfunc(Dash.DashItemContainer.prototype, 'allocate', this._newDashItemContainerAllocate); + } + + LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize; + LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize; + + LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open; + LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + if (Config.PACKAGE_VERSION > '3.35.9') { + let currentAppsView; + + this._oldAnimateIconPosition = IconGrid.animateIconPosition; + IconGrid.animateIconPosition = newAnimateIconPosition.bind(this); + + this._signalsHandler.add( + [ + Utils.DisplayWrapper.getScreen(), + 'window-entered-monitor', + () => this._needsIconAllocate = 1 + ] + ); + + Utils.getAppDisplayViews().forEach(v => { + if (!v.control || v.control.has_style_pseudo_class('checked')) { + currentAppsView = v; + } + + if (v.control) { + this._signalsHandler.add( + [ + v.control, + 'clicked', + () => { + this._needsIconAllocate = currentAppsView != v; + currentAppsView = v; + } + ] + ); + } + + this._signalsHandler.add( + [ + v.view, + 'notify::visible', + () => this._needsIconAllocate = !(currentAppsView != v && !v.view.visible) + ], + [ + v.view._grid, + 'animation-done', + () => this._needsIconAllocate = 0 + ] + ); + }); + } + + //listen settings + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::primary-monitor', + 'changed::multi-monitors', + 'changed::isolate-monitors', + 'changed::panel-positions', + 'changed::panel-lengths', + 'changed::panel-anchors', + 'changed::stockgs-keep-top-panel' + ], + () => this._reset() + ], + [ + Me.settings, + 'changed::panel-element-positions', + () => this._updatePanelElementPositions() + ], + [ + Me.settings, + 'changed::intellihide-key-toggle-text', + () => this._setKeyBindings(true) + ], + [ + Utils.DisplayWrapper.getMonitorManager(), + 'monitors-changed', + () => { + if (Main.layoutManager.primaryMonitor) { + this._saveMonitors(); + this._reset(); + } + } + ] + ); + + Panel.panelBoxes.forEach(c => this._signalsHandler.add( + [Main.panel[c], 'actor-added', (parent, child) => this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, this.primaryPanel.getPosition())] + )); + + this._setKeyBindings(true); + + // keep GS overview.js from blowing away custom panel styles + if(!Me.settings.get_boolean('stockgs-keep-top-panel')) + Object.defineProperty(Main.panel, "style", {configurable: true, set: function(v) {}}); + }, + + disable: function(reset) { + this.overview.disable(); + this.proximityManager.destroy(); + + this.allPanels.forEach(p => { + p.taskbar.iconAnimator.pause(); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => { + if (pmb.menu._boxPointer._dtpGetPreferredHeightId) { + pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId); + } + + pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor; + delete pmb.menu._boxPointer._dtpSourceActor; + pmb.menu._boxPointer._userArrowSide = St.Side.TOP; + }) + + this._removePanelBarriers(p); + + p.disable(); + + let clipContainer = p.panelBox.get_parent(); + + Main.layoutManager._untrackActor(p.panelBox); + Main.layoutManager.removeChrome(clipContainer); + + if (p.isStandalone) { + p.panelBox.destroy(); + } else { + p.panelBox.remove_child(p); + p.remove_child(p.panel.actor); + p.panelBox.add(p.panel.actor); + + p.panelBox.set_position(clipContainer.x, clipContainer.y); + + clipContainer.remove_child(p.panelBox); + Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true }); + } + }); + + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height); + } + + delete Main.wm._getPositionForDirection; + + if (Main.layoutManager.primaryMonitor) { + Main.layoutManager.panelBox.set_position(Main.layoutManager.primaryMonitor.x, Main.layoutManager.primaryMonitor.y); + Main.layoutManager.panelBox.set_size(Main.layoutManager.primaryMonitor.width, -1); + } + + if (reset) return; + + this._setKeyBindings(false); + + this._signalsHandler.destroy(); + + Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners; + Main.layoutManager._updateHotCorners(); + + Me.settings.disconnect(this._forceHotCornerId); + + if (this._enableHotCornersId) { + Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId); + } + + Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier; + Main.layoutManager._updatePanelBarrier(); + + Utils.getPanelGhost().set_size(-1, -1); + + if (this._oldDoSpringAnimation) { + AppDisplay.BaseAppView.prototype._doSpringAnimation = this._oldDoSpringAnimation; + } + + if (this._oldAnimateIconPosition) { + IconGrid.animateIconPosition = this._oldAnimateIconPosition; + } + + LookingGlass.LookingGlass.prototype._resize = LookingGlass.LookingGlass.prototype._oldResize; + delete LookingGlass.LookingGlass.prototype._oldResize; + + LookingGlass.LookingGlass.prototype.open = LookingGlass.LookingGlass.prototype._oldOpen; + delete LookingGlass.LookingGlass.prototype._oldOpen + + delete Main.panel.style; + }, + + setFocusedMonitor: function(monitor, ignoreRelayout) { + // todo show overview on non primary monitor is not working right now on gnome40 + + // this._needsIconAllocate = 1; + + // if (!this.checkIfFocusedMonitor(monitor)) { + // Main.overview._overview._controls._workspacesDisplay._primaryIndex = monitor.index; + + // Main.overview._overview.clear_constraints(); + // Main.overview._overview.add_constraint(new Layout.MonitorConstraint({ index: monitor.index })); + // } + }, + + _saveMonitors: function() { + //Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same + //monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()). + //Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store + //the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell + let primaryIndex = Main.layoutManager.primaryIndex; + let monitors = [primaryIndex]; + + Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => monitors.push(m.index)); + Me.settings.set_value('available-monitors', new GLib.Variant('ai', monitors)); + }, + + checkIfFocusedMonitor: function(monitor) { + return Main.overview._overview._controls._workspacesDisplay._primaryIndex == monitor.index; + }, + + _createPanel: function(monitor, isStandalone) { + let panelBox; + let panel; + let clipContainer = new Clutter.Actor(); + + if (isStandalone) { + panelBox = new St.BoxLayout({ name: 'panelBox' }); + } else { + panelBox = Main.layoutManager.panelBox; + Main.layoutManager._untrackActor(panelBox); + panelBox.remove_child(Main.panel.actor); + Main.layoutManager.removeChrome(panelBox); + } + + Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false }); + clipContainer.add_child(panelBox); + Main.layoutManager.trackChrome(panelBox, { trackFullscreen: true, affectsStruts: true, affectsInputRegion: true }); + + panel = new Panel.dtpPanel(this, monitor, panelBox, isStandalone); + panelBox.add(panel); + panel.enable(); + + panelBox.visible = true; + if (monitor.inFullscreen) { + panelBox.hide(); + } + panelBox.set_position(0, 0); + + return panel; + }, + + _reset: function() { + this.disable(true); + this.allPanels = []; + this.enable(true); + }, + + _updatePanelElementPositions: function() { + this.panelsElementPositions = PanelSettings.getSettingsJson(Me.settings, 'panel-element-positions'); + this.allPanels.forEach(p => p.updateElementPositions()); + }, + + _adjustPanelMenuButton: function(button, monitor, arrowSide) { + if (button) { + Utils.wrapActor(button); + button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor; + button.menu._boxPointer.sourceActor = button.actor; + button.menu._boxPointer._userArrowSide = arrowSide; + button.menu._boxPointer._dtpInPanel = 1; + + if (!button.menu._boxPointer.vfunc_get_preferred_height) { + button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => { + this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor); + }); + } + } + }, + + _getBoxPointerPreferredHeight: function(boxPointer, alloc, monitor) { + if (boxPointer._dtpInPanel && boxPointer.sourceActor && Me.settings.get_boolean('intellihide')) { + monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor); + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor == monitor); + let excess = alloc.natural_size + panel.dtpSize + 10 - monitor.height; // 10 is arbitrary + + if (excess > 0) { + alloc.natural_size -= excess; + } + } + + return [alloc.min_size, alloc.natural_size]; + }, + + _findPanelMenuButtons: function(container) { + let panelMenuButtons = []; + let panelMenuButton; + + let find = parent => parent.get_children().forEach(c => { + if ((panelMenuButton = this._getPanelMenuButton(c))) { + panelMenuButtons.push(panelMenuButton); + } + + find(c); + }); + + find(container); + + return panelMenuButtons; + }, + + _removePanelBarriers: function(panel) { + if (panel.isStandalone && panel._rightPanelBarrier) { + panel._rightPanelBarrier.destroy(); + } + + if (panel._leftPanelBarrier) { + panel._leftPanelBarrier.destroy(); + delete panel._leftPanelBarrier; + } + }, + + _getPanelMenuButton: function(obj) { + return obj._delegate && obj._delegate instanceof PanelMenu.Button ? obj._delegate : 0; + }, + + _setKeyBindings: function(enable) { + let keys = { + 'intellihide-key-toggle': () => this.allPanels.forEach(p => p.intellihide.toggle()) + }; + + Object.keys(keys).forEach(k => { + Utils.removeKeybinding(k); + + if (enable) { + Utils.addKeybinding(k, Me.settings, keys[k], Shell.ActionMode.NORMAL); + } + }); + }, + + _newGetShowAppsButton: function() { + let focusedMonitorIndex = Utils.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor)); + + return this.allPanels[focusedMonitorIndex].taskbar.showAppsButton; + } +}); + +// This class drives long-running icon animations, to keep them running in sync +// with each other. +var IconAnimator = Utils.defineClass({ + Name: 'DashToPanel.IconAnimator', + + _init: function(actor) { + this._count = 0; + this._started = false; + this._animations = { + dance: [], + }; + this._timeline = new Clutter.Timeline({ + duration: 3000, + repeat_count: -1, + }); + + /* Just use the construction property when no need to support 3.36 */ + if (this._timeline.set_actor) + this._timeline.set_actor(actor); + + this._timeline.connect('new-frame', () => { + const progress = this._timeline.get_progress(); + const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0; + const dancers = this._animations.dance; + for (let i = 0, iMax = dancers.length; i < iMax; i++) { + dancers[i].target.rotation_angle_z = danceRotation; + } + }); + }, + + destroy: function() { + this._timeline.stop(); + this._timeline = null; + for (let name in this._animations) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + pair.target.disconnect(pair.targetDestroyId); + } + } + this._animations = null; + }, + + pause: function() { + if (this._started && this._count > 0) { + this._timeline.stop(); + } + this._started = false; + }, + + start: function() { + if (!this._started && this._count > 0) { + this._timeline.start(); + } + this._started = true; + }, + + addAnimation: function(target, name) { + const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name)); + this._animations[name].push({ target: target, targetDestroyId: targetDestroyId }); + if (this._started && this._count === 0) { + this._timeline.start(); + } + this._count++; + }, + + removeAnimation: function(target, name) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + if (pair.target === target) { + target.disconnect(pair.targetDestroyId); + pairs.splice(i, 1); + this._count--; + if (this._started && this._count === 0) { + this._timeline.stop(); + } + return; + } + } + } +}); + +function newGetPositionForDirection(direction, fromWs, toWs) { + let [xDest, yDest] = WM.WindowManager.prototype._getPositionForDirection(direction, fromWs, toWs); + + if (direction == Meta.MotionDirection.UP || + direction == Meta.MotionDirection.UP_LEFT || + direction == Meta.MotionDirection.UP_RIGHT) { + yDest -= Main.panel.height; + } else if (direction != Meta.MotionDirection.LEFT && + direction != Meta.MotionDirection.RIGHT) { + yDest += Main.panel.height; + } + + return [xDest, yDest]; +} + +function newDoSpringAnimation(animationDirection) { + this._grid.opacity = 255; + this._grid.animateSpring(animationDirection, Main.overview.getShowAppsButton()); +} + +function newAnimateIconPosition(icon, box, flags, nChangedIcons) { + if (this._needsIconAllocate) { + Utils.allocate(icon, box, flags); + return; + } + + return this._oldAnimateIconPosition(icon, box, flags, nChangedIcons);; +} + +function newUpdateHotCorners() { + // destroy old hot corners + this.hotCorners.forEach(function(corner) { + if (corner) + corner.destroy(); + }); + this.hotCorners = []; + + //global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner) + //this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34 + if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) || + (this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) { + this.emit('hot-corners-changed'); + return; + } + + // build new hot corners + for (let i = 0; i < this.monitors.length; i++) { + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == i); + let panelPosition = panel ? panel.getPosition() : St.Side.BOTTOM; + let panelTopLeft = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT; + let monitor = this.monitors[i]; + let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; + let cornerY = monitor.y; + + let haveTopLeftCorner = true; + + // If the panel is on the bottom, unless this is explicitly forced, don't add a topleft + // hot corner unless it is actually a top left panel. Otherwise, it stops the mouse + // as you are dragging across. In the future, maybe we will automatically move the + // hotcorner to the bottom when the panel is positioned at the bottom + if (i != this.primaryIndex || (!panelTopLeft && !Me.settings.get_boolean('stockgs-force-hotcorner'))) { + // Check if we have a top left (right for RTL) corner. + // I.e. if there is no monitor directly above or to the left(right) + let besideX = this._rtl ? monitor.x + 1 : cornerX - 1; + let besideY = cornerY; + let aboveX = cornerX; + let aboveY = cornerY - 1; + + for (let j = 0; j < this.monitors.length; j++) { + if (i == j) + continue; + let otherMonitor = this.monitors[j]; + if (besideX >= otherMonitor.x && + besideX < otherMonitor.x + otherMonitor.width && + besideY >= otherMonitor.y && + besideY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + if (aboveX >= otherMonitor.x && + aboveX < otherMonitor.x + otherMonitor.width && + aboveY >= otherMonitor.y && + aboveY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + } + } + + if (haveTopLeftCorner) { + let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY); + + corner.setBarrierSize = size => corner.__proto__.setBarrierSize.call(corner, Math.min(size, 32)); + corner.setBarrierSize(panel ? panel.dtpSize : 32); + this.hotCorners.push(corner); + } else { + this.hotCorners.push(null); + } + } + + this.emit('hot-corners-changed'); +} + +function newUpdatePanelBarrier(panel) { + let barriers = { + _rightPanelBarrier: [(panel.isStandalone ? panel : this)], + _leftPanelBarrier: [panel] + }; + + Object.keys(barriers).forEach(k => { + let obj = barriers[k][0]; + + if (obj[k]) { + obj[k].destroy(); + obj[k] = null; + } + }); + + if (!this.primaryMonitor || !panel.panelBox.height) { + return; + } + + let barrierSize = Math.min(10, panel.panelBox.height); + let fixed1 = panel.monitor.y; + let fixed2 = panel.monitor.y + barrierSize; + + if (panel.checkIfVertical()) { + barriers._rightPanelBarrier.push(panel.monitor.y + panel.monitor.height, Meta.BarrierDirection.POSITIVE_Y); + barriers._leftPanelBarrier.push(panel.monitor.y, Meta.BarrierDirection.NEGATIVE_Y); + } else { + barriers._rightPanelBarrier.push(panel.monitor.x + panel.monitor.width, Meta.BarrierDirection.NEGATIVE_X); + barriers._leftPanelBarrier.push(panel.monitor.x, Meta.BarrierDirection.POSITIVE_X); + } + + switch (panel.getPosition()) { + //values are initialized as St.Side.TOP + case St.Side.BOTTOM: + fixed1 = panel.monitor.y + panel.monitor.height - barrierSize; + fixed2 = panel.monitor.y + panel.monitor.height; + break; + case St.Side.LEFT: + fixed1 = panel.monitor.x; + fixed2 = panel.monitor.x + barrierSize; + break; + case St.Side.RIGHT: + fixed1 = panel.monitor.x + panel.monitor.width; + fixed2 = panel.monitor.x + panel.monitor.width - barrierSize; + break; + } + + //remove left barrier if it overlaps one of the hotcorners + for (let k in this.hotCorners) { + let hc = this.hotCorners[k]; + + if (hc && hc._monitor == panel.monitor && + ((fixed1 == hc._x || fixed2 == hc._x) || fixed1 == hc._y || fixed2 == hc._y)) { + delete barriers._leftPanelBarrier; + break; + } + } + + Object.keys(barriers).forEach(k => { + let barrierOptions = { + display: global.display, + directions: barriers[k][2] + }; + + barrierOptions[panel.varCoord.c1] = barrierOptions[panel.varCoord.c2] = barriers[k][1]; + barrierOptions[panel.fixedCoord.c1] = fixed1; + barrierOptions[panel.fixedCoord.c2] = fixed2; + + barriers[k][0][k] = new Meta.Barrier(barrierOptions); + }); +} + +function _newLookingGlassResize() { + let primaryMonitorPanel = Utils.find(global.dashToPanel.panels, p => p.monitor == Main.layoutManager.primaryMonitor); + let topOffset = primaryMonitorPanel.getPosition() == St.Side.TOP ? primaryMonitorPanel.dtpSize + 8 : 32; + + this._oldResize(); + Utils.wrapActor(this); + Utils.wrapActor(this._objInspector); + + this._hiddenY = Main.layoutManager.primaryMonitor.y + topOffset - this.actor.height; + this._targetY = this._hiddenY + this.actor.height; + this.actor.y = this._hiddenY; + + this._objInspector.actor.set_position(this.actor.x + Math.floor(this.actor.width * 0.1), this._targetY + Math.floor(this.actor.height * 0.1)); +} + +function _newLookingGlassOpen() { + if (this._open) + return; + + this._resize(); + this._oldOpen(); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js new file mode 100644 index 0000000..52458bb --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js @@ -0,0 +1,61 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +var SHOW_APPS_BTN = 'showAppsButton'; +var ACTIVITIES_BTN = 'activitiesButton'; +var TASKBAR = 'taskbar'; +var DATE_MENU = 'dateMenu'; +var SYSTEM_MENU = 'systemMenu'; +var LEFT_BOX = 'leftBox'; +var CENTER_BOX = 'centerBox'; +var RIGHT_BOX = 'rightBox'; +var DESKTOP_BTN = 'desktopButton'; + +var STACKED_TL = 'stackedTL'; +var STACKED_BR = 'stackedBR'; +var CENTERED = 'centered'; +var CENTERED_MONITOR = 'centerMonitor'; + +var TOP = 'TOP'; +var BOTTOM = 'BOTTOM'; +var LEFT = 'LEFT'; +var RIGHT = 'RIGHT'; + +var START = 'START'; +var MIDDLE = 'MIDDLE'; +var END = 'END'; + +var defaults = [ + { element: SHOW_APPS_BTN, visible: true, position: STACKED_TL }, + { element: ACTIVITIES_BTN, visible: false, position: STACKED_TL }, + { element: LEFT_BOX, visible: true, position: STACKED_TL }, + { element: TASKBAR, visible: true, position: STACKED_TL }, + { element: CENTER_BOX, visible: true, position: STACKED_BR }, + { element: RIGHT_BOX, visible: true, position: STACKED_BR }, + { element: DATE_MENU, visible: true, position: STACKED_BR }, + { element: SYSTEM_MENU, visible: true, position: STACKED_BR }, + { element: DESKTOP_BTN, visible: true, position: STACKED_BR }, +]; + +var optionDialogFunctions = {}; + +optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions'; +optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'; + +function checkIfCentered(position) { + return position == CENTERED || position == CENTERED_MONITOR; +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js new file mode 100644 index 0000000..4feb3fd --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js @@ -0,0 +1,112 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Pos = Me.imports.panelPositions; + +/** Return object representing a settings value that is stored as JSON. */ +function getSettingsJson(settings, setting) { + try { + return JSON.parse(settings.get_string(setting)); + } catch(e) { + log('Error parsing positions: ' + e.message); + } +} +/** Write value object as JSON to setting in settings. */ +function setSettingsJson(settings, setting, value) { + try { + const json = JSON.stringify(value); + settings.set_string(setting, json); + } catch(e) { + log('Error serializing setting: ' + e.message); + } +} + +/** Returns size of panel on a specific monitor, in pixels. */ +function getPanelSize(settings, monitorIndex) { + const sizes = getSettingsJson(settings, 'panel-sizes'); + // Pull in deprecated setting if panel-sizes does not have setting for monitor. + const fallbackSize = settings.get_int('panel-size'); + const theDefault = 48; + return sizes[monitorIndex] || fallbackSize || theDefault; +} + +function setPanelSize(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 128 && value >= 16)) { + log('Not setting invalid panel size: ' + value); + return; + } + let sizes = getSettingsJson(settings, 'panel-sizes'); + sizes[monitorIndex] = value; + setSettingsJson(settings, 'panel-sizes', sizes); +} + +/** + * Returns length of panel on a specific monitor, as a whole number percent, + * from settings. e.g. 100 + */ +function getPanelLength(settings, monitorIndex) { + const lengths = getSettingsJson(settings, 'panel-lengths'); + const theDefault = 100; + return lengths[monitorIndex] || theDefault; +} + +function setPanelLength(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 100 && value >= 0)) { + log('Not setting invalid panel length: ' + value); + return; + } + let lengths = getSettingsJson(settings, 'panel-lengths'); + lengths[monitorIndex] = value; + setSettingsJson(settings, 'panel-lengths', lengths); +} + +/** Returns position of panel on a specific monitor. */ +function getPanelPosition(settings, monitorIndex) { + const positions = getSettingsJson(settings, 'panel-positions'); + const fallbackPosition = settings.get_string('panel-position'); + const theDefault = Pos.BOTTOM; + return positions[monitorIndex] || fallbackPosition || theDefault; +} + +function setPanelPosition(settings, monitorIndex, value) { + if (!(value === Pos.TOP || value === Pos.BOTTOM || value === Pos.LEFT + || value === Pos.RIGHT)) { + log('Not setting invalid panel position: ' + value); + return; + } + const positions = getSettingsJson(settings, 'panel-positions'); + positions[monitorIndex] = value; + setSettingsJson(settings, 'panel-positions', positions); +} + +/** Returns anchor location of panel on a specific monitor. */ +function getPanelAnchor(settings, monitorIndex) { + const anchors = getSettingsJson(settings, 'panel-anchors'); + const theDefault = Pos.MIDDLE; + return anchors[monitorIndex] || theDefault; +} + +function setPanelAnchor(settings, monitorIndex, value) { + if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) { + log('Not setting invalid panel anchor: ' + value); + return; + } + const anchors = getSettingsJson(settings, 'panel-anchors'); + anchors[monitorIndex] = value; + setSettingsJson(settings, 'panel-anchors', anchors); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js new file mode 100644 index 0000000..2697ace --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js @@ -0,0 +1,326 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * Ideas for recursing child actors and assigning inline styles + * are based on code from the StatusAreaHorizontalSpacing extension + * https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension + * mathematical.coffee@gmail.com + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const ExtensionUtils = imports.misc.extensionUtils; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const St = imports.gi.St; +const Shell = imports.gi.Shell; + +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +var dtpPanelStyle = Utils.defineClass({ + Name: 'DashToPanel.PanelStyle', + + _init: function() { + + }, + + enable : function(panel) { + this.panel = panel; + + this._applyStyles(); + + this._bindSettingsChanges(); + }, + + disable: function () { + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + + this._removeStyles(); + }, + + _bindSettingsChanges: function() { + let configKeys = [ + "tray-size", + "leftbox-size", + "tray-padding", + "leftbox-padding", + "status-icon-padding", + ]; + + this._dtpSettingsSignalIds = []; + + for(let i in configKeys) { + this._dtpSettingsSignalIds.push(Me.settings.connect('changed::' + configKeys[i], Lang.bind(this, function () { + this._removeStyles(); + this._applyStyles(); + }))); + } + }, + + _applyStyles: function() { + this._rightBoxOperations = []; + + let trayPadding = Me.settings.get_int('tray-padding'); + let isVertical = this.panel.checkIfVertical(); + let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx'); + + if(trayPadding >= 0) { + let operation = {}; + let trayPaddingStyleLine; + + if (isVertical) { + trayPaddingStyleLine = paddingStyle.format(trayPadding); + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + } else { + trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding); + if (trayPadding < 6) { + trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(trayPadding); + } + + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('panel-button')); + }; + } + + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayPaddingStyleLine, operationIdx); + this._refreshPanelButton(actor); + }); + this._rightBoxOperations.push(operation); + } + + let statusIconPadding = Me.settings.get_int('status-icon-padding'); + if(statusIconPadding >= 0) { + let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('system-status-icon')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + } + + let trayContentSize = Me.settings.get_int('tray-size'); + if(trayContentSize > 0) { + let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0); + this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0); + } + + // center box has been moved next to the right box and will be treated the same + this._centerBoxOperations = this._rightBoxOperations; + + this._leftBoxOperations = []; + + let leftboxPadding = Me.settings.get_int('leftbox-padding'); + if(leftboxPadding >= 0) { + let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding); + let operation = {}; + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + } + + let leftboxContentSize = Me.settings.get_int('leftbox-size'); + if(leftboxContentSize > 0) { + let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(leftboxContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(leftboxContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0); + } + + this._applyStylesRecursively(); + + /* connect signal */ + this._rightBoxActorAddedID = this.panel._rightBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._rightBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._rightBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._centerBoxActorAddedID = this.panel._centerBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._centerBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._centerBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._leftBoxActorAddedID = this.panel._leftBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._leftBoxOperations.length) + this._recursiveApply(actor, this._leftBoxOperations); + }) + ); + }, + + _removeStyles: function() { + /* disconnect signal */ + if (this._rightBoxActorAddedID) + this.panel._rightBox.disconnect(this._rightBoxActorAddedID); + if (this._centerBoxActorAddedID) + this.panel._centerBox.disconnect(this._centerBoxActorAddedID); + if (this._leftBoxActorAddedID) + this.panel._leftBox.disconnect(this._leftBoxActorAddedID); + + this._restoreOriginalStyle(this.panel._rightBox); + this._restoreOriginalStyle(this.panel._centerBox); + this._restoreOriginalStyle(this.panel._leftBox); + + this._applyStylesRecursively(true); + }, + + _applyStylesRecursively: function(restore) { + /*recurse actors */ + if(this._rightBoxOperations.length) { + // add the system menu as we move it from the rightbox to the panel to position it independently + let children = this.panel._rightBox.get_children().concat([this.panel.statusArea.aggregateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._rightBoxOperations, restore); + } + + if(this._centerBoxOperations.length) { + // add the date menu as we move it from the centerbox to the panel to position it independently + let children = this.panel._centerBox.get_children().concat([this.panel.statusArea.dateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._centerBoxOperations, restore); + } + + if(this._leftBoxOperations.length) { + let children = this.panel._leftBox.get_children(); + for(let i in children) + this._recursiveApply(children[i], this._leftBoxOperations, restore); + } + }, + + _recursiveApply: function(actor, operations, restore) { + for(let i in operations) { + let o = operations[i]; + if(o.compareFn(actor)) + if(restore) + o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor); + else + o.applyFn(actor, i); + } + + if(actor.get_children) { + let children = actor.get_children(); + for(let i in children) { + this._recursiveApply(children[i], operations, restore); + } + } + }, + + _overrideStyle: function(actor, styleLine, operationIdx) { + if (actor._dtp_original_inline_style === undefined) { + actor._dtp_original_inline_style = actor.get_style(); + } + + if(actor._dtp_style_overrides === undefined) { + actor._dtp_style_overrides = {}; + } + + actor._dtp_style_overrides[operationIdx] = styleLine; + let newStyleLine = ''; + for(let i in actor._dtp_style_overrides) + newStyleLine += actor._dtp_style_overrides[i] + '; '; + actor.set_style(newStyleLine + (actor._dtp_original_inline_style || '')); + }, + + _restoreOriginalStyle: function(actor) { + if (actor._dtp_original_inline_style !== undefined) { + actor.set_style(actor._dtp_original_inline_style); + delete actor._dtp_original_inline_style; + delete actor._dtp_style_overrides; + } + + if (actor.has_style_class_name('panel-button')) { + this._refreshPanelButton(actor); + } + }, + + _refreshPanelButton: function(actor) { + if (actor.visible && imports.misc.config.PACKAGE_VERSION >= '3.34.0') { + //force gnome 3.34+ to refresh (having problem with the -natural-hpadding) + let parent = actor.get_parent(); + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(actor); + } + + this._ignoreAddedChild = [this.panel._centerBox, this.panel._rightBox].indexOf(parent) >= 0; + + parent.remove_child(actor); + parent.insert_child_at_index(actor, actorIndex); + } + } + +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js new file mode 100644 index 0000000..3040787 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js @@ -0,0 +1,2468 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg. + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Lang = imports.lang; +const Mainloop = imports.mainloop; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; +const N_ = function(e) { return e }; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; + +const SCALE_UPDATE_TIMEOUT = 500; +const DEFAULT_PANEL_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; +const DEFAULT_FONT_SIZES = [ 96, 64, 48, 32, 24, 16, 0 ]; +const DEFAULT_MARGIN_SIZES = [ 32, 24, 16, 12, 8, 4, 0 ]; +const DEFAULT_PADDING_SIZES = [ 32, 24, 16, 12, 8, 4, 0, -1 ]; +// Minimum length could be 0, but a higher value may help prevent confusion about where the panel went. +const LENGTH_MARKS = [ 100, 90, 80, 70, 60, 50, 40, 30, 20, 10 ]; +const MAX_WINDOW_INDICATOR = 4; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/dash-to-panel/'; +const GSET = 'gnome-shell-extension-tool'; + +/** + * This function was copied from the activities-config extension + * https://github.com/nls1729/acme-code/tree/master/activities-config + * by Norman L. Smith. + */ +function cssHexString(css) { + let rrggbb = '#'; + let start; + for (let loop = 0; loop < 3; loop++) { + let end = 0; + let xx = ''; + for (let loop = 0; loop < 2; loop++) { + while (true) { + let x = css.slice(end, end + 1); + if ((x == '(') || (x == ',') || (x == ')')) + break; + end++; + } + if (loop == 0) { + end++; + start = end; + } + } + xx = parseInt(css.slice(start, end)).toString(16); + if (xx.length == 1) + xx = '0' + xx; + rrggbb += xx; + css = css.slice(end); + } + return rrggbb; +} + +function setShortcut(settings, shortcutName) { + let shortcut_text = settings.get_string(shortcutName + '-text'); + let [key, mods] = Gtk.accelerator_parse(shortcut_text); + + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + settings.set_strv(shortcutName, [shortcut]); + } + else { + settings.set_strv(shortcutName, []); + } +} + +function checkHotkeyPrefix(settings) { + settings.delay(); + + let hotkeyPrefix = settings.get_string('hotkey-prefix-text'); + if (hotkeyPrefix == 'Super') + hotkeyPrefix = ''; + else if (hotkeyPrefix == 'SuperAlt') + hotkeyPrefix = ''; + let [, mods] = Gtk.accelerator_parse(hotkeyPrefix); + let [, shift_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + let [, ctrl_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + + let numHotkeys = 10; + for (let i = 1; i <= numHotkeys; i++) { + let number = i; + if (number == 10) + number = 0; + let key = Gdk.keyval_from_name(number.toString()); + let key_kp = Gdk.keyval_from_name('KP_' + number.toString()); + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + let shortcut_kp = Gtk.accelerator_name(key_kp, mods); + + // Setup shortcut strings + settings.set_strv('app-hotkey-' + i, [shortcut]); + settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, shift_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods); + settings.set_strv('app-shift-hotkey-' + i, [shortcut]); + settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, ctrl_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods); + settings.set_strv('app-ctrl-hotkey-' + i, [shortcut]); + settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp]); + } + else { + // Reset default settings for the relevant keys if the + // accelerators are invalid + let keys = ['app-hotkey-' + i, 'app-shift-hotkey-' + i, 'app-ctrl-hotkey-' + i, // Regular numbers + 'app-hotkey-kp-' + i, 'app-shift-hotkey-kp-' + i, 'app-ctrl-hotkey-kp-' + i]; // Key-pad numbers + keys.forEach(function(val) { + settings.set_value(val, settings.get_default_value(val)); + }, this); + } + } + + settings.apply(); +} + +function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +const Preferences = new Lang.Class({ + Name: 'DashToPanel.Preferences', + + _init: function() { + this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); + this._builder = new Gtk.Builder(); + this._builder.set_scope(new BuilderScope(this)); + this._builder.set_translation_domain(Me.metadata['gettext-domain']); + this._builder.add_from_file(Me.path + '/Settings.ui'); + this.notebook = this._builder.get_object('settings_notebook'); + + // Timeout to delay the update of the settings + this._panel_size_timeout = 0; + this._dot_height_timeout = 0; + this._tray_size_timeout = 0; + this._leftbox_size_timeout = 0; + this._appicon_margin_timeout = 0; + this._appicon_padding_timeout = 0; + this._opacity_timeout = 0; + this._tray_padding_timeout = 0; + this._statusicon_padding_timeout = 0; + this._leftbox_padding_timeout = 0; + this._addFormatValueCallbacks(); + this._bindSettings(); + }, + + /** + * Connect signals + */ + _connector: function(builder, object, signal, handler) { + object.connect(signal, Lang.bind(this, this._SignalHandler[handler])); + }, + + _updateVerticalRelatedOptions: function() { + let position = this._getPanelPosition(this._currentMonitorIndex); + let isVertical = position == Pos.LEFT || position == Pos.RIGHT; + let showDesktopWidthLabel = this._builder.get_object('show_showdesktop_width_label'); + + showDesktopWidthLabel.set_text(isVertical ? _('Show Desktop button height (px)') : _('Show Desktop button width (px)')); + + this._displayPanelPositionsForMonitor(this._currentMonitorIndex); + }, + + _maybeDisableTopPosition: function() { + let keepTopPanel = this._settings.get_boolean('stockgs-keep-top-panel'); + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let topAvailable = !keepTopPanel || (!monitorSync && this._currentMonitorIndex != this.monitors[0]); + let topRadio = this._builder.get_object('position_top_button'); + + topRadio.set_sensitive(topAvailable); + topRadio.set_tooltip_text(!topAvailable ? _('Unavailable when gnome-shell top panel is present') : ''); + }, + + _getPanelPosition: function(monitorIndex) { + return PanelSettings.getPanelPosition(this._settings, monitorIndex); + }, + + _setPanelPosition: function(position) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelPosition(this._settings, monitorIndex, position); + }); + this._setAnchorLabels(this._currentMonitorIndex); + }, + + _setPositionRadios: function(position) { + this._ignorePositionRadios = true; + + switch (position) { + case Pos.BOTTOM: + this._builder.get_object('position_bottom_button').set_active(true); + break; + case Pos.TOP: + this._builder.get_object('position_top_button').set_active(true); + break; + case Pos.LEFT: + this._builder.get_object('position_left_button').set_active(true); + break; + case Pos.RIGHT: + this._builder.get_object('position_right_button').set_active(true); + break; + } + + this._ignorePositionRadios = false; + }, + + /** + * Set panel anchor combo labels according to whether the monitor's panel is vertical + * or horizontal, or if all monitors' panels are being configured and they are a mix + * of vertical and horizontal. + */ + _setAnchorLabels: function(currentMonitorIndex) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [currentMonitorIndex]; + const allVertical = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.LEFT || position === Pos.RIGHT + }); + const allHorizontal = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.TOP || position === Pos.BOTTOM; + }); + + const anchor_combo = this._builder.get_object('panel_anchor_combo'); + anchor_combo.remove_all(); + + if (allHorizontal) { + anchor_combo.append(Pos.START, _('Left')); + anchor_combo.append(Pos.MIDDLE, _('Center')); + anchor_combo.append(Pos.END, _('Right')); + } else if (allVertical) { + anchor_combo.append(Pos.START, _('Top')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('Bottom')); + } else { + // Setting for a mix of horizontal and vertical panels on different monitors. + anchor_combo.append(Pos.START, _('Start')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('End')); + } + + // Set combo box after re-populating its options. But only if it's for a single-panel + // configuration, or a multi-panel configuration where they all have the same anchor + // setting. So don't set the combo box if there is a multi-panel configuration with + // different anchor settings. + const someAnchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + if (monitorsToSetFor.every(i => + PanelSettings.getPanelAnchor(this._settings, i) === someAnchor)) { + const panel_anchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + this._builder.get_object('panel_anchor_combo').set_active_id(panel_anchor); + } + }, + + /** + * When a monitor is selected, update the widgets for panel position, size, anchoring, + * and contents so they accurately show the settings for the panel on that monitor. + */ + _updateWidgetSettingsForMonitor: function(monitorIndex) { + // Update display of panel screen position setting + this._maybeDisableTopPosition(); + const panelPosition = this._getPanelPosition(monitorIndex); + this._setPositionRadios(panelPosition); + + // Update display of thickness, length, and anchor settings + const panel_size_scale = this._builder.get_object('panel_size_scale'); + const size = PanelSettings.getPanelSize(this._settings, monitorIndex); + panel_size_scale.set_value(size); + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + const length = PanelSettings.getPanelLength(this._settings, monitorIndex); + panel_length_scale.set_value(length); + this._setAnchorWidgetSensitivity(length); + + this._setAnchorLabels(monitorIndex); + + // Update display of panel content settings + this._displayPanelPositionsForMonitor(monitorIndex); + }, + + /** + * Anchor is only relevant if panel length is less than 100%. Enable or disable + * anchor widget sensitivity accordingly. + */ + _setAnchorWidgetSensitivity: function(panelLength) { + const isPartialLength = panelLength < 100; + this._builder.get_object('panel_anchor_label').set_sensitive(isPartialLength); + this._builder.get_object('panel_anchor_combo').set_sensitive(isPartialLength); + }, + + _displayPanelPositionsForMonitor: function(monitorIndex) { + let taskbarListBox = this._builder.get_object('taskbar_display_listbox'); + + while(taskbarListBox.get_first_child()) + { + taskbarListBox.remove(taskbarListBox.get_first_child()); + } + + let labels = {}; + let panelPosition = this._getPanelPosition(monitorIndex); + let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT; + let panelElementPositionsSettings = PanelSettings.getSettingsJson(this._settings, 'panel-element-positions'); + let panelElementPositions = panelElementPositionsSettings[monitorIndex] || Pos.defaults; + let updateElementsSettings = () => { + let newPanelElementPositions = []; + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let monitors = monitorSync ? this.monitors : [monitorIndex]; + + let child = taskbarListBox.get_first_child(); + while (child != null) + { + newPanelElementPositions.push({ + element: child.id, + visible: child.visibleToggleBtn.get_active(), + position: child.positionCombo.get_active_id() + }); + child = child.get_next_sibling(); + } + + monitors.forEach(m => panelElementPositionsSettings[m] = newPanelElementPositions); + this._settings.set_string('panel-element-positions', JSON.stringify(panelElementPositionsSettings)); + }; + + + labels[Pos.SHOW_APPS_BTN] = _('Show Applications button'); + labels[Pos.ACTIVITIES_BTN] = _('Activities button'); + labels[Pos.TASKBAR] = _('Taskbar'); + labels[Pos.DATE_MENU] = _('Date menu'); + labels[Pos.SYSTEM_MENU] = _('System menu'); + labels[Pos.LEFT_BOX] = _('Left box'); + labels[Pos.CENTER_BOX] = _('Center box'); + labels[Pos.RIGHT_BOX] = _('Right box'); + labels[Pos.DESKTOP_BTN] = _('Desktop button'); + + panelElementPositions.forEach(el => { + let row = new Gtk.ListBoxRow(); + let grid = new Gtk.Grid({ margin_start: 12, margin_end: 12, column_spacing: 8 }); + let upDownGrid = new Gtk.Grid({ column_spacing: 2 }); + let upBtn = new Gtk.Button({ tooltip_text: _('Move up') }); + let upImg = new Gtk.Image({ icon_name: 'go-up-symbolic', pixel_size: 12 }); + let downBtn = new Gtk.Button({ tooltip_text: _('Move down') }); + let downImg = new Gtk.Image({ icon_name: 'go-down-symbolic', pixel_size: 12 }); + let visibleToggleBtn = new Gtk.ToggleButton({ label: _('Visible'), active: el.visible }); + let positionCombo = new Gtk.ComboBoxText({ tooltip_text: _('Select element position') }); + let upDownClickHandler = limit => { + let index = row.get_index(); + + if (index != limit) { + taskbarListBox.remove(row); + taskbarListBox.insert(row, index + (!limit ? -1 : 1)); + updateElementsSettings(); + } + }; + + positionCombo.append(Pos.STACKED_TL, isVertical ? _('Stacked to top') : _('Stacked to left')); + positionCombo.append(Pos.STACKED_BR, isVertical ? _('Stacked to bottom') :_('Stacked to right')); + positionCombo.append(Pos.CENTERED, _('Centered')); + positionCombo.append(Pos.CENTERED_MONITOR, _('Monitor Center')); + positionCombo.set_active_id(el.position); + + upBtn.connect('clicked', () => upDownClickHandler(0)); + downBtn.connect('clicked', () => upDownClickHandler(panelElementPositions.length - 1)); + visibleToggleBtn.connect('toggled', () => updateElementsSettings()); + positionCombo.connect('changed', () => updateElementsSettings()); + + upBtn.set_child(upImg); + downBtn.set_child(downImg); + + upDownGrid.attach(upBtn, 0, 0, 1, 1); + upDownGrid.attach(downBtn, 1, 0, 1, 1); + + grid.attach(upDownGrid, 0, 0, 1, 1); + grid.attach(new Gtk.Label({ label: labels[el.element], xalign: 0, hexpand: true }), 1, 0, 1, 1); + + if (Pos.optionDialogFunctions[el.element]) { + let cogImg = new Gtk.Image({ icon_name: 'emblem-system-symbolic' }); + let optionsBtn = new Gtk.Button({ tooltip_text: _('More options') }); + + optionsBtn.get_style_context().add_class('circular'); + optionsBtn.set_child(cogImg); + grid.attach(optionsBtn, 2, 0, 1, 1); + + optionsBtn.connect('clicked', () => this[Pos.optionDialogFunctions[el.element]]()); + } + + grid.attach(visibleToggleBtn, 3, 0, 1, 1); + grid.attach(positionCombo, 4, 0, 1, 1); + + row.id = el.element; + row.visibleToggleBtn = visibleToggleBtn; + row.positionCombo = positionCombo; + + row.set_child(grid); + taskbarListBox.insert(row, -1); + }); + }, + + _showShowAppsButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Applications options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('show_applications_options'); + dialog.get_content_area().append(box); + + let fileChooserButton = this._builder.get_object('show_applications_icon_file_filebutton'); + let fileChooser = new Gtk.FileChooserNative({ title: _('Open icon'), transient_for: dialog }); + let fileImage = this._builder.get_object('show_applications_current_icon_image'); + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + fileChooser.filter = fileFilter; + + let handleIconChange = function(newIconPath) { + if (newIconPath && GLib.file_test(newIconPath, GLib.FileTest.EXISTS)) { + let file = Gio.File.new_for_path(newIconPath); + let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(file.read(null), 32, 32, true, null); + + fileImage.set_from_pixbuf(pixbuf); + fileChooser.set_file(file); + fileChooserButton.set_label(newIconPath); + } else { + newIconPath = ''; + fileImage.set_from_icon_name('view-app-grid-symbolic'); + let picturesFolder = Gio.File.new_for_path(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)); + fileChooser.set_file(picturesFolder); + fileChooserButton.set_label("(None)"); + } + + this._settings.set_string('show-apps-icon-file', newIconPath || ''); + }; + + fileChooserButton.connect('clicked', Lang.bind(this, function() { + fileChooser.show(); + })); + + fileChooser.connect('response', widget => handleIconChange.call(this, widget.get_file().get_path())); + handleIconChange.call(this, this._settings.get_string('show-apps-icon-file')); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-apps-icon-side-padding', this._settings.get_default_value('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._settings.set_value('show-apps-override-escape', this._settings.get_default_value('show-apps-override-escape')); + handleIconChange.call(this, null); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + fileChooser.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _showDesktopButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Desktop options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_show_showdesktop_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('showdesktop-button-width', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-delay', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-time', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('showdesktop-button-width', this._settings.get_default_value('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + + this._settings.set_value('show-showdesktop-hover', this._settings.get_default_value('show-showdesktop-hover')); + + this._settings.set_value('show-showdesktop-delay', this._settings.get_default_value('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + + this._settings.set_value('show-showdesktop-time', this._settings.get_default_value('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _addFormatValueCallbacks: function() { + // position + this._builder.get_object('panel_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // style + this._builder.get_object('appicon_margin_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('appicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box1 + this._builder.get_object('tray_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box2 + this._builder.get_object('tray_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('statusicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // animate hovering app icons dialog + this._builder.get_object('animate_appicon_hover_options_duration_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d ms").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_rotation_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d °").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_travel_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_zoom_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_convexity_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%.1f").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_extent_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return Gettext.ngettext("%d icon", "%d icons", value).format(value); + })); + }, + + _bindSettings: function() { + // size options + let panel_size_scale = this._builder.get_object('panel_size_scale'); + panel_size_scale.set_range(DEFAULT_PANEL_SIZES[DEFAULT_PANEL_SIZES.length - 1], DEFAULT_PANEL_SIZES[0]); + DEFAULT_PANEL_SIZES.slice(1, -1).forEach(function(val) { + panel_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Correct for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + panel_size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + panel_size_scale.set_flippable(false); + panel_size_scale.set_inverted(true); + } + + // Dots Position option + let dotPosition = this._settings.get_string('dot-position'); + + switch (dotPosition) { + case 'BOTTOM': + this._builder.get_object('dots_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('dots_top_button').set_active(true); + break; + case 'LEFT': + this._builder.get_object('dots_left_button').set_active(true); + break; + case 'RIGHT': + this._builder.get_object('dots_right_button').set_active(true); + break; + } + + this._builder.get_object('dot_style_focused_combo').set_active_id(this._settings.get_string('dot-style-focused')); + this._builder.get_object('dot_style_focused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-focused', widget.get_active_id()); + })); + + this._builder.get_object('dot_style_unfocused_combo').set_active_id(this._settings.get_string('dot-style-unfocused')); + this._builder.get_object('dot_style_unfocused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-unfocused', widget.get_active_id()); + })); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let idx = i; + this._builder.get_object('dot_color_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-' + idx, hexString); + })); + + this._builder.get_object('dot_color_unfocused_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-unfocused-' + idx, hexString); + })); + } + + this._builder.get_object('dot_color_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_value('dot-color-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('dot_color_unfocused_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_value('dot-color-unfocused-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('focus_highlight_color_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('focus-highlight-color', hexString); + })); + + this._builder.get_object('dot_style_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Running Indicator Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dots_options'); + dialog.get_content_area().append(box); + + this._settings.bind('dot-color-dominant', + this._builder.get_object('dot_color_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // when either becomes active, turn the other off + this._builder.get_object('dot_color_dominant_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-override', false); + })); + this._builder.get_object('dot_color_override_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-dominant', false); + })); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('dot_color_unfocused_different_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('grid_dot_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_unfocused_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('grid_dot_color_unfocused'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.bind('focus-highlight', + this._builder.get_object('focus_highlight_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight', + this._builder.get_object('grid_focus_highlight_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_label'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('focus-highlight-opacity', widget.get_value()); + })); + + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + this._builder.get_object('dot_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('dot-size', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('dot-color-dominant', this._settings.get_default_value('dot-color-dominant')); + this._settings.set_value('dot-color-override', this._settings.get_default_value('dot-color-override')); + this._settings.set_value('dot-color-unfocused-different', this._settings.get_default_value('dot-color-unfocused-different')); + + this._settings.set_value('focus-highlight-color', this._settings.get_default_value('focus-highlight-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('focus-highlight-opacity', this._settings.get_default_value('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_default_value('dot-color-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_default_value('dot-color-unfocused-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.set_value('dot-size', this._settings.get_default_value('dot-size')); + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + + this._settings.set_value('focus-highlight', this._settings.get_default_value('focus-highlight')); + this._settings.set_value('focus-highlight-dominant', this._settings.get_default_value('focus-highlight-dominant')); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + //multi-monitor + this.monitors = this._settings.get_value('available-monitors').deep_unpack(); + + let dtpPrimaryMonitorIndex = this.monitors.indexOf(this._settings.get_int('primary-monitor')); + + if (dtpPrimaryMonitorIndex < 0) { + dtpPrimaryMonitorIndex = 0; + } + + this._currentMonitorIndex = this.monitors[dtpPrimaryMonitorIndex]; + + this._settings.connect('changed::panel-positions', () => this._updateVerticalRelatedOptions()); + this._updateVerticalRelatedOptions(); + + for (let i = 0; i < this.monitors.length; ++i) { + //the primary index is the first one in the "available-monitors" setting + let label = !i ? _('Primary monitor') : _('Monitor ') + (i + 1); + + this._builder.get_object('multimon_primary_combo').append_text(label); + this._builder.get_object('taskbar_position_monitor_combo').append_text(label); + } + + this._builder.get_object('multimon_primary_combo').set_active(dtpPrimaryMonitorIndex); + this._builder.get_object('taskbar_position_monitor_combo').set_active(dtpPrimaryMonitorIndex); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_sync_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_monitor_combo'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.connect('changed::panel-element-positions-monitors-sync', () => { + this._maybeDisableTopPosition(); + // The anchor combo box may has different labels for single- or all-monitor configuration. + this._setAnchorLabels(this._currentMonitorIndex); + }); + + this._builder.get_object('multimon_primary_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('primary-monitor', this.monitors[widget.get_active()]); + })); + + this._builder.get_object('taskbar_position_monitor_combo').connect('changed', Lang.bind (this, function(widget) { + this._currentMonitorIndex = this.monitors[widget.get_active()]; + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + })); + + this._settings.bind('multi-monitors', + this._builder.get_object('multimon_multi_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + if (this.monitors.length === 1) { + this._builder.get_object('multimon_multi_switch').set_sensitive(false); + } + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + panel_length_scale.connect('value-changed', Lang.bind (this, function(widget) { + const value = widget.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelLength(this._settings, monitorIndex, value); + }); + + this._setAnchorWidgetSensitivity(value); + })); + + this._builder.get_object('panel_anchor_combo').connect('changed', Lang.bind (this, function(widget) { + const value = widget.get_active_id(); + // Value can be null while anchor labels are being swapped out + if (value !== null) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelAnchor(this._settings, monitorIndex, value); + }); + } + })); + + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + + //dynamic opacity + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('trans-bg-color')); + this._builder.get_object('trans_bg_color_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_bg_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-bg-color', hexString); + })); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('trans_opacity_override_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('trans_dyn_switch').set_active(false); + }); + + this._builder.get_object('trans_opacity_spinbutton').set_value(this._settings.get_double('trans-panel-opacity') * 100); + this._builder.get_object('trans_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-panel-opacity', widget.get_value() * 0.01); + })); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-dynamic-behavior', + this._builder.get_object('trans_options_window_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('trans-gradient-top-color')); + this._builder.get_object('trans_gradient_color1_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color1_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-top-color', hexString); + })); + + this._builder.get_object('trans_gradient_color1_spinbutton').set_value(this._settings.get_double('trans-gradient-top-opacity') * 100); + this._builder.get_object('trans_gradient_color1_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-top-opacity', widget.get_value() * 0.01); + })); + + rgba.parse(this._settings.get_string('trans-gradient-bottom-color')); + this._builder.get_object('trans_gradient_color2_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color2_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-bottom-color', hexString); + })); + + this._builder.get_object('trans_gradient_color2_spinbutton').set_value(this._settings.get_double('trans-gradient-bottom-opacity') * 100); + this._builder.get_object('trans_gradient_color2_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-bottom-opacity', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-distance', widget.get_value()); + })); + + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + this._builder.get_object('trans_options_min_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-dynamic-anim-target', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-anim-time', widget.get_value()); + })); + + this._builder.get_object('trans_dyn_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Dynamic opacity options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dynamic_opacity_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('trans-dynamic-behavior', this._settings.get_default_value('trans-dynamic-behavior')); + + this._settings.set_value('trans-dynamic-distance', this._settings.get_default_value('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + + this._settings.set_value('trans-dynamic-anim-target', this._settings.get_default_value('trans-dynamic-anim-target')); + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + + this._settings.set_value('trans-dynamic-anim-time', this._settings.get_default_value('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('desktop-line-custom-color')); + this._builder.get_object('override_show_desktop_line_color_colorbutton').set_rgba(rgba); + this._builder.get_object('override_show_desktop_line_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + this._settings.set_string('desktop-line-custom-color', css); + })); + + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_window_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_behaviour_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-behaviour', + this._builder.get_object('intellihide_behaviour_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-show-in-fullscreen', + this._builder.get_object('intellihide_show_in_fullscreen_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-only-secondary', + this._builder.get_object('intellihide_only_secondary_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('multi-monitors', + this._builder.get_object('grid_intellihide_only_secondary'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('multimon_multi_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('intellihide_only_secondary_switch').set_active(false); + }); + + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-threshold', widget.get_value()); + })); + + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-time', widget.get_value()); + })); + + this._settings.bind('intellihide-key-toggle-text', + this._builder.get_object('intellihide_toggle_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::intellihide-key-toggle-text', () => setShortcut(this._settings, 'intellihide-key-toggle')); + + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-animation-time', widget.get_value()); + })); + + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-close-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-enable-start-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Intellihide options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_intellihide_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('intellihide-hide-from-windows', this._settings.get_default_value('intellihide-hide-from-windows')); + this._settings.set_value('intellihide-behaviour', this._settings.get_default_value('intellihide-behaviour')); + this._settings.set_value('intellihide-use-pressure', this._settings.get_default_value('intellihide-use-pressure')); + this._settings.set_value('intellihide-show-in-fullscreen', this._settings.get_default_value('intellihide-show-in-fullscreen')); + this._settings.set_value('intellihide-only-secondary', this._settings.get_default_value('intellihide-only-secondary')); + + this._settings.set_value('intellihide-pressure-threshold', this._settings.get_default_value('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + + this._settings.set_value('intellihide-pressure-time', this._settings.get_default_value('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + + this._settings.set_value('intellihide-key-toggle-text', this._settings.get_default_value('intellihide-key-toggle-text')); + + this._settings.set_value('intellihide-animation-time', this._settings.get_default_value('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + + this._settings.set_value('intellihide-close-delay', this._settings.get_default_value('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + + this._settings.set_value('intellihide-enable-start-delay', this._settings.get_default_value('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + // Behavior panel + + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-apps-icon-side-padding', widget.get_value()); + })); + + this._settings.bind('show-apps-override-escape', + this._builder.get_object('show_applications_esc_key_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('show_showdesktop_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('grid_show_showdesktop_hide_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-appmenu', + this._builder.get_object('show_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-tooltip', + this._builder.get_object('show_tooltip_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('show_favorite_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites-all-monitors', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-running-apps', + this._builder.get_object('show_runnning_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._setPreviewTitlePosition(); + + this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('window-preview-title-font-color', hexString); + })); + + this._builder.get_object('show_window_previews_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Window preview options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let scrolledWindow = this._builder.get_object('box_window_preview_options'); + + dialog.get_content_area().append(scrolledWindow); + + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-window-previews-timeout', widget.get_value()); + })); + + this._settings.bind('preview-middle-click-close', + this._builder.get_object('preview_middle_click_close_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-x', + this._builder.get_object('preview_aspect_ratio_x_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-y', + this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('preview-custom-opacity', widget.get_value()); + })); + + this._settings.bind('peek-mode', + this._builder.get_object('peek_mode_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_enter_peek_mode_timeout'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_peek_mode_opacity'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-show-title', + this._builder.get_object('preview_show_title_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_custom_icon_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_weight'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_font_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('enter-peek-mode-timeout', widget.get_value()); + })); + + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('leave-timeout', widget.get_value()); + })); + + this._settings.bind('window-preview-hide-immediate-click', + this._builder.get_object('preview_immediate_click_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-animation-time', widget.get_value()); + })); + + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('peek-mode-opacity', widget.get_value()); + })); + + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-size', widget.get_value()); + })); + + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + this._builder.get_object('preview_aspect_ratio_x_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-x', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + this._builder.get_object('preview_aspect_ratio_y_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-y', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-padding', widget.get_value()); + })); + + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-title-font-size', widget.get_value()); + })); + + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-custom-icon-size', widget.get_value()); + })); + + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('window-preview-title-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-window-previews-timeout', this._settings.get_default_value('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + + this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + + this._settings.set_value('window-preview-hide-immediate-click', this._settings.get_default_value('window-preview-hide-immediate-click')); + + this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + + this._settings.set_value('preview-use-custom-opacity', this._settings.get_default_value('preview-use-custom-opacity')); + + this._settings.set_value('window-preview-use-custom-icon-size', this._settings.get_default_value('window-preview-use-custom-icon-size')); + + this._settings.set_value('preview-custom-opacity', this._settings.get_default_value('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + + this._settings.set_value('window-preview-title-position', this._settings.get_default_value('window-preview-title-position')); + this._setPreviewTitlePosition(); + + this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); + this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); + this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + + this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + + this._settings.set_value('window-preview-fixed-x', this._settings.get_default_value('window-preview-fixed-x')); + this._settings.set_value('window-preview-fixed-y', this._settings.get_default_value('window-preview-fixed-y')); + + this._settings.set_value('window-preview-aspect-ratio-x', this._settings.get_default_value('window-preview-aspect-ratio-x')); + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + + this._settings.set_value('window-preview-aspect-ratio-y', this._settings.get_default_value('window-preview-aspect-ratio-y')); + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + + this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + + this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); + + this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + + this._settings.set_value('window-preview-custom-icon-size', this._settings.get_default_value('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + + this._settings.set_value('window-preview-title-font-weight', this._settings.get_default_value('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + + this._settings.set_value('window-preview-title-font-color', this._settings.get_default_value('window-preview-title-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(scrolledWindow); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('isolate-workspaces', + this._builder.get_object('isolate_workspaces_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('isolate-monitors', + this._builder.get_object('multimon_multi_isolate_monitor_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overview-click-to-exit', + this._builder.get_object('clicktoexit_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('hide-overview-on-startup', + this._builder.get_object('hide_overview_on_startup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps', + this._builder.get_object('group_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('group-apps', + this._builder.get_object('show_group_apps_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._builder.get_object('group_apps_label_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color', hexString); + })); + + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color-minimized', hexString); + })); + + this._settings.bind('group-apps-use-fixed-width', + this._builder.get_object('group_apps_use_fixed_width_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-underline-unfocused', + this._builder.get_object('group_apps_underline_unfocused_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-use-launchers', + this._builder.get_object('group_apps_use_launchers_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('show_group_apps_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Ungrouped application options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_group_apps_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-font-size', widget.get_value()); + })); + + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('group-apps-label-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-max-width', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('group-apps-label-font-size', this._settings.get_default_value('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + + this._settings.set_value('group-apps-label-font-weight', this._settings.get_default_value('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + + this._settings.set_value('group-apps-label-font-color', this._settings.get_default_value('group-apps-label-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('group-apps-label-font-color-minimized', this._settings.get_default_value('group-apps-label-font-color-minimized')); + let minimizedFontColor = new Gdk.RGBA(); + minimizedFontColor.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(minimizedFontColor); + + this._settings.set_value('group-apps-label-max-width', this._settings.get_default_value('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + + this._settings.set_value('group-apps-use-fixed-width', this._settings.get_default_value('group-apps-use-fixed-width')); + this._settings.set_value('group-apps-underline-unfocused', this._settings.get_default_value('group-apps-underline-unfocused')); + this._settings.set_value('group-apps-use-launchers', this._settings.get_default_value('group-apps-use-launchers')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + this._builder.get_object('click_action_combo').set_active_id(this._settings.get_string('click-action')); + this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('click-action', widget.get_active_id()); + })); + + this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-click-action', widget.get_active_id()); + })); + + this._builder.get_object('middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('middle-click-action', widget.get_active_id()); + })); + this._builder.get_object('shift_middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-middle-click-action', widget.get_active_id()); + })); + + // Create dialog for middle-click options + this._builder.get_object('middle_click_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Customize middle-click behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_middle_click_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + + this._settings.bind('shift-click-action', + this._builder.get_object('shift_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('middle-click-action', + this._builder.get_object('middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('shift-middle-click-action', + this._builder.get_object('shift_middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(700, 1); + + })); + + this._builder.get_object('scroll_panel_combo').set_active_id(this._settings.get_string('scroll-panel-action')); + this._builder.get_object('scroll_panel_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-panel-action', widget.get_active_id()); + })); + + this._builder.get_object('scroll_icon_combo').set_active_id(this._settings.get_string('scroll-icon-action')); + this._builder.get_object('scroll_icon_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-icon-action', widget.get_active_id()); + })); + + // Create dialog for panel scroll options + this._builder.get_object('scroll_panel_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize panel scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_panel_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-panel-delay', widget.get_value()); + })); + + this._settings.bind('scroll-panel-show-ws-popup', + this._builder.get_object('scroll_panel_options_show_ws_popup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-panel-delay', this._settings.get_default_value('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + + this._settings.set_value('scroll-panel-show-ws-popup', this._settings.get_default_value('scroll-panel-show-ws-popup')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + // Create dialog for icon scroll options + this._builder.get_object('scroll_icon_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize icon scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_icon_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-icon-delay', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-icon-delay', this._settings.get_default_value('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + this._settings.bind('hot-keys', + this._builder.get_object('hot_keys_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('hot-keys', + this._builder.get_object('overlay_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id()); + })); + + this._settings.bind('shortcut-previews', + this._builder.get_object('shortcut_preview_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('shortcut_num_keys_combo').set_active_id(this._settings.get_string('shortcut-num-keys')); + this._builder.get_object('shortcut_num_keys_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shortcut-num-keys', widget.get_active_id()); + })); + + this._settings.connect('changed::hotkey-prefix-text', Lang.bind(this, function() {checkHotkeyPrefix(this._settings);})); + + this._builder.get_object('hotkey_prefix_combo').set_active_id(this._settings.get_string('hotkey-prefix-text')); + + this._settings.bind('hotkey-prefix-text', + this._builder.get_object('hotkey_prefix_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').set_active_id(this._settings.get_string('hotkeys-overlay-combo')); + + this._settings.bind('hotkeys-overlay-combo', + this._builder.get_object('overlay_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overlay-timeout', + this._builder.get_object('timeout_spinbutton'), + 'value', + Gio.SettingsBindFlags.DEFAULT); + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') { + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + } + + this._settings.connect('changed::hotkeys-overlay-combo', Lang.bind(this, function() { + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + else + this._builder.get_object('timeout_spinbutton').set_sensitive(true); + })); + + this._settings.bind('shortcut-text', + this._builder.get_object('shortcut_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::shortcut-text', Lang.bind(this, function() {setShortcut(this._settings, 'shortcut');})); + + // Create dialog for number overlay options + this._builder.get_object('overlay_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced hotkeys options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_overlay_shortcut'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['hotkey-prefix-text', 'shortcut-text', 'hotkeys-overlay-combo', 'overlay-timeout', 'shortcut-previews']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + // setup dialog for secondary menu options + this._builder.get_object('secondarymenu_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Secondary Menu Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_secondarymenu_options'); + dialog.get_content_area().append(box); + + this._settings.bind('secondarymenu-contains-appmenu', + this._builder.get_object('secondarymenu_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('secondarymenu-contains-showdetails', + this._builder.get_object('secondarymenu_showdetails_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('secondarymenu-contains-appmenu', this._settings.get_default_value('secondarymenu-contains-appmenu')); + this._settings.set_value('secondarymenu-contains-showdetails', this._settings.get_default_value('secondarymenu-contains-showdetails')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // setup dialog for advanced options + this._builder.get_object('button_advanced_options').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_advanced_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // Fine-tune panel + + let sizeScales = [ + {objectName: 'tray_size_scale', valueName: 'tray-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'leftbox_size_scale', valueName: 'leftbox-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'appicon_margin_scale', valueName: 'appicon-margin', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'appicon_padding_scale', valueName: 'appicon-padding', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'tray_padding_scale', valueName: 'tray-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'leftbox_padding_scale', valueName: 'leftbox-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'statusicon_padding_scale', valueName: 'status-icon-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'panel_length_scale', valueName: '', range: LENGTH_MARKS } + ]; + + for(var idx in sizeScales) { + let size_scale = this._builder.get_object(sizeScales[idx].objectName); + let range = sizeScales[idx].range; + size_scale.set_range(range[range.length - 1], range[0]); + let value; + if (sizeScales[idx].objectName === 'panel_length_scale') { + value = PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex); + } else { + value = this._settings.get_int(sizeScales[idx].valueName); + } + size_scale.set_value(value); + // Add marks from range arrays, omitting the first and last values. + range.slice(1, -1).forEach(function(val) { + size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Corrent for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + size_scale.set_flippable(false); + size_scale.set_inverted(true); + } + } + + this._settings.bind('animate-app-switch', + this._builder.get_object('animate_app_switch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-window-launch', + this._builder.get_object('animate_window_launch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + { + this._settings.bind('animate-appicon-hover-animation-type', + this._builder.get_object('animate_appicon_hover_options_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + let scales = [ + ['animate_appicon_hover_options_duration_scale', 'animate-appicon-hover-animation-duration', 1], + ['animate_appicon_hover_options_rotation_scale', 'animate-appicon-hover-animation-rotation', 1], + ['animate_appicon_hover_options_travel_scale', 'animate-appicon-hover-animation-travel', 100], + ['animate_appicon_hover_options_zoom_scale', 'animate-appicon-hover-animation-zoom', 100], + ['animate_appicon_hover_options_convexity_scale', 'animate-appicon-hover-animation-convexity', 1], + ['animate_appicon_hover_options_extent_scale', 'animate-appicon-hover-animation-extent', 1], + ]; + + let updateScale = scale => { + let [id, key, factor] = scale; + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let value = this._settings.get_value(key).deep_unpack()[type]; + let defaultValue = this._settings.get_default_value(key).deep_unpack()[type]; + this._builder.get_object(id).sensitive = defaultValue !== undefined; + this._builder.get_object(id).set_value(value * factor || 0); + this._builder.get_object(id).clear_marks(); + this._builder.get_object(id).add_mark(defaultValue * factor, Gtk.PositionType.TOP, + defaultValue !== undefined ? (defaultValue * factor).toString() : ' '); + }; + + scales.forEach(scale => { + let [id, key, factor] = scale; + this._settings.connect('changed::' + key, () => updateScale(scale)); + this._builder.get_object(id).connect('value-changed', widget => { + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let variant = this._settings.get_value(key); + let unpacked = variant.deep_unpack(); + if (unpacked[type] != widget.get_value() / factor) { + unpacked[type] = widget.get_value() / factor; + this._settings.set_value(key, new GLib.Variant(variant.get_type_string(), unpacked)); + } + }); + }); + + this._settings.connect('changed::animate-appicon-hover-animation-type', () => scales.forEach(updateScale)); + scales.forEach(updateScale); + } + + this._builder.get_object('animate_appicon_hover_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('App icon animation options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('animate_appicon_hover_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('animate-appicon-hover-animation-type', this._settings.get_default_value('animate-appicon-hover-animation-type')); + this._settings.set_value('animate-appicon-hover-animation-duration', this._settings.get_default_value('animate-appicon-hover-animation-duration')); + this._settings.set_value('animate-appicon-hover-animation-rotation', this._settings.get_default_value('animate-appicon-hover-animation-rotation')); + this._settings.set_value('animate-appicon-hover-animation-travel', this._settings.get_default_value('animate-appicon-hover-animation-travel')); + this._settings.set_value('animate-appicon-hover-animation-zoom', this._settings.get_default_value('animate-appicon-hover-animation-zoom')); + this._settings.set_value('animate-appicon-hover-animation-convexity', this._settings.get_default_value('animate-appicon-hover-animation-convexity')); + this._settings.set_value('animate-appicon-hover-animation-extent', this._settings.get_default_value('animate-appicon-hover-animation-extent')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('stockgs-keep-dash', + this._builder.get_object('stockgs_dash_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-keep-top-panel', + this._builder.get_object('stockgs_top_panel_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + + + this._settings.connect('changed::stockgs-keep-top-panel', () => this._maybeDisableTopPosition()); + + this._maybeDisableTopPosition(); + + this._settings.bind('stockgs-panelbtn-click-only', + this._builder.get_object('stockgs_panelbtn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-force-hotcorner', + this._builder.get_object('stockgs_hotcorner_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // About Panel + + this._builder.get_object('extension_version').set_label(Me.metadata.version.toString() + (Me.metadata.commit ? ' (' + Me.metadata.commit + ')' : '')); + + this._builder.get_object('importexport_export_button').connect('clicked', widget => { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE }, + "Save", + filename => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + this._builder.get_object('importexport_import_button').connect('clicked', widget => { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "Open", + filename => { + if (filename && GLib.file_test(filename, GLib.FileTest.EXISTS)) { + let settingsFile = Gio.File.new_for_path(filename); + let [ , pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + let [ , , , retCode] = GLib.spawn_command_line_sync(GSET + ' -d ' + Me.uuid); + if (retCode == 0) { + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => GLib.spawn_command_line_sync(GSET + ' -e ' + Me.uuid)); + } + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + } + ); + }); + + }, + + _setPreviewTitlePosition: function() { + switch (this._settings.get_string('window-preview-title-position')) { + case 'BOTTOM': + this._builder.get_object('preview_title_position_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('preview_title_position_top_button').set_active(true); + break; + } + }, + + _showFileChooser: function(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog(mergeObjects({ title: title, transient_for: this.notebook.get_root() }, params)); + + dialog.add_button("Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.show(); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + acceptHandler.call(this, dialog.get_file().get_path()); + dialog.destroy(); + })); + } +}); + + +const BuilderScope = GObject.registerClass({ + Implements: [Gtk.BuilderScope], +}, class BuilderScope extends GObject.Object { + + _init(preferences) { + this._preferences = preferences; + super._init(); + } + + vfunc_create_closure(builder, handlerName, flags, connectObject) { + if (flags & Gtk.BuilderClosureFlags.SWAPPED) + throw new Error('Unsupported template signal flag "swapped"'); + + if (typeof this[handlerName] === 'undefined') + throw new Error(`${handlerName} is undefined`); + + return this[handlerName].bind(connectObject || this); + } + + on_btn_click(connectObject) { + connectObject.set_label("Clicked"); + } + + position_bottom_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.BOTTOM); + } + + position_top_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.TOP); + } + + position_left_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.LEFT); + } + + position_right_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.RIGHT); + } + + dots_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "BOTTOM"); + } + + dots_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "TOP"); + } + + dots_left_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "LEFT"); + } + + dots_right_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "RIGHT"); + } + + preview_title_position_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'BOTTOM'); + } + + preview_title_position_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'TOP'); + } + + panel_size_scale_value_changed_cb(scale) { + // Avoid settings the size continuously + if (this._preferences._panel_size_timeout > 0) + Mainloop.source_remove(this._preferences._panel_size_timeout); + + this._preferences._panel_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this._preferences, function() { + const value = scale.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelSize(this._settings, monitorIndex, value); + }); + + this._panel_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_size_timeout > 0) + Mainloop.source_remove(this._preferences._tray_size_timeout); + + this._preferences._tray_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-size', scale.get_value()); + this._preferences._tray_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_size_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_size_timeout); + + this._preferences._leftbox_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-size', scale.get_value()); + this._preferences._leftbox_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_margin_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_margin_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_margin_timeout); + + this._preferences._appicon_margin_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-margin', scale.get_value()); + this._preferences._appicon_margin_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_padding_timeout); + + this._preferences._appicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-padding', scale.get_value()); + this._preferences._appicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_padding_timeout > 0) + Mainloop.source_remove(this._preferences._tray_padding_timeout); + + this._preferences._tray_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-padding', scale.get_value()); + this._preferences._tray_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + statusicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._statusicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._statusicon_padding_timeout); + + this._preferences._statusicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('status-icon-padding', scale.get_value()); + this._preferences._statusicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_padding_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_padding_timeout); + + this._preferences._leftbox_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-padding', scale.get_value()); + this._preferences._leftbox_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } +}); + +function init() { + Convenience.initTranslations(); +} + +function buildPrefsWidget() { + Gtk.Window.list_toplevels()[0].set_default_size(680, 740); + + let preferences = new Preferences(); + + return preferences.notebook; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js new file mode 100644 index 0000000..1e84e82 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js @@ -0,0 +1,598 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gio = imports.gi.Gio; +const Cairo = imports.cairo; +const Clutter = imports.gi.Clutter; +const Pango = imports.gi.Pango; +const St = imports.gi.St; +const Signals = imports.signals; +const Utils = Me.imports.utils; + + +var ProgressManager = Utils.defineClass({ + Name: 'DashToPanel.ProgressManager', + + _init: function() { + + this._entriesByDBusName = {}; + + this._launcher_entry_dbus_signal_id = + Gio.DBus.session.signal_subscribe(null, // sender + 'com.canonical.Unity.LauncherEntry', // iface + null, // member + null, // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onEntrySignalReceived.bind(this)); + + this._dbus_name_owner_changed_signal_id = + Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender + 'org.freedesktop.DBus', // interface + 'NameOwnerChanged', // member + '/org/freedesktop/DBus', // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onDBusNameOwnerChanged.bind(this)); + + this._acquireUnityDBus(); + }, + + destroy: function() { + if (this._launcher_entry_dbus_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id); + } + + if (this._dbus_name_owner_changed_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id); + } + + this._releaseUnityDBus(); + }, + + size: function() { + return Object.keys(this._entriesByDBusName).length; + }, + + lookupByDBusName: function(dbusName) { + return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null; + }, + + lookupById: function(appId) { + let ret = []; + for (let dbusName in this._entriesByDBusName) { + let entry = this._entriesByDBusName[dbusName]; + if (entry && entry.appId() == appId) { + ret.push(entry); + } + } + + return ret; + }, + + addEntry: function(entry) { + let existingEntry = this.lookupByDBusName(entry.dbusName()); + if (existingEntry) { + existingEntry.update(entry); + } else { + this._entriesByDBusName[entry.dbusName()] = entry; + this.emit('progress-entry-added', entry); + } + }, + + removeEntry: function(entry) { + delete this._entriesByDBusName[entry.dbusName()] + this.emit('progress-entry-removed', entry); + }, + + _acquireUnityDBus: function() { + if (!this._unity_bus_id) { + Gio.DBus.session.own_name('com.canonical.Unity', + Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); + } + }, + + _releaseUnityDBus: function() { + if (this._unity_bus_id) { + Gio.DBus.session.unown_name(this._unity_bus_id); + this._unity_bus_id = 0; + } + }, + + _onEntrySignalReceived: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !signal_name) + return; + + if (signal_name == 'Update') { + if (!sender_name) { + return; + } + + this._handleUpdateRequest(sender_name, parameters); + } + }, + + _onDBusNameOwnerChanged: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !this.size()) + return; + + let [name, before, after] = parameters.deep_unpack(); + + if (!after) { + if (this._entriesByDBusName.hasOwnProperty(before)) { + this.removeEntry(this._entriesByDBusName[before]); + } + } + }, + + _handleUpdateRequest: function(senderName, parameters) { + if (!senderName || !parameters) { + return; + } + + let [appUri, properties] = parameters.deep_unpack(); + let appId = appUri.replace(/(^\w+:|^)\/\//, ''); + let entry = this.lookupByDBusName(senderName); + + if (entry) { + entry.setDBusName(senderName); + entry.update(properties); + } else { + let entry = new AppProgress(senderName, appId, properties); + this.addEntry(entry); + } + } +}); +Signals.addSignalMethods(ProgressManager.prototype); + +var AppProgress = Utils.defineClass({ + Name: 'DashToPanel.AppProgress', + + _init: function(dbusName, appId, properties) { + this._dbusName = dbusName; + this._appId = appId; + this._count = 0; + this._countVisible = false; + this._progress = 0.0; + this._progressVisible = false; + this._urgent = false; + this.update(properties); + }, + + appId: function() { + return this._appId; + }, + + dbusName: function() { + return this._dbusName; + }, + + count: function() { + return this._count; + }, + + setCount: function(count) { + if (this._count != count) { + this._count = count; + this.emit('count-changed', this._count); + } + }, + + countVisible: function() { + return this._countVisible; + }, + + setCountVisible: function(countVisible) { + if (this._countVisible != countVisible) { + this._countVisible = countVisible; + this.emit('count-visible-changed', this._countVisible); + } + }, + + progress: function() { + return this._progress; + }, + + setProgress: function(progress) { + if (this._progress != progress) { + this._progress = progress; + this.emit('progress-changed', this._progress); + } + }, + + progressVisible: function() { + return this._progressVisible; + }, + + setProgressVisible: function(progressVisible) { + if (this._progressVisible != progressVisible) { + this._progressVisible = progressVisible; + this.emit('progress-visible-changed', this._progressVisible); + } + }, + + urgent: function() { + return this._urgent; + }, + + setUrgent: function(urgent) { + if (this._urgent != urgent) { + this._urgent = urgent; + this.emit('urgent-changed', this._urgent); + } + }, + + setDBusName: function(dbusName) { + if (this._dbusName != dbusName) { + let oldName = this._dbusName; + this._dbusName = dbusName; + this.emit('dbus-name-changed', oldName); + } + }, + + update: function(other) { + if (other instanceof AppProgress) { + this.setDBusName(other.dbusName()) + this.setCount(other.count()); + this.setCountVisible(other.countVisible()); + this.setProgress(other.progress()); + this.setProgressVisible(other.progressVisible()) + this.setUrgent(other.urgent()); + } else { + for (let property in other) { + if (other.hasOwnProperty(property)) { + if (property == 'count') { + this.setCount(other[property].get_int64()); + } else if (property == 'count-visible') { + this.setCountVisible(Me.settings.get_boolean('progress-show-count') && other[property].get_boolean()); + } else if (property == 'progress') { + this.setProgress(other[property].get_double()); + } else if (property == 'progress-visible') { + this.setProgressVisible(Me.settings.get_boolean('progress-show-bar') && other[property].get_boolean()); + } else if (property == 'urgent') { + this.setUrgent(other[property].get_boolean()); + } else { + // Not implemented yet + } + } + } + } + } +}); +Signals.addSignalMethods(AppProgress.prototype); + + +var ProgressIndicator = Utils.defineClass({ + Name: 'DashToPanel.ProgressIndicator', + + _init: function(source, progressManager) { + this._source = source; + this._progressManager = progressManager; + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._sourceDestroyId = this._source.actor.connect('destroy', () => { + this._signalsHandler.destroy(); + }); + + this._notificationBadgeLabel = new St.Label({ style_class: 'badge' }); + this._notificationBadgeBin = new St.Bin({ + child: this._notificationBadgeLabel, y: 2, x: 2 + }); + this._notificationBadgeLabel.add_style_class_name('notification-badge'); + this._notificationBadgeCount = 0; + this._notificationBadgeBin.hide(); + + this._source._dtpIconContainer.add_child(this._notificationBadgeBin); + this._source._dtpIconContainer.connect('notify::allocation', this.updateNotificationBadge.bind(this)); + + this._progressManagerEntries = []; + this._progressManager.lookupById(this._source.app.id).forEach( + (entry) => { + this.insertEntry(entry); + } + ); + + this._signalsHandler.add([ + this._progressManager, + 'progress-entry-added', + this._onEntryAdded.bind(this) + ], [ + this._progressManager, + 'progress-entry-removed', + this._onEntryRemoved.bind(this) + ]); + }, + + destroy: function() { + this._source.actor.disconnect(this._sourceDestroyId); + this._signalsHandler.destroy(); + }, + + _onEntryAdded: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.insertEntry(entry); + } + }, + + _onEntryRemoved: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.removeEntry(entry); + } + }, + + updateNotificationBadge: function() { + this._source.updateNumberOverlay(this._notificationBadgeBin); + this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; + }, + + _notificationBadgeCountToText: function(count) { + if (count <= 9999) { + return count.toString(); + } else if (count < 1e5) { + let thousands = count / 1e3; + return thousands.toFixed(1).toString() + "k"; + } else if (count < 1e6) { + let thousands = count / 1e3; + return thousands.toFixed(0).toString() + "k"; + } else if (count < 1e8) { + let millions = count / 1e6; + return millions.toFixed(1).toString() + "M"; + } else if (count < 1e9) { + let millions = count / 1e6; + return millions.toFixed(0).toString() + "M"; + } else { + let billions = count / 1e9; + return billions.toFixed(1).toString() + "B"; + } + }, + + setNotificationBadge: function(count) { + this._notificationBadgeCount = count; + let text = this._notificationBadgeCountToText(count); + this._notificationBadgeLabel.set_text(text); + }, + + toggleNotificationBadge: function(activate) { + if (activate && this._notificationBadgeCount > 0) { + this.updateNotificationBadge(); + this._notificationBadgeBin.show(); + } + else + this._notificationBadgeBin.hide(); + }, + + _showProgressOverlay: function() { + if (this._progressOverlayArea) { + this._updateProgressOverlay(); + return; + } + + this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); + this._progressOverlayArea.add_style_class_name('progress-bar'); + this._progressOverlayArea.connect('repaint', () => { + this._drawProgressOverlay(this._progressOverlayArea); + }); + + this._source._iconContainer.add_child(this._progressOverlayArea); + let node = this._progressOverlayArea.get_theme_node(); + + let [hasColor, color] = node.lookup_color('-progress-bar-background', false); + if (hasColor) + this._progressbar_background = color + else + this._progressbar_background = new Clutter.Color({red: 204, green: 204, blue: 204, alpha: 255}); + + [hasColor, color] = node.lookup_color('-progress-bar-border', false); + if (hasColor) + this._progressbar_border = color; + else + this._progressbar_border = new Clutter.Color({red: 230, green: 230, blue: 230, alpha: 255}); + + this._updateProgressOverlay(); + }, + + _hideProgressOverlay: function() { + if (this._progressOverlayArea) + this._progressOverlayArea.destroy(); + + this._progressOverlayArea = null; + this._progressbar_background = null; + this._progressbar_border = null; + }, + + _updateProgressOverlay: function() { + + if (this._progressOverlayArea) { + this._progressOverlayArea.queue_repaint(); + } + }, + + _drawProgressOverlay: function(area) { + let scaleFactor = Utils.getScaleFactor(); + let [surfaceWidth, surfaceHeight] = area.get_surface_size(); + let cr = area.get_context(); + + let iconSize = this._source.icon.iconSize * scaleFactor; + + let x = Math.floor((surfaceWidth - iconSize) / 2); + let y = Math.floor((surfaceHeight - iconSize) / 2); + + let lineWidth = Math.floor(1.0 * scaleFactor); + let padding = Math.floor(iconSize * 0.05); + let width = iconSize - 2.0*padding; + let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize)); + x += padding; + y += iconSize - height - padding; + + cr.setLineWidth(lineWidth); + + // Draw the outer stroke + let stroke = new Cairo.LinearGradient(0, y, 0, y + height); + let fill = null; + stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1); + stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the background + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9); + fill = new Cairo.LinearGradient(0, y, 0, y + height); + fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0); + fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the finished bar + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + let finishedWidth = Math.ceil(this._progress * width); + + let bg = this._progressbar_background; + let bd = this._progressbar_border; + + stroke = Cairo.SolidPattern.createRGBA(bd.red/255, bd.green/255, bd.blue/255, bd.alpha/255); + fill = Cairo.SolidPattern.createRGBA(bg.red/255, bg.green/255, bg.blue/255, bg.alpha/255); + + if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) + Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + else + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + + cr.$dispose(); + }, + + setProgress: function(progress) { + this._progress = Math.min(Math.max(progress, 0.0), 1.0); + this._updateProgressOverlay(); + }, + + toggleProgressOverlay: function(activate) { + if (activate) { + this._showProgressOverlay(); + } + else { + this._hideProgressOverlay(); + } + }, + + insertEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) !== -1) + return; + + this._progressManagerEntries.push(appProgress); + this._selectEntry(appProgress); + }, + + removeEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) == -1) + return; + + this._progressManagerEntries.splice(this._progressManagerEntries.indexOf(appProgress), 1); + + if (this._progressManagerEntries.length > 0) { + this._selectEntry(this._progressManagerEntries[this._progressManagerEntries.length-1]); + } else { + this.setNotificationBadge(0); + this.toggleNotificationBadge(false); + this.setProgress(0); + this.toggleProgressOverlay(false); + this.setUrgent(false); + } + }, + + _selectEntry: function(appProgress) { + if (!appProgress) + return; + + this._signalsHandler.removeWithLabel('progress-entry'); + + this._signalsHandler.addWithLabel('progress-entry', + [ + appProgress, + 'count-changed', + (appProgress, value) => { + this.setNotificationBadge(value); + } + ], [ + appProgress, + 'count-visible-changed', + (appProgress, value) => { + this.toggleNotificationBadge(value); + } + ], [ + appProgress, + 'progress-changed', + (appProgress, value) => { + this.setProgress(value); + } + ], [ + appProgress, + 'progress-visible-changed', + (appProgress, value) => { + this.toggleProgressOverlay(value); + } + ], [ + appProgress, + 'urgent-changed', + (appProgress, value) => { + this.setUrgent(value) + } + ]); + + this.setNotificationBadge(appProgress.count()); + this.toggleNotificationBadge(appProgress.countVisible()); + this.setProgress(appProgress.progress()); + this.toggleProgressOverlay(appProgress.progressVisible()); + + this._isUrgent = false; + }, + + setUrgent: function(urgent) { + const icon = this._source.icon._iconBin; + if (urgent) { + if (!this._isUrgent) { + icon.set_pivot_point(0.5, 0.5); + this._source.iconAnimator.addAnimation(icon, 'dance'); + this._isUrgent = true; + } + } else { + if (this._isUrgent) { + this._source.iconAnimator.removeAnimation(icon, 'dance'); + this._isUrgent = false; + } + icon.rotation_angle_z = 0; + } + } +}); diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js new file mode 100644 index 0000000..c298f84 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js @@ -0,0 +1,262 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Meta = imports.gi.Meta; + +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; + +//timeout intervals +const MIN_UPDATE_MS = 200; + +//timeout names +const T1 = 'limitUpdateTimeout'; + +var Mode = { + ALL_WINDOWS: 0, + FOCUSED_WINDOWS: 1, + MAXIMIZED_WINDOWS: 2 +}; + +var ProximityWatch = Utils.defineClass({ + Name: 'DashToPanel.ProximityWatch', + + _init: function(actor, mode, xThreshold, yThreshold, handler) { + this.actor = actor; + this.overlap = 0; + this.mode = mode; + this.threshold = [xThreshold, yThreshold]; + this.handler = handler; + + this._allocationChangedId = actor.connect('notify::allocation', () => this._update()); + + this._update(); + }, + + destroy: function() { + this.actor.disconnect(this._allocationChangedId); + }, + + _update: function() { + this.monitorIndex = Main.layoutManager.findIndexForActor(this.actor); + + this._updateWatchRect(); + }, + + _updateWatchRect: function() { + let [actorX, actorY] = this.actor.get_position(); + + this.rect = new Meta.Rectangle({ + x: actorX - this.threshold[0], + y: actorY - this.threshold[1], + width: this.actor.width + this.threshold[0] * 2, + height: this.actor.height + this.threshold[1] * 2 + }); + }, +}); + +var ProximityManager = Utils.defineClass({ + Name: 'DashToPanel.ProximityManager', + + _init: function() { + this._counter = 1; + this._watches = {}; + this._focusedWindowInfo = null; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._bindSignals(); + this._setFocusedWindow(); + }, + + createWatch: function(actor, mode, xThreshold, yThreshold, handler) { + let watch = new ProximityWatch(actor, mode, xThreshold, yThreshold, handler); + + this._watches[this._counter] = watch; + this.update(); + + return this._counter++; + }, + + removeWatch: function(id) { + if (this._watches[id]) { + this._watches[id].destroy(); + delete this._watches[id]; + } + }, + + update: function() { + this._queueUpdate(true); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + this._disconnectFocusedWindow(); + Object.keys(this._watches).forEach(id => this.removeWatch(id)); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + global.window_manager, + 'switch-workspace', + () => Object.keys(this._watches).forEach(id => this._watches[id].overlap = 0) + ], + [ + Main.overview, + 'hidden', + () => this._queueUpdate() + ], + [ + global.display, + 'notify::focus-window', + () => { + this._setFocusedWindow(); + this._queueUpdate(); + } + ], + [ + global.window_group, + [ + 'actor-added', + 'actor-removed' + ], + () => this._queueUpdate() + ] + ); + }, + + _setFocusedWindow: function() { + this._disconnectFocusedWindow(); + + let focusedWindow = global.display.focus_window; + + if (focusedWindow) { + let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow); + + if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) { + focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('notify::allocation', () => this._queueUpdate()); + focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true)); + + this._focusedWindowInfo = focusedWindowInfo; + } + } + }, + + _getFocusedWindowInfo: function(focusedWindow) { + let window = focusedWindow.get_compositor_private(); + let focusedWindowInfo; + + if (window) { + focusedWindowInfo = { window: window }; + focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window(); + + if (focusedWindow.is_attached_dialog()) { + let mainMetaWindow = focusedWindow.get_transient_for(); + + if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) { + focusedWindowInfo.window = mainMetaWindow.get_compositor_private(); + focusedWindowInfo.metaWindow = mainMetaWindow; + } + } + } + + return focusedWindowInfo; + }, + + _disconnectFocusedWindow: function(destroy) { + if (this._focusedWindowInfo && !destroy) { + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId); + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId); + } + + this._focusedWindowInfo = null; + }, + + _getHandledWindows: function() { + return global.get_window_actors() + .filter(w => w.visible) + .map(w => w.get_meta_window()) + .filter(mw => this._checkIfHandledWindow(mw)); + }, + + _checkIfHandledWindow: function(metaWindow) { + return metaWindow && !metaWindow.minimized && + this._checkIfHandledWindowType(metaWindow); + }, + + _checkIfHandledWindowType: function(metaWindow) { + let metaWindowType = metaWindow.get_window_type(); + + //https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html + return metaWindowType <= Meta.WindowType.SPLASHSCREEN && + metaWindowType != Meta.WindowType.DESKTOP; + }, + + _queueUpdate: function(noDelay) { + if (!noDelay && this._timeoutsHandler.getId(T1)) { + //limit the number of updates + this._pendingUpdate = true; + return; + } + + this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + + let metaWindows = this._getHandledWindows(); + + Object.keys(this._watches).forEach(id => { + let watch = this._watches[id]; + let overlap = this._update(watch, metaWindows); + + if (overlap !== watch.overlap) { + watch.handler(overlap); + watch.overlap = overlap; + } + }); + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdate(); + } + }, + + _update: function(watch, metaWindows) { + if (watch.mode === Mode.FOCUSED_WINDOWS) { + return (this._focusedWindowInfo && + this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) && + this._checkProximity(this._focusedWindowInfo.metaWindow, watch)); + } else if (watch.mode === Mode.MAXIMIZED_WINDOWS) { + return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally && + mw.get_monitor() == watch.monitorIndex); + } + + //Mode.ALL_WINDOWS + return metaWindows.some(mw => this._checkProximity(mw, watch)); + }, + + _checkProximity: function(metaWindow, watch) { + return metaWindow.get_frame_rect().overlap(watch.rect); + }, +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled new file mode 100644 index 0000000..ef5dc7d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml new file mode 100644 index 0000000..7e8ea3a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -0,0 +1,1278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'BOTTOM' + Panel position (Deprecated) + Panel is shown on the Bottom or Top of the screen. + + + true + Sync element positions + Sync panel element positions on all monitors. + + + '{}' + Panel positions + Panel positions (JSON). + + + '{}' + Panel element positions + Panel element positions (JSON). + + + '{}' + Percentages of screen edge for panel to span + Length of the panels, in percent (JSON). + + + '{}' + Positions along screen edge + Where to show the panels if it is not the full length of the screen edge (JSON). + + + '{}' + Panel sizes + Sizes of panels, in pixels. + + + 48 + Panel size (Deprecated) + Set the size of the panel. + + + false + Override Show Desktop line color + Replace current Show Desktop button line color + + + "rgba(200,200,200,0.2)" + Custom Show Desktop line color + Custom Show Desktop button line color + + + 'BOTTOM' + Dot position + Running indicators are shown on the Bottom or Top of the screen. + + + 'METRO' + Style of the running indicator (focused) + Style of the running indicator for the icon for the currently focused application + + + 'METRO' + Style of the running indicator (unfocused) + Style of the running indicator for the icon for applications which are not currently focused + + + false + Running indicator dominant color + Whether to use the app icon's dominant color for .app-well-running-dot + + + false + Running indicator color override + Whether to override the theme background color for .app-well-running-dot + + + "#5294e2" + Color of running indicator (1 window) + Customize the color of the running indicator when one window is running for that application + + + "#5294e2" + Color of running indicator (2 windows) + Customize the color of the running indicator when two windows are running for that application + + + "#5294e2" + Color of running indicator (3 windows) + Customize the color of the running indicator when three windows are running for that application + + + "#5294e2" + Color of running indicator (4+ windows) + Customize the color of the running indicator when four or more windows are running for that application + + + false + Unfocused color is different than focused + Whether to apply a 2nd color scheme to the indicator when the app is not focused + + + "#5294e2" + Color of unfocused running indicator (1 window) + Customize the color of the unfocused running indicator when one window is running for that application + + + "#5294e2" + Color of unfocused running indicator (2 windows) + Customize the color of the unfocused running indicator when two windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (3 windows) + Customize the color of the unfocused running indicator when three windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (4+ windows) + Customize the color of the unfocused running indicator when four or more windows are running for that application + + + 3 + Running indicator height + Height of the running indicator line/diameter of window indicator dots + + + true + Highlight icon of focused application + Whether to highlight the background of the currently focused application's icon + + + false + Highlight icon dominant color + Base the active window highlight color on that application's icon + + + "#EEEEEE" + Color of highlight of focused application + Customize the color of the highlight of the focused application + + + 25 + Opacity of highlight of focused application + Customize the opacity of the highlight of the focused application + + + false + Keep dash + Whether to keep the stock gnome-shell dash while in overview + + + false + Keep top panel + Whether to keep the stock gnome-shell top panel + + + false + Panel menu buttons require click + Whether to activate the panel menu buttons on hover or on click + + + false + Force hot corner + Wheter to force having an Activities hot corner on the primary monitor + + + false + Lock the taskbar + Specifies if the user can modify the taskbar + + + false + Override theme background color + Replace current theme background color for the panel + + + "#000" + Custom background color + Custom background color for the panel + + + false + Custom background color + Replace current theme background color for the panel + + + false + Dynamic opacity + Enable dynamic opacity + + + 0.4 + Panel opacity + Custom opacity for the panel + + + 'ALL_WINDOWS' + Dynamic opacity behavior + Dictates which window type affects the panel opacity + + + 20 + Distance to change opacity + The distance a window needs to be from the panel to change opacity + + + 0.8 + Modified panel opacity + Modified opacity for the panel when a window is near + + + 300 + Opacity change duration + The duration of the animation when the opacity changes + + + false + Custom gradient + Replace current theme gradient for the panel + + + "#000" + Custom gradient top color + Custom gradient top color for the panel + + + 0 + Custom gradient top opacity + Custom gradient top opacity for the panel + + + "#000" + Custom gradient bottom color + Custom gradient bottom color for the panel + + + 0.2 + Custom gradient bottom opacity + Custom gradient bottom opacity for the panel + + + false + Intellihide + Whether to intelligently hide the panel + + + false + Only hide from windows + Dictates if the dash should only hide when in conflict with windows + + + 'FOCUSED_WINDOWS' + Intellihide behaviour + Dictates how to intelligently hide the panel + + + false + Intellihide pressure + To reveal the panel, pressure needs to be applied to the edege of the screen + + + 100 + Intellihide pressure threshold + The pressure needed to reveal the panel + + + 1000 + Intellihide pressure time + The numer of milliseconds that the pressure needs to be applied to reveal the panel + + + false + Intellihide pressure + Allow the panel to be revealed while an application is in fullscreen mode + + + false + Intellihide only secondary + Whether to only hide secondary panels + + + 200 + Intellihide animation time + The animation time (ms) to hide and reveal the panel + + + 400 + Intellihide close delay + The delay (ms) before hiding the panel + + + "<Super>i" + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + i']]]> + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + 2000 + Intellihide enable start delay + The delay before enabling intellihide on start + + + "" + Custom Show Applications icon + Customize the Show Applications icon + + + 8 + Show Applications icon side padding + Customize the Show Applications icon side padding + + + true + Override escape key + Override the escape key to return to the desktop when entering the overview using the Show Applications button + + + [] + Show Apps button context menu commands + Commands to add to the Show Apps button right click menu + + + [] + Show Apps button context menu titles + Titles for commands added to Show Apps button right click menu + + + [] + Panel context menu commands + Commands to add to the panel right click menu + + + [] + Panel context menu titles + Titles for commands added to panel right click menu + + + false + Show activities button + Show activities button on the left hand side of the taskbar + + + 8 + Width of show Desktop button + Customize the width of the show Desktop button + + + false + Show desktop on hover + Show the desktop on mouse hover + + + 1000 + Delay show desktop + Delay before showing the desktop + + + 300 + Show desktop animation time + Window fade animation time when showing the destop + + + false + Show appMenu button + Show appMenu on the right hand side of the panel + + + true + Show window preview + Show preview of running window on hover of app icon + + + true + Show tooltip + Show tooltip on hover of app icon + + + true + Show running apps + Show or hide running application icons in the dash + + + true + Show favorites apps + Show or hide favorite application icons in the dash + + + 400 + Icon enter display time + Amount of time after entering icon to wait before displaying window preview if icon is not clicked or mouse has not left. + + + true + Enable peek mode + Peek a window upon hover for some time + + + true + Display title in preview + Display window title in preview + + + false + Window previews manual styling + This defines if the default window previews styling should be applied + + + 'TOP' + Title position + Position of the window title, close button and icon in preview. + + + "#dddddd" + Window previews title font color + This defines the window preview titles font color. + + + 14 + Window previews title font size + This defines the window preview titles font size. + + + false + Window previews use custom icon size + Window previews use custom application icon size. + + + 16 + Window previews custom icon size + Window previews custom application icon size. + + + 260 + Window previews animation time + This defines the window previews animation time. + + + 'inherit' + Font weight of window preview titles + This defines the font weight of window preview titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + 240 + Window previews size + Preferred window previews size + + + false + Fixed aspect ratio X + This defines if the window previews use a fixed aspect ratio X. + + + true + Fixed aspect ratio Y + This defines if the window previews use a fixed aspect ratio Y. + + + 8 + Window previews padding + The padding of the window previews + + + 16 + Aspect ratio X + The window previews respected aspect ratio X. + + + 9 + Aspect ratio Y + The window previews respected aspect ratio Y. + + + false + Immediate hide on icon click + The window previews immediately hide when an application icon is clicked. + + + false + Provide workspace isolation + Dash shows only windows from the current workspace + + + false + Close overview by clicking in empty space + Close overview or app grid by clicking in empty space + + + false + Hide overview on startup + Hide overview on startup, which would be shown by default at gnome startup. + + + true + Group applications + Dash groups the application instances under the same icon + + + 14 + Application title font size + When the applications are ungrouped, this defines the application titles font size. + + + 'inherit' + Font weight of application titles + When the applications are ungrouped, this defines font weight of application titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + "#dddddd" + Application title font color + When the applications are ungrouped, this defines the application titles font color. + + + "#dddddd" + Minimized application title font color + When the applications are ungrouped, this defines the titles font color for minimized applications. + + + 160 + Application title max width + When the applications are ungrouped, this defines the application titles maximum width. + + + true + Use a fixed width for the application titles + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + + + true + Display running indicators on unfocused applications + When the applications are ungrouped, this defines if running applications should display an indicator. + + + false + Use favorite icons as application launchers + When the applications are ungrouped, this defines if running applications stay separate from the favorite icons. + + + 0 + Primary monitor index + Specifies the index of the primary monitor. + + + true + Display panels on all monitors + Specifies if a panel is shown on every monitors + + + [] + Available monitors + Available gnome-shell (Mutter) monitors, internal use + + + false + Provide monitor isolation + Dash shows only windows from the current monitor + + + true + Display the favorites on all monitors + Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor. + + + true + Customize click behaviour + Customize action on various mouse events + + + true + Minimize on shift+click + + + true + Activate only one window + + + 'CYCLE-MIN' + Action when clicking on a running app + Set the action that is executed when clicking on the icon of a running application + + + 'MINIMIZE' + Action when shift+clicking on a running app + Set the action that is executed when shift+clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when middle-clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when shift+middle-clicking on the icon of a running application + + + 'SWITCH_WORKSPACE' + Action when scrolling over the panel + Set the action that is executed when scrolling over the panel + + + 0 + Delay between panel mouse scroll events + Set the minimum delay between panel mouse scroll events + + + true + Show the workspace switch head-up when workspace is changed by scrolling on the panel + + + 'CYCLE_WINDOWS' + Action when scrolling over a running app + Set the action that is executed when scrolling over a running application + + + 0 + Delay between icon mouse scroll events + Set the minimum delay between icon mouse scroll events + + + 100 + Icon leave preview timeout + Amount of time to leave preview windows open when the mouse has left the application's icon. + + + 500 + Enter window peeking mode timeout + Amount of time of inactivity to enter the window peeking mode when the mouse has entered a window preview. + + + 40 + Window peeking mode opacity + All windows except for the peeked one have their opacity set to the same value. + + + true + Middle click preview to close window + Middle click on the window preview to close that window + + + true + Window previews use custom opacity + Window previews background use a different opacity from the panel + + + 80 + Window previews background opacity + Window previews use this custom background opacity. + + + 0 + Tray font size + Set the size of the tray font. (0 for default) + + + 0 + Leftbox font size + Set the size of the leftBox font. (0 for default) + + + 8 + App icon margin + Set the margin for application icons in the embedded dash. + + + 4 + App icon padding + Set the padding for application icons in the embedded dash. + + + -1 + Tray item padding + Set the size of the tray padding. (-1 for default) + + + -1 + Leftbox item padding + Set the size of the leftBox padding. (-1 for default) + + + -1 + Status icon padding + Set the size of the aggregate (status) menu icon padding. (-1 for default) + + + true + Animate running indicator when open/closing/switching applications + + + true + Animate when new window launched + + + false + Animate app icon on hover + + + 'SIMPLE' + App icon hover animation type + + + {'RIPPLE':2,'PLANK':1} + App icon hover animation curve convexity (1 is linear, more is convex, less is concave) + + + {'SIMPLE':160,'RIPPLE':130,'PLANK':100} + App icon hover animation duration in milliseconds + + + {'RIPPLE':4,'PLANK':4} + App icon hover animation extent (maximum number of animated icons) + + + {'SIMPLE':0,'RIPPLE':10,'PLANK':0} + App icon hover animation rotation in degrees + + + {'SIMPLE':0.30,'RIPPLE':0.40,'PLANK':0} + App icon hover animation travel translation in relation to the app icon size + + + {'SIMPLE':1,'RIPPLE':1.25,'PLANK':2} + App icon hover animation zoom scale in relation to the app icon size + + + true + Integrate items from the gnome appmenu into the right click menu + + + false + Display Show Details to open Gnome Software from right click menu + + + "<Super>q" + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + q']]]> + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + 2000 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 750 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 'TEMPORARILY' + Transitivity of the number overlay + You can choose between NEVER, TEMPORARILY and ALWAYS. + + + false + Super Hot-Keys + Launch and switch between dash items using Super+(0-9) + + + 'Super' + Prefix to use for hotkeys + You can choose between Super or SuperAlt as the prefix for hotkeys. + + + false + Show window previews + When multiple instances of the application are available, show their window previews + + + 'BOTH' + Hotkeys number keys + Which number keys are used for the hotkeys + + + 1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + 2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + 3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + 4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + 5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + 6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + 7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + 8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + 9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + 0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + 1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + 2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + 3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + 4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + 5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + 6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + 7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + 8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + 9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + 0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + 1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + 2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + 3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + 4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + 5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + 6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + 7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + 8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + 9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + 0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + KP_1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + KP_2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + KP_3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + KP_4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + KP_5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + KP_6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + KP_7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + KP_8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + KP_9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + KP_0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + KP_1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + KP_4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + KP_5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + KP_6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + KP_7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + KP_8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + KP_9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + KP_0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + KP_1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + KP_4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + KP_5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + KP_6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + KP_7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + KP_8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + KP_9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + KP_0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + true + Show progress bar on app icon + Whether to show progress bar overlay on app icon, for supported applications. + + + true + Show badge count on app icon + Whether to show badge count overlay on app icon, for supported applications. + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css new file mode 100644 index 0000000..6917e24 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css @@ -0,0 +1,151 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +#dashtopanelTaskbar .dash-item-container > StWidget { + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-icon, +.dashtopanelMainPanel .show-apps .overview-icon { + background: none; + border: none; + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-label { + /* must match TITLE_RIGHT_PADDING in apppicons.js */ + padding-right: 8px; +} + +#dashtopanelScrollview .app-well-app:hover .overview-icon, +#dashtopanelScrollview .app-well-app:focus .overview-icon { + background: none; +} + +.dashtopanelMainPanel .show-apps:hover .overview-icon, +#dashtopanelScrollview .app-well-app:hover .dtp-container, +#dashtopanelScrollview .app-well-app:focus .dtp-container { + background-color: rgba(238, 238, 236, 0.1); +} + +#dashtopanelScrollview .app-well-app:hover .dtp-container.animate-appicon-hover { + background: none; +} + +#dashtopanelScrollview .app-well-app:active .dtp-container { + background-color: rgba(238, 238, 236, 0.18); +} + +#dashtopanelScrollview .app-well-app .favorite { + background-color: rgba(80, 150, 255, 0.4); +} + +#dashtopanelScrollview .app-well-app-running-dot { + margin-bottom: 0; +} + +#dashtopanelTaskbar .scrollview-fade { + background-gradient-end: rgba(0, 0, 0, 0); +} + +.dashtopanelSecondaryMenu { + max-width: 400px; +} + +.dashtopanelMainPanel.vertical .panel-button { + text-align: center; +} + +.dashtopanelMainPanel.vertical .panel-button.vertical *, +.dashtopanelMainPanel.vertical .panel-button.clock-display * { + padding: 0; + margin: 0; +} + +.dashtopanelMainPanel.vertical .panel-button > *, +.dashtopanelMainPanel.vertical .panel-button.vertical > *, +.dashtopanelMainPanel.vertical .panel-button.clock-display > * { + padding: 8px 0; +} + +#dashtopanelThumbnailList { + spacing: 0em; + padding: 0 1em; +} + +#dashtopanelThumbnailList .popup-menu-item { + padding: 0; + border-radius: 5px; + spacing: 0; +} + +#dashtopanelThumbnailList .window-box { + padding: 0; + spacing: 0; +} + +#dashtopanelThumbnailList .preview-window-title { + padding-top: 1em; +} + +.popup-menu.panel-menu { + margin-bottom: 0; +} + +#panel #panelLeft, #panel #panelCenter { + spacing: 0px; +} + +.showdesktop-button-dark-hovered { + background-color: rgba(200, 200, 200, .4); +} + +.showdesktop-button-light-hovered { + background-color: rgba(55, 55, 55, .4); +} + +.panel-corner.hidden:active, .panel-corner.hidden:overview, .panel-corner.hidden:focus { + -panel-corner-border-color: rgba(0, 0, 0, .001); +} +#dashtopanelScrollview .badge { + color: rgba(255, 255, 255, 1); + font-weight: bold; + text-align: center; +} + +#dashtopanelScrollview .number-overlay { + background-color: rgba(0,0,0,0.8); +} + +#dashtopanelScrollview .notification-badge { + background-color: rgba(255,0,0,0.8); +} + +#dashtopanelScrollview .progress-bar { + /* Customization of the progress bar style, e.g.: + -progress-bar-background: rgba(0.8, 0.8, 0.8, 1); + -progress-bar-border: rgba(0.9, 0.9, 0.9, 1); + */ +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js new file mode 100644 index 0000000..4f74d1e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js @@ -0,0 +1,1557 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const SearchController = imports.ui.main.overview._overview._controls._searchController; +const AppDisplay = imports.ui.main.overview._overview._controls.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const AppIcons = Me.imports.appIcons; +const Panel = Me.imports.panel; +const PanelManager = Me.imports.panelManager; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; +const Utils = Me.imports.utils; +const WindowPreview = Me.imports.windowPreview; + +var DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME / (Dash.DASH_ANIMATION_TIME > 1 ? 1000 : 1); +var DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; +var MIN_ICON_SIZE = 4; + +/** + * Extend DashItemContainer + * + * - set label position based on taskbar orientation + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this ugly pattern. + */ + +function extendDashItemContainer(dashItemContainer) { + dashItemContainer.showLabel = AppIcons.ItemShowLabel; +}; + +const iconAnimationSettings = { + _getDictValue: function(key) { + let type = Me.settings.get_string('animate-appicon-hover-animation-type'); + return Me.settings.get_value(key).deep_unpack()[type] || 0; + }, + + get type() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return ""; + + return Me.settings.get_string('animate-appicon-hover-animation-type'); + }, + + get convexity() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-convexity')); + }, + + get duration() { + return this._getDictValue('animate-appicon-hover-animation-duration'); + }, + + get extent() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-extent')); + }, + + get rotation() { + return this._getDictValue('animate-appicon-hover-animation-rotation'); + }, + + get travel() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-travel')); + }, + + get zoom() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-zoom')); + }, +}; + +/* This class is a fork of the upstream DashActor class (ui.dash.js) + * + * Summary of changes: + * - modified chldBox calculations for when 'show-apps-at-top' option is checked + * - handle horizontal dash + */ +var taskbarActor = Utils.defineClass({ + Name: 'DashToPanel-TaskbarActor', + Extends: St.Widget, + + _init: function(delegate) { + this._delegate = delegate; + this._currentBackgroundColor = 0; + this.callParent('_init', { name: 'dashtopanelTaskbar', + layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation[delegate.dtpPanel.getOrientation().toUpperCase()] }), + clip_to_allocation: true }); + }, + + vfunc_allocate: function(box, flags)  { + Utils.setAllocation(this, box, flags); + + let panel = this._delegate.dtpPanel; + let availFixedSize = box[panel.fixedCoord.c2] - box[panel.fixedCoord.c1]; + let availVarSize = box[panel.varCoord.c2] - box[panel.varCoord.c1]; + let [dummy, scrollview, leftFade, rightFade] = this.get_children(); + let [, natSize] = this[panel.sizeFunc](availFixedSize); + let childBox = new Clutter.ActorBox(); + let orientation = panel.getOrientation(); + + Utils.allocate(dummy, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c1]; + childBox[panel.varCoord.c2] = Math.min(availVarSize, natSize); + childBox[panel.fixedCoord.c1] = box[panel.fixedCoord.c1]; + childBox[panel.fixedCoord.c2] = box[panel.fixedCoord.c2]; + + Utils.allocate(scrollview, childBox, flags); + + let [value, , upper, , , pageSize] = scrollview[orientation[0] + 'scroll'].adjustment.get_values(); + upper = Math.floor(upper); + scrollview._dtpFadeSize = upper > pageSize ? this._delegate.iconSize : 0; + + if (this._currentBackgroundColor !== panel.dynamicTransparency.currentBackgroundColor) { + this._currentBackgroundColor = panel.dynamicTransparency.currentBackgroundColor; + let gradientStyle = 'background-gradient-start: ' + this._currentBackgroundColor + + 'background-gradient-direction: ' + orientation; + + leftFade.set_style(gradientStyle); + rightFade.set_style(gradientStyle); + } + + childBox[panel.varCoord.c2] = childBox[panel.varCoord.c1] + (value > 0 ? scrollview._dtpFadeSize : 0); + Utils.allocate(leftFade, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c2] - (value + pageSize < upper ? scrollview._dtpFadeSize : 0); + childBox[panel.varCoord.c2] = box[panel.varCoord.c2]; + Utils.allocate(rightFade, childBox, flags); + }, + + // We want to request the natural size of all our children + // as our natural width, so we chain up to StWidget (which + // then calls BoxLayout) + vfunc_get_preferred_width: function(forHeight) { + let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); + + return [0, natWidth]; + }, + + vfunc_get_preferred_height: function(forWidth) { + let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); + + return [0, natHeight]; + }, +}); + +/* This class is a fork of the upstream dash class (ui.dash.js) + * + * Summary of changes: + * - disconnect global signals adding a destroy method; + * - play animations even when not in overview mode + * - set a maximum icon size + * - show running and/or favorite applications + * - emit a custom signal when an app icon is added + * - Add scrollview + * Ensure actor is visible on keyfocus inside the scrollview + * - add 128px icon size, might be useful for hidpi display + * - Sync minimization application target position. + */ + +var taskbar = Utils.defineClass({ + Name: 'DashToPanel.Taskbar', + + _init : function(panel) { + this.dtpPanel = panel; + + // start at smallest size due to running indicator drawing area expanding but not shrinking + this.iconSize = 16; + + this._shownInitially = false; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._showLabelTimeoutId = 0; + this._resetHoverTimeoutId = 0; + this._ensureAppIconVisibilityTimeoutId = 0; + this._labelShowing = false; + this.fullScrollView = 0; + + let isVertical = panel.checkIfVertical(); + + this._box = new St.BoxLayout({ vertical: isVertical, + clip_to_allocation: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START }); + + this._container = new taskbarActor(this); + this._scrollView = new St.ScrollView({ name: 'dashtopanelScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true }); + + this._scrollView.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this._scrollView.connect('motion-event', Lang.bind(this, this._onMotionEvent)); + this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); + this._scrollView.add_actor(this._box); + + this._showAppsIconWrapper = panel.showAppsIconWrapper; + this._showAppsIconWrapper.connect('menu-state-changed', Lang.bind(this, function(showAppsIconWrapper, opened) { + this._itemMenuStateChanged(showAppsIconWrapper, opened); + })); + // an instance of the showAppsIcon class is encapsulated in the wrapper + this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon; + this.showAppsButton = this._showAppsIcon.toggleButton; + + if (isVertical) { + this.showAppsButton.set_width(panel.geom.w); + } + + this.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); + + this.showAppsButton.checked = (SearchController._showAppsButton) ? SearchController._showAppsButton.checked : false; + + this._showAppsIcon.childScale = 1; + this._showAppsIcon.childOpacity = 255; + this._showAppsIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper); + + this._container.add_child(new St.Widget({ width: 0, reactive: false })); + this._container.add_actor(this._scrollView); + + let orientation = panel.getOrientation(); + let fadeStyle = 'background-gradient-direction:' + orientation; + let fade1 = new St.Widget({ style_class: 'scrollview-fade', reactive: false }); + let fade2 = new St.Widget({ style_class: 'scrollview-fade', + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: 180 }); + + fade1.set_style(fadeStyle); + fade2.set_style(fadeStyle); + + this._container.add_actor(fade1); + this._container.add_actor(fade2); + + this.previewMenu = new WindowPreview.PreviewMenu(panel); + this.previewMenu.enable(); + + let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + this.actor = new St.Bin({ child: this._container, + y_align: St.Align.START, x_align:rtl?St.Align.END:St.Align.START + }); + + let adjustment = this._scrollView[orientation[0] + 'scroll'].adjustment; + + this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); + + this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); + + this._appSystem = Shell.AppSystem.get_default(); + + this.iconAnimator = new PanelManager.IconAnimator(this.dtpPanel.panel.actor); + + this._signalsHandler.add( + [ + this.dtpPanel.panel.actor, + 'notify::height', + () => this._queueRedisplay() + ], + [ + this.dtpPanel.panel.actor, + 'notify::width', + () => this._queueRedisplay() + ], + [ + this._appSystem, + 'installed-changed', + Lang.bind(this, function() { + AppFavorites.getAppFavorites().reload(); + this._queueRedisplay(); + }) + ], + [ + this._appSystem, + 'app-state-changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + AppFavorites.getAppFavorites(), + 'changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + global.window_manager, + 'switch-workspace', + () => this._connectWorkspaceSignals() + ], + [ + Utils.DisplayWrapper.getScreen(), + [ + 'window-entered-monitor', + 'window-left-monitor' + ], + () => { + if (Me.settings.get_boolean('isolate-monitors')) { + this._queueRedisplay(); + } + } + ], + [ + Main.overview, + 'item-drag-begin', + Lang.bind(this, this._onDragBegin) + ], + [ + Main.overview, + 'item-drag-end', + Lang.bind(this, this._onDragEnd) + ], + [ + Main.overview, + 'item-drag-cancelled', + Lang.bind(this, this._onDragCancelled) + ], + [ + // Ensure the ShowAppsButton status is kept in sync + SearchController._showAppsButton, + 'notify::checked', + Lang.bind(this, this._syncShowAppsButtonToggled) + ], + [ + Me.settings, + [ + 'changed::dot-size', + 'changed::show-favorites', + 'changed::show-running-apps', + 'changed::show-favorites-all-monitors' + ], + Lang.bind(this, this._redisplay) + ], + [ + Me.settings, + 'changed::group-apps', + Lang.bind(this, function() { + this.isGroupApps = Me.settings.get_boolean('group-apps'); + this._connectWorkspaceSignals(); + }) + ], + [ + Me.settings, + [ + 'changed::group-apps-use-launchers', + 'changed::taskbar-locked' + ], + () => this.resetAppIcons() + ], + [ + adjustment, + [ + 'notify::upper', + 'notify::pageSize' + ], + () => this._onScrollSizeChange(adjustment) + ] + ); + + this.isGroupApps = Me.settings.get_boolean('group-apps'); + + this._onScrollSizeChange(adjustment); + this._connectWorkspaceSignals(); + }, + + destroy: function() { + this.iconAnimator.destroy(); + + this._signalsHandler.destroy(); + this._signalsHandler = 0; + + this._container.destroy(); + + this.previewMenu.disable(); + this.previewMenu.destroy(); + + this._disconnectWorkspaceSignals(); + }, + + _dropIconAnimations: function() { + this._getTaskbarIcons().forEach(item => { + item.raise(0); + item.stretch(0); + }); + }, + + _updateIconAnimations: function(pointerX, pointerY) { + this._iconAnimationTimestamp = Date.now(); + let type = iconAnimationSettings.type; + + if (!pointerX || !pointerY) + [pointerX, pointerY] = global.get_pointer(); + + this._getTaskbarIcons().forEach(item => { + let [x, y] = item.get_transformed_position(); + let [width, height] = item.get_transformed_size(); + let [centerX, centerY] = [x + width / 2, y + height / 2]; + let size = this._box.vertical ? height : width; + let difference = this._box.vertical ? pointerY - centerY : pointerX - centerX; + let distance = Math.abs(difference); + let maxDistance = (iconAnimationSettings.extent / 2) * size; + + if (type == 'PLANK') { + // Make the position stable for items that are far from the pointer. + let translation = distance <= maxDistance ? + distance / (2 + 8 * distance / maxDistance) : + // the previous expression with distance = maxDistance + maxDistance / 10; + + if (difference > 0) + translation *= -1; + + item.stretch(translation); + } + + if (distance <= maxDistance) { + let level = (maxDistance - distance) / maxDistance; + level = Math.pow(level, iconAnimationSettings.convexity); + item.raise(level); + } else { + item.raise(0); + } + }); + }, + + _onLeaveEvent: function(actor) { + let [stageX, stageY] = global.get_pointer(); + let [success, x, y] = actor.transform_stage_point(stageX, stageY); + if (success && !actor.allocation.contains(x, y) && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._dropIconAnimations(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMotionEvent: function(actor_, event) { + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + let timestamp = Date.now(); + if (!this._iconAnimationTimestamp || + (timestamp - this._iconAnimationTimestamp >= iconAnimationSettings.duration / 2)) { + let [pointerX, pointerY] = event.get_coords(); + this._updateIconAnimations(pointerX, pointerY); + } + } + + return Clutter.EVENT_PROPAGATE; + }, + + _onScrollEvent: function(actor, event) { + + let orientation = this.dtpPanel.getOrientation(); + + // reset timeout to avid conflicts with the mousehover event + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + // Skip to avoid double events mouse + if (event.is_pointer_emulated()) + return Clutter.EVENT_STOP; + + let adjustment, delta; + + adjustment = this._scrollView[orientation[0] + 'scroll'].get_adjustment(); + + let increment = adjustment.step_increment; + + switch ( event.get_scroll_direction() ) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + delta = -increment; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + delta = +increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy*increment; + delta += dx*increment; + break; + + } + + adjustment.set_value(adjustment.get_value() + delta); + + return Clutter.EVENT_STOP; + + }, + + _onScrollSizeChange: function(adjustment) { + // Update minimization animation target position on scrollview change. + this._updateAppIcons(); + + // When applications are ungrouped and there is some empty space on the horizontal taskbar, + // force a fixed label width to prevent the icons from "wiggling" when an animation runs + // (adding or removing an icon). When the taskbar is full, revert to a dynamic label width + // to allow them to resize and make room for new icons. + if (!this.dtpPanel.checkIfVertical() && !this.isGroupApps) { + let initial = this.fullScrollView; + + if (!this.fullScrollView && Math.floor(adjustment.upper) > adjustment.page_size) { + this.fullScrollView = adjustment.page_size; + } else if (adjustment.page_size < this.fullScrollView) { + this.fullScrollView = 0; + } + + if (initial != this.fullScrollView) { + this._getAppIcons().forEach(a => a.updateTitleStyle()); + } + } + }, + + _onDragBegin: function() { + this._dragCancelled = false; + this._dragMonitor = { + dragMotion: Lang.bind(this, this._onDragMotion) + }; + DND.addDragMonitor(this._dragMonitor); + + if (this._box.get_n_children() == 0) { + this._emptyDropTarget = new Dash.EmptyDropTargetItem(); + this._box.insert_child_at_index(this._emptyDropTarget, 0); + this._emptyDropTarget.show(true); + } + + this._toggleFavortieHighlight(true); + }, + + _onDragCancelled: function() { + this._dragCancelled = true; + + if (this._dragInfo) { + this._box.set_child_at_index(this._dragInfo[1]._dashItemContainer, this._dragInfo[0]); + } + + this._endDrag(); + }, + + _onDragEnd: function() { + if (this._dragCancelled) + return; + + this._endDrag(); + }, + + _endDrag: function() { + if (this._dragInfo && this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem) { + this._box.remove_child(this._dragInfo[1]._dashItemContainer); + this._dragInfo[1]._dashItemContainer.destroy(); + delete this._dragInfo[1]._dashItemContainer; + } + + this._dragInfo = null; + this._clearEmptyDropTarget(); + this._showAppsIcon.setDragApp(null); + DND.removeDragMonitor(this._dragMonitor); + + this._toggleFavortieHighlight(); + }, + + _onDragMotion: function(dragEvent) { + let app = Dash.getAppFromSource(dragEvent.source); + if (app == null) + return DND.DragMotionResult.CONTINUE; + + let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor); + + if (showAppsHovered) + this._showAppsIcon.setDragApp(app); + else + this._showAppsIcon.setDragApp(null); + + return DND.DragMotionResult.CONTINUE; + }, + + _toggleFavortieHighlight: function(show) { + let appFavorites = AppFavorites.getAppFavorites(); + let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name'; + + this._getAppIcons().filter(appIcon => appFavorites.isFavorite(appIcon.app.get_id())) + .forEach(fav => fav._container[cssFuncName]('favorite')); + }, + + handleIsolatedWorkspaceSwitch: function() { + this._shownInitially = this.isGroupApps; + this._queueRedisplay(); + }, + + _connectWorkspaceSignals: function() { + this._disconnectWorkspaceSignals(); + + this._lastWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + + this._workspaceWindowAddedId = this._lastWorkspace.connect('window-added', () => this._queueRedisplay()); + this._workspaceWindowRemovedId = this._lastWorkspace.connect('window-removed', () => this._queueRedisplay()); + }, + + _disconnectWorkspaceSignals: function() { + if (this._lastWorkspace) { + this._lastWorkspace.disconnect(this._workspaceWindowAddedId); + this._lastWorkspace.disconnect(this._workspaceWindowRemovedId); + + this._lastWorkspace = null; + } + }, + + _queueRedisplay: function () { + Main.queueDeferredWork(this._workId); + }, + + _hookUpLabel: function(item, syncHandler) { + item.child.connect('notify::hover', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + + syncHandler.connect('sync-tooltip', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + }, + + _createAppItem: function(app, window, isLauncher) { + let appIcon = new AppIcons.taskbarAppIcon( + { + app: app, + window: window, + isLauncher: isLauncher + }, + this.dtpPanel, + { + setSizeManually: true, + showLabel: false, + isDraggable: !Me.settings.get_boolean('taskbar-locked'), + }, + this.previewMenu, + this.iconAnimator + ); + + if (appIcon._draggable) { + appIcon._draggable.connect('drag-begin', + Lang.bind(this, function() { + appIcon.actor.opacity = 0; + appIcon.isDragged = 1; + this._dropIconAnimations(); + })); + appIcon._draggable.connect('drag-end', + Lang.bind(this, function() { + appIcon.actor.opacity = 255; + delete appIcon.isDragged; + this._updateAppIcons(); + })); + } + + appIcon.connect('menu-state-changed', + Lang.bind(this, function(appIcon, opened) { + this._itemMenuStateChanged(item, opened); + })); + + let item = new TaskbarItemContainer(); + + item._dtpPanel = this.dtpPanel + extendDashItemContainer(item); + + item.setChild(appIcon.actor); + appIcon._dashItemContainer = item; + + appIcon.actor.connect('notify::hover', Lang.bind(this, function() { + if (appIcon.actor.hover){ + this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ + Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize); + this._ensureAppIconVisibilityTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(1); + else if (!appIcon.isDragged && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._updateIconAnimations(); + } else { + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(0); + } + })); + + appIcon.actor.connect('clicked', + Lang.bind(this, function(actor) { + Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + })); + + appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { + let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + + // This signal is triggered also by mouse click. The popup menu is opened at the original + // coordinates. Thus correct for the shift which is going to be applied to the scrollview. + if (appIcon._menu) { + appIcon._menu._boxPointer.xOffset = -x_shift; + appIcon._menu._boxPointer.yOffset = -y_shift; + } + })); + + // Override default AppIcon label_actor, now the + // accessible_name is set at DashItemContainer.setLabelText + appIcon.actor.label_actor = null; + item.setLabelText(app.get_name()); + + appIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(item, appIcon); + + return item; + }, + + // Return an array with the "proper" appIcons currently in the taskbar + _getAppIcons: function() { + // Only consider children which are "proper" icons and which are not + // animating out (which means they will be destroyed at the end of + // the animation) + return this._getTaskbarIcons().map(function(actor){ + return actor.child._delegate; + }); + }, + + _getTaskbarIcons: function(includeAnimated) { + return this._box.get_children().filter(function(actor) { + return actor.child && + actor.child._delegate && + actor.child._delegate.icon && + (includeAnimated || !actor.animatingOut); + }); + }, + + _updateAppIcons: function() { + let appIcons = this._getAppIcons(); + + appIcons.filter(icon => icon.constructor === AppIcons.taskbarAppIcon).forEach(icon => { + icon.updateIcon(); + }); + }, + + _itemMenuStateChanged: function(item, opened) { + // When the menu closes, it calls sync_hover, which means + // that the notify::hover handler does everything we need to. + if (opened) { + if (this._showLabelTimeoutId > 0) { + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + } + + item.hideLabel(); + } else { + // I want to listen from outside when a menu is closed. I used to + // add a custom signal to the appIcon, since gnome 3.8 the signal + // calling this callback was added upstream. + this.emit('menu-closed'); + + // The icon menu grabs the events and, once it is closed, the pointer is maybe + // no longer over the taskbar and the animations are not dropped. + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + this._scrollView.sync_hover(); + if (!this._scrollView.hover) + this._dropIconAnimations(); + } + } + }, + + _syncLabel: function (item, syncHandler) { + let shouldShow = syncHandler ? syncHandler.shouldShowTooltip() : item.child.get_hover(); + + if (shouldShow) { + if (this._showLabelTimeoutId == 0) { + let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; + this._showLabelTimeoutId = Mainloop.timeout_add(timeout, + Lang.bind(this, function() { + this._labelShowing = true; + item.showLabel(); + this._showLabelTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); + if (this._resetHoverTimeoutId > 0) { + Mainloop.source_remove(this._resetHoverTimeoutId); + this._resetHoverTimeoutId = 0; + } + } + } else { + if (this._showLabelTimeoutId > 0) + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + item.hideLabel(); + if (this._labelShowing) { + this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, + Lang.bind(this, function() { + this._labelShowing = false; + this._resetHoverTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing'); + } + } + }, + + _adjustIconSize: function() { + const thisMonitorIndex = this.dtpPanel.monitor.index; + let panelSize = PanelSettings.getPanelSize(Me.settings, thisMonitorIndex); + let availSize = panelSize - Me.settings.get_int('appicon-padding') * 2; + let minIconSize = MIN_ICON_SIZE + panelSize % 2; + + if (availSize == this.iconSize) + return; + + if (availSize < minIconSize) { + availSize = minIconSize; + } + + // For the icon size, we only consider children which are "proper" + // icons and which are not animating out (which means they will be + // destroyed at the end of the animation) + let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon]); + let scale = this.iconSize / availSize; + + this.iconSize = availSize; + + for (let i = 0; i < iconChildren.length; i++) { + let icon = iconChildren[i].child._delegate.icon; + + // Set the new size immediately, to keep the icons' sizes + // in sync with this.iconSize + icon.setIconSize(this.iconSize); + + // Don't animate the icon size change when the overview + // is transitioning, or when initially filling + // the taskbar + if (Main.overview.animationInProgress || + !this._shownInitially) + continue; + + let [targetWidth, targetHeight] = icon.icon.get_size(); + + // Scale the icon's texture to the previous size and + // tween to the new size + icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale); + + Utils.animate(icon.icon, + { width: targetWidth, + height: targetHeight, + time: DASH_ANIMATION_TIME, + transition: 'easeOutQuad', + }); + } + }, + + sortAppsCompareFunction: function(appA, appB) { + return getAppStableSequence(appA, this.dtpPanel.monitor) - + getAppStableSequence(appB, this.dtpPanel.monitor); + }, + + getAppInfos: function() { + //get the user's favorite apps + let favoriteApps = this._checkIfShowingFavorites() ? AppFavorites.getAppFavorites().getFavorites() : []; + + //find the apps that should be in the taskbar: the favorites first, then add the running apps + // When using isolation, we filter out apps that have no windows in + // the current workspace (this check is done in AppIcons.getInterestingWindows) + let runningApps = this._checkIfShowingRunningApps() ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this)) : []; + + if (!this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers')) { + return this._createAppInfos(favoriteApps, [], true) + .concat(this._createAppInfos(runningApps) + .filter(appInfo => appInfo.windows.length)); + } else { + return this._createAppInfos(favoriteApps.concat(runningApps.filter(app => favoriteApps.indexOf(app) < 0))) + .filter(appInfo => appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0); + } + }, + + _redisplay: function () { + if (!this._signalsHandler) { + return; + } + + //get the currently displayed appIcons + let currentAppIcons = this._getTaskbarIcons(); + let expectedAppInfos = this.getAppInfos(); + + //remove the appIcons which are not in the expected apps list + for (let i = currentAppIcons.length - 1; i > -1; --i) { + let appIcon = currentAppIcons[i].child._delegate; + let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app && + appInfo.isLauncher == appIcon.isLauncher); + + if (appIndex < 0 || + (appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) || + (!appIcon.window && !appIcon.isLauncher && + !this.isGroupApps && expectedAppInfos[appIndex].windows.length)) { + currentAppIcons[i][this._shownInitially ? 'animateOutAndDestroy' : 'destroy'](); + currentAppIcons.splice(i, 1); + } + } + + //if needed, reorder the existing appIcons and create the missing ones + let currentPosition = 0; + for (let i = 0, l = expectedAppInfos.length; i < l; ++i) { + let neededAppIcons = this.isGroupApps || !expectedAppInfos[i].windows.length ? + [{ app: expectedAppInfos[i].app, window: null, isLauncher: expectedAppInfos[i].isLauncher }] : + expectedAppInfos[i].windows.map(window => ({ app: expectedAppInfos[i].app, window: window, isLauncher: false })); + + for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) { + //check if the icon already exists + let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app && + appIcon.child._delegate.window == neededAppIcons[j].window); + + if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) { + //moved icon, reposition it + this._box.remove_child(currentAppIcons[matchingAppIconIndex]); + this._box.insert_child_at_index(currentAppIcons[matchingAppIconIndex], currentPosition); + } else if (matchingAppIconIndex < 0) { + //the icon doesn't exist yet, create a new one + let newAppIcon = this._createAppItem(neededAppIcons[j].app, neededAppIcons[j].window, neededAppIcons[j].isLauncher); + + this._box.insert_child_at_index(newAppIcon, currentPosition); + currentAppIcons.splice(currentPosition, 0, newAppIcon); + + // Skip animations on first run when adding the initial set + // of items, to avoid all items zooming in at once + newAppIcon.show(this._shownInitially); + } + + ++currentPosition; + } + } + + this._adjustIconSize(); + + // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 + // Without it, StBoxLayout may use a stale size cache + this._box.queue_relayout(); + + // This is required for icon reordering when the scrollview is used. + this._updateAppIcons(); + + // This will update the size, and the corresponding number for each icon on the primary panel + if (this.dtpPanel.isPrimary) { + this._updateNumberOverlay(); + } + + this._shownInitially = true; + }, + + _checkIfShowingRunningApps: function() { + return Me.settings.get_boolean('show-running-apps'); + }, + + _checkIfShowingFavorites: function() { + return Me.settings.get_boolean('show-favorites') && + (this.dtpPanel.isPrimary || Me.settings.get_boolean('show-favorites-all-monitors')); + }, + + _getRunningApps: function() { + let tracker = Shell.WindowTracker.get_default(); + let windows = global.get_window_actors(); + let apps = []; + + for (let i = 0, l = windows.length; i < l; ++i) { + let app = tracker.get_window_app(windows[i].metaWindow); + + if (app && apps.indexOf(app) < 0) { + apps.push(app); + } + } + + return apps; + }, + + _createAppInfos: function(apps, defaultWindows, defaultIsLauncher) { + return apps.map(app => ({ + app: app, + isLauncher: defaultIsLauncher || false, + windows: defaultWindows || AppIcons.getInterestingWindows(app, this.dtpPanel.monitor) + .sort(sortWindowsCompareFunction) + })); + }, + + // Reset the displayed apps icon to mantain the correct order + resetAppIcons : function(geometryChange) { + let children = this._getTaskbarIcons(true); + + for (let i = 0; i < children.length; i++) { + let item = children[i]; + item.destroy(); + } + + // to avoid ugly animations, just suppress them like when taskbar is first loaded. + this._shownInitially = false; + this._redisplay(); + + if (geometryChange && this.dtpPanel.checkIfVertical()) { + this.previewMenu._updateClip(); + } + }, + + _updateNumberOverlay: function() { + let seenApps = {}; + let counter = 0; + + this._getAppIcons().forEach(function(icon) { + if (!seenApps[icon.app]) { + seenApps[icon.app] = 1; + counter++; + } + + if (counter <= 10) { + icon.setNumberOverlay(counter == 10 ? 0 : counter); + } else { + // No overlay after 10 + icon.setNumberOverlay(-1); + } + + icon.updateHotkeyNumberOverlay(); + }); + + if (Me.settings.get_boolean('hot-keys') && + Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.toggleNumberOverlay(true); + }, + + toggleNumberOverlay: function(activate) { + let appIcons = this._getAppIcons(); + appIcons.forEach(function(icon) { + icon.toggleNumberOverlay(activate); + }); + }, + + _clearEmptyDropTarget: function() { + if (this._emptyDropTarget) { + this._emptyDropTarget.animateOutAndDestroy(); + this._emptyDropTarget = null; + } + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) + return DND.DragMotionResult.CONTINUE; + + // Don't allow favoriting of transient apps + if (source.app == null || source.app.is_window_backed()) + return DND.DragMotionResult.NO_DROP; + + if (!this._settings.is_writable('favorite-apps')) + return DND.DragMotionResult.NO_DROP; + + let sourceActor = source instanceof St.Widget ? source : source.actor; + let isVertical = this.dtpPanel.checkIfVertical(); + + if (!this._box.contains(sourceActor) && !source._dashItemContainer) { + //not an appIcon of the taskbar, probably from the applications view + source._dashItemContainer = new DragPlaceholderItem(source, this.iconSize, isVertical); + this._box.insert_child_above(source._dashItemContainer, null); + } + + let sizeProp = isVertical ? 'height' : 'width'; + let posProp = isVertical ? 'y' : 'x'; + let pos = isVertical ? y : x; + + let currentAppIcons = this._getAppIcons(); + let sourceIndex = currentAppIcons.indexOf(source); + let hoveredIndex = Utils.findIndex(currentAppIcons, + appIcon => pos >= appIcon._dashItemContainer[posProp] && + pos <= (appIcon._dashItemContainer[posProp] + appIcon._dashItemContainer[sizeProp])); + + if (!this._dragInfo) { + this._dragInfo = [sourceIndex, source]; + } + + if (hoveredIndex >= 0) { + let isLeft = pos < currentAppIcons[hoveredIndex]._dashItemContainer[posProp] + currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * .5; + + // Don't allow positioning before or after self and between icons of same app + if (!(hoveredIndex === sourceIndex || + (isLeft && hoveredIndex - 1 == sourceIndex) || + (isLeft && hoveredIndex - 1 >= 0 && source.app != currentAppIcons[hoveredIndex - 1].app && + currentAppIcons[hoveredIndex - 1].app == currentAppIcons[hoveredIndex].app) || + (!isLeft && hoveredIndex + 1 == sourceIndex) || + (!isLeft && hoveredIndex + 1 < currentAppIcons.length && source.app != currentAppIcons[hoveredIndex + 1].app && + currentAppIcons[hoveredIndex + 1].app == currentAppIcons[hoveredIndex].app))) { + this._box.set_child_at_index(source._dashItemContainer, hoveredIndex); + + // Ensure the next and previous icon are visible when moving the icon + // (I assume there's room for both of them) + if (hoveredIndex > 1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize); + if (hoveredIndex < this._box.get_children().length-1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize); + } + } + + return this._dragInfo[0] !== sourceIndex ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.CONTINUE; + }, + + // Draggable target interface + acceptDrop : function(source, actor, x, y, time) { + // Don't allow favoriting of transient apps + if (!source.app || source.app.is_window_backed() || !this._settings.is_writable('favorite-apps')) { + return false; + } + + let appIcons = this._getAppIcons(); + let sourceIndex = appIcons.indexOf(source); + let usingLaunchers = !this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers'); + + // dragging the icon to its original position + if (this._dragInfo[0] === sourceIndex) { + return true; + } + + let appFavorites = AppFavorites.getAppFavorites(); + let sourceAppId = source.app.get_id(); + let appIsFavorite = appFavorites.isFavorite(sourceAppId); + let replacingIndex = sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1); + let favoriteIndex = replacingIndex >= 0 ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app) : 0; + let sameApps = appIcons.filter(a => a != source && a.app == source.app); + let showingFavorites = this._checkIfShowingFavorites(); + let favoritesCount = 0; + let position = 0; + let interestingWindows = {}; + let getAppWindows = app => { + if (!interestingWindows[app]) { + interestingWindows[app] = AppIcons.getInterestingWindows(app, this.dtpPanel.monitor); + } + + let appWindows = interestingWindows[app]; //prevents "reference to undefined property Symbol.toPrimitive" warning + return appWindows; + }; + + if (sameApps.length && + ((!appIcons[sourceIndex - 1] || appIcons[sourceIndex - 1].app !== source.app) && + (!appIcons[sourceIndex + 1] || appIcons[sourceIndex + 1].app !== source.app))) { + appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length); + Array.prototype.splice.apply(appIcons, [sourceIndex + 1, 0].concat(sameApps)); + } + + for (let i = 0, l = appIcons.length; i < l; ++i) { + let windows = []; + + if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) { + windows = appIcons[i].window ? [appIcons[i].window] : getAppWindows(appIcons[i].app); + } + + windows.forEach(w => w._dtpPosition = position++); + + if (showingFavorites && + ((usingLaunchers && appIcons[i].isLauncher) || + (!usingLaunchers && appFavorites.isFavorite(appIcons[i].app.get_id())))) { + ++favoritesCount; + } + } + + if (sourceIndex < favoritesCount) { + if (appIsFavorite) { + appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex); + } else { + appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex); + } + } else if (appIsFavorite && showingFavorites && (!usingLaunchers || source.isLauncher)) { + appFavorites.removeFavorite(sourceAppId); + } + + appFavorites.emit('changed'); + + return true; + }, + + _onShowAppsButtonToggled: function() { + // Sync the status of the default appButtons. Only if the two statuses are + // different, that means the user interacted with the extension provided + // application button, cutomize the behaviour. Otherwise the shell has changed the + // status (due to the _syncShowAppsButtonToggled function below) and it + // has already performed the desired action. + let selector = SearchController; + + if (selector._showAppsButton && + selector._showAppsButton.checked !== this.showAppsButton.checked) { + // find visible view + + if (this.showAppsButton.checked) { + if (Me.settings.get_boolean('show-apps-override-escape')) { + //override escape key to return to the desktop when entering the overview using the showapps button + SearchController._onStageKeyPress = function(actor, event) { + if (Main.modalCount == 1 && event.get_key_symbol() === Clutter.KEY_Escape) { + this._searchActive ? this.reset() : Main.overview.hide(); + + return Clutter.EVENT_STOP; + } + + return this.__proto__._onStageKeyPress.call(this, actor, event); + }; + } + + // force spring animation triggering.By default the animation only + // runs if we are already inside the overview. + if (!Main.overview._shown) { + this.forcedOverview = true; + let grid = AppDisplay._grid; + let onShownCb; + let overviewSignal = Config.PACKAGE_VERSION > '3.38.1' ? 'showing' : 'shown'; + let overviewShowingId = Main.overview.connect(overviewSignal, () => { + Main.overview.disconnect(overviewShowingId); + onShownCb(); + }); + + onShownCb = () => grid.emit('animation-done'); + } + + //temporarily use as primary the monitor on which the showapps btn was clicked, this is + //restored by the panel when exiting the overview + this.dtpPanel.panelManager.setFocusedMonitor(this.dtpPanel.monitor); + + let overviewHiddenId = Main.overview.connect('hidden', () => { + Main.overview.disconnect(overviewHiddenId); + delete SearchController._onStageKeyPress; + }); + + // Finally show the overview + selector._showAppsButton.checked = true; + Main.overview.show(2 /*APP_GRID*/); + } + else { + if (this.forcedOverview) { + // force exiting overview if needed + + Main.overview.hide(); + this.forcedOverview = false; + } + else { + selector._showAppsButton.checked = false; + this.forcedOverview = false; + } + } + } + }, + + _syncShowAppsButtonToggled: function() { + let status = SearchController._showAppsButton.checked; + if (this.showAppsButton.checked !== status) + this.showAppsButton.checked = status; + }, + + showShowAppsButton: function() { + this.showAppsButton.visible = true; + this.showAppsButton.set_width(-1); + this.showAppsButton.set_height(-1); + }, + + popupFocusedAppSecondaryMenu: function() { + let appIcons = this._getAppIcons(); + let tracker = Shell.WindowTracker.get_default(); + + for(let i in appIcons) { + if(appIcons[i].app == tracker.focus_app) { + let appIcon = appIcons[i]; + if(appIcon._menu && appIcon._menu.isOpen) + appIcon._menu.close(); + else + appIcon.popupMenu(); + + appIcon.sync_hover(); + break; + } + } + }, +}); + +Signals.addSignalMethods(taskbar.prototype); + +const CloneContainerConstraint = Utils.defineClass({ + Name: 'DashToPanel-CloneContainerConstraint', + Extends: Clutter.BindConstraint, + + vfunc_update_allocation: function(actor, actorBox) { + if (!this.source) + return; + + let [stageX, stageY] = this.source.get_transformed_position(); + let [width, height] = this.source.get_transformed_size(); + + actorBox.set_origin(stageX, stageY); + actorBox.set_size(width, height); + }, +}); + +var TaskbarItemContainer = Utils.defineClass({ + Name: 'DashToPanel-TaskbarItemContainer', + Extends: Dash.DashItemContainer, + + vfunc_allocate: function(box, flags) { + if (this.child == null) + return; + + Utils.setAllocation(this, box, flags); + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; + let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = this.child.get_preferred_size(); + let [childScaleX, childScaleY] = this.child.get_scale(); + + let childWidth = Math.min(natChildWidth * childScaleX, availWidth); + let childHeight = Math.min(natChildHeight * childScaleY, availHeight); + let childBox = new Clutter.ActorBox(); + + childBox.x1 = (availWidth - childWidth) / 2; + childBox.y1 = (availHeight - childHeight) / 2; + childBox.x2 = childBox.x1 + childWidth; + childBox.y2 = childBox.y1 + childHeight; + + Utils.allocate(this.child, childBox, flags); + }, + + // In case appIcon is removed from the taskbar while it is hovered, + // restore opacity before dashItemContainer.animateOutAndDestroy does the destroy animation. + animateOutAndDestroy: function() { + if (this._raisedClone) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + } + + this.callParent('animateOutAndDestroy'); + }, + + // For ItemShowLabel + _getIconAnimationOffset: function() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return 0; + + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + return this._dtpPanel.dtpSize * (travel + (zoom - 1) / 2); + }, + + _updateCloneContainerPosition: function(cloneContainer) { + let [stageX, stageY] = this.get_transformed_position(); + + if (Config.PACKAGE_VERSION >= '3.36') + cloneContainer.set_position(stageX - this.translation_x, stageY - this.translation_y); + else + cloneContainer.set_position(stageX, stageY); + }, + + _createRaisedClone: function() { + let [width, height] = this.get_transformed_size(); + + // "clone" of this child (appIcon actor) + let cloneButton = this.child._delegate.getCloneButton(); + + // "clone" of this (taskbarItemContainer) + let cloneContainer = new St.Bin({ + child: cloneButton, + width: width, height: height, + reactive: false, + }); + + this._updateCloneContainerPosition(cloneContainer); + + // For the stretch animation + if (Config.PACKAGE_VERSION >= '3.36') { + let boundProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + this.bind_property(boundProperty, cloneContainer, boundProperty, GObject.BindingFlags.SYNC_CREATE); + } else { + let constraint = new CloneContainerConstraint({ source: this }); + cloneContainer.add_constraint(constraint); + } + + // The clone follows its source when the taskbar is scrolled. + let taskbarScrollView = this.get_parent().get_parent(); + let adjustment = this._dtpPanel.checkIfVertical() ? taskbarScrollView.vscroll.get_adjustment() : taskbarScrollView.hscroll.get_adjustment(); + let adjustmentChangedId = adjustment.connect('notify::value', () => this._updateCloneContainerPosition(cloneContainer)); + + // Update clone position when an item is added to / removed from the taskbar. + let taskbarBox = this.get_parent(); + let taskbarBoxAllocationChangedId = taskbarBox.connect('notify::allocation', () => this._updateCloneContainerPosition(cloneContainer)); + + // The clone itself + this._raisedClone = cloneButton.child; + this._raisedClone.connect('destroy', () => { + adjustment.disconnect(adjustmentChangedId); + taskbarBox.disconnect(taskbarBoxAllocationChangedId); + Mainloop.idle_add(() => cloneContainer.destroy()); + delete this._raisedClone; + }); + + this._raisedClone.source.opacity = 0; + Main.uiGroup.add_actor(cloneContainer); + }, + + // Animate the clone. + // AppIcon actors cannot go outside the taskbar so the animation is done with a clone. + // If level is zero, the clone is dropped and destroyed. + raise: function(level) { + if (this._raisedClone) + Utils.stopAnimations(this._raisedClone); + else if (level) + this._createRaisedClone(); + else + return; + + let panelPosition = this._dtpPanel.getPosition(); + let panelElementPositions = this._dtpPanel.panelManager.panelsElementPositions[this._dtpPanel.monitor.index] || Pos.defaults; + let taskbarPosition = panelElementPositions.filter(pos => pos.element == 'taskbar')[0].position; + + let vertical = panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT; + let translationDirection = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT ? 1 : -1; + let rotationDirection; + if (panelPosition == St.Side.LEFT || taskbarPosition == Pos.STACKED_TL) + rotationDirection = -1; + else if (panelPosition == St.Side.RIGHT || taskbarPosition == Pos.STACKED_BR) + rotationDirection = 1; + else { + let items = this.get_parent().get_children(); + let index = items.indexOf(this); + rotationDirection = (index - (items.length - 1) / 2) / ((items.length - 1) / 2); + } + + let duration = iconAnimationSettings.duration / 1000; + let rotation = iconAnimationSettings.rotation; + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + + // level is about 1 for the icon that is hovered, less for others. + // time depends on the translation to do. + let [width, height] = this._raisedClone.source.get_transformed_size(); + let translationMax = (vertical ? width : height) * (travel + (zoom - 1) / 2); + let translationEnd = translationMax * level; + let translationDone = vertical ? this._raisedClone.translation_x : this._raisedClone.translation_y; + let translationTodo = Math.abs(translationEnd - translationDone); + let scale = 1 + (zoom - 1) * level; + let rotationAngleZ = rotationDirection * rotation * level; + let time = duration * translationTodo / translationMax; + + let options = { + scale_x: scale, scale_y: scale, + rotation_angle_z: rotationAngleZ, + time: time, + transition: 'easeOutQuad', + onComplete: () => { + if (!level) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + delete this._raisedClone; + } + }, + }; + options[vertical ? 'translation_x' : 'translation_y'] = translationDirection * translationEnd; + + Utils.animate(this._raisedClone, options); + }, + + // Animate this and cloneContainer, since cloneContainer translation is bound to this. + stretch: function(translation) { + let duration = iconAnimationSettings.duration / 1000; + let zoom = iconAnimationSettings.zoom; + let animatedProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + let isShowing = this.opacity != 255 || this.child.opacity != 255; + + if (isShowing) { + // Do no stop the animation initiated in DashItemContainer.show. + this[animatedProperty] = zoom * translation; + } else { + let options = { + time: duration, + transition: 'easeOutQuad', + }; + options[animatedProperty] = zoom * translation; + + Utils.stopAnimations(this); + Utils.animate(this, options); + } + }, +}); + +var DragPlaceholderItem = Utils.defineClass({ + Name: 'DashToPanel-DragPlaceholderItem', + Extends: St.Widget, + + _init: function(appIcon, iconSize, isVertical) { + this.callParent('_init', { style: AppIcons.getIconContainerStyle(isVertical), layout_manager: new Clutter.BinLayout() }); + + this.child = { _delegate: appIcon }; + + this._clone = new Clutter.Clone({ + source: appIcon.icon._iconBin, + width: iconSize, + height: iconSize + }); + + this.add_actor(this._clone); + }, + + destroy: function() { + this._clone.destroy(); + this.callParent('destroy'); + }, +}); + +function getAppStableSequence(app, monitor) { + let windows = AppIcons.getInterestingWindows(app, monitor); + + return windows.reduce((prevWindow, window) => { + return Math.min(prevWindow, getWindowStableSequence(window)); + }, Infinity); +} + +function sortWindowsCompareFunction(windowA, windowB) { + return getWindowStableSequence(windowA) - getWindowStableSequence(windowB); +} + +function getWindowStableSequence(window) { + return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence()); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js new file mode 100644 index 0000000..aa86d7a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js @@ -0,0 +1,269 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Lang = imports.lang; +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const St = imports.gi.St; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +var DynamicTransparency = Utils.defineClass({ + Name: 'DashToPanel.DynamicTransparency', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._proximityManager = dtpPanel.panelManager.proximityManager; + this._proximityWatchId = 0; + this._windowOverlap = false; + this.currentBackgroundColor = 0; + + this._initialPanelStyle = dtpPanel.panel.actor.get_style(); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._initialPanelCornerStyle = dtpPanel.panel._leftCorner.actor.get_style(); + } + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._bindSignals(); + + this._updateAnimationDuration(); + this._updateAllAndSet(); + this._updateProximityWatch(); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._proximityManager.removeWatch(this._proximityWatchId); + + this._dtpPanel.panel.actor.set_style(this._initialPanelStyle); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(this._initialPanelCornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(this._initialPanelCornerStyle); + } + }, + + updateExternalStyle: function() { + this._updateComplementaryStyles(); + this._setBackground(); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + Utils.getStageTheme(), + 'changed', + () => this._updateAllAndSet() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-bg', + 'changed::trans-bg-color' + ], + () => this._updateColorAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-opacity', + 'changed::trans-panel-opacity', + 'changed::trans-bg-color', + 'changed::trans-dynamic-anim-target', + 'changed::trans-use-dynamic-opacity' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-gradient', + 'changed::trans-gradient-top-color', + 'changed::trans-gradient-bottom-color', + 'changed::trans-gradient-top-opacity', + 'changed::trans-gradient-bottom-opacity' + ], + () => this._updateGradientAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-dynamic-behavior', + 'changed::trans-use-dynamic-opacity', + 'changed::trans-dynamic-distance' + ], + () => this._updateProximityWatch() + ], + [ + Me.settings, + 'changed::trans-dynamic-anim-time', + () => this._updateAnimationDuration() + ] + ); + }, + + _updateProximityWatch: function() { + this._proximityManager.removeWatch(this._proximityWatchId); + + if (Me.settings.get_boolean('trans-use-dynamic-opacity')) { + let isVertical = this._dtpPanel.checkIfVertical(); + let threshold = Me.settings.get_int('trans-dynamic-distance'); + + this._proximityWatchId = this._proximityManager.createWatch( + this._dtpPanel.panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('trans-dynamic-behavior')], + isVertical ? threshold : 0, + isVertical ? 0 : threshold, + overlap => { + this._windowOverlap = overlap; + this._updateAlphaAndSet(); + } + ); + } + }, + + _updateAnimationDuration: function() { + this.animationDuration = (Me.settings.get_int('trans-dynamic-anim-time') * 0.001) + 's;'; + }, + + _updateAllAndSet: function() { + let themeBackground = this._getThemeBackground(true); + + this._updateColor(themeBackground); + this._updateAlpha(themeBackground); + this._updateComplementaryStyles(); + this._updateGradient(); + this._setBackground(); + this._setGradient(); + }, + + _updateColorAndSet: function() { + this._updateColor(); + this._setBackground(); + }, + + _updateAlphaAndSet: function() { + this._updateAlpha(); + this._setBackground(); + }, + + _updateGradientAndSet: function() { + this._updateGradient(); + this._setGradient(); + }, + + _updateComplementaryStyles: function() { + let panelThemeNode = this._dtpPanel.panel.actor.get_theme_node(); + + this._complementaryStyles = 'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;'; + }, + + _updateColor: function(themeBackground) { + this.backgroundColorRgb = Me.settings.get_boolean('trans-use-custom-bg') ? + Me.settings.get_string('trans-bg-color') : + (themeBackground || this._getThemeBackground()); + }, + + _updateAlpha: function(themeBackground) { + if (this._windowOverlap && !Main.overview.visibleTarget && Me.settings.get_boolean('trans-use-dynamic-opacity')) { + this.alpha = Me.settings.get_double('trans-dynamic-anim-target'); + } else { + this.alpha = Me.settings.get_boolean('trans-use-custom-opacity') ? + Me.settings.get_double('trans-panel-opacity') : + (themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569 + } + }, + + _updateGradient: function() { + this._gradientStyle = ''; + + if (Me.settings.get_boolean('trans-use-custom-gradient')) { + this._gradientStyle += 'background-gradient-direction: ' + (this._dtpPanel.checkIfVertical() ? 'horizontal;' : 'vertical;') + + 'background-gradient-start: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-top-color'), + Me.settings.get_double('trans-gradient-top-opacity')) + + 'background-gradient-end: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-bottom-color'), + Me.settings.get_double('trans-gradient-bottom-opacity')); + } + }, + + _setBackground: function() { + this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha); + + let transition = 'transition-duration:' + this.animationDuration; + let cornerStyle = '-panel-corner-background-color: ' + this.currentBackgroundColor + transition; + + this._dtpPanel.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(cornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(cornerStyle); + } + }, + + _setGradient: function() { + this._dtpPanel.panel.actor.set_style( + 'background: none; ' + + 'border-image: none; ' + + 'background-image: none; ' + + this._gradientStyle + + 'transition-duration:' + this.animationDuration + ); + }, + + _getThemeBackground: function(reload) { + if (reload || !this._themeBackground) { + let fakePanel = new St.Bin({ name: 'panel' }); + Main.uiGroup.add_child(fakePanel); + let fakeTheme = fakePanel.get_theme_node() + this._themeBackground = this._getBackgroundImageColor(fakeTheme) || fakeTheme.get_background_color(); + Main.uiGroup.remove_child(fakePanel); + } + + return this._themeBackground; + }, + + _getBackgroundImageColor: function(theme) { + let bg = null; + + try { + let imageFile = theme.get_background_image() || theme.get_border_image().get_file(); + + if (imageFile) { + let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path()); + let pixels = imageBuf.get_pixels(); + + bg = { red: pixels[0], green: pixels[1], blue: pixels[2], alpha: pixels[3] }; + } + } catch (error) {} + + return bg; + } +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js new file mode 100644 index 0000000..d90d2cc --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js @@ -0,0 +1,1040 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gi = imports._gi; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const Main = imports.ui.main; +const MessageTray = imports.ui.messageTray; +const Util = imports.misc.util; + +var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain']; +var SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1); + +//Clutter implicit animations are available since 3.34 +//prefer those over Tweener if available +if (Config.PACKAGE_VERSION < '3.34') { + var Tweener = imports.ui.tweener; +} + +var defineClass = function (classDef) { + let parentProto = classDef.Extends ? classDef.Extends.prototype : null; + + if (Config.PACKAGE_VERSION < '3.31.9') { + if (parentProto && (classDef.Extends.name || classDef.Extends.toString()).indexOf('DashToPanel.') < 0) { + classDef.callParent = function() { + let args = Array.prototype.slice.call(arguments); + let func = args.shift(); + + classDef.Extends.prototype[func].apply(this, args); + }; + } + + return new imports.lang.Class(classDef); + } + + let isGObject = parentProto instanceof GObject.Object; + let needsSuper = parentProto && !isGObject; + let getParentArgs = function(args) { + let parentArgs = []; + + (classDef.ParentConstrParams || parentArgs).forEach(p => { + if (p.constructor === Array) { + let param = args[p[0]]; + + parentArgs.push(p[1] ? param[p[1]] : param); + } else { + parentArgs.push(p); + } + }); + + return parentArgs; + }; + + let C = eval( + '(class C ' + (needsSuper ? 'extends Object' : '') + ' { ' + + ' constructor(...args) { ' + + (needsSuper ? 'super(...getParentArgs(args));' : '') + + (needsSuper || !parentProto ? 'this._init(...args);' : '') + + ' }' + + ' callParent(...args) { ' + + ' let func = args.shift(); ' + + ' if (!(func === \'_init\' && needsSuper))' + + ' super[func](...args); ' + + ' }' + + '})' + ); + + if (parentProto) { + Object.setPrototypeOf(C.prototype, parentProto); + Object.setPrototypeOf(C, classDef.Extends); + } + + Object.defineProperty(C, 'name', { value: classDef.Name }); + Object.keys(classDef) + .filter(k => classDef.hasOwnProperty(k) && classDef[k] instanceof Function) + .forEach(k => C.prototype[k] = classDef[k]); + + if (isGObject) { + C = GObject.registerClass({ Signals: classDef.Signals || {} }, C); + } + + return C; +}; + +// simplify global signals and function injections handling +// abstract class +var BasicHandler = defineClass({ + Name: 'DashToPanel.BasicHandler', + + _init: function(){ + this._storage = new Object(); + }, + + add: function(/*unlimited 3-long array arguments*/){ + + // convert arguments object to array, concatenate with generic + let args = [].concat('generic', [].slice.call(arguments)); + // call addWithLabel with ags as if they were passed arguments + this.addWithLabel.apply(this, args); + }, + + destroy: function() { + for( let label in this._storage ) + this.removeWithLabel(label); + }, + + addWithLabel: function( label /* plus unlimited 3-long array arguments*/) { + + if(this._storage[label] == undefined) + this._storage[label] = new Array(); + + // skip first element of the arguments + for( let i = 1; i < arguments.length; i++ ) { + let item = this._storage[label]; + let handlers = this._create(arguments[i]); + + for (let j = 0, l = handlers.length; j < l; ++j) { + item.push(handlers[j]); + } + } + + }, + + removeWithLabel: function(label){ + + if(this._storage[label]) { + for( let i = 0; i < this._storage[label].length; i++ ) { + this._remove(this._storage[label][i]); + } + + delete this._storage[label]; + } + }, + + /* Virtual methods to be implemented by subclass */ + // create single element to be stored in the storage structure + _create: function(item){ + throw new Error('no implementation of _create in ' + this); + }, + + // correctly delete single element + _remove: function(item){ + throw new Error('no implementation of _remove in ' + this); + } +}); + +// Manage global signals +var GlobalSignalsHandler = defineClass({ + Name: 'DashToPanel.GlobalSignalsHandler', + Extends: BasicHandler, + + _create: function(item) { + let handlers = []; + + item[1] = [].concat(item[1]); + + for (let i = 0, l = item[1].length; i < l; ++i) { + let object = item[0]; + let event = item[1][i]; + let callback = item[2] + try { + let id = object.connect(event, callback); + + handlers.push([object, id]); + } catch (e) + { + + } + } + + return handlers; + }, + + _remove: function(item){ + item[0].disconnect(item[1]); + } +}); + +/** + * Manage function injection: both instances and prototype can be overridden + * and restored + */ +var InjectionsHandler = defineClass({ + Name: 'DashToPanel.InjectionsHandler', + Extends: BasicHandler, + + _create: function(item) { + let object = item[0]; + let name = item[1]; + let injectedFunction = item[2]; + let original = object[name]; + + object[name] = injectedFunction; + return [[object, name, injectedFunction, original]]; + }, + + _remove: function(item) { + let object = item[0]; + let name = item[1]; + let original = item[3]; + object[name] = original; + } +}); + +/** + * Manage timeouts: the added timeouts have their id reset on completion + */ +var TimeoutsHandler = defineClass({ + Name: 'DashToPanel.TimeoutsHandler', + Extends: BasicHandler, + + _create: function(item) { + let name = item[0]; + let delay = item[1]; + let timeoutHandler = item[2]; + + this._remove(item); + + this[name] = Mainloop.timeout_add(delay, () => { + this[name] = 0; + timeoutHandler(); + }); + + return [[name]]; + }, + + remove: function(name) { + this._remove([name]) + }, + + _remove: function(item) { + let name = item[0]; + + if (this[name]) { + Mainloop.source_remove(this[name]); + this[name] = 0; + } + }, + + getId: function(name) { + return this[name] ? this[name] : 0; + } +}); + +// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as +// previous versions. +var DisplayWrapper = { + getScreen: function() { + return global.screen || global.display; + }, + + getWorkspaceManager: function() { + return global.screen || global.workspace_manager; + }, + + getMonitorManager: function() { + return global.screen || Meta.MonitorManager.get(); + } +}; + +var getCurrentWorkspace = function() { + return DisplayWrapper.getWorkspaceManager().get_active_workspace(); +}; + +var getWorkspaceByIndex = function(index) { + return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index); +}; + +var getWorkspaceCount = function() { + return DisplayWrapper.getWorkspaceManager().n_workspaces; +}; + +var getStageTheme = function() { + return St.ThemeContext.get_for_stage(global.stage); +}; + +var getScaleFactor = function() { + return getStageTheme().scale_factor || 1; +}; + +var getAppDisplayViews = function() { + //gnome-shell 3.38 only has one view and it is now the appDisplay + return imports.ui.appDisplay._views || [{ view: imports.ui.appDisplay }]; +}; + +var findIndex = function(array, predicate) { + if (Array.prototype.findIndex) { + return array.findIndex(predicate); + } + + for (let i = 0, l = array.length; i < l; ++i) { + if (predicate(array[i])) { + return i; + } + } + + return -1; +}; + +var find = function(array, predicate) { + let index = findIndex(array, predicate); + + if (index > -1) { + return array[index]; + } +}; + +var mergeObjects = function(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +var hookVfunc = function(proto, symbol, func) { + if (Gi.hook_up_vfunc_symbol && func) { + //gjs > 1.53.3 + proto[Gi.hook_up_vfunc_symbol](symbol, func); + } else { + //On older gjs, this is how to hook vfunc. It is buggy and can't be used reliably to replace + //already hooked functions. Since it's our only use for it, disabled for now (and probably forever) + //Gi.hook_up_vfunc(proto, symbol, func); + } +}; + +var wrapActor = function(actor) { + if (actor) { + Object.defineProperty(actor, 'actor', { + value: actor instanceof Clutter.Actor ? actor : actor.actor + }); + } +}; + +var getTransformedAllocation = function(actor) { + if (Config.PACKAGE_VERSION < '3.37') { + return Shell.util_get_transformed_allocation(actor); + } + + let extents = actor.get_transformed_extents(); + let topLeft = extents.get_top_left(); + let bottomRight = extents.get_bottom_right(); + + return { x1: topLeft.x, x2: bottomRight.x, y1: topLeft.y, y2: bottomRight.y }; +}; + +var allocate = function(actor, box, flags, useParent) { + let allocateObj = useParent ? actor.__proto__ : actor; + + allocateObj.allocate.apply(actor, getAllocationParams(box, flags)); +}; + +var setAllocation = function(actor, box, flags) { + actor.set_allocation.apply(actor, getAllocationParams(box, flags)); +}; + +var getAllocationParams = function(box, flags) { + let params = [box]; + + if (Config.PACKAGE_VERSION < '3.37') { + params.push(flags); + } + + return params; +}; + +var setClip = function(actor, x, y, width, height) { + actor.set_clip(0, 0, width, height); + actor.set_position(x, y); + actor.set_size(width, height); +}; + +var addKeybinding = function(key, settings, handler, modes) { + if (!Main.wm._allowedKeybindings[key]) { + Main.wm.addKeybinding( + key, + settings, + Meta.KeyBindingFlags.NONE, + modes || (Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW), + handler + ); + } +}; + +var removeKeybinding = function(key) { + if (Main.wm._allowedKeybindings[key]) { + Main.wm.removeKeybinding(key); + } +}; + +var getrgbColor = function(color) { + color = typeof color === 'string' ? Clutter.color_from_string(color)[1] : color; + + return { red: color.red, green: color.green, blue: color.blue }; +}; + +var getrgbaColor = function(color, alpha, offset) { + if (alpha <= 0) { + return 'transparent; '; + } + + let rgb = getrgbColor(color); + + if (offset) { + ['red', 'green', 'blue'].forEach(k => { + rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset)); + + if (rgb[k] == color[k]) { + rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset)); + } + }); + } + + return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; +}; + +var checkIfColorIsBright = function(color) { + let rgb = getrgbColor(color); + let brightness = 0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue; + + return brightness > 128; +}; + +var getMouseScrollDirection = function(event) { + let direction; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + direction = 'up'; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + direction = 'down'; + break; + } + + return direction; +}; + +var checkIfWindowHasTransient = function(window) { + let hasTransient; + + window.foreach_transient(t => !(hasTransient = true)); + + return hasTransient; +}; + +var activateSiblingWindow = function(windows, direction, startWindow) { + let windowIndex = windows.indexOf(global.display.focus_window); + let nextWindowIndex = windowIndex < 0 ? + startWindow ? windows.indexOf(startWindow) : 0 : + windowIndex + (direction == 'up' ? 1 : -1); + + if (nextWindowIndex == windows.length) { + nextWindowIndex = 0; + } else if (nextWindowIndex < 0) { + nextWindowIndex = windows.length - 1; + } + + if (windowIndex != nextWindowIndex) { + Main.activateWindow(windows[nextWindowIndex]); + } +}; + +var animateWindowOpacity = function(window, tweenOpts) { + //there currently is a mutter bug with the windowactor opacity, starting with 3.34 + //https://gitlab.gnome.org/GNOME/mutter/issues/836 + + if (Config.PACKAGE_VERSION > '3.35') { + //on 3.36, a workaround is to use the windowactor's child for the fade animation + //this leaves a "shadow" on the desktop, so the windowactor needs to be hidden + //when the animation is complete + let visible = tweenOpts.opacity > 0; + let windowActor = window; + + window = windowActor.get_first_child() || windowActor; + + if (!windowActor.visible && visible) { + window.opacity = 0; + windowActor.visible = visible; + } + + if (!visible) { + let initialOpacity = window.opacity; + + tweenOpts.onComplete = () => { + windowActor.visible = visible; + window.opacity = initialOpacity; + }; + } + } else if (Config.PACKAGE_VERSION > '3.33') { + //the workaround only works on 3.35+, so on 3.34, let's just hide the + //window without animation + return window.visible = (tweenOpts.opacity == 255); + } + + animate(window, tweenOpts); +}; + +var animate = function(actor, options) { + if (Tweener) { + return Tweener.addTween(actor, options); + } + + //to support both Tweener and Clutter animations, we use Tweener "time" + //and "delay" properties defined in seconds, as opposed to Clutter animations + //"duration" and "delay" which are defined in milliseconds + if (options.delay) { + options.delay = options.delay * 1000; + } + + options.duration = options.time * 1000; + delete options.time; + + if (options.transition) { + //map Tweener easing equations to Clutter animation modes + options.mode = { + 'easeInCubic': Clutter.AnimationMode.EASE_IN_CUBIC, + 'easeInOutCubic': Clutter.AnimationMode.EASE_IN_OUT_CUBIC, + 'easeInOutQuad': Clutter.AnimationMode.EASE_IN_OUT_QUAD, + 'easeOutQuad': Clutter.AnimationMode.EASE_OUT_QUAD + }[options.transition] || Clutter.AnimationMode.LINEAR; + + delete options.transition; + } + + let params = [options]; + + if ('value' in options && actor instanceof St.Adjustment) { + params.unshift(options.value); + delete options.value; + } + + actor.ease.apply(actor, params); +} + +var isAnimating = function(actor, prop) { + if (Tweener) { + return Tweener.isTweening(actor); + } + + return !!actor.get_transition(prop); +} + +var stopAnimations = function(actor) { + if (Tweener) { + return Tweener.removeTweens(actor); + } + + actor.remove_all_transitions(); +} + +var getIndicators = function(delegate) { + if (delegate instanceof St.BoxLayout) { + return delegate; + } + + return delegate.indicators; +} + +var getPoint = function(coords) { + if (Config.PACKAGE_VERSION > '3.35.1') { + return new imports.gi.Graphene.Point(coords); + } + + return new Clutter.Point(coords); +} + +var getPanelGhost = function() { + if (!Main.overview._panelGhost) { + return Main.overview._overview.get_first_child(); + } + + return Main.overview._panelGhost; +} + +var notify = function(text, iconName, action, isTransient) { + let source = new MessageTray.SystemNotificationSource(); + let notification = new MessageTray.Notification(source, 'Dash to Panel', text); + let notifyFunc = source.showNotification || source.notify; + + if (iconName) { + source.createIcon = function() { + return new St.Icon({ icon_name: iconName }); + }; + } + + if (action) { + if (!(action instanceof Array)) { + action = [action]; + } + + action.forEach(a => notification.addAction(a.text, a.func)); + } + + Main.messageTray.add(source); + + notification.setTransient(isTransient); + notifyFunc.call(source, notification); +}; + +/* + * This is a copy of the same function in utils.js, but also adjust horizontal scrolling + * and perform few further cheks on the current value to avoid changing the values when + * it would be clamp to the current one in any case. + * Return the amount of shift applied +*/ +var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) { + let vadjustment = scrollView.vscroll.adjustment; + let hadjustment = scrollView.hscroll.adjustment; + let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values(); + let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values(); + + let [hvalue0, vvalue0] = [hvalue, vvalue]; + + let voffset = fadeSize; + let hoffset = fadeSize; + + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2; + + let parent = actor.get_parent(); + while (parent != scrollView) { + if (!parent) + throw new Error("actor not in scroll view"); + + let box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + x1 += box.x1; + x2 += box.x1; + parent = parent.get_parent(); + } + + if (y1 < vvalue + voffset) + vvalue = Math.max(0, y1 - voffset); + else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset) + vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize); + + if (x1 < hvalue + hoffset) + hvalue = Math.max(0, x1 - hoffset); + else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset) + hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize); + + let tweenOpts = { + time: SCROLL_TIME, + onComplete: onComplete || (() => {}), + transition: 'easeOutQuad' + }; + + if (vvalue !== vvalue0) { + animate(vadjustment, mergeObjects(tweenOpts, { value: vvalue })); + } + + if (hvalue !== hvalue0) { + animate(hadjustment, mergeObjects(tweenOpts, { value: hvalue })); + } + + return [hvalue- hvalue0, vvalue - vvalue0]; +} + +/** + * ColorUtils is adapted from https://github.com/micheleg/dash-to-dock + */ +var ColorUtils = { + colorLuminance: function(r, g, b, dlum) { + // Darken or brighten color by a fraction dlum + // Each rgb value is modified by the same fraction. + // Return "#rrggbb" strin + + let rgbString = '#'; + + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2); + + return rgbString; + }, + + _decimalToHex: function(d, padding) { + // Convert decimal to an hexadecimal string adding the desired padding + + let hex = d.toString(16); + while (hex.length < padding) + hex = '0'+ hex; + return hex; + }, + + HSVtoRGB: function(h, s, v) { + // Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (h,s,v) independently or {h:h, s:s, v:v} object. + // Return {r:r, g:g, b:b} object. + + if (arguments.length === 1) { + s = h.s; + v = h.v; + h = h.h; + } + + let r,g,b; + let c = v*s; + let h1 = h*6; + let x = c*(1 - Math.abs(h1 % 2 - 1)); + let m = v - c; + + if (h1 <=1) + r = c + m, g = x + m, b = m; + else if (h1 <=2) + r = x + m, g = c + m, b = m; + else if (h1 <=3) + r = m, g = c + m, b = x + m; + else if (h1 <=4) + r = m, g = x + m, b = c + m; + else if (h1 <=5) + r = x + m, g = m, b = c + m; + else + r = c + m, g = m, b = x + m; + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; + }, + + RGBtoHSV: function(r, g, b) { + // Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (r,g,b) independently or {r:r, g:g, b:b} object. + // Return {h:h, s:s, v:v} object. + + if (arguments.length === 1) { + r = r.r; + g = r.g; + b = r.b; + } + + let h,s,v; + + let M = Math.max(r, g, b); + let m = Math.min(r, g, b); + let c = M - m; + + if (c == 0) + h = 0; + else if (M == r) + h = ((g-b)/c) % 6; + else if (M == g) + h = (b-r)/c + 2; + else + h = (r-g)/c + 4; + + h = h/6; + v = M/255; + if (M !== 0) + s = c/M; + else + s = 0; + + return {h: h, s: s, v: v}; + } +}; + +/** + * DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock + */ +let themeLoader = null; +let iconCacheMap = new Map(); +const MAX_CACHED_ITEMS = 1000; +const BATCH_SIZE_TO_DELETE = 50; +const DOMINANT_COLOR_ICON_SIZE = 64; + +var DominantColorExtractor = defineClass({ + Name: 'DashToPanel.DominantColorExtractor', + + _init: function(app){ + this._app = app; + }, + + /** + * Try to get the pixel buffer for the current icon, if not fail gracefully + */ + _getIconPixBuf: function() { + let iconTexture = this._app.create_icon_texture(16); + + if (themeLoader === null) { + let ifaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" }); + + themeLoader = new Gtk.IconTheme(), + themeLoader.set_custom_theme(ifaceSettings.get_string('icon-theme')); // Make sure the correct theme is loaded + } + + // Unable to load the icon texture, use fallback + if (iconTexture instanceof St.Icon === false) { + return null; + } + + iconTexture = iconTexture.get_gicon(); + + // Unable to load the icon texture, use fallback + if (iconTexture === null) { + return null; + } + + if (iconTexture instanceof Gio.FileIcon) { + // Use GdkPixBuf to load the pixel buffer from the provided file path + return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path()); + } + + // Get the pixel buffer from the icon theme + let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0); + if (icon_info !== null) + return icon_info.load_icon(); + else + return null; + }, + + /** + * The backlight color choosing algorithm was mostly ported to javascript from the + * Unity7 C++ source of Canonicals: + * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp + * so it more or less works the same way. + */ + _getColorPalette: function() { + if (iconCacheMap.get(this._app.get_id())) { + // We already know the answer + return iconCacheMap.get(this._app.get_id()); + } + + let pixBuf = this._getIconPixBuf(); + if (pixBuf == null) + return null; + + let pixels = pixBuf.get_pixels(), + offset = 0; + + let total = 0, + rTotal = 0, + gTotal = 0, + bTotal = 0; + + let resample_y = 1, + resample_x = 1; + + // Resampling of large icons + // We resample icons larger than twice the desired size, as the resampling + // to a size s + // DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE, + // most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally + // a multiple of it. + let width = pixBuf.get_width(); + let height = pixBuf.get_height(); + + // Resample + if (height >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE); + + if (width >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE); + + if (resample_x !==1 || resample_y !== 1) + pixels = this._resamplePixels(pixels, resample_x, resample_y); + + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length; + for (let offset = 0; offset < limit; offset+=4) { + let r = pixels[offset], + g = pixels[offset + 1], + b = pixels[offset + 2], + a = pixels[offset + 3]; + + let saturation = (Math.max(r,g, b) - Math.min(r,g, b)); + let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation; + + rTotal += r * relevance; + gTotal += g * relevance; + bTotal += b * relevance; + + total += relevance; + } + + total = total * 255; + + let r = rTotal / total, + g = gTotal / total, + b = bTotal / total; + + let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255); + + if (hsv.s > 0.15) + hsv.s = 0.65; + hsv.v = 0.90; + + let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v); + + // Cache the result. + let backgroundColor = { + lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2), + original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0), + darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5) + }; + + if (iconCacheMap.size >= MAX_CACHED_ITEMS) { + //delete oldest cached values (which are in order of insertions) + let ctr=0; + for (let key of iconCacheMap.keys()) { + if (++ctr > BATCH_SIZE_TO_DELETE) + break; + iconCacheMap.delete(key); + } + } + + iconCacheMap.set(this._app.get_id(), backgroundColor); + + return backgroundColor; + }, + + /** + * Downsample large icons before scanning for the backlight color to + * improve performance. + * + * @param pixBuf + * @param pixels + * @param resampleX + * @param resampleY + * + * @return []; + */ + _resamplePixels: function (pixels, resampleX, resampleY) { + let resampledPixels = []; + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length / (resampleX * resampleY) / 4; + for (let i = 0; i < limit; i++) { + let pixel = i * resampleX * resampleY; + + resampledPixels.push(pixels[pixel * 4]); + resampledPixels.push(pixels[pixel * 4 + 1]); + resampledPixels.push(pixels[pixel * 4 + 2]); + resampledPixels.push(pixels[pixel * 4 + 3]); + } + + return resampledPixels; + } + +}); + +var drawRoundedLine = function(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { + if (height > width) { + y += Math.floor((height - width) / 2.0); + height = width; + } + + height = 2.0 * Math.floor(height / 2.0); + + var leftRadius = isRoundLeft ? height / 2.0 : 0.0; + var rightRadius = isRoundRight ? height / 2.0 : 0.0; + + cr.moveTo(x + width - rightRadius, y); + cr.lineTo(x + leftRadius, y); + if (isRoundLeft) + cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2); + else + cr.lineTo(x, y + height); + cr.lineTo(x + width - rightRadius, y + height); + if (isRoundRight) + cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2); + else + cr.lineTo(x + width, y); + cr.closePath(); + + if (fill != null) { + cr.setSource(fill); + cr.fillPreserve(); + } + if (stroke != null) + cr.setSource(stroke); + cr.stroke(); +} + +/** + * Check if an app exists in the system. + */ +var checkedCommandsMap = new Map(); + +function checkIfCommandExists(app) { + let answer = checkedCommandsMap.get(app); + if (answer === undefined) { + // Command is a shell built in, use shell to call it. + // Quotes around app value are important. They let command operate + // on the whole value, instead of having shell interpret it. + let cmd = "sh -c 'command -v \"" + app + "\"'"; + try { + let out = GLib.spawn_command_line_sync(cmd); + // out contains 1: stdout, 2: stderr, 3: exit code + answer = out[3] == 0; + } catch (ex) { + answer = false; + } + + checkedCommandsMap.set(app, answer); + } + return answer; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js new file mode 100644 index 0000000..45d08a0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js @@ -0,0 +1,1145 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Meta = imports.gi.Meta; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +//timeout intervals +const ENSURE_VISIBLE_MS = 200; + +//timeout names +const T1 = 'openMenuTimeout'; +const T2 = 'closeMenuTimeout'; +const T3 = 'peekTimeout'; +const T4 = 'ensureVisibleTimeout'; + +const MAX_TRANSLATION = 40; +const HEADER_HEIGHT = 38; +const MAX_CLOSE_BUTTON_SIZE = 30; +const MIN_DIMENSION = 100; +const FOCUSED_COLOR_OFFSET = 24; +const HEADER_COLOR_OFFSET = -12; +const FADE_SIZE = 36; +const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; + +let headerHeight = 0; +let alphaBg = 0; +let isLeftButtons = false; +let isTopHeader = true; +let isManualStyling = false; +let scaleFactor = 1; +let animationTime = 0; +let aspectRatio = {}; + +var PreviewMenu = Utils.defineClass({ + Name: 'DashToPanel-PreviewMenu', + Extends: St.Widget, + Signals: { 'open-state-changed': {} }, + + _init: function(panel) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + let geom = panel.geom; + this.panel = panel; + this.currentAppIcon = null; + this._focusedPreview = null; + this._peekedWindow = null; + this.peekInitialWorkspaceIndex = -1; + this.opened = false; + this.isVertical = geom.position == St.Side.LEFT || geom.position == St.Side.RIGHT; + this._translationProp = 'translation_' + (this.isVertical ? 'x' : 'y'); + this._translationDirection = (geom.position == St.Side.TOP || geom.position == St.Side.LEFT ? -1 : 1); + this._translationOffset = Math.min(panel.dtpSize, MAX_TRANSLATION) * this._translationDirection; + + this.menu = new St.Widget({ + name: 'preview-menu', + layout_manager: new Clutter.BinLayout(), + reactive: true, + track_hover: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign[geom.position != St.Side.RIGHT ? 'START' : 'END'], + y_align: Clutter.ActorAlign[geom.position != St.Side.BOTTOM ? 'START' : 'END'] + }); + this._box = new St.BoxLayout({ vertical: this.isVertical }); + this._scrollView = new St.ScrollView({ + name: 'dashtopanelPreviewScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true, + y_expand: !this.isVertical + }); + + this._scrollView.add_actor(this._box); + this.menu.add_child(this._scrollView); + this.add_child(this.menu); + }, + + enable: function() { + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + Main.layoutManager.addChrome(this, { affectsInputRegion: false }); + Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); + + this._resetHiddenState(); + this._refreshGlobals(); + this._updateClip(); + this.menu.set_position(1, 1); + + this._signalsHandler.add( + [ + this.menu, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._scrollView, + 'scroll-event', + this._onScrollEvent.bind(this) + ], + [ + this.panel.panelBox, + 'style-changed', + () => this._updateClip() + ], + [ + Utils.DisplayWrapper.getScreen(), + 'in-fullscreen-changed', + () => { + if (global.display.focus_window && global.display.focus_window.is_fullscreen()) { + this.close(true); + } + } + ], + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::window-preview-size', + 'changed::window-preview-padding', + 'changed::window-preview-show-title' + ], + () => { + this._refreshGlobals(); + this._updateClip(); + } + ] + ); + }, + + disable: function() { + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + + this.close(true); + + Main.layoutManager.untrackChrome(this.menu); + Main.layoutManager.removeChrome(this); + }, + + requestOpen: function(appIcon) { + let timeout = Me.settings.get_int('show-window-previews-timeout'); + + if (this.opened) { + timeout = Math.min(100, timeout); + } + + this._endOpenCloseTimeouts(); + this._timeoutsHandler.add([T1, timeout, () => this.open(appIcon)]); + }, + + requestClose: function() { + this._endOpenCloseTimeouts(); + this._addCloseTimeout(); + }, + + open: function(appIcon) { + if (this.currentAppIcon != appIcon) { + this.currentAppIcon = appIcon; + + if (!this.opened) { + this._refreshGlobals(); + + this.set_height(this.clipHeight); + this.menu.show(); + + setStyle(this.menu, 'background: ' + Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, alphaBg)); + } + + this._mergeWindows(appIcon); + this._updatePosition(); + this._animateOpenOrClose(true); + + this._setReactive(true); + this._setOpenedState(true); + } + }, + + close: function(immediate) { + this._endOpenCloseTimeouts(); + this._removeFocus(); + this._endPeek(); + + if (immediate) { + Utils.stopAnimations(this.menu); + this._resetHiddenState(); + } else { + this._animateOpenOrClose(false, () => this._resetHiddenState()); + } + + this._setReactive(false); + this.currentAppIcon = null; + }, + + update: function(appIcon, windows) { + if (this.currentAppIcon == appIcon) { + if (windows && !windows.length) { + this.close(); + } else { + this._addAndRemoveWindows(windows); + this._updatePosition(); + } + } + }, + + updatePosition: function() { + this._updatePosition(); + }, + + focusNext: function() { + let previews = this._box.get_children(); + let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1; + let nextIndex = currentIndex + 1; + + nextIndex = previews[nextIndex] ? nextIndex : 0; + + if (previews[nextIndex]) { + this._removeFocus(); + previews[nextIndex].setFocus(true); + this._focusedPreview = previews[nextIndex]; + } + + return nextIndex; + }, + + activateFocused: function() { + if (this.opened && this._focusedPreview) { + this._focusedPreview.activate(); + } + }, + + requestPeek: function(window) { + this._timeoutsHandler.remove(T3); + + if (Me.settings.get_boolean('peek-mode')) { + if (this.peekInitialWorkspaceIndex < 0) { + this._timeoutsHandler.add([T3, Me.settings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]); + } else { + this._peek(window); + } + } + }, + + endPeekHere: function() { + this._endPeek(true); + }, + + ensureVisible: function(preview) { + let [ , upper, pageSize] = this._getScrollAdjustmentValues(); + + if (upper > pageSize) { + this._timeoutsHandler.add([ + T4, + ENSURE_VISIBLE_MS, + () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION, () => this._updateScrollFade()) + ]); + } + }, + + getCurrentAppIcon: function() { + return this.currentAppIcon; + }, + + _setReactive: function(reactive) {  + this._box.get_children().forEach(c => c.reactive = reactive); + this.menu.reactive = reactive; + }, + + _setOpenedState: function(opened) { + this.opened = opened; + this.emit('open-state-changed'); + }, + + _resetHiddenState: function() { + this.menu.hide(); + this.set_height(0); + this._setOpenedState(false); + this.menu.opacity = 0; + this.menu[this._translationProp] = this._translationOffset; + this._box.get_children().forEach(c => c.destroy()); + }, + + _removeFocus: function() { + if (this._focusedPreview) { + this._focusedPreview.setFocus(false); + this._focusedPreview = null; + } + }, + + _mergeWindows: function(appIcon, windows) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + windows.sort(Taskbar.sortWindowsCompareFunction); + + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); + + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i]) { + currentPreviews[i].assignWindow(windows[i], this.opened); + } else if (!currentPreviews[i]) { + this._addNewPreview(windows[i]); + } else if (!windows[i]) { + currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); + } + } + }, + + _addAndRemoveWindows: function(windows) { + let currentPreviews = this._box.get_children(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + + for (let i = 0, l = windows.length; i < l; ++i) { + let currentIndex = Utils.findIndex(currentPreviews, c => c.window == windows[i]); + + if (currentIndex < 0) { + this._addNewPreview(windows[i]); + } else { + currentPreviews[currentIndex].assignWindow(windows[i]); + currentPreviews.splice(currentIndex, 1); + + if (this._peekedWindow && this._peekedWindow == windows[i]) { + this.requestPeek(windows[i]); + } + } + } + + currentPreviews.forEach(c => c.animateOut()); + }, + + _addNewPreview: function(window) { + let preview = new Preview(this); + + this._box.add_child(preview); + preview.adjustOnStage(); + preview.assignWindow(window, this.opened); + }, + + _addCloseTimeout: function() { + this._timeoutsHandler.add([T2, Me.settings.get_int('leave-timeout'), () => this.close()]); + }, + + _onHoverChanged: function() { + this._endOpenCloseTimeouts(); + + if (this.currentAppIcon && !this.menu.hover) { + this._addCloseTimeout(); + this._endPeek(); + } + }, + + _onScrollEvent: function(actor, event) { + if (!event.is_pointer_emulated()) { + let vOrh = this.isVertical ? 'v' : 'h'; + let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment(); + let increment = adjustment.step_increment; + let delta = increment; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + delta = -increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy * increment; + delta += dx * increment; + break; + } + + adjustment.set_value(adjustment.get_value() + delta); + this._updateScrollFade(); + } + + return Clutter.EVENT_STOP; + }, + + _endOpenCloseTimeouts: function() { + this._timeoutsHandler.remove(T1); + this._timeoutsHandler.remove(T2); + this._timeoutsHandler.remove(T4); + }, + + _refreshGlobals: function() { + isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + isTopHeader = Me.settings.get_string('window-preview-title-position') == 'TOP'; + isManualStyling = Me.settings.get_boolean('window-preview-manual-styling'); + scaleFactor = Utils.getScaleFactor(); + headerHeight = Me.settings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; + animationTime = Me.settings.get_int('window-preview-animation-time') * .001; + aspectRatio.x = { + size: Me.settings.get_int('window-preview-aspect-ratio-x'), + fixed: Me.settings.get_boolean('window-preview-fixed-x') + }; + aspectRatio.y = { + size: Me.settings.get_int('window-preview-aspect-ratio-y'), + fixed: Me.settings.get_boolean('window-preview-fixed-y') + }; + + alphaBg = Me.settings.get_boolean('preview-use-custom-opacity') ? + Me.settings.get_int('preview-custom-opacity') * .01 : + this.panel.dynamicTransparency.alpha; + }, + + _updateClip: function() { + let x, y, w; + let geom = this.panel.getGeometry(); + let panelBoxTheme = this.panel.panelBox.get_theme_node(); + let previewSize = (Me.settings.get_int('window-preview-size') + + Me.settings.get_int('window-preview-padding') * 2) * scaleFactor; + + if (this.isVertical) { + w = previewSize; + this.clipHeight = this.panel.monitor.height; + y = this.panel.monitor.y; + } else { + w = this.panel.monitor.width; + this.clipHeight = (previewSize + headerHeight); + x = this.panel.monitor.x; + } + + if (geom.position == St.Side.LEFT) { + x = this.panel.monitor.x + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.LEFT); + } else if (geom.position == St.Side.RIGHT) { + x = this.panel.monitor.x + this.panel.monitor.width - (this.panel.dtpSize + previewSize) - panelBoxTheme.get_padding(St.Side.RIGHT); + } else if (geom.position == St.Side.TOP) { + y = this.panel.monitor.y + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.TOP); + } else { //St.Side.BOTTOM + y = this.panel.monitor.y + this.panel.monitor.height - (this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.BOTTOM) + previewSize + headerHeight); + } + + Utils.setClip(this, x, y, w, this.clipHeight); + }, + + _updatePosition: function() { + let sourceNode = this.currentAppIcon.actor.get_theme_node(); + let sourceContentBox = sourceNode.get_content_box(this.currentAppIcon.actor.get_allocation_box()); + let sourceAllocation = Utils.getTransformedAllocation(this.currentAppIcon.actor); + let [previewsWidth, previewsHeight] = this._getPreviewsSize(); + let appIconMargin = Me.settings.get_int('appicon-margin') / scaleFactor; + let x = 0, y = 0; + + previewsWidth = Math.min(previewsWidth, this.panel.monitor.width); + previewsHeight = Math.min(previewsHeight, this.panel.monitor.height); + this._updateScrollFade(previewsWidth < this.panel.monitor.width && previewsHeight < this.panel.monitor.height); + + if (this.isVertical) { + y = sourceAllocation.y1 + appIconMargin - this.panel.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; + y = Math.max(y, 0); + y = Math.min(y, this.panel.monitor.height - previewsHeight); + } else { + x = sourceAllocation.x1 + appIconMargin - this.panel.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; + x = Math.max(x, 0); + x = Math.min(x, this.panel.monitor.width - previewsWidth); + } + + if (!this.opened) { + this.menu.set_position(x, y); + this.menu.set_size(previewsWidth, previewsHeight); + } else { + Utils.animate(this.menu, getTweenOpts({ x: x, y: y, width: previewsWidth, height: previewsHeight })); + } + }, + + _updateScrollFade: function(remove) { + let [value, upper, pageSize] = this._getScrollAdjustmentValues(); + let needsFade = Math.round(upper) > Math.round(pageSize); + let fadeWidgets = this.menu.get_children().filter(c => c != this._scrollView); + + if (!remove && needsFade) { + if (!fadeWidgets.length) { + fadeWidgets.push(this._getFadeWidget()); + fadeWidgets.push(this._getFadeWidget(true)); + + this.menu.add_child(fadeWidgets[0]); + this.menu.add_child(fadeWidgets[1]); + } + + fadeWidgets[0].visible = value > 0; + fadeWidgets[1].visible = value + pageSize < upper; + } else if (remove || (!needsFade && fadeWidgets.length)) { + fadeWidgets.forEach(fw => fw.destroy()); + } + }, + + _getScrollAdjustmentValues: function() { + let [value , , upper, , , pageSize] = this._scrollView[(this.isVertical ? 'v' : 'h') + 'scroll'].adjustment.get_values(); + + return [value, upper, pageSize]; + }, + + _getFadeWidget: function(end) { + let x = 0, y = 0; + let startBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, Math.min(alphaBg + .1, 1)); + let endBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, 0) + let fadeStyle = 'background-gradient-start:' + startBg + + 'background-gradient-end:' + endBg + + 'background-gradient-direction:' + this.panel.getOrientation(); + + if (this.isVertical) { + y = end ? this.panel.monitor.height - FADE_SIZE : 0; + } else { + x = end ? this.panel.monitor.width - FADE_SIZE : 0; + } + + let fadeWidget = new St.Widget({ + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: end ? 180 : 0, + style: fadeStyle, + x: x, y: y, + width: this.isVertical ? this.width : FADE_SIZE, + height: this.isVertical ? FADE_SIZE : this.height + }); + + return fadeWidget; + }, + + _getPreviewsSize: function() { + let previewsWidth = 0; + let previewsHeight = 0; + + this._box.get_children().forEach(c => { + if (!c.animatingOut) { + let [width, height] = c.getSize(); + + if (this.isVertical) { + previewsWidth = Math.max(width, previewsWidth); + previewsHeight += height; + } else { + previewsWidth += width; + previewsHeight = Math.max(height, previewsHeight); + } + } + }); + + return [previewsWidth, previewsHeight]; + }, + + _animateOpenOrClose: function(show, onComplete) { + let isTranslationAnimation = this.menu[this._translationProp] != 0; + let tweenOpts = { + opacity: show ? 255 : 0, + transition: show ? 'easeInOutQuad' : 'easeInCubic', + onComplete: () => { + if (isTranslationAnimation) { + Main.layoutManager._queueUpdateRegions(); + } + + (onComplete || (() => {}))(); + } + }; + + tweenOpts[this._translationProp] = show ? this._translationDirection : this._translationOffset; + + Utils.animate(this.menu, getTweenOpts(tweenOpts)); + }, + + _peek: function(window) { + let currentWorkspace = Utils.getCurrentWorkspace(); + let windowWorkspace = window.get_workspace(); + let focusWindow = () => this._focusMetaWindow(Me.settings.get_int('peek-mode-opacity'), window); + + this._restorePeekedWindowStack(); + this._peekedWindow = window; + + if (currentWorkspace != windowWorkspace) { + this._switchToWorkspaceImmediate(windowWorkspace.index()); + this._timeoutsHandler.add([T3, 100, focusWindow]); + } else { + focusWindow(); + } + + if (this.peekInitialWorkspaceIndex < 0) { + this.peekInitialWorkspaceIndex = currentWorkspace.index(); + } + }, + + _endPeek: function(stayHere) { + this._timeoutsHandler.remove(T3); + + if (this._peekedWindow) { + let immediate = !stayHere && this.peekInitialWorkspaceIndex != Utils.getCurrentWorkspace().index(); + + this._restorePeekedWindowStack(); + this._focusMetaWindow(255, this._peekedWindow, immediate, true); + this._peekedWindow = null; + + if (!stayHere) { + this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); + } + + this.peekInitialWorkspaceIndex = -1; + } + }, + + _switchToWorkspaceImmediate: function(workspaceIndex) { + let workspace = Utils.getWorkspaceByIndex(workspaceIndex); + let shouldAnimate = Main.wm._shouldAnimate; + + if (!workspace || (!workspace.list_windows().length && + workspaceIndex < Utils.getWorkspaceCount() - 1)) { + workspace = Utils.getCurrentWorkspace(); + } + + Main.wm._shouldAnimate = () => false; + workspace.activate(global.display.get_current_time_roundtrip()); + Main.wm._shouldAnimate = shouldAnimate; + }, + + _focusMetaWindow: function(dimOpacity, window, immediate, ignoreFocus) { + window.get_workspace().list_windows().forEach(mw => { + let wa = mw.get_compositor_private(); + let isFocused = !ignoreFocus && mw == window; + + if (wa) { + if (isFocused) { + mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa); + wa.get_parent().set_child_above_sibling(wa, null); + } + + if (isFocused && mw.minimized) { + wa.show(); + } + + if (!mw.minimized) { + let tweenOpts = getTweenOpts({ opacity: isFocused ? 255 : dimOpacity }); + + if (immediate && !mw.is_on_all_workspaces()) { + tweenOpts.time = 0; + } + + Utils.animateWindowOpacity(wa, tweenOpts); + } + } + }); + }, + + _restorePeekedWindowStack: function() { + let windowActor = this._peekedWindow ? this._peekedWindow.get_compositor_private() : null; + + if (windowActor) { + if (this._peekedWindow.hasOwnProperty(PEEK_INDEX_PROP)) { + windowActor.get_parent().set_child_at_index(windowActor, this._peekedWindow[PEEK_INDEX_PROP]); + delete this._peekedWindow[PEEK_INDEX_PROP]; + } + + if (this._peekedWindow.minimized) { + windowActor.hide(); + } + } + }, +}); + +var Preview = Utils.defineClass({ + Name: 'DashToPanel-Preview', + Extends: St.Widget, + + _init: function(previewMenu) { + this.callParent('_init', { + style_class: 'preview-container', + reactive: true, + track_hover: true, + layout_manager: new Clutter.BinLayout() + }); + + this.window = null; + this._waitWindowId = 0; + this._needsCloseButton = true; + this.cloneWidth = this.cloneHeight = 0; + this._previewMenu = previewMenu; + this._padding = Me.settings.get_int('window-preview-padding') * scaleFactor; + this._previewDimensions = this._getPreviewDimensions(); + this.animatingOut = false; + + let box = new St.Widget({ layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL }), y_expand: true }); + let [previewBinWidth, previewBinHeight] = this._getBinSize(); + let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); + + if (Config.PACKAGE_VERSION >= '3.31.9') { + closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); + } + + this._closeButtonBin = new St.Widget({ + style_class: 'preview-close-btn-container', + layout_manager: new Clutter.BinLayout(), + opacity: 0, + x_expand: true, y_expand: true, + x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + this._closeButtonBin.add_child(closeButton); + + this._previewBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + style: 'padding: ' + this._padding / scaleFactor + 'px;' + }); + + this._previewBin.set_size(previewBinWidth, previewBinHeight); + + box.add_child(this._previewBin); + + if (headerHeight) { + let headerBox = new St.Widget({ + style_class: 'preview-header-box', + layout_manager: new Clutter.BoxLayout(), + x_expand: true, + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + setStyle(headerBox, this._getBackgroundColor(HEADER_COLOR_OFFSET, 1)); + this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); + this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); + + this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._iconBin.set_size(headerHeight, headerHeight); + + headerBox.add_child(this._iconBin); + headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1); + headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); + + box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1); + } + + this.add_child(box); + this.add_child(this._closeButtonBin); + + closeButton.connect('clicked', () => this._onCloseBtnClick()); + this.connect('notify::hover', () => this._onHoverChanged()); + this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); + this.connect('destroy', () => this._onDestroy()); + }, + + adjustOnStage: function() { + let closeButton = this._closeButtonBin.get_first_child(); + let closeButtonHeight = closeButton.height; + let maxCloseButtonSize = MAX_CLOSE_BUTTON_SIZE * scaleFactor; + let closeButtonBorderRadius = ''; + + if (closeButtonHeight > maxCloseButtonSize) { + closeButtonHeight = maxCloseButtonSize; + closeButton.set_size(closeButtonHeight, closeButtonHeight); + } + + if (!headerHeight) { + closeButtonBorderRadius = 'border-radius: '; + + if (isTopHeader) { + closeButtonBorderRadius += (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + } else { + closeButtonBorderRadius += (isLeftButtons ? '0 4px 0 0;' : '4px 0 0 0;'); + } + } + + setStyle( + this._closeButtonBin, + 'padding: ' + (headerHeight ? Math.round((headerHeight - closeButtonHeight) * .5 / scaleFactor) : 4) + 'px;' + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + + closeButtonBorderRadius + ); + }, + + assignWindow: function(window, animateSize) { + if (this.window != window) { + let _assignWindowClone = () => { + if (window.get_compositor_private()) { + let cloneBin = this._getWindowCloneBin(window); + + this._resizeClone(cloneBin, window); + this._addClone(cloneBin, animateSize); + this._previewMenu.updatePosition(); + } else if (!this._waitWindowId) { + this._waitWindowId = Mainloop.idle_add(() => { + this._waitWindowId = 0; + + if (this._previewMenu.opened) { + _assignWindowClone(); + } + }); + } + }; + + _assignWindowClone(); + } + + this._cancelAnimateOut(); + this._removeWindowSignals(); + this.window = window; + this._needsCloseButton = window.can_close() && !Utils.checkIfWindowHasTransient(window); + this._updateHeader(); + }, + + animateOut: function() { + if (!this.animatingOut) { + let tweenOpts = getTweenOpts({ opacity: 0, width: 0, height: 0, onComplete: () => this.destroy() }); + + this.animatingOut = true; + + Utils.stopAnimations(this); + Utils.animate(this, tweenOpts); + } + }, + + getSize: function() { + let [binWidth, binHeight] = this._getBinSize(); + + binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2); + binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight; + + return [binWidth, binHeight]; + }, + + setFocus: function(focused) { + this._hideOrShowCloseButton(!focused); + setStyle(this, this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); + + if (focused) { + this._previewMenu.ensureVisible(this); + this._previewMenu.requestPeek(this.window); + } + }, + + activate: function() { + this._previewMenu.endPeekHere(); + this._previewMenu.close(); + Main.activateWindow(this.window); + }, + + _onDestroy: function() { + if (this._waitWindowId) { + GLib.source_remove(this._waitWindowId); + this._waitWindowId = 0; + } + + this._removeWindowSignals(); + }, + + _onHoverChanged: function() { + this.setFocus(this.hover); + }, + + _onCloseBtnClick: function() { + this._hideOrShowCloseButton(true); + this.reactive = false; + + if (!Me.settings.get_boolean('group-apps')) { + this._previewMenu.close(); + } else { + this._previewMenu.endPeekHere(); + } + + this.window.delete(global.get_current_time()); + }, + + _onButtonReleaseEvent: function(e) { + switch (e.get_button()) { + case 1: // Left click + this.activate(); + break; + case 2: // Middle click + if (Me.settings.get_boolean('preview-middle-click-close')) { + this._onCloseBtnClick(); + } + break; + case 3: // Right click + this._showContextMenu(e); + break; + } + + return Clutter.EVENT_STOP; + }, + + _cancelAnimateOut: function() { + if (this.animatingOut) { + this.animatingOut = false; + + Utils.stopAnimations(this); + Utils.animate(this, getTweenOpts({ opacity: 255, width: this.cloneWidth, height: this.cloneHeight })); + } + }, + + _showContextMenu: function(e) { + let coords = e.get_coords(); + let currentWorkspace = this._previewMenu.peekInitialWorkspaceIndex < 0 ? + Utils.getCurrentWorkspace() : + Utils.getWorkspaceByIndex(this._previewMenu.peekInitialWorkspaceIndex); + + Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, { + x: coords[0], + y: coords[1], + width: 0, + height: 0 + }); + + let ctxMenuData = Main.wm._windowMenuManager._manager._menus[0]; + + ctxMenuData.menu.connect('open-state-changed', () => this._previewMenu.menu.sync_hover()); + + if (this.window.get_workspace() != currentWorkspace) { + let menuItem = new PopupMenu.PopupMenuItem(_('Move to current Workspace') + ' [' + (currentWorkspace.index() + 1) + ']'); + let menuItems = ctxMenuData.menu.box.get_children(); + let insertIndex = Utils.findIndex(menuItems, c => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem); + + insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1; + ctxMenuData.menu.addMenuItem(menuItem, insertIndex); + menuItem.connect('activate', () => this.window.change_workspace(currentWorkspace)); + } + }, + + _removeWindowSignals: function() { + if (this._titleWindowChangeId) { + this.window.disconnect(this._titleWindowChangeId); + this._titleWindowChangeId = 0; + } + }, + + _updateHeader: function() { + if (headerHeight) { + let iconTextureSize = Me.settings.get_boolean('window-preview-use-custom-icon-size') ? + Me.settings.get_int('window-preview-custom-icon-size') : + headerHeight / scaleFactor * .6; + let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize); + let workspaceIndex = ''; + let workspaceStyle = null; + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let commonTitleStyles = 'color: ' + Me.settings.get_string('window-preview-title-font-color') + ';' + + 'font-size: ' + Me.settings.get_int('window-preview-title-font-size') * fontScale + 'px;' + + 'font-weight: ' + Me.settings.get_string('window-preview-title-font-weight') + ';'; + + this._iconBin.destroy_all_children(); + this._iconBin.add_child(icon); + + if (!Me.settings.get_boolean('isolate-workspaces')) { + workspaceIndex = (this.window.get_workspace().index() + 1).toString(); + workspaceStyle = 'margin: 0 4px 0 ' + (isLeftButtons ? Math.round((headerHeight - icon.width) * .5) + 'px' : '0') + '; padding: 0 4px;' + + 'border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px;' + commonTitleStyles; + } + + this._workspaceIndicator.text = workspaceIndex; + setStyle(this._workspaceIndicator, workspaceStyle); + + this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle()); + setStyle(this._windowTitle, 'max-width: 0px; padding-right: 4px;' + commonTitleStyles); + this._updateWindowTitle(); + } + }, + + _updateWindowTitle: function() { + this._windowTitle.text = this.window.title; + }, + + _hideOrShowCloseButton: function(hide) { + if (this._needsCloseButton) { + Utils.animate(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + } + }, + + _getBackgroundColor: function(offset, alpha) { + return 'background-color: ' + this._getRgbaColor(offset, alpha) + + 'transition-duration:' + this._previewMenu.panel.dynamicTransparency.animationDuration; + }, + + _getRgbaColor: function(offset, alpha) { + alpha = Math.abs(alpha); + + if (isNaN(alpha)) { + alpha = alphaBg; + } + + return Utils.getrgbaColor(this._previewMenu.panel.dynamicTransparency.backgroundColorRgb, alpha, offset); + }, + + _addClone: function(newCloneBin, animateSize) { + let currentClones = this._previewBin.get_children(); + let newCloneOpts = getTweenOpts({ opacity: 255 }); + + this._previewBin.add_child(newCloneBin); + + if (currentClones.length) { + let currentCloneBin = currentClones.pop(); + let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentCloneBin.destroy() }); + + if (newCloneBin.width > currentCloneBin.width) { + newCloneOpts.width = newCloneBin.width; + newCloneBin.width = currentCloneBin.width; + } else { + currentCloneOpts.width = newCloneBin.width; + } + + if (newCloneBin.height > currentCloneBin.height) { + newCloneOpts.height = newCloneBin.height; + newCloneBin.height = currentCloneBin.height; + } else { + currentCloneOpts.height = newCloneBin.height; + } + + currentClones.forEach(c => c.destroy()); + Utils.animate(currentCloneBin, currentCloneOpts); + } else if (animateSize) { + newCloneBin.width = 0; + newCloneBin.height = 0; + newCloneOpts.width = this.cloneWidth; + newCloneOpts.height = this.cloneHeight; + } + + Utils.animate(newCloneBin, newCloneOpts); + }, + + _getWindowCloneBin: function(window) { + let frameRect = window.get_frame_rect(); + let bufferRect = window.get_buffer_rect(); + let clone = new Clutter.Clone({ source: window.get_compositor_private() }); + let cloneBin = new St.Widget({ + opacity: 0, + layout_manager: frameRect.width != bufferRect.width || + frameRect.height != bufferRect.height ? + new WindowCloneLayout(frameRect, bufferRect) : + new Clutter.BinLayout() + }); + + cloneBin.add_child(clone); + + return cloneBin; + }, + + _getBinSize: function() { + let [fixedWidth, fixedHeight] = this._previewDimensions; + + return [ + aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1, + aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1 + ]; + }, + + _resizeClone: function(cloneBin, window) { + let frameRect = cloneBin.layout_manager.frameRect || window.get_frame_rect(); + let [fixedWidth, fixedHeight] = this._previewDimensions; + let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1); + let cloneWidth = frameRect.width * ratio; + let cloneHeight = frameRect.height * ratio; + + let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; + let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0; + let clonePaddingTop = clonePaddingTB * .5; + let clonePaddingLeft = clonePaddingLR * .5; + + this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor; + this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor; + + cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;'); + cloneBin.layout_manager.ratio = ratio; + cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor]; + + cloneBin.get_first_child().set_size(cloneWidth, cloneHeight); + }, + + _getPreviewDimensions: function() { + let size = Me.settings.get_int('window-preview-size') * scaleFactor; + let w, h; + + if (this._previewMenu.isVertical) { + w = size; + h = w * aspectRatio.y.size / aspectRatio.x.size; + } else { + h = size; + w = h * aspectRatio.x.size / aspectRatio.y.size; + } + + return [w, h]; + } +}); + +var WindowCloneLayout = Utils.defineClass({ + Name: 'DashToPanel-WindowCloneLayout', + Extends: Clutter.BinLayout, + + _init: function(frameRect, bufferRect) { + this.callParent('_init'); + + //the buffer_rect contains the transparent padding that must be removed + this.frameRect = frameRect; + this.bufferRect = bufferRect; + }, + + vfunc_allocate: function(actor, box, flags) { + let [width, height] = box.get_size(); + + box.set_origin( + (this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0], + (this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1] + ); + + box.set_size( + width + (this.bufferRect.width - this.frameRect.width) * this.ratio, + height + (this.bufferRect.height - this.frameRect.height) * this.ratio + ); + + Utils.allocate(actor.get_first_child(), box, flags); + } +}); + +function setStyle(actor, style) { + if (!isManualStyling) { + actor.set_style(style); + } +} + +function getTweenOpts(opts) { + let defaults = { + time: animationTime, + transition: 'easeInOutQuad' + }; + + return Utils.mergeObjects(opts || {}, defaults); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE @@ -0,0 +1,674 @@ + 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 +. diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js new file mode 100644 index 0000000..904c7de --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js @@ -0,0 +1,52 @@ +/* exported init */ + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils + +class Extension { + constructor() { + this.available_mods = Self.imports.src.modsList.get() + } + + _refresh_mod(name) { + if (!this.available_mods[name]) return + + if (this.settings.get_boolean(name)) { // enable + if (this.mods[name]) return + + const mod = new this.available_mods[name]() + mod.enable() + this.mods[name] = mod + } else if (this.mods[name]) { //disable + this.mods[name].disable() + delete this.mods[name] + } + } + + enable() { + this.mods = {} + + this.settings = extensionUtils.getSettings() + + Object.keys(this.available_mods).forEach(name => { + this.settings.connect('changed::' + name, () => { + this._refresh_mod(name) + }); + this._refresh_mod(name) + }) + } + + disable() { + for (const key in this.mods) { + if (!this.mods.hasOwnProperty(key)) continue; + this.mods[key].disable() + } + + delete this.mods + delete this.settings + } +} + +function init() { + return new Extension(); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..a042c9c Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..5791425 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..985e2ef Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0c2d259 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..9f6dc63 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..f657030 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0bcf35d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..74449f3 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json new file mode 100644 index 0000000..326c5f5 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json @@ -0,0 +1,14 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Tunes gnome 40-43 Overview UI to make it more usable.\n\nChanges:\n- Search textbox is hidden by default and shown only when user begins to type-to-search\n- Scale of workspaces' thumbnails increased 2x\n- Restores wallpaper on workspaces' thumbnails. No more gray background\n- Show workspaces' thumbnails even when there is only one workspace\n- Firefox's PIP (picture in picture) window is now displayed on the overview screen\n\nAll modifications can be disabled in the extension's settings.\n\nATTENTION!\nAfter extension update, gnome-shell restart is required:\nX11: Alt+F2 => r\nWayland: logout => login", + "name": "Gnome 4x UI Improvements", + "settings-schema": "org.gnome.shell.extensions.gnome-ui-tune", + "shell-version": [ + "40", + "41", + "42" + ], + "url": "https://github.com/axxapy/gnome-ui-tune", + "uuid": "gnome-ui-tune@itstime.tech", + "version": 13 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js new file mode 100644 index 0000000..f7b8669 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js @@ -0,0 +1,55 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Gtk = imports.gi.Gtk; + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils +const _ = imports.gettext.domain(Self.metadata.uuid).gettext + + +function init() { +} + +function buildPrefsWidget() { + extensionUtils.initTranslations(Self.metadata.uuid); + + const settings = extensionUtils.getSettings() + + let prefsWidget = new Gtk.Grid({ + margin_top: 18, + margin_bottom: 18, + margin_start: 18, + margin_end: 18, + column_spacing: 12, + row_spacing: 22, + visible: true + }); + + let title = new Gtk.Label({ + label: `${_('settings-mods-list')}`, + halign: Gtk.Align.START, + use_markup: true, + visible: true + }); + prefsWidget.attach(title, 0, 0, 2, 1); + + const mods = Self.imports.src.modsList.getNames() + + for (let modNum = 0; modNum < mods.length; modNum++) { + const key = mods[modNum] + + const row = modNum + 1 + + const label = new Gtk.Label({label: _(key), halign: Gtk.Align.START}) + const toggle = new Gtk.Switch({halign: Gtk.Align.END, active: settings.get_boolean(key)}) + + prefsWidget.attach(label, 0, row, 1, 1); + prefsWidget.attach(toggle, 1, row, 1, 1); + + settings.bind(key, toggle, 'active', Gio.SettingsBindFlags.DEFAULT) + } + + + return prefsWidget +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled new file mode 100644 index 0000000..86313cb Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml new file mode 100644 index 0000000..659d656 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml @@ -0,0 +1,30 @@ + + + + + true + Hide search input + Hide search input on overview screen. Search input will be shown when user starts to type-to-search. + + + true + Increase thumbnails size + Increases thumbnails size twice to make them actually usable. + + + true + Restore thumbnails background + Use desktop wallpaper for thumbnails background instead of solid grey color. + + + true + Always show thumbnails + Show workspaces' thumbnails even when there is only single workspace. + + + true + Show firefox's Picture-In-Picture window in desktop overview + By default, firefox's PiP window (for instance, extracted media player) is not displayed in overview. Fix it. + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js new file mode 100644 index 0000000..7dc6b77 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js @@ -0,0 +1,8 @@ + +var Base = /*abstract*/ class { + constructor() { + //this.enable() + } + enable() {} + disable() {} +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js new file mode 100644 index 0000000..26c30c0 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js @@ -0,0 +1,21 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const ThumbnailsBox = imports.ui.workspaceThumbnail.ThumbnailsBox + +var Mod = class extends mod.Base { + enable() { + this.bkp = ThumbnailsBox.prototype._updateShouldShow + ThumbnailsBox.prototype._updateShouldShow = function() { + if (!this._shouldShow) { + this._shouldShow = true; + this.notify('should-show'); + } + } + } + + disable() { + if (this.bkp) { + ThumbnailsBox.prototype._updateShouldShow = this.bkp + } + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js new file mode 100644 index 0000000..f79bd5c --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js @@ -0,0 +1,22 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Workspace = imports.ui.workspace.Workspace + +var Mod = class extends mod.Base { + enable() { + this.bkp_isOverviewWindow = Workspace.prototype._isOverviewWindow + const _isOverviewWindow = this.bkp_isOverviewWindow + Workspace.prototype._isOverviewWindow = function(win) { + if (win.title && win.title === 'Picture-in-Picture') { + if (win.get_wm_class && win.get_wm_class().includes("firefox")) return true; + } + return _isOverviewWindow.call(this, win); + } + } + + disable() { + if (this.bkp_isOverviewWindow) { + Workspace.prototype._isOverviewWindow = this.bkp_isOverviewWindow + } + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js new file mode 100644 index 0000000..1b56a12 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js @@ -0,0 +1,30 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main + +var Mod = class extends mod.Base { + enable() { + this.c = { + searchEntry: Main.overview.searchEntry, + searchController: Main.overview._overview.controls._searchController, + } + + this.c.searchEntry.hide() + + this.connectedId = this.c.searchController.connect('notify::search-active', () => { + if (this.c.searchController.searchActive) { + this.c.searchEntry.show(); + } else { + this.c.searchEntry.hide(); + } + }) + } + + disable() { + if (this.connectedId) { + this.c.searchController.disconnect(this.connectedId) + } + + this.c.searchEntry.show() + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js new file mode 100644 index 0000000..693ba74 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js @@ -0,0 +1,73 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main +const workspaceThumbnail = imports.ui.workspaceThumbnail +const BackgroundManager = imports.ui.background.BackgroundManager + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_thumb_init = workspaceThumbnail.WorkspaceThumbnail.prototype._init; + const _init = this.bkp_thumb_init + workspaceThumbnail.WorkspaceThumbnail.prototype._init = function(metaWorkspace, monitorIndex) { + _init.call(this, metaWorkspace, monitorIndex) + this._bgManager = new BackgroundManager({ + monitorIndex: monitorIndex, + container: this._contents, + vignette: false + }); + } + + this.bkp_thumb_onDestroy = workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy; + const _onDestroy = this.bkp_thumb_onDestroy + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = function() { + _onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + + // Thumbnails on second monitor + if (!imports.ui.workspacesView.ThumbnailsBox) return; // gnome 42 does not require this hack + this.bkp_layoutManager_thumbnailsBox_updateStates = imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates + const layoutManager_thumbnailsBox_updateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = function() { + layoutManager_thumbnailsBox_updateStates.call(this) + + this._thumbnails.forEach(thumbnail => { + if (thumbnail._bgManager && thumbnail._bgManager.HACKED) { + return + } + thumbnail._bgManager = new BackgroundManager({ + monitorIndex: this._monitorIndex, + container: thumbnail._contents, + vignette: false + }); + thumbnail._bgManager.HACKED = true + const onDestroy = this._thumbnails[0]._onDestroy + thumbnail._onDestroy = function() { + onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + }) + } + } + + disable() { + if (this.bkp_thumb_init) { + workspaceThumbnail.WorkspaceThumbnail.prototype._init = this.bkp_thumb_init + } + + if (this.bkp_thumb_onDestroy) { + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = this.bkp_thumb_onDestroy + } + + if (this.bkp_layoutManager_thumbnailsBox_updateStates) { + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + } + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js new file mode 100644 index 0000000..04dea1b --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js @@ -0,0 +1,40 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const workspaceThumbnail = imports.ui.workspaceThumbnail +let SecondaryMonitorDisplay = imports.ui.workspacesView.SecondaryMonitorDisplay + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_MAX_THUMBNAIL_SCALE = workspaceThumbnail.MAX_THUMBNAIL_SCALE + workspaceThumbnail.MAX_THUMBNAIL_SCALE = 0.1 + + // Thumbnails on second monitor + + // for gnome 42: SecondaryMonitorDisplay may get initialized after extension code is loaded => import above will not work + SecondaryMonitorDisplay = SecondaryMonitorDisplay ?? imports.ui.workspacesView.SecondaryMonitorDisplay + + this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight = SecondaryMonitorDisplay.prototype._getThumbnailsHeight + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = function(box) { + if (!this._thumbnails.visible) + return 0; + + const [width, height] = box.get_size(); + const { expandFraction } = this._thumbnails; + const [thumbnailsHeight] = this._thumbnails.get_preferred_height(width); + return Math.min( + thumbnailsHeight * expandFraction, + height * workspaceThumbnail.MAX_THUMBNAIL_SCALE); + } + } + + disable() { + if (this.bkp_MAX_THUMBNAIL_SCALE) { + workspaceThumbnail.MAX_THUMBNAIL_SCALE = this.bkp_MAX_THUMBNAIL_SCALE + } + + if (this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight) { + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight + } + } +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js new file mode 100644 index 0000000..f5d7203 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js @@ -0,0 +1,23 @@ + +// This func can not be used from prefs.js due to mods being actually loaded when they're imported +function get() { + const src = imports.misc.extensionUtils.getCurrentExtension().imports.src + return { + 'hide-search': src.modHideSearchInput.Mod, + 'increase-thumbnails-size': src.modScaleThumbnails.Mod, + 'restore-thumbnails-background': src.modRestoreThumbnailsBackground.Mod, + 'always-show-thumbnails': src.modAlwaysShowThumbnails.Mod, + 'overview-firefox-pip': src.modFirefoxPipInOverview.Mod, + } +} + +// This func is safe to use from prefs.js as it has no external dependencies +function getNames() { + return [ + 'hide-search', + 'increase-thumbnails-size', + 'restore-thumbnails-background', + 'always-show-thumbnails', + 'overview-firefox-pip', + ]; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README new file mode 100644 index 0000000..1f14023 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README @@ -0,0 +1,6 @@ +Dependencies: +libclutter, libgtop and NetworkManager gir bindings, and gnome-system-monitor + on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gnome-system-monitor + on Fedora: libgtop2-devel NetworkManager-libnm-devel, gnome-system-monitor + on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor + on Arch Linux: libgtop, networkmanager, gnome-system-monitor diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js new file mode 100644 index 0000000..2e1be07 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js @@ -0,0 +1,51 @@ +const Config = imports.misc.config; +const Clutter = imports.gi.Clutter; + +/** Compare two dotted version strings (like '10.2.3'). + * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2 + */ +function versionCompare(v1, v2) { + let v1parts = ('' + v1).split('.') + let v2parts = ('' + v2).split('.') + let minLength = Math.min(v1parts.length, v2parts.length) + let i, p1, p2; + // Compare tuple pair-by-pair. + for (i = 0; i < minLength; i++) { + // Convert to integer if possible, because "8" > "10". + p1 = parseInt(v1parts[i], 10); + p2 = parseInt(v2parts[i], 10); + if (isNaN(p1)) { + p1 = v1parts[i]; + } + if (isNaN(p2)) { + p2 = v2parts[i]; + } + if (p1 === p2) { + continue; + } else if (p1 > p2) { + return 1; + } else if (p1 < p2) { + return -1; + } + // one operand is NaN + return NaN; + } + // The longer tuple is always considered 'greater' + if (v1parts.length === v2parts.length) { + return 0; + } + return (v1parts.length < v2parts.length) ? -1 : 1; +} + +function color_from_string(color) { + let clutterColor, res; + + if (!Clutter.Color.from_string) { + clutterColor = new Clutter.Color(); + clutterColor.from_string(color); + } else { + [res, clutterColor] = Clutter.Color.from_string(color); + } + + return clutterColor; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js new file mode 100644 index 0000000..79b85c1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js @@ -0,0 +1,94 @@ +/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (c) 2011-2012, Giovanni Campagna + + 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 the GNOME 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 HOLDER 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. +*/ + +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) { + Gettext.bindtextdomain(domain, localeDir.get_path()); + } else { + Gettext.bindtextdomain(domain, Config.LOCALEDIR); + } +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) { + throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); + } + + return new Gio.Settings({settings_schema: schemaObj}); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js new file mode 100644 index 0000000..1c56f0d --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js @@ -0,0 +1,2592 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// system-monitor: Gnome shell extension displaying system informations in gnome shell status bar, such as memory usage, cpu usage, network rates… +// Copyright (C) 2011 Florian Mounier aka paradoxxxzero + +// 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 . + +// Author: Florian Mounier aka paradoxxxzero + +/* Ugly. This is here so that we don't crash old libnm-glib based shells unnecessarily + * by loading the new libnm.so. Should go away eventually */ + +var libnm_glib = imports.gi.GIRepository.Repository.get_default().is_registered('NMClient', '1.0'); + +var smDepsGtop = true; +var smDepsNM = true; + +var Config = imports.misc.config; +var Clutter = imports.gi.Clutter; +var GLib = imports.gi.GLib; +var GObject = imports.gi.GObject; +var Lang = imports.lang; + +var Gio = imports.gi.Gio; +var Shell = imports.gi.Shell; +var St = imports.gi.St; +const UPower = imports.gi.UPowerGlib; + +// const System = imports.system; +var ModalDialog = imports.ui.modalDialog; + +var ByteArray = imports.byteArray; + +var ExtensionSystem = imports.ui.extensionSystem; +var ExtensionUtils = imports.misc.extensionUtils; + +var Me = ExtensionUtils.getCurrentExtension(); +var Convenience = Me.imports.convenience; +var Compat = Me.imports.compat; + +var Background, GTop, IconSize, Locale, MountsMonitor, NM, NetworkManager, Schema, StatusArea, Style, gc_timeout, menu_timeout; + +try { + GTop = imports.gi.GTop; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsGtop = false; +} + +try { + NM = libnm_glib ? imports.gi.NMClient : imports.gi.NM; + NetworkManager = libnm_glib ? imports.gi.NetworkManager : NM; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsNM = false; +} + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const Gettext = imports.gettext.domain('system-monitor'); +const Mainloop = imports.mainloop; +const Util = imports.misc.util; +const _ = Gettext.gettext; + +const MESSAGE = _('Dependencies Missing\n\ +Please install: \n\ +gnome-system-monitor and libgtop, clutter and Network Manager gir bindings \n\ +\t on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gir1.2-clutter-1.0, gnome-system-monitor \n\ +\t on Fedora: libgtop2-devel, NetworkManager-libnm-devel, gnome-system-monitor \n\ +\t on Arch: libgtop, networkmanager, gnome-system-monitor\n\ +\t on openSUSE: typelib-1_0-GTop-2_0, typelib-1_0-NetworkManager-1_0, gnome-system-monitor \n\ +\t on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor\n'); + +// stale network shares will cause the shell to freeze, enable this with caution +const ENABLE_NETWORK_DISK_USAGE = false; + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let metadata = extension.metadata; +let shell_Version = Config.PACKAGE_VERSION; + +Clutter.Actor.prototype.raise_top = function raise_top() { + const parent = this.get_parent(); + if (!parent) { + return; + } + parent.set_child_above_sibling(this, null); +} +Clutter.Actor.prototype.reparent = function reparent(newParent) { + const parent = this.get_parent(); + if (parent) { + parent.remove_child(this); + } + newParent.add_child(this); +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function l_limit(t) { + return (t > 0) ? t : 1000; +} + +function change_text() { + this.label.visible = Schema.get_boolean(this.elt + '-show-text'); +} + +function change_style() { + let style = Schema.get_string(this.elt + '-style'); + this.text_box.visible = style === 'digit' || style === 'both'; + this.chart.actor.visible = style === 'graph' || style === 'both'; +} + +function build_menu_info() { + let elts = Main.__sm.elts; + let tray_menu = Main.__sm.tray.menu; + + if (tray_menu._getMenuItems().length && + typeof tray_menu._getMenuItems()[0].actor.get_last_child() !== 'undefined') { + tray_menu._getMenuItems()[0].actor.get_last_child().destroy_all_children(); + for (let elt in elts) { + elts[elt].menu_items = elts[elt].create_menu_items(); + } + } else { + return; + } + + let menu_info_box_table = new St.Widget({ + style: 'padding: 10px 0px 10px 0px; spacing-rows: 10px; spacing-columns: 15px;', + layout_manager: new Clutter.GridLayout({orientation: Clutter.Orientation.VERTICAL}) + }); + let menu_info_box_table_layout = menu_info_box_table.layout_manager; + + // Populate Table + let row_index = 0; + for (let elt in elts) { + if (!elts[elt].menu_visible) { + continue; + } + + // Add item name to table + menu_info_box_table_layout.attach( + new St.Label({ + text: elts[elt].item_name, + style_class: Style.get('sm-title'), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER + }), 0, row_index, 1, 1); + + // Add item data to table + let col_index = 1; + for (let item in elts[elt].menu_items) { + menu_info_box_table_layout.attach( + elts[elt].menu_items[item], col_index, row_index, 1, 1); + + col_index++; + } + + row_index++; + } + if (shell_Version < '3.36') { + tray_menu._getMenuItems()[0].actor.get_last_child().add(menu_info_box_table, {expand: true}); + } else { + tray_menu._getMenuItems()[0].actor.get_last_child().add_child(menu_info_box_table); + } +} + +function change_menu() { + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + build_menu_info(); +} + +function change_usage() { + let usage = Schema.get_string('disk-usage-style'); + Main.__sm.pie.show(usage === 'pie'); + Main.__sm.bar.show(usage === 'bar'); +} +let color_from_string = Compat.color_from_string; + +function interesting_mountpoint(mount) { + if (mount.length < 3) { + return false; + } + + return ((mount[0].indexOf('/dev/') === 0 || mount[2].toLowerCase() === 'nfs') && mount[2].toLowerCase() !== 'udf'); +} + + +const smStyleManager = class SystemMonitor_smStyleManager { + constructor() { + this._extension = ''; + this._iconsize = 1; + this._diskunits = _('MiB/s'); + this._netunits_kbytes = _('KiB/s'); + this._netunits_mbytes = _('MiB/s'); + this._netunits_gbytes = _('GiB/s'); + this._netunits_kbits = _('kbit/s'); + this._netunits_mbits = _('Mbit/s'); + this._netunits_gbits = _('Gbit/s'); + this._pie_size = 300; + this._pie_fontsize = 14; + this._bar_width = 300; + this._bar_thickness = 15; + this._bar_fontsize = 14; + this._compact = Schema.get_boolean('compact-display'); + + if (this._compact) { + this._extension = '-compact'; + this._iconsize = 3 / 5; + this._diskunits = _('MB'); + this._netunits_kbytes = _('kB'); + this._netunits_mbytes = _('MB'); + this._netunits_gbytes = _('GB'); + this._netunits_kbits = 'kb'; + this._netunits_mbits = 'Mb'; + this._netunits_gbits = 'Gb'; + this._pie_size *= 4 / 5; + this._pie_fontsize = 12; + this._bar_width *= 3 / 5; + this._bar_thickness = 12; + this._bar_fontsize = 12; + } + } + get(style) { + return style + this._extension; + } + iconsize() { + return this._iconsize; + } + diskunits() { + return this._diskunits; + } + netunits_kbytes() { + return this._netunits_kbytes; + } + netunits_mbytes() { + return this._netunits_mbytes; + } + netunits_gbytes() { + return this._netunits_gbytes; + } + netunits_kbits() { + return this._netunits_kbits; + } + netunits_mbits() { + return this._netunits_mbits; + } + netunits_gbits() { + return this._netunits_gbits; + } + pie_size() { + return this._pie_size; + } + pie_fontsize() { + return this._pie_fontsize; + } + bar_width() { + return this._bar_width; + } + bar_thickness() { + return this._bar_thickness; + } + bar_fontsize() { + return this._bar_fontsize; + } +} + +const smDialog = class SystemMonitor_smDialog extends ModalDialog.ModalDialog { + constructor() { + super({styleClass: 'prompt-dialog'}); + let mainContentBox = new St.BoxLayout({style_class: 'prompt-dialog-main-layout', + vertical: false}); + this.contentLayout.add(mainContentBox, + {x_fill: true, + y_fill: true}); + + let messageBox = new St.BoxLayout({style_class: 'prompt-dialog-message-layout', + vertical: true}); + mainContentBox.add(messageBox, + {y_align: St.Align.START}); + + this._subjectLabel = new St.Label({style_class: 'prompt-dialog-headline', + text: _('System Monitor Extension')}); + + messageBox.add(this._subjectLabel, + {y_fill: false, + y_align: St.Align.START}); + + this._descriptionLabel = new St.Label({style_class: 'prompt-dialog-description', + text: MESSAGE}); + + messageBox.add(this._descriptionLabel, + {y_fill: true, + y_align: St.Align.START}); + + + this.setButtons([ + { + label: _('Cancel'), + action: () => { + this.close(); + }, + key: Clutter.Escape + } + ]); + } +} + +const Chart = class SystemMonitor_Chart { + constructor(width, height, parent) { + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.parentC = parent; + this.width = width; + let themeContext = St.ThemeContext.get_for_stage(global.stage); + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); + this.actor.set_height(height); + this.data = []; + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = []; + } + themeContext.connect('notify::scale-factor', this.rescale.bind(this)); + this.actor.connect('repaint', this._draw.bind(this)); + } + update() { + let data_a = this.parentC.vals; + if (data_a.length !== this.parentC.colors.length) { + return; + } + let accdata = []; + for (let l = 0; l < data_a.length; l++) { + accdata[l] = (l === 0) ? data_a[0] : accdata[l - 1] + ((data_a[l] > 0) ? data_a[l] : 0); + this.data[l].push(accdata[l]); + if (this.data[l].length > this.width) { + this.data[l].shift(); + } + } + if (!this.actor.visible) { + return; + } + this.actor.queue_repaint(); + } + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let max; + if (this.parentC.max) { + max = this.parentC.max; + } else { + max = Math.max.apply(this, this.data[this.data.length - 1]); + max = Math.max(1, Math.pow(2, Math.ceil(Math.log(max) / Math.log(2)))); + } + Clutter.cairo_set_source_color(cr, Background); + cr.rectangle(0, 0, width, height); + cr.fill(); + for (let i = this.parentC.colors.length - 1; i >= 0; i--) { + let samples = this.data[i].length - 1; + if (samples > 0) { + cr.moveTo(width, height); // bottom right + let x = width - 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][samples] / max) * height); + x -= 0.5 * this.scale_factor; + for (let j = samples; j >= 0; j--) { + let y = (1 - this.data[i][j] / max) * height; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + } + x += 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][0] / max) * height); + cr.lineTo(x, height); + cr.closePath(); + Clutter.cairo_set_source_color(cr, this.parentC.colors[i]); + cr.fill(); + } + } + cr.$dispose(); + } + resize(width) { + if (this.width === width) { + return; + } + this.width = width; + if (this.width < this.data[0].length) { + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = this.data[i].slice(-this.width); + } + } + this.actor.set_width(this.width * this.scale_factor); // repaints + } + rescale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); // repaints + } +} + +// Class to deal with volumes insertion / ejection +const smMountsMonitor = class SystemMonitor_smMountsMonitor { + constructor() { + this.files = []; + this.num_mounts = -1; + this.listeners = []; + this.connected = false; + + this._volumeMonitor = Gio.VolumeMonitor.get(); + let sys_mounts = ['/home', '/tmp', '/boot', '/usr', '/usr/local']; + this.base_mounts = ['/']; + sys_mounts.forEach((sMount) => { + if (this.is_sys_mount(sMount + '/')) { + this.base_mounts.push(sMount); + } + }); + this.connect(); + } + refresh() { + // try check that number of volumes has changed + // try { + // let num_mounts = this.manager.getMounts().length; + // if (num_mounts == this.num_mounts) + // return; + // this.num_mounts = num_mounts; + // } catch (e) {}; + + // Can't get mountlist: + // GTop.glibtop_get_mountlist + // Error: No symbol 'glibtop_get_mountlist' in namespace 'GTop' + // Getting it with mtab + // let mount_lines = Shell.get_file_contents_utf8_sync('/etc/mtab').split("\n"); + // this.mounts = []; + // for(let mount_line in mount_lines) { + // let mount = mount_lines[mount_line].split(" "); + // if(interesting_mountpoint(mount) && this.mounts.indexOf(mount[1]) < 0) { + // this.mounts.push(mount[1]); + // } + // } + // log("[System monitor] old mounts: " + this.mounts); + this.mounts = []; + for (let base in this.base_mounts) { + // log("[System monitor] " + this.base_mounts[base]); + this.mounts.push(this.base_mounts[base]); + } + let mount_lines = this._volumeMonitor.get_mounts(); + mount_lines.forEach((mount) => { + if ((!this.is_net_mount(mount) || ENABLE_NETWORK_DISK_USAGE) && + !this.is_ro_mount(mount)) { + let mpath = mount.get_root().get_path() || mount.get_default_location().get_path(); + if (mpath) { + this.mounts.push(mpath); + } + } + }); + // log("[System monitor] base: " + this.base_mounts); + // log("[System monitor] mounts: " + this.mounts); + for (let i in this.listeners) { + this.listeners[i](this.mounts); + } + } + add_listener(cb) { + this.listeners.push(cb); + } + remove_listener(cb) { + this.listeners.pop(cb); + } + get_mounts() { + return this.mounts; + } + is_sys_mount(mpath) { + let file = Gio.file_new_for_path(mpath); + let info = file.query_info(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT, + Gio.FileQueryInfoFlags.NONE, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT); + } + is_ro_mount(mount) { + // FIXME: running this function after "login after waking from suspend" + // can make login hang. Actual issue seems to occur when a former net + // mount got broken (e.g. due to a VPN connection terminated or + // otherwise broken connection) + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY); + } catch (e) { + return false; + } + } + is_net_mount(mount) { + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE, null); + let result = info.get_attribute_string(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE); + let net_fs = ['nfs', 'smbfs', 'cifs', 'ftp', 'sshfs', 'sftp', 'mtp', 'mtpfs']; + return !file.is_native() || net_fs.indexOf(result) > -1; + } catch (e) { + return false; + } + } + connect() { + if (this.connected) { + return; + } + try { + this.manager = this._volumeMonitor; + this.mount_added_id = this.manager.connect('mount-added', this.refresh.bind(this)); + this.mount_removed_id = this.manager.connect('mount-removed', this.refresh.bind(this)); + // need to add the other signals here + this.connected = true; + } catch (e) { + log('[System monitor] Failed to register on placesManager notifications'); + log('[System monitor] Got exception : ' + e); + } + this.refresh(); + } + disconnect() { + if (!this.connected) { + return; + } + this.manager.disconnect(this.mount_added_id); + this.manager.disconnect(this.mount_removed_id); + this.connected = false; + } + destroy() { + this.disconnect(); + } +} + +const Graph = class SystemMonitor_Graph { + constructor(width, height) { + this.menu_item = ''; + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.width = width; + this.height = height; + this.gtop = new GTop.glibtop_fsusage(); + this.colors = ['#888', '#aaa', '#ccc']; + for (let color in this.colors) { + this.colors[color] = color_from_string(this.colors[color]); + } + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + themeContext.connect('notify::scale-factor', this.set_scale.bind(this)); + this.scale_factor = themeContext.scale_factor; + let interfaceSettings = new Gio.Settings({ + schema: 'org.gnome.desktop.interface' + }); + interfaceSettings.connect('changed', this.set_text_scaling.bind(this)); + this.text_scaling = interfaceSettings.get_double('text-scaling-factor'); + if (!this.text_scaling) { + this.text_scaling = 1; + } + + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + this.actor.connect('repaint', this._draw.bind(this)); + } + create_menu_item() { + this.menu_item = new PopupMenu.PopupBaseMenuItem({reactive: false}); + if (shell_Version < '3.36') { + this.menu_item.actor.add(this.actor, {span: -1, expand: true}); + } else { + this.menu_item.actor.add_child(this.actor); + } + // tray.menu.addMenuItem(this.menu_item); + } + show(visible) { + this.menu_item.actor.visible = visible; + } + set_scale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } + set_text_scaling(interfaceSettings, key) { + // FIXME: for some reason we only get this signal once, not on later + // changes to the setting + //log('[System monitor] got text scaling signal'); + this.text_scaling = interfaceSettings.get_double(key); + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } +} + +const Bar = class SystemMonitor_Bar extends Graph { + constructor() { + // Height doesn't matter, it gets set on every draw. + super(Style.bar_width(), 100); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + _draw() { + if (!this.actor.visible) { + return; + } + let thickness = Style.bar_thickness() * this.scale_factor * this.text_scaling; + let fontsize = Style.bar_fontsize() * this.scale_factor * this.text_scaling; + this.actor.set_height(this.mounts.length * (3 * thickness)); + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + + let x0 = width / 8; + let y0 = thickness / 2; + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + let perc_full = (this.gtop.blocks - this.gtop.bfree) / this.gtop.blocks; + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y0 + thickness / 3); + cr.showText(text); + cr.moveTo(width - x0, y0 + thickness / 3); + cr.showText(Math.round(perc_full * 100).toString() + '%'); + y0 += (5 * thickness) / 4; + + cr.moveTo(0, y0); + cr.relLineTo(perc_full * width, 0); + cr.stroke(); + y0 += (7 * thickness) / 4; + } + cr.$dispose(); + } + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +const Pie = class SystemMonitor_Pie extends Graph { + constructor() { + super(Style.pie_size(), Style.pie_size()); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let xc = width / 2; + let yc = height / 2; + let pi = Math.PI; + function arc(r, value, max, angle) { + if (max === 0) { + return angle; + } + let new_angle = angle + (value * 2 * pi / max); + cr.arc(xc, yc, r, angle, new_angle); + return new_angle; + } + + // Set the ring thickness so that at least 7 rings can be displayed. If + // there are more mounts, make the rings thinner. If the rings are too + // thin to have a line height of 1.2 for the labels, shrink the labels. + let rings = Math.max(this.mounts.length, 7); + let ring_width = width / (2 * rings); + let fontsize = Style.pie_fontsize() * this.scale_factor * this.text_scaling; + if (ring_width < 1.2 * fontsize) { + fontsize = ring_width / 1.2; + } + let thickness = ring_width / 1.5; + + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + let r = (height - ring_width) / 2; + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + arc(r, this.gtop.blocks - this.gtop.bfree, this.gtop.blocks, -pi / 2); + cr.stroke(); + r -= ring_width; + } + let y = (ring_width + fontsize) / 2; + for (let mount in this.mounts) { + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y); + cr.showText(text); + y += ring_width; + } + cr.$dispose(); + } + + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +var TipItem = null; + +if (shell_Version < '3.36') { + TipItem = class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + constructor() { + super(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } +} else { + TipItem = GObject.registerClass( + { + GTypeName: 'TipItem' + }, + class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + _init() { + super._init(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } + ); +} +const TipMenu = class SystemMonitor_TipMenu extends PopupMenu.PopupMenuBase { + constructor(sourceActor) { + // PopupMenu.PopupMenuBase.prototype._init.call(this, sourceActor, 'sm-tooltip-box'); + super(sourceActor, 'sm-tooltip-box'); + this.actor = new Clutter.Actor(); + // this.actor.connect('get-preferred-width', + // this._boxGetPreferredWidth).bind(this); + // this.actor.connect('get-preferred-height', + // this._boxGetPreferredHeight.bind(this)); + this.actor.add_actor(this.box); + } + // _boxGetPreferredWidth (actor, forHeight, alloc) { + // // let columnWidths = this.getColumnWidths(); + // // this.setColumnWidths(columnWidths); + // + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_width(forHeight); + // } + // _boxGetPreferredHeight (actor, forWidth, alloc) { + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_height(forWidth); + // } + // _boxAllocate (actor, box, flags) { + // this.box.allocate(box, flags); + // } + _shift() { + // Probably old but works + let node = this.sourceActor.get_theme_node(); + let contentbox = node.get_content_box(this.sourceActor.get_allocation_box()); + + let sourceTopLeftX = 0; + let sourceTopLeftY = 0; + if (typeof this.sourceActor.get_transformed_extents === 'function') { + let extents = this.sourceActor.get_transformed_extents(); + let sourceTopLeft = extents.get_top_left(); + sourceTopLeftY = sourceTopLeft.y; + sourceTopLeftX = sourceTopLeft.x; + } else { + let allocation = Shell.util_get_transformed_allocation(this.sourceActor); + sourceTopLeftY = allocation.y1; + sourceTopLeftX = allocation.x1; + } + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + let [x, y] = [sourceTopLeftX + contentbox.x1, + sourceTopLeftY + contentbox.y1]; + let [cx, cy] = [sourceTopLeftX + (contentbox.x1 + contentbox.x2) / 2, + sourceTopLeftY + (contentbox.y1 + contentbox.y2) / 2]; + let [xm, ym] = [sourceTopLeftX + contentbox.x2, + sourceTopLeftY + contentbox.y2]; + let [width, height] = this.actor.get_size(); + let tipx = cx - width / 2; + tipx = Math.max(tipx, monitor.x); + tipx = Math.min(tipx, monitor.x + monitor.width - width); + let tipy = Math.floor(ym); + // Hacky condition to determine if the status bar is at the top or at the bottom of the screen + if (sourceTopLeftY / monitor.height > 0.3) { + tipy = sourceTopLeftY - height; // If it is at the bottom, place the tooltip above instead of below + } + this.actor.set_position(tipx, tipy); + } + open(animate) { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this.actor.show(); + this._shift(); + this.actor.raise_top(); + this.emit('open-state-changed', true); + } + close(animate) { + this.isOpen = false; + this.actor.hide(); + this.emit('open-state-changed', false); + } +} + +const TipBox = class SystemMonitor_TipBox { + constructor() { + this.actor = new St.BoxLayout({reactive: true}); + this.actor._delegate = this; + this.set_tip(new TipMenu(this.actor)); + this.in_to = this.out_to = 0; + this.actor.connect('enter-event', this.on_enter.bind(this)); + this.actor.connect('leave-event', this.on_leave.bind(this)); + } + set_tip(tipmenu) { + if (this.tipmenu) { + this.tipmenu.destroy(); + } + this.tipmenu = tipmenu; + if (this.tipmenu) { + Main.uiGroup.add_actor(this.tipmenu.actor); + this.hide_tip(); + } + } + show_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.open(); + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + hide_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.close(); + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + on_enter() { + let show_tooltip = Schema.get_boolean('show-tooltip'); + + if (!show_tooltip) { + return; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (!this.in_to) { + this.in_to = Mainloop.timeout_add(500, + this.show_tip.bind(this)); + } + } + on_leave() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + if (!this.out_to) { + this.out_to = Mainloop.timeout_add(500, + this.hide_tip.bind(this)); + } + } + destroy() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + + this.actor.destroy(); + } +} + +const ElementBase = class SystemMonitor_ElementBase extends TipBox { + constructor(properties) { + super(); + this.elt = ''; + this.item_name = _(''); + this.color_name = []; + this.text_items = []; + this.menu_items = []; + this.menu_visible = true; + + Object.assign(this, properties); + + // TipBox.prototype._init.apply(this, arguments); + this.vals = []; + this.tip_labels = []; + this.tip_vals = []; + this.tip_unit_labels = []; + + this.colors = []; + for (let color in this.color_name) { + let name = this.elt + '-' + this.color_name[color] + '-color'; + let clutterColor = color_from_string(Schema.get_string(name)); + Schema.connect('changed::' + name, (schema, key) => { + this.clutterColor = color_from_string(Schema.get_string(key)); + }); + Schema.connect('changed::' + name, () => { + this.chart.actor.queue_repaint(); + }); + this.colors.push(clutterColor); + } + + let element_width = Schema.get_int(this.elt + '-graph-width'); + if (Style.get('') === '-compact') { + element_width = Math.round(element_width / 1.5); + } + this.chart = new Chart(element_width, IconSize, this); + + Schema.connect('changed::background', () => { + this.chart.actor.queue_repaint(); + }); + + this.actor.visible = Schema.get_boolean(this.elt + '-display'); + Schema.connect( + 'changed::' + this.elt + '-display', (schema, key) => { + this.actor.visible = Schema.get_boolean(key); + }); + + this.interval = l_limit(Schema.get_int(this.elt + '-refresh-time')); + this.timeout = Mainloop.timeout_add( + this.interval, + this.update.bind(this), + GLib.PRIORITY_DEFAULT_IDLE + ); + + Schema.connect( + 'changed::' + this.elt + '-refresh-time', + (schema, key) => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.interval = l_limit(Schema.get_int(key)); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + Schema.connect('changed::' + this.elt + '-graph-width', this.resize.bind(this)); + + if (this.elt === 'thermal') { + Schema.connect('changed::thermal-threshold', + () => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.reset_style(); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + } + + this.label = new St.Label({text: this.elt === 'memory' ? _('mem') : _(this.elt), + style_class: Style.get('sm-status-label')}); + change_text.call(this); + Schema.connect('changed::' + this.elt + '-show-text', change_text.bind(this)); + + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + Schema.connect('changed::' + this.elt + '-show-menu', change_menu.bind(this)); + + this.actor.add_actor(this.label); + this.text_box = new St.BoxLayout(); + + this.actor.add_actor(this.text_box); + this.text_items = this.create_text_items(); + for (let item in this.text_items) { + this.text_box.add_actor(this.text_items[item]); + } + this.actor.add_actor(this.chart.actor); + change_style.call(this); + Schema.connect('changed::' + this.elt + '-style', change_style.bind(this)); + this.menu_items = this.create_menu_items(); + } + tip_format(unit) { + if (typeof (unit) === 'undefined') { + unit = '%'; + } + if (typeof (unit) === 'string') { + let all_unit = unit; + unit = []; + for (let i = 0; i < this.color_name.length; i++) { + unit.push(all_unit); + } + } + for (let i = 0; i < this.color_name.length; i++) { + let tipline = new TipItem(); + this.tipmenu.addMenuItem(tipline); + tipline.actor.add(new St.Label({text: _(this.color_name[i])})); + this.tip_labels[i] = new St.Label({text: ''}); + tipline.actor.add(this.tip_labels[i]); + + this.tip_unit_labels[i] = new St.Label({text: unit[i]}); + tipline.actor.add(this.tip_unit_labels[i]); + this.tip_vals[i] = 0; + } + } + // set_tip_unit: function(unit) { + // for (let i = 0;i < this.tip_unit_labels.length;i++) { + // this.tip_unit_labels[i].text = unit[i]; + // } + // } + update() { + if (!this.menu_visible && !this.actor.visible) { + return false; + } + this.refresh(); + this._apply(); + if (this.elt === 'thermal') { + this.threshold(); + } + this.chart.update(); + for (let i = 0; i < this.tip_vals.length; i++) { + if (this.tip_labels[i]) { + this.tip_labels[i].text = this.tip_vals[i].toString(); + } + } + return true; + } + reset_style() { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + threshold() { + if (Schema.get_int('thermal-threshold')) { + if (this.temp_over_threshold) { + this.text_items[0].set_style('color: rgba(255, 0, 0, 1)'); + } else { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + } + } + resize(schema, key) { + let width = Schema.get_int(key); + if (Style.get('') === '-compact') { + width = Math.round(width / 1.5); + } + this.chart.resize(width); + } + destroy() { + TipBox.prototype.destroy.call(this); + if (this.timeout) { + Mainloop.source_remove(this.timeout); + this.timeout = null; + } + } +} + +const Battery = class SystemMonitor_Battery extends ElementBase { + constructor() { + super({ + elt: 'battery', + item_name: _('Battery'), + color_name: ['batt0'], + icon: '. GThemedIcon battery-good-symbolic battery-good' + }); + + this.max = 100; + this.icon_hidden = false; + this.percentage = 0; + this.timeString = '-- '; + this._proxy = StatusArea.aggregateMenu._power._proxy; + if (typeof (this._proxy) === 'undefined') { + this._proxy = StatusArea.battery._proxy; + } + this.powerSigID = this._proxy.connect('g-properties-changed', this.update_battery.bind(this)); + + // need to specify a default icon, since the contructor completes before UPower callback + this.gicon = Gio.icon_new_for_string(this.icon); + + this.tip_format('%'); + + this.update_battery(); + this.update_tips(); + // this.hide_system_icon(); + this.update(); + + // Schema.connect('changed::' + this.elt + '-hidesystem', this.hide_system_icon.bind(this)); + Schema.connect('changed::' + this.elt + '-time', this.update_tips.bind(this)); + } + refresh() { + // do nothing here? + } + update_battery() { + // callback function for when battery stats updated. + let battery_found = false; + let isBattery = false; + if (typeof (this._proxy.GetDevicesRemote) === 'undefined') { + let device_type = this._proxy.Type; + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + let icon = this._proxy.IconName; + let percentage = this._proxy.Percentage; + let seconds = this._proxy.TimeToEmpty; + this.update_battery_value(seconds, percentage, icon); + } else { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + } else { + this._proxy.GetDevicesRemote((devices, error) => { + if (error) { + log('[System monitor] Power proxy error: ' + error); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + return; + } + + let [result] = devices; + for (let i = 0; i < result.length; i++) { + let [device_id, device_type, icon, percentage, state, seconds] = result[i]; + + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + this.update_battery_value(seconds, percentage, icon); + break; + } + } + + if (!battery_found) { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + }); + } + } + update_battery_value(seconds, percentage, icon) { + if (seconds > 60) { + let time = Math.round(seconds / 60); + let minutes = time % 60; + let hours = Math.floor(time / 60); + this.timeString = C_('battery time remaining', '%d:%02d').format(hours, minutes); + } else { + this.timeString = '-- '; + } + this.percentage = Math.ceil(percentage); + this.gicon = Gio.icon_new_for_string(icon); + + if (Schema.get_boolean(this.elt + '-display')) { + this.actor.show() + } + if (Schema.get_boolean(this.elt + '-show-menu') && !this.menu_visible) { + this.menu_visible = true; + build_menu_info(); + } + } + hide_system_icon(override) { + let value = Schema.get_boolean(this.elt + '-hidesystem'); + if (!override) { + value = false; + } + if (value && Schema.get_boolean(this.elt + '-display')) { + if (shell_Version > '3.5') { + if (StatusArea.battery.actor.visible) { + StatusArea.battery.destroy(); + this.icon_hidden = true; + } + } else { + for (let Index = 0; Index < Main.panel._rightBox.get_children().length; Index++) { + if (StatusArea.battery === Main.panel._rightBox.get_children()[Index]._delegate) { + Main.panel._rightBox.get_children()[Index].destroy(); + StatusArea.battery = null; + this.icon_hidden = true; + break; + } + } + } + } else if (this.icon_hidden) { + if (shell_Version < '3.5') { + let Indicator = new Panel.STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION.battery(); + Main.panel.addToStatusArea('battery', Indicator, Panel.STANDARD_STATUS_AREA_ORDER.indexOf('battery')); + } else { + let Indicator = new Panel.PANEL_ITEM_IMPLEMENTATIONS.battery(); + Main.panel.addToStatusArea('battery', Indicator, Main.sessionMode.panel.right.indexOf('battery'), 'right'); + } + this.icon_hidden = false; + // Main.panel._updatePanel('right'); + } + } + get_battery_unit() { + let unitString; + let value = Schema.get_boolean(this.elt + '-time'); + + if (value) { + unitString = 'h'; + } else { + unitString = '%'; + } + + return unitString; + } + update_tips() { + let unitString = this.get_battery_unit(); + + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[2].text = unitString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[1].text = unitString; + } + + this.update(); + } + _apply() { + let displayString; + let value = Schema.get_boolean(this.elt + '-time'); + if (value) { + displayString = this.timeString; + } else { + displayString = this.percentage.toString() + } + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[0].gicon = this.gicon; + this.text_items[1].text = displayString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[0].text = displayString; + } + this.vals = [this.percentage]; + this.tip_vals[0] = Math.round(this.percentage); + } + create_text_items() { + return [ + new St.Icon({ + gicon: Gio.icon_new_for_string(this.icon), + style_class: Style.get('sm-status-icon')}), + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-label')}) + ]; + } + destroy() { + ElementBase.prototype.destroy.call(this); + this._proxy.disconnect(this.powerSigID); + } +} + +const Cpu = class SystemMonitor_Cpu extends ElementBase { + constructor(cpuid) { + super({ + elt: 'cpu', + item_name: _('CPU'), + color_name: ['user', 'system', 'nice', 'iowait', 'other'], + cpuid: -1 // cpuid is -1 when all cores are displayed in the same graph + }); + this.max = 100; + + this.cpuid = cpuid; + this.gtop = new GTop.glibtop_cpu(); + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + try { + this.total_cores = GTop.glibtop_get_sysinfo().ncpu; + if (cpuid === -1) { + this.max *= this.total_cores; + } + } catch (e) { + this.total_cores = this.get_cores(); + global.logError(e) + } + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + this.item_name = _('Cpu'); + if (cpuid !== -1) { + this.item_name += ' ' + (cpuid + 1); + } // append cpu number to cpu name in popup + // ElementBase.prototype._init.call(this); + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_cpu(this.gtop); + // display global cpu usage on 1 graph + if (this.cpuid === -1) { + this.current[0] = this.gtop.user; + this.current[1] = this.gtop.sys; + this.current[2] = this.gtop.nice; + this.current[3] = this.gtop.idle; + this.current[4] = this.gtop.iowait; + let delta = (this.gtop.total - this.last_total) / (100 * this.total_cores); + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.total; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } else { + // display per cpu data + this.current[0] = this.gtop.xcpu_user[this.cpuid]; + this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + let delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total) / 100; + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.xcpu_total[this.cpuid]; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } + + // GTop.glibtop_get_cpu(this.gtop); + // // display global cpu usage on 1 graph + // if (this.cpuid == -1) { + // this.current[0] = this.gtop.user; + // this.current[1] = this.gtop.sys; + // this.current[2] = this.gtop.nice; + // this.current[3] = this.gtop.idle; + // this.current[4] = this.gtop.iowait; + // } else { + // // display cpu usage for given core + // this.current[0] = this.gtop.xcpu_user[this.cpuid]; + // this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + // this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + // this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + // this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + // } + // + // let delta = 0; + // if (this.cpuid == -1) + // delta = (this.gtop.total - this.last_total)/(100*this.total_cores); + // else + // delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total)/100; + // + // if (delta > 0) { + // for (let i = 0;i < 5;i++) { + // this.usage[i] = Math.round((this.current[i] - this.last[i])/delta); + // this.last[i] = this.current[i]; + // } + // if (this.cpuid == -1) + // this.last_total = this.gtop.total; + // else + // this.last_total = this.gtop.xcpu_total[this.cpuid]; + // } + } + _apply() { + let percent = 0; + if (this.cpuid === -1) { + percent = Math.round(((100 * this.total_cores) - this.usage[3]) / + this.total_cores); + } else { + percent = Math.round((100 - this.usage[3])); + } + + this.text_items[0].text = this.menu_items[0].text = percent.toString(); + let other = 100; + for (let i = 0; i < this.usage.length; i++) { + other -= this.usage[i]; + } + // Not to be confusing + other = Math.max(0, other); + this.vals = [this.usage[0], this.usage[1], + this.usage[2], this.usage[4], other]; + for (let i = 0; i < 5; i++) { + this.tip_vals[i] = Math.round(this.vals[i]); + } + } + + get_cores() { + // Getting xcpu_total makes gjs 1.29.18 segfault + // let cores = 0; + // GTop.glibtop_get_cpu(this.gtop); + // let gtop_total = this.gtop.xcpu_total + // for (let i = 0; i < gtop_total.length;i++) { + // if (gtop_total[i] > 0) + // cores++; + // } + // return cores; + return 1; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}) + ]; + } +} + +// Check if one graph per core must be displayed and create the +// appropriate number of cpu items +function createCpus() { + let array = []; + let numcores = 1; + + if (Schema.get_boolean('cpu-individual-cores')) { + // get number of cores + let gtop = new GTop.glibtop_cpu(); + try { + numcores = GTop.glibtop_get_sysinfo().ncpu; + } catch (e) { + global.logError(e); + numcores = 1; + } + } + + // there are several cores to display, + // instantiate each cpu + if (numcores > 1) { + for (let i = 0; i < numcores; i++) { + array.push(new Cpu(i)); + } + } else { + // individual cores option is not set or we failed to + // get the number of cores, create a global cpu item + array.push(new Cpu(-1)); + } + + return array; +} + +const Disk = class SystemMonitor_Disk extends ElementBase { + constructor() { + super({ + elt: 'disk', + item_name: _('Disk'), + color_name: ['read', 'write'] + }); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + this.last = [0, 0]; + this.usage = [0, 0]; + this.last_time = 0; + this.tip_format(_('MiB/s')); + this.update(); + } + update_mounts(mounts) { + this.mounts = mounts; + } + refresh() { + let accum = [0, 0]; + + let file = Gio.file_new_for_path('/proc/diskstats'); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result); + let lines = parse_bytearray(as_r[1]).toString().split('\n'); + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let entry = line.trim().split(/[\s]+/); + if (typeof (entry[1]) === 'undefined') { + break; + } + accum[0] += parseInt(entry[5]); + accum[1] += parseInt(entry[9]); + } + + let time = GLib.get_monotonic_time() / 1000; + let delta = (time - this.last_time) / 1000; + if (delta > 0) { + for (let i = 0; i < 2; i++) { + this.usage[i] = ((accum[i] - this.last[i]) / delta / 1024 / 8); + this.last[i] = accum[i]; + } + } + this.last_time = time; + }); + } + _apply() { + this.vals = this.usage.slice(); + for (let i = 0; i < 2; i++) { + if (this.usage[i] < 10) { + this.usage[i] = Math.round(10 * this.usage[i]) / 10; + } else { + this.usage[i] = Math.round(this.usage[i]); + } + } + this.tip_vals = [this.usage[0], this.usage[1]]; + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toLocaleString(Locale); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[1].toLocaleString(Locale); + } + create_text_items() { + return [ + new St.Label({ + text: _('R'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('W'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _('R'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: ' ' + _('W'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Freq = class SystemMonitor_Freq extends ElementBase { + constructor() { + super({ + elt: 'freq', + item_name: _('Freq'), + color_name: ['freq'] + }); + this.freq = 0; + this.tip_format('MHz'); + this.update(); + } + refresh() { + let total_frequency = 0; + let num_cpus = GTop.glibtop_get_sysinfo().ncpu; + let i = 0; + let file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + var that = this; + file.load_contents_async(null, function cb(source, result) { + let as_r = source.load_contents_finish(result); + total_frequency += parseInt(parse_bytearray(as_r[1])); + + if (++i >= num_cpus) { + that.freq = Math.round(total_frequency / num_cpus / 1000); + } else { + file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + file.load_contents_async(null, cb.bind(that)); + } + }); + } + _apply() { + let value = this.freq.toString(); + this.text_items[0].text = value + ' '; + this.vals[0] = value; + this.tip_vals[0] = value; + if (Style.get('') !== '-compact') { + this.menu_items[0].text = value; + } else { + this.menu_items[0].text = this._pad(value, 4); + } + } + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-big-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: 'MHz', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: 'MHz', + style_class: Style.get('sm-label')}) + ]; + } +} + +const Mem = class SystemMonitor_Mem extends ElementBase { + constructor() { + super({ + elt: 'memory', + item_name: _('Memory'), + color_name: ['program', 'buffer', 'cache'] + }); + this.max = 1; + + this.gtop = new GTop.glibtop_mem(); + this.mem = [0, 0, 0]; + + GTop.glibtop_get_mem(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_mem(this.gtop); + if (this.useGiB) { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[0] /= this._decimals; + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[1] /= this._decimals; + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.mem[2] /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0, 0, 0]; + } else { + for (let i = 0; i < 3; i++) { + this.vals[i] = this.mem[i] / this.total; + this.tip_vals[i] = Math.round(this.vals[i] * 100); + } + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem[0]) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.mem[0]) + + '/' + this._pad(this.total); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Net = class SystemMonitor_Net extends ElementBase { + constructor() { + super({ + elt: 'net', + item_name: _('Net'), + color_name: ['down', 'downerrors', 'up', 'uperrors', 'collisions'] + }); + this.speed_in_bits = false; + this.ifs = []; + this.client = libnm_glib ? NM.Client.new() : NM.Client.new(null); + this.update_iface_list(); + + if (!this.ifs.length) { + let net_lines = Shell.get_file_contents_utf8_sync('/proc/net/dev').split('\n'); + for (let i = 2; i < net_lines.length - 1; i++) { + let ifc = net_lines[i].replace(/^\s+/g, '').split(':')[0]; + if (Shell.get_file_contents_utf8_sync('/sys/class/net/' + ifc + '/operstate') + .replace(/\s/g, '') === 'up' && + ifc.indexOf('br') < 0 && + ifc.indexOf('lo') < 0) { + this.ifs.push(ifc); + } + } + } + this.gtop = new GTop.glibtop_netload(); + this.last = [0, 0, 0, 0, 0]; + this.usage = [0, 0, 0, 0, 0]; + this.last_time = 0; + this.tip_format([_('KiB/s'), '/s', _('KiB/s'), '/s', '/s']); + this.update_units(); + Schema.connect('changed::' + this.elt + '-speed-in-bits', this.update_units.bind(this)); + try { + let iface_list = this.client.get_devices(); + this.NMsigID = []; + for (let j = 0; j < iface_list.length; j++) { + this.NMsigID[j] = iface_list[j].connect('state-changed', this.update_iface_list.bind(this)); + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings: ' + e); + } + this.update(); + } + update_units() { + this.speed_in_bits = Schema.get_boolean(this.elt + '-speed-in-bits'); + } + update_iface_list() { + try { + this.ifs = []; + let iface_list = this.client.get_devices(); + for (let j = 0; j < iface_list.length; j++) { + if (iface_list[j].state === NetworkManager.DeviceState.ACTIVATED) { + this.ifs.push(iface_list[j].get_ip_iface() || iface_list[j].get_iface()); + } + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings'); + } + } + refresh() { + let accum = [0, 0, 0, 0, 0]; + + for (let ifn in this.ifs) { + GTop.glibtop_get_netload(this.gtop, this.ifs[ifn]); + accum[0] += this.gtop.bytes_in; + accum[1] += this.gtop.errors_in; + accum[2] += this.gtop.bytes_out; + accum[3] += this.gtop.errors_out; + accum[4] += this.gtop.collisions; + } + + let time = GLib.get_monotonic_time() * 0.001024; + let delta = time - this.last_time; + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((accum[i] - this.last[i]) / delta); + this.last[i] = accum[i]; + this.vals[i] = this.usage[i]; + } + } + this.last_time = time; + } + + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + + _apply() { + this.tip_vals = this.usage; + if (this.speed_in_bits) { + this.tip_vals[0] = Math.round(this.tip_vals[0] * 8.192); + this.tip_vals[2] = Math.round(this.tip_vals[2] * 8.192); + if (this.tip_vals[0] < 1000) { + this.text_items[2].text = Style.netunits_kbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('kbit/s'); + } else if (this.tip_vals[0] < 1000000) { + this.text_items[2].text = Style.netunits_mbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Mbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Gbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000000).toPrecision(3); + } + if (this.tip_vals[2] < 1000) { + this.text_items[5].text = Style.netunits_kbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('kbit/s'); + } else if (this.tip_vals[2] < 1000000) { + this.text_items[5].text = Style.netunits_mbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Mbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Gbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000000).toPrecision(3); + } + } else { + if (this.tip_vals[0] < 1024) { + this.text_items[2].text = Style.netunits_kbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('KiB/s'); + } else if (this.tip_vals[0] < 1048576) { + this.text_items[2].text = Style.netunits_mbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('MiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1024).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('GiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1048576).toPrecision(3); + } + if (this.tip_vals[2] < 1024) { + this.text_items[5].text = Style.netunits_kbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('KiB/s'); + } else if (this.tip_vals[2] < 1048576) { + this.text_items[5].text = Style.netunits_mbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('MiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1024).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('GiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1048576).toPrecision(3); + } + } + + if (Style.get('') !== '-compact') { + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toString(); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[2].toString(); + } else { + this.menu_items[0].text = this.text_items[1].text = this._pad(this.tip_vals[0].toString(), 4); + this.menu_items[3].text = this.text_items[4].text = this._pad(this.tip_vals[2].toString(), 4); + } + } + create_text_items() { + return [ + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-down-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-up-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↓'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(' KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↑'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Swap = class SystemMonitor_Swap extends ElementBase { + constructor() { + super({ + elt: 'swap', + item_name: _('Swap'), + color_name: ['used'] + }); + this.max = 1; + this.gtop = new GTop.glibtop_swap(); + + GTop.glibtop_get_swap(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_swap(this.gtop); + if (this.useGiB) { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.swap /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0]; + } else { + this.vals[0] = this.swap / this.total; + this.tip_vals[0] = Math.round(this.vals[0] * 100); + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toString(); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.swap) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.swap) + + '/' + this._pad(this.total); + } + } + + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = 'MiB'; + if (this.useGiB) { + unit = 'GiB'; + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(unit), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Thermal = class SystemMonitor_Thermal extends ElementBase { + constructor() { + super({ + elt: 'thermal', + item_name: _('Thermal'), + color_name: ['tz0'] + }); + this.max = 100; + + this.item_name = _('Thermal'); + this.temperature = '-- '; + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + this.display_error = true; + this.tip_format(this.temperature_symbol()); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.temperature = Math.round(parseInt(parse_bytearray(as_r[1])) / 1000); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + } + _apply() { + this.text_items[0].text = this.menu_items[0].text = this.temperature_text(); + this.temp_over_threshold = this.temperature > Schema.get_int('thermal-threshold'); + this.vals = [this.temperature]; + this.tip_vals[0] = this.temperature_text(); + this.text_items[1].text = this.menu_items[1].text = this.temperature_symbol(); + this.tip_unit_labels[0].text = _(this.temperature_symbol()); + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-temp-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-label')}) + ]; + } + temperature_text() { + let temperature = this.temperature; + if (this.fahrenheit_unit) { + temperature = Math.round(temperature * 1.8 + 32); + } + return temperature.toString(); + } + temperature_symbol() { + return this.fahrenheit_unit ? '°F' : '°C'; + } +} + +const Fan = class SystemMonitor_Fan extends ElementBase { + constructor() { + super({ + elt: 'fan', + item_name: _('Fan'), + color_name: ['fan0'] + }); + this.rpm = 0; + this.display_error = true; + this.tip_format(_('rpm')); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.rpm = parseInt(parse_bytearray(as_r[1])); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + } + _apply() { + this.text_items[0].text = this.rpm.toString(); + this.menu_items[0].text = this.rpm.toString(); + this.vals = [this.rpm / 10]; + this.tip_vals[0] = this.rpm; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('rpm'), style_class: Style.get('sm-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('rpm'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Gpu = class SystemMonitor_Gpu extends ElementBase { + constructor() { + super({ + elt: 'gpu', + item_name: _('GPU'), + color_name: ['used', 'memory'] + }); + this.max = 100; + + this.item_name = _('GPU'); + this.mem = 0; + this.total = 0; + this.tip_format(); + this.update(); + } + _unit(total) { + this.total = total; + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + } + refresh() { + // Run asynchronously, to avoid shell freeze + try { + let path = Me.dir.get_path(); + let script = ['/bin/bash', path + '/gpu_usage.sh']; + + // Create subprocess and capture STDOUT + let proc = new Gio.Subprocess({argv: script, flags: Gio.SubprocessFlags.STDOUT_PIPE}); + proc.init(null); + // Asynchronously call the output handler when script output is ready + proc.communicate_utf8_async(null, null, Lang.bind(this, this._handleOutput)); + } catch (err) { + global.logError(err.message); + } + } + _handleOutput(proc, result) { + let [ok, output, ] = proc.communicate_utf8_finish(result); + if (ok) { + this._readTemperature(output); + } else { + global.logError('gpu_usage.sh invocation failed'); + } + } + _sanitizeUsageValue(val) { + val = parseInt(val); + if (isNaN(val)) { + val = 0 + } + return val; + } + _readTemperature(procOutput) { + let usage = procOutput.split('\n'); + let memTotal = this._sanitizeUsageValue(usage[0]); + let memUsed = this._sanitizeUsageValue(usage[1]); + this.percentage = this._sanitizeUsageValue(usage[2]); + if (typeof this.useGiB === 'undefined') { + this._unit(memTotal); + this._update_unit(); + } + + if (this.useGiB) { + this.mem = Math.round(memUsed / this._unitConversion); + this.mem /= this._decimals; + this.total = Math.round(memTotal / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem = Math.round(memUsed / this._unitConversion); + this.total = Math.round(memTotal / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toFixed(2); + } + // examples: 5.85, 16.0, 128 + return number.toPrecision(3); + } + + return number; + } + _update_unit() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + this.menu_items[4].text = unit; + } + _apply() { + this.tip_unit_labels[1].text = "/ " + this.total + " " + this.menu_items[4].text; + if (this.total === 0) { + this.vals = [0, 0]; + this.tip_vals = [0, 0]; + } else { + // we subtract percentage from memory because we do not want memory to be + // "accumulated" in the chart with utilization; these two measures should be + // independent + this.vals = [this.percentage, this.mem / this.total * 100 - this.percentage]; + this.tip_vals = [Math.round(this.vals[0]), this.mem]; + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + ' / ' + this._pad(this.total).toLocaleString(Locale); + } else { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + '/' + this._pad(this.total).toLocaleString(Locale); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Icon = class SystemMonitor_Icon { + constructor() { + this.actor = new St.Icon({ + icon_name: 'org.gnome.SystemMonitor-symbolic', + style_class: 'system-status-icon' + }); + this.actor.visible = Schema.get_boolean('icon-display'); + Schema.connect( + 'changed::icon-display', + () => { + this.actor.visible = Schema.get_boolean('icon-display'); + } + ); + } +} + +function init() { + log('[System monitor] applet init from ' + extension.path); + + Convenience.initTranslations(); + // Get locale, needed as an argument for toLocaleString() since GNOME Shell 3.24 + // See: mozjs library bug https://bugzilla.mozilla.org/show_bug.cgi?id=999003 + Locale = GLib.get_language_names()[0]; + if (Locale.indexOf('_') !== -1) { + Locale = Locale.split('_')[0]; + } + + IconSize = Math.round(Panel.PANEL_ICON_SIZE * 4 / 5); +} + +function enable() { + log('[System monitor] applet enabling'); + Schema = Convenience.getSettings(); + + Style = new smStyleManager(); + MountsMonitor = new smMountsMonitor(); + + Background = color_from_string(Schema.get_string('background')); + + if (!(smDepsGtop && smDepsNM)) { + Main.__sm = { + smdialog: new smDialog() + }; + + let dialog_timeout = Mainloop.timeout_add_seconds( + 1, + () => { + Main.__sm.smdialog.open(); + Mainloop.source_remove(dialog_timeout); + return true; + }); + } else { + let panel = Main.panel._rightBox; + StatusArea = Main.panel._statusArea; + if (typeof (StatusArea) === 'undefined') { + StatusArea = Main.panel.statusArea; + } + if (Schema.get_boolean('center-display')) { + panel = Main.panel._centerBox; + } + + MountsMonitor.connect(); + + // Debug + Main.__sm = { + tray: new PanelMenu.Button(0.5), + icon: new Icon(), + pie: new Pie(), + bar: new Bar(), + elts: [], + }; + + // Items to Monitor + Main.__sm.elts = createCpus(); + Main.__sm.elts.push(new Freq()); + Main.__sm.elts.push(new Mem()); + Main.__sm.elts.push(new Swap()); + Main.__sm.elts.push(new Net()); + Main.__sm.elts.push(new Disk()); + Main.__sm.elts.push(new Gpu()); + Main.__sm.elts.push(new Thermal()); + Main.__sm.elts.push(new Fan()); + Main.__sm.elts.push(new Battery()); + + let tray = Main.__sm.tray; + let elts = Main.__sm.elts; + + if (Schema.get_boolean('move-clock')) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._centerBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, -1, Main.panel._rightBox); + tray.clockMoved = true; + } + + Schema.connect('changed::background', (schema, key) => { + Background = color_from_string(Schema.get_string(key)); + }); + Main.panel._addToPanelBox('system-monitor', tray, 1, panel); + + // The spacing adds a distance between the graphs/text on the top bar + let spacing = Schema.get_boolean('compact-display') ? '1' : '4'; + let box = new St.BoxLayout({style: 'spacing: ' + spacing + 'px;'}); + if (shell_Version < '3.36') { + tray.actor.add_actor(box); + } else { + tray.add_actor(box); + } + box.add_actor(Main.__sm.icon.actor); + // Add items to panel box + for (let elt in elts) { + box.add_actor(elts[elt].actor); + } + + // Build Menu Info Box Table + let menu_info = new PopupMenu.PopupBaseMenuItem({reactive: false}); + let menu_info_box = new St.BoxLayout(); + menu_info.actor.add(menu_info_box); + Main.__sm.tray.menu.addMenuItem(menu_info, 0); + + build_menu_info(); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + let pie_item = Main.__sm.pie; + pie_item.create_menu_item(); + tray.menu.addMenuItem(pie_item.menu_item); + + let bar_item = Main.__sm.bar; + bar_item.create_menu_item(); + tray.menu.addMenuItem(bar_item.menu_item); + + change_usage(); + Schema.connect('changed::disk-usage-style', change_usage); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + tray.menu.connect( + 'open-state-changed', + function (menu, isOpen) { + if (isOpen) { + Main.__sm.pie.actor.queue_repaint(); + + menu_timeout = Mainloop.timeout_add_seconds( + 5, + () => { + Main.__sm.pie.actor.queue_repaint(); + return true; + }); + } else { + Mainloop.source_remove(menu_timeout); + } + } + ); + + let _appSys = Shell.AppSystem.get_default(); + let _gsmApp = _appSys.lookup_app('gnome-system-monitor.desktop'); + let _gsmPrefs = _appSys.lookup_app('gnome-shell-extension-prefs.desktop'); + if (_gsmPrefs === null) { + _gsmPrefs = _appSys.lookup_app('org.gnome.Extensions.desktop'); + } + let item; + item = new PopupMenu.PopupMenuItem(_('System Monitor...')); + item.connect('activate', () => { + _gsmApp.activate(); + }); + tray.menu.addMenuItem(item); + + item = new PopupMenu.PopupMenuItem(_('Preferences...')); + item.connect('activate', () => { + if (typeof ExtensionUtils.openPrefs === 'function') { + ExtensionUtils.openPrefs(); + } else if (_gsmPrefs.get_state() === _gsmPrefs.SHELL_APP_STATE_RUNNING) { + _gsmPrefs.activate(); + } else { + let info = _gsmPrefs.get_app_info(); + let timestamp = global.display.get_current_time_roundtrip(); + info.launch_uris([metadata.uuid], global.create_app_launch_context(timestamp, -1)); + } + }); + tray.menu.addMenuItem(item); + Main.panel.menuManager.addMenu(tray.menu); + } + log('[System monitor] applet enabling done'); +} + +function disable() { + // restore clock + if (Main.__sm.tray.clockMoved) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._rightBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, Main.sessionMode.panel.center.indexOf('dateMenu'), Main.panel._centerBox); + } + // restore system power icon if necessary + // workaround bug introduced by multiple cpus init : + // if (Schema.get_boolean('battery-hidesystem') && Main.__sm.elts.battery.icon_hidden) { + // Main.__sm.elts.battery.hide_system_icon(false); + // } + // for (let i in Main.__sm.elts) { + // if (Main.__sm.elts[i].elt == 'battery') + // Main.__sm.elts[i].hide_system_icon(false); + // } + + if (MountsMonitor) { + MountsMonitor.disconnect(); + MountsMonitor = null; + } + + if (Style) { + Style = null; + } + + Schema.run_dispose(); + for (let eltName in Main.__sm.elts) { + Main.__sm.elts[eltName].destroy(); + } + if (shell_Version < '3.36') { + Main.__sm.tray.actor.destroy(); + } else { + Main.__sm.tray.destroy(); + } + Main.__sm = null; + + log('[System monitor] applet disable'); +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh new file mode 100644 index 0000000..de840b9 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh @@ -0,0 +1,49 @@ +#!/bin/sh +################################################################################## +# This file is part of System Monitor Gnome extension. +# System Monitor Gnome extension 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. +# System Monitor Gnome extension 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 System Monitor. If not, see . +# Copyright 2017 Fran Glais, David King, indigohedgehog@github. +################################################################################## + +################################## +# # +# Check for GPU memory usage # +# # +################################## + +checkcommand() +{ + command -v "$1" > /dev/null 2>&1 +} + +# This will print three lines. The first one is the the total vRAM available, +# the second one is the used vRAM and the third on is the GPU usage in %. +if checkcommand nvidia-smi; then + nvidia-smi -i 0 --query-gpu=memory.total,memory.used,utilization.gpu --format=csv,noheader,nounits | while IFS=', ' read -r a b c; do echo "$a"; echo "$b"; echo "$c"; done + +elif lsmod | grep amdgpu > /dev/null; then + total=$(cat /sys/class/drm/card0/device/mem_info_vram_total) + echo $((total / 1024 / 1024)) + + used=$(cat /sys/class/drm/card0/device/mem_info_vram_used) + echo $((used / 1024 / 1024)) + + cat /sys/class/drm/card0/device/gpu_busy_percent + +elif checkcommand glxinfo; then + TOTALVRAM=$(glxinfo | grep -A2 -i GL_NVX_gpu_memory_info | grep -E -i "dedicated" | cut -f2- -d ':' | gawk '{print $1}') + AVAILVRAM=$(glxinfo | grep -A4 -i GL_NVX_gpu_memory_info | grep -E -i "available dedicated" | cut -f2- -d ':' | gawk '{print $1}') + FREEVRAM=$((TOTALVRAM-AVAILVRAM)) + echo "$TOTALVRAM" + echo "$FREEVRAM" + +fi diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ed116be Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ab48c30 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..be4ab2d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..a14e961 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7302234 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7f3d4b3 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b1ccb17 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7623fac Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..e567368 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..5ffcee0 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..8fb4592 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..4e96e8e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..94c2ce3 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..472482f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9537a6e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b756a3d Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7d79d27 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c789c33 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..3bca914 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c362e0e Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..1d4ff15 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9169a1f Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..09f9162 Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json new file mode 100644 index 0000000..44e737a --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json @@ -0,0 +1,19 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Display system information in GNOME Shell status bar, such as memory, CPU, disk and battery usages, network rates\u2026", + "gettext-domain": "system-monitor", + "name": "system-monitor", + "settings-schema": "org.gnome.shell.extensions.system-monitor", + "shell-version": [ + "3.26", + "3.28", + "3.30", + "3.34", + "3.32", + "3.36", + "40" + ], + "url": "https://github.com/paradoxxxzero/gnome-shell-system-monitor-applet", + "uuid": "system-monitor@paradoxxx.zero.gmail.com", + "version": 40 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js new file mode 100644 index 0000000..388f512 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js @@ -0,0 +1,553 @@ +const Gtk = imports.gi.Gtk; +const Gio = imports.gi.Gio; +const Gdk = imports.gi.Gdk; +const GLib = imports.gi.GLib; +const ByteArray = imports.byteArray; +const Config = imports.misc.config; + +const Gettext = imports.gettext.domain('system-monitor'); + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let convenience = extension.imports.convenience; + +const _ = Gettext.gettext; +const N_ = function (e) { + return e; +}; + +let Schema; + +const shellMajorVersion = parseInt(Config.PACKAGE_VERSION.split('.')[0]); + +function init() { + convenience.initTranslations(); + Schema = convenience.getSettings(); +} + +String.prototype.capitalize = function () { + return this.replace(/(^|\s)([a-z])/g, function (m, p1, p2) { + return p1 + p2.toUpperCase(); + }); +}; + +function color_to_hex(color) { + var output = N_('#%02x%02x%02x%02x').format( + 255 * color.red, + 255 * color.green, + 255 * color.blue, + 255 * color.alpha); + return output; +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function check_sensors(sensor_type) { + const hwmon_path = '/sys/class/hwmon/'; + const hwmon_dir = Gio.file_new_for_path(hwmon_path); + + const sensor_files = []; + const sensor_labels = []; + + function get_label_from(file) { + if (file.query_exists(null)) { + // load_contents (and even cat) fails with "Invalid argument" for some label files + try { + let [success, contents] = file.load_contents(null); + if (success) { + return String(parse_bytearray(contents)).split('\n')[0]; + } + } catch (e) { + log('[System monitor] error loading label from file ' + file.get_path() + ': ' + e); + } + } + return null; + } + + function add_sensors_from(chip_dir, chip_label) { + const chip_children = chip_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!chip_children) { + log('[System monitor] error enumerating children of chip ' + chip_dir.get_path()); + return false; + } + + const input_entry_regex = new RegExp('^' + sensor_type + '(\\d+)_input$'); + let info; + let added = false; + while ((info = chip_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.REGULAR) { + continue; + } + const matches = info.get_name().match(input_entry_regex); + if (!matches) { + continue; + } + const input_ordinal = matches[1]; + const input = chip_children.get_child(info); + const input_label = get_label_from(chip_dir.get_child(sensor_type + input_ordinal + '_label')); + + sensor_files.push(input.get_path()); + sensor_labels.push(chip_label + ' - ' + (input_label || input_ordinal)); + added = true; + } + return added; + } + + const hwmon_children = hwmon_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!hwmon_children) { + log('[System monitor] error enumerating hwmon children'); + return [[], []]; + } + + let info; + while ((info = hwmon_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.DIRECTORY || !info.get_name().match(/^hwmon\d+$/)) { + continue; + } + const chip = hwmon_children.get_child(info); + const chip_label = get_label_from(chip.get_child('name')) || chip.get_basename(); + + if (!add_sensors_from(chip, chip_label)) { + // This is here to provide compatibility with previous code, but I can't find any + // information about sensors being stored in chip/device directory. Can we delete it? + const chip_device = chip.get_child('device'); + if (chip_device.query_exists(null)) { + add_sensors_from(chip_device, chip_label); + } + } + } + return [sensor_files, sensor_labels]; +} + +/** + * @param args.hasBorder Whether the box has a border (true) or not + * @param args.horizontal Whether the box is horizontal (true) + * or vertical (false) + * @param args.shouldPack Determines whether a horizontal box should have + * uniform spacing for its children. Only applies to horizontal boxes + * @param args.spacing The amount of spacing for a given box + * @returns a new Box with settings specified by args + */ +function box(args = {}) { + const options = { }; + + if (typeof args.spacing !== 'undefined') { + options.spacing = args.spacing; + } + + if (shellMajorVersion < 40) { + if (args.hasBorder) { + options.border_width = 10; + } + + return args.horizontal ? + new Gtk.HBox(options) : new Gtk.VBox(options); + } + + if (args.hasBorder) { + options.margin_top = 10; + options.margin_bottom = 10; + options.margin_start = 10; + options.margin_end = 10; + } + + options.orientation = args.horizontal ? + Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL; + + const aliasBox = new Gtk.Box(options); + + if (args.shouldPack) { + aliasBox.set_homogeneous(true); + } + + + aliasBox.add = aliasBox.append; + aliasBox.pack_start = aliasBox.prepend; + // normally, this would be append; it is aliased to prepend because + // that appears to yield the same behavior as version < 40 + aliasBox.pack_end = aliasBox.prepend; + + return aliasBox; +} + +const ColorSelect = class SystemMonitor_ColorSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.picker = new Gtk.ColorButton(); + this.actor = box({horizontal: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.picker); + this.picker.set_use_alpha(true); + } + set_value(value) { + let color = new Gdk.RGBA(); + + if (Gtk.get_major_version() >= 4) { + // GDK did not support parsing hex colours with alpha before GTK 4. + color.parse(value); + } else { + // Use the Compat only when GTK 4 is not available, + // since it depends on the deprecated Clutter library. + let Compat = extension.imports.compat; + let clutterColor = Compat.color_from_string(value); + let ctemp = [clutterColor.red, clutterColor.green, clutterColor.blue, clutterColor.alpha / 255]; + color.parse('rgba(' + ctemp.join(',') + ')'); + } + + this.picker.set_rgba(color); + } +} + +const IntSelect = class SystemMonitor_IntSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.spin = new Gtk.SpinButton(); + this.actor = box({horizontal: true, shouldPack: true, }); + this.actor.add(this.label); + this.actor.add(this.spin); + this.spin.set_numeric(true); + } + set_args(minv, maxv, incre, page) { + this.spin.set_range(minv, maxv); + this.spin.set_increments(incre, page); + } + set_value(value) { + this.spin.set_value(value); + } +} + +const Select = class SystemMonitor_Select { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + // this.label.set_justify(Gtk.Justification.RIGHT); + this.selector = new Gtk.ComboBoxText(); + this.actor = box({horizontal: true, shouldPack: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.selector); + } + set_value(value) { + this.selector.set_active(value); + } + add(items) { + items.forEach((item) => { + this.selector.append_text(item); + }) + } +} + +function set_enum(combo, schema, name) { + Schema.set_enum(name, combo.get_active()); +} + +function set_color(color, schema, name) { + Schema.set_string(name, color_to_hex(color.get_rgba())) +} + +function set_string(combo, schema, name, _slist) { + Schema.set_string(name, _slist[combo.get_active()]); +} + +const SettingFrame = class SystemMonitor { + constructor(name, schema) { + this.schema = schema; + this.label = new Gtk.Label({label: name}); + + this.vbox = box({horizontal: false, shouldPack: true, spacing: 20}); + this.hbox0 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox1 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox2 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox3 = box({horizontal: true, shouldPack: true, spacing: 20}); + + if (shellMajorVersion < 40) { + this.frame = new Gtk.Frame({border_width: 10}); + this.frame.add(this.vbox); + } else { + this.frame = new Gtk.Frame({ + margin_top: 10, + margin_bottom: 10, + margin_start: 10, + margin_end: 10 + }); + this.frame.set_child(this.vbox); + } + + + if (shellMajorVersion < 40) { + this.vbox.pack_start(this.hbox0, true, false, 0); + this.vbox.pack_start(this.hbox1, true, false, 0); + this.vbox.pack_start(this.hbox2, true, false, 0); + this.vbox.pack_start(this.hbox3, true, false, 0); + } else { + this.vbox.append(this.hbox0); + this.vbox.append(this.hbox1); + this.vbox.append(this.hbox2); + this.vbox.append(this.hbox3); + } + } + + /** Enforces child ordering of first 2 boxes by label */ + _reorder() { + if (shellMajorVersion < 40) { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_children) { + return labelOf(el.get_children()[0]); + } + return el && el.label || ''; + }; + [this.hbox0, this.hbox1].forEach(hbox => { + hbox.get_children() + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))) + .forEach((child, index) => hbox.reorder_child(child, index)); + }); + } else { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_label) { + return el.get_label(); + } + return labelOf(el.get_first_child()); + } + + [this.hbox0, this.hbox1].forEach(hbox => { + const children = []; + let next = hbox.get_first_child(); + + while (next !== null) { + children.push(next); + next = next.get_next_sibling(); + } + + const sorted = children + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))); + + sorted + .forEach((child, index) => { + hbox.reorder_child_after(child, sorted[index - 1] || null); + }); + }); + } + } + + add(key) { + const configParent = key.substring(0, key.indexOf('-')); + const config = key.substring(configParent.length + 1); + + // hbox0 + if (config === 'display') { + let item = new Gtk.CheckButton({label: _('Display')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-text') { + let item = new Gtk.CheckButton({label: _('Show Text')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-menu') { + let item = new Gtk.CheckButton({label: _('Show In Menu')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox1 + } else if (config === 'refresh-time') { + let item = new IntSelect(_('Refresh Time')); + item.set_args(50, 100000, 1000, 5000); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'graph-width') { + let item = new IntSelect(_('Graph Width')); + item.set_args(1, 1000, 1, 10); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'style') { + let item = new Select(_('Display Style')); + item.add([_('digit'), _('graph'), _('both')]); + item.set_value(this.schema.get_enum(key)); + this.hbox1.add(item.actor); + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + // Schema.bind(key, item.selector, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox2 + } else if (config.match(/-color$/)) { + let item = new ColorSelect(_(config.split('-')[0].capitalize())); + item.set_value(this.schema.get_string(key)); + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else if (config.match(/sensor/)) { + let sensor_type = configParent === 'fan' ? 'fan' : 'temp'; + let [_slist, _strlist] = check_sensors(sensor_type); + let item = new Select(_('Sensor')); + if (_slist.length === 0) { + item.add([_('Please install lm-sensors')]); + } else if (_slist.length === 1) { + this.schema.set_string(key, _slist[0]); + } + item.add(_strlist); + try { + item.set_value(_slist.indexOf(this.schema.get_string(key))); + } catch (e) { + item.set_value(0); + } + // this.hbox3.add(item.actor); + if (configParent === 'fan') { + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + } else if (shellMajorVersion < 40) { + this.hbox2.pack_start(item.actor, true, false, 0); + } else { + this.hbox2.prepend(item.actor); + } + item.selector.connect('changed', function (combo) { + set_string(combo, Schema, key, _slist); + }); + // hbox3 + } else if (config === 'speed-in-bits') { + let item = new Gtk.CheckButton({label: _('Show network speed in bits')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'individual-cores') { + let item = new Gtk.CheckButton({label: _('Display Individual Cores')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'time') { + let item = new Gtk.CheckButton({label: _('Show Time Remaining')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'hidesystem') { + let item = new Gtk.CheckButton({label: _('Hide System Icon')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'usage-style') { + let item = new Select(_('Usage Style')); + item.add([_('pie'), _('bar'), _('none')]); + item.set_value(this.schema.get_enum(key)); + if (shellMajorVersion < 40) { + this.hbox3.pack_end(item.actor, false, false, 20); + } else { + this.hbox3.append(item.actor); + } + + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + } else if (config === 'fahrenheit-unit') { + let item = new Gtk.CheckButton({label: _('Display temperature in Fahrenheit')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'threshold') { + let item = new IntSelect(_('Temperature threshold (0 to disable)')); + item.set_args(0, 300, 5, 5); + this.hbox3.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } + if (configParent.indexOf('gpu') !== -1 && + config === 'display') { + let item = new Gtk.Label({label: _('** Only Nvidia GPUs supported so far **')}); + this.hbox3.add(item); + } + this._reorder(); + } +} + +const App = class SystemMonitor_App { + constructor() { + let setting_items = ['cpu', 'memory', 'swap', 'net', 'disk', 'gpu', 'thermal', 'fan', 'freq', 'battery']; + let keys = Schema.list_keys(); + + this.items = []; + this.settings = []; + + setting_items.forEach((setting) => { + this.settings[setting] = new SettingFrame(_(setting.capitalize()), Schema); + }); + + this.main_vbox = box({ + hasBorder: true, horizontal: false, spacing: 10}); + this.hbox1 = box({ + hasBorder: true, horizontal: true, shouldPack: true, spacing: 20}); + if (shellMajorVersion < 40) { + this.main_vbox.pack_start(this.hbox1, false, false, 0); + } else { + this.main_vbox.prepend(this.hbox1); + } + + keys.forEach((key) => { + if (key === 'icon-display') { + let item = new Gtk.CheckButton({label: _('Display Icon')}); + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'center-display') { + let item = new Gtk.CheckButton({label: _('Display in the Middle')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'compact-display') { + let item = new Gtk.CheckButton({label: _('Compact Display')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'show-tooltip') { + let item = new Gtk.CheckButton({label: _('Show tooltip')}) + item.set_active(Schema.get_boolean(key)) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'move-clock') { + let item = new Gtk.CheckButton({label: _('Move the clock')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'background') { + let item = new ColorSelect(_('Background Color')) + item.set_value(Schema.get_string(key)) + this.items.push(item) + if (shellMajorVersion < 40) { + this.hbox1.pack_start(item.actor, true, false, 0) + } else { + this.hbox1.prepend(item.actor) + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else { + let sections = key.split('-'); + if (setting_items.indexOf(sections[0]) >= 0) { + this.settings[sections[0]].add(key); + } + } + }); + this.notebook = new Gtk.Notebook() + setting_items.forEach((setting) => { + this.notebook.append_page(this.settings[setting].frame, this.settings[setting].label) + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + this.main_vbox.pack_start(this.notebook, true, true, 0) + } else { + this.main_vbox.append(this.notebook); + } + }); + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + } + } +} + +function buildPrefsWidget() { + let widget = new App(); + return widget.main_vbox; +} diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled new file mode 100644 index 0000000..aeef9ca Binary files /dev/null and b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml new file mode 100644 index 0000000..6247263 --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + true + Display system monitor icon + Set to true to display system monitor icon in status bar.(NOTICE: The icon will be shown when none of the others is shown.) + + + true + Display memory + Set to false to remove memory display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refresh of memory + + + 100 + Memory graph width + Graph width in pixel + + + true + Display 'mem' + Set to true to show 'mem' before memory display + + + true + Display Memory In Menu + Set to true to show memory in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display swap + Set to false to remove swap display in status bar + + + 5000 + Swap refresh time + Time in ms between 2 refresh of swap + + + 100 + Swap graph width + Graph width in pixel + + + true + Display 'swap' + Set to true to show 'swap' before swap display + + + true + Display Swap In Menu + Set to true to show swap in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display cpu + Set to false to remove cpu display in status bar + + + 1500 + Cpu refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu graph width + Graph width in pixel + + + true + Display 'cpu' + Set to true to show 'cpu' before cpu display + + + true + Display Cpu In Menu + Set to true to show cpu in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display one graph per cpu core + Set to true to display one graph per cpu core + + + false + Display GPU usage + Set to false to remove GPU display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refreshes of GPU usage + + + 100 + GPU usage graph width + Graph width in pixel + + + true + Display 'gpu' + Set to true to show 'gpu' before GPU display + + + false + Display GPU In Menu + Set to true to show GPU in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display freq + Set to false to remove freq display in status bar + + + 1500 + Cpu frequency refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu frequency graph width + Graph width in pixel + + + false + Display freq' + Set to true to show 'freq' before cpu frequency display + + + false + Display Freq In Menu + Set to true to show freq in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display net + Set to false to remove net display in status bar + + + 1000 + Net refresh time + Time in ms between 2 refresh of net + + + 100 + Net graph width + Graph width in pixel + + + true + Display 'net' + Set to true to show 'net' before net display + + + true + Display Net In Menu + Set to true to show net in pop-up menu + + + 'graph' + Choose the display style. + + + false + Show network speed in bits/sec + + + false + Display disk io speed + Set to false to remove disk display in status bar + + + 2000 + Disk IO refresh time + Time in ms between 2 refresh of Disk IO + + + 100 + Disk IO graph width + Graph width in pixel + + + true + Display 'disk' + Set to true to show 'disk' before disk io display + + + true + Display Disk In Menu + Set to true to show disk in pop-up menu + + + 'graph' + Choose the display style. + + + 'pie' + Choose the disk usage display style. + + + false + Display thermal + Set to false to remove thermal display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'thermal' + Set to true to show 'thermal' before thermal display + + + true + Display Temps In Menu + Set to true to show thermal in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/thermal_zone0/temp' + Sensor File + Location of the sensor file for cpu temp + + + 0 + Thermal threshold + When the temprature passes the threshold, the text is set to red as an alert. + + + false + Display fan + Set to false to remove fan display in status bar + + + 5000 + fan refresh time + Time in ms between 2 refresh of fan + + + 100 + fan graph width + Graph width in pixel + + + true + Display 'fan' + Set to true to show 'fan' before fan display + + + true + Display Fans In Menu + Set to true to show fan in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/cooling_device0/cur_state' + Sensor File + Location of the sensor file for fan + + + '#f2002e' + Color of fan in the chart + + + false + Display informations next to the clock + True: Set information at the center, False: Set information in status bar (at top right) + + + false + Move the clock to the right when center-display is true + True: Move the clock to the right, False: Keep it in center + + + false + Enable or disable the tooltip + True: show tool tip on mouse hover + + + false + Optimize view for small displays + Optimize texts sizes to fit on a small display + + + '#00b35b' + Color of program memory in the chart + + + '#00ff82' + Color of buffer memory in the chart + + + '#aaf5d0' + Color of cache memory in the chart + + + '#fce94f' + Color of download speed in the chart + + + '#fb74fb' + Color of upload speed in the chart + + + '#ff6e00' + Color of download errors + + + '#e0006e' + Color of upload errors + + + '#ff0000' + Color of collisions + + + '#0072b3' + Color of user cpu in the chart + + + '#0092e6' + Color of system cpu in the chart + + + '#00a3ff' + Color of nice cpu in the chart + + + '#002f3d' + Color of iowait in the chart + + + '#001d26' + Color of other cpu in the chart + + + '#001d26' + Color of freq in the chart + + + '#8b00c3' + Color of used swap in the chart + + + '#c65000' + Color of disk reading speed in the chart + + + '#ff6700' + Color of disk writing speed in the chart + + + '#00b35b' + Color of program GPU usage in the chart + + + '#00ff82' + Color of program GPU memory in the chart + + + '#f2002e' + Color of user thermal in the chart + + + false + Display temperature in Fahrenheit + Set to true to show temperature in Fahrenheit + + + '#ffffff16' + Color of background + + + false + Display battery + Set to false to remove battery display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'batt' + Set to true to show 'batt' before net display + + + false + Display 'batt' + Set to true to show battery in pop-up menu + + + 'digit' + Choose the display style. + + + '#f2002e' + Color of battery + + + false + Display battery time remaining rather than percentage + + + false + Hide system battery icon + + + + diff --git a/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css new file mode 100644 index 0000000..5f7120e --- /dev/null +++ b/UIDev/ansibleshed/Packages/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css @@ -0,0 +1,204 @@ +.sm-title { + font-size: 1em; + padding: 0px 25px 0px 0px; +} + +.sm-label { + color: #bbb; + font-size: 0.75em; + padding-top: 5px; + font-family: monospace; +} + +.sm-label-left { + color: #bbb; + font-size: 0.75em; + padding: 5px 5px 0 0; +} + +.sm-value { + text-align: right; + min-width: 40px; + padding: 2px 5px 0 0; + font-family: monospace; +} + +.sm-status-label { + color: #bbb; + font-size: 0.625em; + padding: 0 2px 0 5px; +} + +.sm-unit-label, +.sm-net-unit-label { + color: #aaa; + font-size: 0.5em; + padding: 0 5px 0 2px; +} + +.sm-disk-unit-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-net-unit-label { + min-width: 25px; +} + +.sm-perc-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-temp-label { + color: #aaa; + font-size: 0.6875em; + padding: 0 5px 0 2px; +} + +.sm-status-value { + min-width: 25px; + text-align: right; +} + +.sm-net-value { + min-width: 40px; + text-align: center; +} + +.sm-disk-value { + min-width: 25px; + text-align: right; +} + +.sm-big-status-value { + min-width: 42px; + text-align: right; +} + +.sm-chart { + padding: 0 2px; +} + +.sm-tooltip-box { + font-size: 0.85em; + font-weight: bold; + color: rgba(255, 255, 255, 0.9); + background-color: rgba(10, 10, 10, 0.7); + border-radius: 5px; + padding: 3px; + border: 1px solid #a5a5a5; +} + +.sm-tooltip-item { + padding: 0px; + spacing: 10px; +} +.sm-status-icon { + padding: 0px 2px; + icon-size: 1.14em; +} + +.sm-popup-menu-item-compact { +} + +/* style definition when 'compact-display' option is activated */ + +.sm-title-compact { + font-size: 0.75em; +} + +.sm-label-compact { + color: #bbb; + font-size: 0.6875em; + font-family: monospace; +} /* Bat, Net... units in menu items */ + +.sm-value-compact { + font-size: 0.6875em; + text-align: right; + font-family: monospace; +} /* Values in menu items */ + +.sm-status-label-compact { + color: #bbb; + font-size: 0.5em; + padding: 2px 0px 0 0px; +} /* names and Disk R and W signs in text items */ + +.sm-unit-label-compact, +.sm-net-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 1px; + text-align: right; + font-size: 0.4375em; +} /* Bat, Net... units in text items */ + +.sm-disk-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 0px; + text-align: right; + font-size: 0.4375em; +} /* Disk units in text items */ + +.sm-perc-label-compact { + padding: 0 3px 0 0px; + color: #aaa; + font-size: 0.5em; +} /* Cpu, Mem ... % sign in text items */ + +.sm-temp-label-compact { + font-size: 0.625em; + color: #aaa; + padding: 0 1px 0 1px; +} /* Thermal °C sign in text items */ + +.sm-status-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:16px; +} /* Cpu, Mem... value in text items */ + +.sm-net-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:24px; +} /* Net value in text items */ + +.sm-disk-value-compact { + padding: 0 1px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width: 20px; +} /* Disk value in text items */ + +.sm-big-status-value-compact { + padding: 0 0px 0px 1px; + font-size: 0.6875em; + min-width: 38px; + text-align: right; +} /* freq in text_items */ + +.sm-chart-compact { + padding: 0 2px; +} + +.sm-tooltip-item-compact { + padding: 0px; + spacing: 10px; +} + +.sm-status-icon-compact { + padding: 1px 0 0 2px; + icon-size: 1.00em; +} /* BAT icon in text_items */ + +.sm-popup-menu-item-compact { + font-size: 0.6875em; + width: 20px; + padding: 1px 2px 1px 7px; +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path.py b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path.py new file mode 100644 index 0000000..2af9157 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path.py @@ -0,0 +1,4 @@ +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'nautilus-copy-path')) +from nautilus_copy_path import NautilusCopyPath diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/config.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/config.json new file mode 100644 index 0000000..64384f3 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/config.json @@ -0,0 +1,11 @@ +{ + "items": { + "path": true + }, + "selections": { + "clipboard": true, + "primary": true + }, + "language": "auto", + "separator": ", " +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py new file mode 100644 index 0000000..2a0570e --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py @@ -0,0 +1,73 @@ +import os +import json +from translation import Translation +from gi.repository import Nautilus, GObject, Gtk, Gdk +from gi import require_version + +require_version('Gtk', '3.0') +require_version('Nautilus', '3.0') + + +class NautilusCopyPath(Nautilus.MenuProvider, GObject.GObject): + + def __init__(self): + self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + self.clipboard_primary = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY) + + self.config = { + "items": { + "path": True, + }, + "selections": { + "clipboard": True, + "primary": True + }, + "language": "auto", + "separator": ", " + } + + with open(os.path.join(os.path.dirname(__file__), "config.json")) as json_file: + try: + self.config.update(json.load(json_file)) + if self.config["language"]: + Translation.select_language(self.config["language"]) + except: + pass + + def get_file_items(self, window, files): + return self._create_menu_items(files, "File") + + def get_background_items(self, window, file): + return self._create_menu_items([file], "Background") + + def _create_menu_items(self, files, group): + plural = len(files) > 1 + config_items = self.config["items"] + active_items = [] + + if config_items["path"]: + item_path = Nautilus.MenuItem( + name="NautilusCopyPath::CopyPath" + group, + label=Translation.t("copy_paths" if plural else "copy_path"), + ) + item_path.connect("activate", self._copy_paths, files) + active_items.append(item_path) + + return active_items + + def _copy_paths(self, menu, files): + self._copy_value(list(map(lambda f: f.get_location().get_path(), files))) + + def _copy_uris(self, menu, files): + self._copy_value(list(map(lambda f: f.get_uri(), files))) + + def _copy_names(self, menu, files): + self._copy_value(list(map(lambda x: os.path.basename(x.get_location().get_path()), files))) + + def _copy_value(self, value): + if len(value) > 0: + new_value = self.config["separator"].join(value) + if self.config["selections"]["clipboard"]: + self.clipboard.set_text(new_value, -1) + if self.config["selections"]["primary"]: + self.clipboard_primary.set_text(new_value, -1) diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translation.py b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translation.py new file mode 100644 index 0000000..6ee1f26 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translation.py @@ -0,0 +1,52 @@ +import locale +import json +import glob +import os + + +class Translation: + _translations_path = os.path.join(os.path.dirname(__file__), 'translations') + _translations = [] + _default_translations = [] + + @staticmethod + def select_language(lang_code="auto"): + if not lang_code or lang_code == "auto": + default_locale = locale.getdefaultlocale()[0] + try: + lang = default_locale.split("_") + lang_code = lang[0] if len(lang) else "en" + except AttributeError: + lang_code = "en" + + if lang_code in Translation.available_languages(): + Translation.lang_code = lang_code + else: + Translation.lang_code = "en" + + Translation._load_lang(Translation.lang_code) + + @staticmethod + def _load_lang(lang_code): + file_path = Translation._translations_path + '/' + lang_code + ".json" + if os.path.isfile(file_path): + with open(file_path) as json_file: + Translation._translations = json.load(json_file) + + file_path_en = Translation._translations_path + "/en.json" + if os.path.isfile(file_path_en): + with open(file_path_en) as json_file: + Translation._default_translations = json.load(json_file) + + @staticmethod + def available_languages(): + return [os.path.splitext(os.path.basename(x))[0] for x in glob.glob(Translation._translations_path + '/*.json')] + + @staticmethod + def t(translation): + if not Translation._translations: + Translation.select_language() + if translation in Translation._translations: + return Translation._translations[translation] + elif translation in Translation._default_translations: + return Translation._default_translations[translation] diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ar.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ar.json new file mode 100644 index 0000000..6bb6c71 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ar.json @@ -0,0 +1,8 @@ +{ + "copy_path": "نسخ مسار الملف", + "copy_paths": "نسخ مسارات الملفات", + "copy_name": "نسخ اسم الملف", + "copy_names": "نسخ اسماء الملفات", + "copy_uri": "نسخ معرّف المصادر الموحد", + "copy_uris": "نسخ معرفي المصادر الموحدة" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/da.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/da.json new file mode 100644 index 0000000..50e3498 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/da.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiér sti", + "copy_paths": "Kopiér stier", + "copy_name": "Kopiér navn", + "copy_names": "Kopiér navne", + "copy_uri": "Kopiér URI", + "copy_uris": "Kopiér URIer" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/de.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/de.json new file mode 100644 index 0000000..1e49c74 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/de.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Pfad kopieren", + "copy_paths": "Pfade kopieren", + "copy_name": "Name kopieren", + "copy_names": "Namen kopieren", + "copy_uri": "URI kopieren", + "copy_uris": "URIs kopieren" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/el.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/el.json new file mode 100644 index 0000000..d11cdbe --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/el.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Αντιγραφή Διαδρομής", + "copy_paths": "Αντιγραφή Διαδρομών", + "copy_name": "Αντιγραφή Ονόματος", + "copy_names": "Αντιγραφή Ονομάτων", + "copy_uri": "Αντιγραφή URI", + "copy_uris": "Αντιγραφή URIs" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/en.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/en.json new file mode 100644 index 0000000..d0b7a3b --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/en.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copy Path", + "copy_paths": "Copy Paths", + "copy_name": "Copy Name", + "copy_names": "Copy Names", + "copy_uri": "Copy URI", + "copy_uris": "Copy URIs" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/es.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/es.json new file mode 100644 index 0000000..5b12ffe --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/es.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiar ruta", + "copy_paths": "Copiar rutas", + "copy_name": "Copiar nombre", + "copy_names": "Copiar nombres" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/fr.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/fr.json new file mode 100644 index 0000000..d98d1ad --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/fr.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copier le chemin", + "copy_paths": "Copier les chemins", + "copy_name": "Copier le nom", + "copy_names": "Copier les noms" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/it.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/it.json new file mode 100644 index 0000000..8a31219 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/it.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copia Percorso", + "copy_paths": "Copia Percorsi", + "copy_name": "Copia Nome", + "copy_names": "Copia Nomi" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ja.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ja.json new file mode 100644 index 0000000..664f124 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ja.json @@ -0,0 +1,8 @@ +{ + "copy_path": "パスをコピー", + "copy_paths": "パスをコピー", + "copy_name": "ファイル名をコピー", + "copy_names": "ファイル名をコピー", + "copy_uri": "URIをコピー", + "copy_uris": "URIをコピー" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/no.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/no.json new file mode 100644 index 0000000..2965771 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/no.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopier sti", + "copy_paths": "Kopier stier", + "copy_name": "Kopier navn", + "copy_names": "Kopier navn", + "copy_uri": "Kopier URI", + "copy_uris": "Kopier URIer" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pl.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pl.json new file mode 100644 index 0000000..45830ad --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pl.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Skopiuj ścieżkę", + "copy_paths": "Skopiuj ścieżki", + "copy_name": "Skopiuj nazwę", + "copy_names": "Skopiuj nazwy", + "copy_uri": "Skopiuj URI", + "copy_uris": "Skopiuj URI" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pt.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pt.json new file mode 100644 index 0000000..dd7aed4 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/pt.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copiar endereço", + "copy_paths": "Copiar endereços", + "copy_name": "Copiar nome", + "copy_names": "Copiar nomes", + "copy_uri": "Copiar URI", + "copy_uris": "Copiar URIs" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ro.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ro.json new file mode 100644 index 0000000..47327a6 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ro.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiază locația", + "copy_paths": "Copiază locațiile", + "copy_name": "Copiază nume", + "copy_names": "Copiază numele" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ru.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ru.json new file mode 100644 index 0000000..7a0ca43 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/ru.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Скопировать путь", + "copy_paths": "Скопировать пути", + "copy_name": "Скопировать имя", + "copy_names": "Скопировать имена", + "copy_uri": "Скопировать URI", + "copy_uris": "Скопировать URIs" +} diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/se.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/se.json new file mode 100644 index 0000000..f9ac706 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/se.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiera stig", + "copy_paths": "Kopiera stigar", + "copy_name": "Kopiera namn", + "copy_names": "Kopiera namn", + "copy_uri": "Kopiera URI", + "copy_uris": "Kopiera URIer" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/tr.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/tr.json new file mode 100644 index 0000000..a0aead1 --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/tr.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Yolu Kopyala", + "copy_paths": "Yolları Kopyala", + "copy_name": "İsmi Kopyala", + "copy_names": "İsimleri Kopyala", + "copy_uri": "URI'yi Kopyala", + "copy_uris": "URI'leri Kopyala" + } \ No newline at end of file diff --git a/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/zh.json b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/zh.json new file mode 100644 index 0000000..a534d3e --- /dev/null +++ b/UIDev/ansibleshed/Packages/nautilus-extensions/nautilus-copy-path/translations/zh.json @@ -0,0 +1,8 @@ +{ + "copy_path": "复制路径", + "copy_paths": "复制各个路径", + "copy_name": "复制文件名", + "copy_names": "复制各个文件名", + "copy_uri": "复制URI", + "copy_uris": "复制各个URI" +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/COPYING b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/COPYING new file mode 100644 index 0000000..0cf672a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/README.md b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/README.md new file mode 100644 index 0000000..a81ec23 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/README.md @@ -0,0 +1,148 @@ +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_WideBanner.png) + +----- + +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_Banner.png) + +----- + +### Introduction + +ArcMenu is an application menu for GNOME Shell, designed to provide a more traditional user experience and workflow. This extension has many features, including multiple menu layout styles, GNOME search, quick access to system shorctus, and more! If you are a new user to GNOME and are looking for a Windows style start menu, this extension will be perfect for you! + +**For ArcMenu to work properly, you may need [these dependencies](https://gitlab.com/arcmenu/ArcMenu/-/wikis/ArcMenu-Dependencies).** + +----- + +### Support ArcMenu + +ArcMenu is provided free of charge. If you enjoy using ArcMenu and wish to help support the project, feel free to use the link below! + +[![Donate via Paypal](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/paypal_donate.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url) + + +----- + +### Installation + +#### To install the most recent official release: Visit ArcMenu on the [Official GNOME Extensions](https://extensions.gnome.org/extension/3628/arcmenu/) website. + +- **To install ArcMenu from source**: Please see the: [Install From Source wiki Guide](https://gitlab.com/arcmenu/ArcMenu/-/wikis/Install-From-Source-Guide). + +

+ + + + +----- + +### Bugs + +Bugs should be reported [here](https://gitlab.com/arcmenu/ArcMenu/issues) on the GitLab issues page. + +When reporting a bug, please provide as much information as you can about the issue and make sure to include your Linux distribution, GNOME Shell version, and ArcMenu version. + +----- + +### Credits: + +**@[AndrewZaech](https://gitlab.com/AndrewZaech) - Current Project Maintainer and Developer** + +**@[AndyC](https://gitlab.com/LinxGem33) - Founder of ArcMenu and former project maintainer** + +**@[lexruee](https://github.com/lexruee) - Former UI/UX Designer | @[Thomas Ingvarsson](https://gitlab.com/tingvarsson) - Former Developer** + +Additional credits: +* The 'ArcMenu' layout design is insipired by the Zorin OS menu extension. +* ArcMenu utilizes various code from GNOME Shell and the GNOME Shell extensions package. +* Borrowed code from Dash-to-Dock's extension 'location.js' file to implement a trash shortcut in ArcMenu. + +----- + +### Contributors: + +#### Thanks to the following people for contributing via pull requests: + +**@[fishears](https://github.com/fishears/Arc-Menu)** | **@[JasonLG1979](https://github.com/JasonLG1979)** | **@[itmitica](https://github.com/itmitica)** | **@[vikaig](https://gitlab.com/vikaig)** | **@[MagneFire](https://gitlab.com/MagneFire)** + +**@[tognee](https://gitlab.com/tognee)** | **@[hlechner](https://gitlab.com/hlechner)** | **@[vanillajonathan](https://gitlab.com/vanillajonathan)** | **@[epskampie](https://gitlab.com/epskampie)** | **@[GnomeBook](https://gitlab.com/GnomeBook)** + +**@[charlesg99](https://github.com/charlesg99)** | **@[harshadgavali](https://gitlab.com/harshadgavali)** | **@[O. Giesmann ](https://gitlab.com/Etamuk)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Bug Fixes: + +**@[JasonLG1979](https://github.com/JasonLG1979)** | **@[lexruee](https://github.com/lexruee/Arc-Menu)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Translators: + +**@[Nilvus](https://gitlab.com/Nilvus) - French** | **@[Etamuk](https://gitlab.com/Etamuk) - German** | **@[alex4401](https://gitlab.com/alex4401) - Polish** | **@[frnogueira](https://gitlab.com/frnogueira), @[Z Bed](https://gitlab.com/zbed) - Brazilian Portuguese** | **@[sigbjokj](https://gitlab.com/sigbjokj), @[sssandum](https://gitlab.com/sssandum) - Norwegian** + + **@[Ivan](https://gitlab.com/vantu5z), @[Ser82-png](https://gitlab.com/Ser82-png) - Russian** | **@[gkkulik](https://gitlab.com/gkkulik) - Silesian** | **@[vikaig](https://gitlab.com/vikaig) - Ukrainian** | **@[jordim](https://gitlab.com/jordim) - Catalan** | **@[aylinux](https://gitlab.com/aylinux) - Turkish** + + +**@[MorganAntonsson](https://gitlab.com/MorganAntonsson) - Swedish** | **@[jiri.doubravsky](https://gitlab.com/jiri.doubravsky), @[panmourovaty ](https://gitlab.com/panmourovaty) - Czech** | **@[juanlucer](https://gitlab.com/juanlucer) - Spanish** | **@[plesry](https://gitlab.com/plesry) - Chinese (Taiwan)** | **@[Vombato](https://gitlab.com/Vombato), @[matguidi](https://gitlab.com/matguidi) - Italian** + +**@[skygmin](https://gitlab.com/skygmin) - Simplified Chinese** | **@[Vistaus](https://gitlab.com/Vistaus), @[vinno97](https://gitlab.com/vinno97) - Dutch** | **@[artnay](https://gitlab.com/artnay) - Finnish** | **@[rimasx](https://gitlab.com/rimasx) - Estonian** | **@[stevendobay](https://gitlab.com/stevendobay) - Hungarian** + +**@[omeritzics](https://gitlab.com/omeritzics) - Hebrew** | **@[prescott66](https://gitlab.com/prescott66) - Slovak** | **@[Mejans](https://gitlab.com/Mejans) - Occitan** | **@[KuroeHanako](https://gitlab.com/KuroeHanako) - Korean** | **@[sayuri](https://gitlab.com/sayuri-) - Sinhalese** + +**@[Latgardi](https://gitlab.com/Latgardi) - Belarusian** + +----- + +### License & Terms + +ArcMenu is available under the terms of the GPL-2.0 license See [`COPYING`](https://gitlab.com/arcmenu/ArcMenu/blob/master/COPYING) for details. + +Most of ArcMenu's image assets including, but not limited to, custom menu button icons, wire frame svgs, and custom settings icons, are created by [LinxGem33](https://gitlab.com/LinxGem33) and licensed under; [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +**Legal disclaimer for brand icons and trademarks:** + +*" All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer. "* + +

+Read More... + +

+ +* **UBUNTU ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Ubuntu name and Ubuntu logo is a trademark of Canonical ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Ltd. + +* **FEDORA ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Fedora and the Infinity design logo are trademarks of Red Hat, Inc. + +* **DEBIAN ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project. + +* **MANJARO ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - (logo) and name is a trademark of Manjaro GmbH & Co. KG + +* **POP_OS! ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Name and (logo) is a trademark of system 76 ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Inc. + +* **ARCH LINUX ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - The stylized Arch Linux logo are recognised trademarks of Arch Linux, copyright 2002-2017 Judd Vinet and Aaron Griffin + +* **SOLUS** - name and logo is Copyright ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) 2014-2018 by Solus Project + +* **KALI LINUX** - logo and name is part of ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) OffSec Services Limited 2020 + +* **PUREOS** - name and logo is developed by members of the Purism community + +* **RASPBERRY PI** ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) - Logo and name is part of Raspberry Pi Foundation +UK Registered Charity 1129409 + +* **Gentoo Authors![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2001–2020 +Gentoo is a trademark of the Gentoo Foundation, Inc. + +* **Voyager ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Linux** +(name) and (logo) + +* **MXLinux![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2020 - +Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries. + +* **Red Hat, Inc.![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** Copyright 2020 +(name) and (logo) + +* **ZORIN OS** - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd + +

+
+ +----- diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/constants.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/constants.js new file mode 100644 index 0000000..082cb4b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/constants.js @@ -0,0 +1,460 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var SearchbarLocation = { + BOTTOM: 0, + TOP: 1 +} + +var MenuItemLocation = { + BOTTOM: 0, + TOP: 1 +} + +var DisplayType = { + LIST: 0, + GRID: 1, + BUTTON: 2, + SIMPLE_CATEGORY: 3, + SUBMENU_CATEGORY: 4, +} + +var CategoryType = { + FAVORITES: 0, + FREQUENT_APPS: 1, + ALL_PROGRAMS: 2, + PINNED_APPS: 3, + RECENT_FILES: 4, + HOME_SCREEN: 5, + SEARCH_RESULTS: 6, + CATEGORIES_LIST: 7, +}; + +var DefaultMenuView = { + PINNED_APPS: 0, + CATEGORIES_LIST: 1, + FREQUENT_APPS: 2, + ALL_PROGRAMS: 3 +} + +var PrefsVisiblePage = { + MAIN: 0, + MENU_LAYOUT: 1, + BUTTON_APPEARANCE: 2, + LAYOUT_TWEAKS: 3, + ABOUT: 4, + CUSTOMIZE_MENU: 5, + RUNNER_TWEAKS: 6 +} + +var DefaultMenuViewTognee = { + CATEGORIES_LIST: 0, + ALL_PROGRAMS: 1 +} + +var SoftwareManagerIDs = ['org.manjaro.pamac.manager.desktop', 'pamac-manager.desktop', 'io.elementary.appcenter.desktop', + 'snap-store_ubuntu-software.desktop', 'snap-store_snap-store.desktop', 'org.gnome.Software.desktop']; + +var Categories = [ + {CATEGORY: CategoryType.FAVORITES, NAME: _("Favorites"), ICON: 'emblem-favorite-symbolic', FULL_COLOR_ICON: 'emblem-favorite'}, + {CATEGORY: CategoryType.FREQUENT_APPS, NAME: _("Frequent Apps"), ICON: 'user-bookmarks-symbolic', FULL_COLOR_ICON: 'user-bookmarks'}, + {CATEGORY: CategoryType.ALL_PROGRAMS, NAME: _("All Apps"), ICON: 'view-grid-symbolic', FULL_COLOR_ICON: 'view-grid-symbolic'}, + {CATEGORY: CategoryType.PINNED_APPS, NAME: _("Pinned Apps"), ICON: 'view-pin-symbolic', FULL_COLOR_ICON: 'view-pin-symbolic'}, + {CATEGORY: CategoryType.RECENT_FILES, NAME: _("Recent Files"), ICON: 'document-open-recent-symbolic', FULL_COLOR_ICON: 'document-open-recent'} +] + +var ArcMenuPlacement = { + PANEL: 0, + DTP: 1, + DASH: 2 +}; + +var TooltipLocation = { + TOP_CENTERED: 0, + BOTTOM_CENTERED: 1, + BOTTOM: 2, +}; + +var SeparatorAlignment = { + VERTICAL: 0, + HORIZONTAL: 1 +}; + +var SeparatorStyle = { + SHORT: 0, + MEDIUM: 1, + LONG: 2, + MAX: 3, + HEADER_LABEL: 4, + NORMAL: 5, + ALWAYS_SHOW: 6, +}; + +var CaretPosition = { + END: -1, + START: 0, + MIDDLE: 2, +}; + +var CategoryIconType = { + FULL_COLOR: 0, + SYMBOLIC: 1, +} + +var ForcedMenuLocation = { + OFF: 0, + TOP_CENTERED: 1, + BOTTOM_CENTERED: 2, +} + +var IconSize = { + DEFAULT: 0, + EXTRA_SMALL: 1, + SMALL: 2, + MEDIUM: 3, + LARGE: 4, + EXTRA_LARGE: 5, +} + +var GridIconSize = { + DEFAULT: 0, + SMALL: 1, + MEDIUM: 2, + LARGE: 3, + SMALL_RECT: 4, + MEDIUM_RECT: 5, + LARGE_RECT: 6, +}; + +var GridIconInfo = [ + { NAME: 'SmallIconGrid', SIZE: 90, ICON_SIZE: 36, ENUM: GridIconSize.SMALL }, + { NAME: 'MediumIconGrid', SIZE: 97, ICON_SIZE: 42, ENUM: GridIconSize.MEDIUM }, + { NAME: "LargeIconGrid", SIZE: 105, ICON_SIZE: 52, ENUM: GridIconSize.LARGE }, + { NAME: 'SmallRectIconGrid', SIZE: 95, ICON_SIZE: 28, ENUM: GridIconSize.SMALL_RECT }, + { NAME: 'MediumRectIconGrid', SIZE: 102, ICON_SIZE: 34, ENUM: GridIconSize.MEDIUM_RECT }, + { NAME: 'LargeRectIconGrid', SIZE: 105, ICON_SIZE: 42, ENUM: GridIconSize.LARGE_RECT }, +] + +var EXTRA_SMALL_ICON_SIZE = 16; +var SMALL_ICON_SIZE = 20; +var MEDIUM_ICON_SIZE = 25; +var LARGE_ICON_SIZE = 30; +var EXTRA_LARGE_ICON_SIZE = 35; +var MISC_ICON_SIZE = 24; + +var SUPER_L = 'Super_L'; +var SUPER_R = 'Super_R'; +var EMPTY_STRING = ''; + +var HotKey = { + UNDEFINED: 0, + SUPER_L: 1, + CUSTOM: 2, + // Inverse mapping + 0: EMPTY_STRING, + 1: SUPER_L, +}; + +var RunnerHotKey = { + SUPER_L: 0, + CUSTOM: 1, + 0: SUPER_L, +}; + +var HotCornerAction = { + DEFAULT: 0, + DISABLED: 1, + TOGGLE_ARCMENU: 2, + CUSTOM: 3 +} + +var SECTIONS = [ + 'devices', + 'network', + 'bookmarks', +]; + +var MenuPosition = { + LEFT: 0, + CENTER: 1, + RIGHT: 2 +}; + +var RavenPosition = { + LEFT: 0, + RIGHT: 1 +}; + +var DiaglogType = { + DEFAULT: 0, + OTHER: 1, + APPLICATIONS: 2, + DIRECTORIES: 3 +}; + +var MenuButtonAppearance = { + ICON: 0, + TEXT: 1, + ICON_TEXT: 2, + TEXT_ICON: 3, + NONE: 4 +}; + +var MenuIcon = { + ARC_MENU: 0, + DISTRO_ICON: 1, + CUSTOM: 2 +}; + +var PowerType = { + LOGOUT: 0, + LOCK: 1, + RESTART: 2, + POWER_OFF: 3, + SUSPEND: 4, + HYBRID_SLEEP: 5, + HIBERNATE: 6, +}; + +var SleepIcon = { + PATH: '/media/icons/menu_icons/sleep-symbolic.svg' +}; + +var PowerOptions = [ + { TYPE: PowerType.LOGOUT, IMAGE: 'application-exit-symbolic', TITLE: _("Log Out") }, + { TYPE: PowerType.LOCK, IMAGE: 'changes-prevent-symbolic', TITLE: _("Lock") }, + { TYPE: PowerType.RESTART, IMAGE: 'system-reboot-symbolic', TITLE: _("Restart") }, + { TYPE: PowerType.POWER_OFF, IMAGE: 'system-shutdown-symbolic', TITLE: _("Power Off") }, + { TYPE: PowerType.SUSPEND, IMAGE: 'media-playback-pause-symbolic', TITLE: _("Suspend") }, + { TYPE: PowerType.HYBRID_SLEEP, IMAGE: Me.path + SleepIcon.PATH, TITLE: _("Hybrid Sleep") }, + { TYPE: PowerType.HIBERNATE, IMAGE: 'document-save-symbolic', TITLE: _("Hibernate") }, +]; + +var MenuIcons = [ + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/curved-a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/focus-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sums-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arrow-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/lins-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/search-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/transform-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3d-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/alien-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cloud-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/fly-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pacman-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peaks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pie-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pointer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/toxic-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/tree-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/zegon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/apps-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bug-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cita-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/eclipse-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/heddy-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/helmet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/palette-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peeks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/record-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/saucer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/step-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vancer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vibe-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/start-box-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dolphin-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dota-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/loveheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/rewind-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/snap-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/time-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3D-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bat-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dra-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/equal-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/gnacs-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/groove-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/kaaet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pac-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/robots-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sheild-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/somnia-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/utool-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/swirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/round-symbolic.svg'}, +] + +var DistroIcons = [ + { PATH: 'start-here-symbolic'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg'}, +] + +var MenuLayout = { + ARCMENU: 0, + BRISK: 1, + WHISKER: 2, + GNOME_MENU: 3, + MINT: 4, + ELEMENTARY: 5, + GNOME_OVERVIEW: 6, + SIMPLE: 7, + SIMPLE_2: 8, + REDMOND: 9, + UNITY: 10, + BUDGIE: 11, + INSIDER: 12, + RUNNER: 13, + CHROMEBOOK: 14, + RAVEN: 15, + TOGNEE: 16, + PLASMA: 17, + WINDOWS: 18, + LAUNCHER: 19, + ELEVEN: 20, + AZ: 21, +}; + +var TraditionalMenus = [ + { IMAGE: 'arcmenu-layout-symbolic', TITLE: _('ArcMenu'), LAYOUT: MenuLayout.ARCMENU}, + { IMAGE: 'brisk-layout-symbolic', TITLE: _('Brisk'), LAYOUT: MenuLayout.BRISK}, + { IMAGE: 'whisker-layout-symbolic', TITLE: _('Whisker'), LAYOUT: MenuLayout.WHISKER}, + { IMAGE: 'gnomemenu-layout-symbolic', TITLE: _('GNOME Menu'), LAYOUT: MenuLayout.GNOME_MENU}, + { IMAGE: 'mint-layout-symbolic', TITLE: _('Mint'), LAYOUT: MenuLayout.MINT}, + { IMAGE: 'budgie-layout-symbolic', TITLE: _('Budgie'), LAYOUT: MenuLayout.BUDGIE}]; + +var ModernMenus = [ + { IMAGE: 'unity-layout-symbolic', TITLE: _('Unity'), LAYOUT: MenuLayout.UNITY}, + { IMAGE: 'plasma-layout-symbolic', TITLE: _('Plasma'), LAYOUT: MenuLayout.PLASMA}, + { IMAGE: 'tognee-layout-symbolic', TITLE: _('tognee'), LAYOUT: MenuLayout.TOGNEE}, + { IMAGE: 'insider-layout-symbolic', TITLE: _('Insider'), LAYOUT: MenuLayout.INSIDER}, + { IMAGE: 'redmond-layout-symbolic', TITLE: _('Redmond'), LAYOUT: MenuLayout.REDMOND}, + { IMAGE: 'windows-layout-symbolic', TITLE: _('Windows'), LAYOUT: MenuLayout.WINDOWS}, + { IMAGE: 'eleven-layout-symbolic', TITLE: _('11'), LAYOUT: MenuLayout.ELEVEN}, + { IMAGE: 'az-layout-symbolic', TITLE: _('a.z.'), LAYOUT: MenuLayout.AZ}]; + +var TouchMenus = [ + { IMAGE: 'elementary-layout-symbolic', TITLE: _('Elementary'), LAYOUT: MenuLayout.ELEMENTARY}, + { IMAGE: 'chromebook-layout-symbolic', TITLE: _('Chromebook'), LAYOUT: MenuLayout.CHROMEBOOK}]; + +var LauncherMenus = [ + { IMAGE: 'launcher-layout-symbolic', TITLE: _('Launcher'), LAYOUT: MenuLayout.LAUNCHER}, + { IMAGE: 'runner-layout-symbolic', TITLE: _('Runner'), LAYOUT: MenuLayout.RUNNER}, + { IMAGE: 'gnomeoverview-layout-symbolic', TITLE: _('GNOME Overview'), LAYOUT: MenuLayout.GNOME_OVERVIEW}]; + +var SimpleMenus = [ + { IMAGE: 'simple-layout-symbolic', TITLE: _('Simple'), LAYOUT: MenuLayout.SIMPLE}, + { IMAGE: 'simple2-layout-symbolic', TITLE: _('Simple 2'), LAYOUT: MenuLayout.SIMPLE_2}]; + +var AlternativeMenus = [ + { IMAGE: 'raven-layout-symbolic', TITLE: _('Raven'), LAYOUT: MenuLayout.RAVEN}]; + +var MenuStyles = { + STYLES: [ + { IMAGE: 'traditional-category-symbolic', TITLE: _("Traditional"), MENU_TYPE: TraditionalMenus }, + { IMAGE: 'modern-category-symbolic', TITLE: _("Modern"), MENU_TYPE: ModernMenus }, + { IMAGE: 'touch-category-symbolic', TITLE: _("Touch"), MENU_TYPE: TouchMenus }, + { IMAGE: 'simple-category-symbolic', TITLE: _("Simple"), MENU_TYPE: SimpleMenus }, + { IMAGE: 'launcher-category-symbolic', TITLE: _("Launcher"), MENU_TYPE: LauncherMenus }, + { IMAGE: 'alternative-category-symbolic', TITLE: _("Alternative"), MENU_TYPE: AlternativeMenus } + ] +}; + +var ArcMenuSettingsCommand = 'gnome-extensions prefs arcmenu@arcmenu.com'; + +var HamburgerIcon = { + PATH: '/media/icons/menu_icons/hamburger-symbolic.svg' +}; + +var DistroIconsDisclaimer = '"All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer."'+ + '\n\n• Ubuntu® - Ubuntu name and Ubuntu logo are trademarks of Canonical© Ltd.'+ + '\n\n• Fedora® - Fedora and the Infinity design logo are trademarks of Red Hat, Inc.'+ + '\n\n• Debian® - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project.'+ + '\n\n• Manjaro® - logo and name are trademarks of Manjaro GmbH & Co. KG'+ + '\n\n• Pop_OS!® - logo and name are trademarks of system 76© Inc.'+ + '\n\n• Arch Linux™ - The stylized Arch Linux logo is a recognized trademark of Arch Linux, copyright 2002–2017 Judd Vinet and Aaron Griffin.'+ + '\n\n• openSUSE® - logo and name 2001–2020 SUSE LLC, © 2005–2020 openSUSE Contributors & others.'+ + '\n\n• Raspberry Pi® - logo and name are part of Raspberry Pi Foundation UK Registered Charity 1129409'+ + '\n\n• Kali Linux™ - logo and name are part of © OffSec Services Limited 2020'+ + '\n\n• PureOS - logo and name are developed by members of the Purism community'+ + '\n\n• Solus - logo and name are copyright © 2014–2018 by Solus Project'+ + '\n\n• Gentoo Authors© - 2001–2020 Gentoo is a trademark of the Gentoo Foundation, Inc.'+ + '\n\n• Voyager© Linux - name and logo'+ + '\n\n• MX Linux© - 2020 - Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries.'+ + '\n\n• Red Hat, Inc.© - Copyright 2020 name and logo' + + '\n\n• ZORIN OS - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd'; + +var DEVELOPERS = 'Andrew Zaech @AndrewZaech\nLead Project Developer and Maintainer\t' + + '\n\nLinxGem33 aka Andy C @LinxGem33 - (Inactive)\nArcMenu Founder - Former Maintainer - Former Digital Art Designer'; +var TRANSLATORS = 'Thank you to all translators!\n\n' + + 'For a list of all translators please visit ArcMenu on GitLab'; +var CONTRIBUTORS = 'Thank you to all who contributed to, and/or helped, the developement of ArcMenu!' + +'\n\nFor a list of all contributors please visit ArcMenu on GitLab'; +var ARTWORK = 'LinxGem33 aka Andy C\nWiki Screens, Icons, Wire-Frames, ArcMenu Assets' + + '\n\nAndrew Zaech\nIcons, Wire-Frames'; + +var GNU_SOFTWARE = '' + + 'This program comes with absolutely no warranty.\n' + + 'See the ' + + 'GNU General Public License, version 2 or later for details.' + + ''; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/controller.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/controller.js new file mode 100644 index 0000000..7c35a80 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/controller.js @@ -0,0 +1,749 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Gio, GLib, Gtk, St} = imports.gi; +const Constants = Me.imports.constants; +const Helper = Me.imports.helper; +const Main = imports.ui.main; +const MenuButton = Me.imports.menuButton; +const {StandaloneRunner} = Me.imports.standaloneRunner; +const Utils = Me.imports.utils; + +var MenuSettingsController = class { + constructor(settings, settingsControllers, panel, panelIndex, arcMenuPlacement) { + this._settings = settings; + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this.panel = panel; + this.arcMenuPlacement = arcMenuPlacement; + + global.toggleArcMenu = () => this.toggleMenus(); + + this.currentMonitorIndex = 0; + this._activitiesButton = Main.panel.statusArea.activities; + this.isPrimary = panelIndex === 0 ? true : false; + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel); + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel, panelIndex); + this.menuButtonAdjustedActor = this._menuButton.container; + } + + this._settingsControllers = settingsControllers + + if(this.isPrimary){ + this._menuHotKeybinder = new Helper.MenuHotKeybinder(); + this._keybindingManager = new Helper.KeybindingManager(this._settings); + this._hotCornerManager = new Helper.HotCornerManager(this._settings,() => this.toggleMenus()); + } + this._applySettings(); + } + + // Load and apply the settings from the arc-menu settings + _applySettings() { + if(this.isPrimary){ + this._updateHotCornerManager(); + this._updateHotKeyBinder(); + } + + this._setButtonAppearance(); + this._setButtonText(); + this._setButtonIcon(); + this._setButtonIconSize(); + this._setButtonIconPadding(); + this._configureActivitiesButton(); + } + // Bind the callbacks for handling the settings changes to the event signals + bindSettingsChanges() { + this.settingsChangeIds = [ + this._settings.connect('changed::hot-corners', this._updateHotCornerManager.bind(this)), + this._settings.connect('changed::menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::runner-menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::enable-standlone-runner-menu', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::position-in-panel', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-button-position-offset', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-position-alignment', this._setMenuPositionAlignment.bind(this)), + this._settings.connect('changed::menu-button-appearance', this._setButtonAppearance.bind(this)), + this._settings.connect('changed::custom-menu-button-text', this._setButtonText.bind(this)), + this._settings.connect('changed::menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::distro-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::arc-menu-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon-size', this._setButtonIconSize.bind(this)), + this._settings.connect('changed::button-padding', this._setButtonIconPadding.bind(this)), + this._settings.connect('changed::enable-menu-button-arrow', this._setMenuButtonArrow.bind(this)), + this._settings.connect('changed::enable-custom-arc-menu', this._updateStyle.bind(this)), + this._settings.connect('changed::remove-menu-arrow', this._updateStyle.bind(this)), + this._settings.connect('changed::disable-searchbox-border', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-color', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-text-color', this._updateStyle.bind(this)), + this._settings.connect('changed::directory-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::application-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::disable-recently-installed-apps', this._initiateRecentlyInstalledApps.bind(this)), + this._settings.connect('changed::extra-categories', this._reload.bind(this)), + this._settings.connect('changed::power-options', this._reload.bind(this)), + this._settings.connect('changed::show-external-devices', this._reload.bind(this)), + this._settings.connect('changed::show-bookmarks', this._reload.bind(this)), + this._settings.connect('changed::disable-user-avatar', this._reload.bind(this)), + this._settings.connect('changed::enable-activities-shortcut', this._reload.bind(this)), + this._settings.connect('changed::enable-horizontal-flip', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-bottom-location', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._plasmaMenuReloadTheme.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._reload.bind(this)), + this._settings.connect('changed::multi-lined-labels', this._reload.bind(this)), + this._settings.connect('changed::apps-show-extra-details', this._reload.bind(this)), + this._settings.connect('changed::show-search-result-details', this._reload.bind(this)), + this._settings.connect('changed::search-provider-open-windows', this._reload.bind(this)), + this._settings.connect('changed::search-provider-recent-files', this._reload.bind(this)), + this._settings.connect('changed::disable-scrollview-fade-effect', this._reload.bind(this)), + this._settings.connect('changed::menu-height', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::menu-width-adjustment', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::reload-theme', this._reloadTheme.bind(this)), + this._settings.connect('changed::pinned-app-list',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::brisk-shortcuts-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::windows-disable-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::windows-disable-pinned-apps', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view-tognee',this._reload.bind(this)), + this._settings.connect('changed::alphabetize-all-programs',this._reload.bind(this)), + this._settings.connect('changed::enable-unity-homescreen',this._setDefaultMenuView.bind(this)), + this._settings.connect('changed::menu-layout', this._updateMenuLayout.bind(this)), + this._settings.connect('changed::menu-item-grid-icon-size', this._reload.bind(this)), + this._settings.connect('changed::menu-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::button-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::quicklinks-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::misc-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::runner-position', this.updateLocation.bind(this)), + this._settings.connect('changed::runner-show-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::enable-sub-menus', this._reload.bind(this)), + this._settings.connect('changed::show-activities-button', this._configureActivitiesButton.bind(this)), + this._settings.connect('changed::force-menu-location', this._forceMenuLocation.bind(this)), + this._settings.connect('changed::category-icon-type', this._reload.bind(this)), + this._settings.connect('changed::shortcut-icon-type', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links-location', this._reload.bind(this)), + ]; + } + + _reload(){ + this._menuButton.reload(); + if(this.runnerMenu) + this.runnerMenu.reload(); + } + + _forceMenuLocation(){ + this._menuButton.forceMenuLocation(); + } + + _initiateRecentlyInstalledApps(){ + this._menuButton.initiateRecentlyInstalledApps(); + this._menuButton.reload(); + if(this.runnerMenu){ + this.runnerMenu.initiateRecentlyInstalledApps(); + this.runnerMenu.reload(); + } + } + + _plasmaMenuReloadTheme(){ + if(this._settings.get_enum('menu-layout') === Constants.MenuLayout.PLASMA){ + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this._settings.set_boolean('reload-theme', true); + } + } + + updateLocation(){ + this._menuButton.updateLocation(); + if(this.runnerMenu) + this.runnerMenu.updateLocation(); + } + + _updateMenuLayout(){ + this._menuButton.updateMenuLayout(); + } + + _setDefaultMenuView(){ + this._menuButton.setDefaultMenuView(); + } + + toggleStandaloneRunner(){ + this._closeAllArcMenus(); + if(this.runnerMenu) + this.runnerMenu.toggleMenu(); + } + + toggleMenus(){ + if(this.runnerMenu && this.runnerMenu.arcMenu.isOpen) + this.runnerMenu.toggleMenu(); + if(global.dashToPanel || this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + const MultipleArcMenus = this._settingsControllers.length > 1; + const ShowArcMenuOnPrimaryMonitor = this._settings.get_boolean('hotkey-open-primary-monitor'); + if(MultipleArcMenus && ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.primaryMonitor); + else if(MultipleArcMenus && !ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.currentMonitor); + else + this._menuButton.toggleMenu(); + } + else + this._menuButton.toggleMenu(); + } + + _toggleMenuOnMonitor(monitor){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + let monitorIndex = this._settingsControllers[i].monitorIndex; + if(monitor.index === monitorIndex) + this.currentMonitorIndex = i; + else{ + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + //open the current monitors menu + this._settingsControllers[this.currentMonitorIndex]._menuButton.toggleMenu(); + } + + _closeAllArcMenus(){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + + _reloadTheme(){ + if(this.isPrimary && this._settings.get_boolean('reload-theme')) { + this._settings.reset('reload-theme'); + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(this._settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + menuButton.updateStyle(); + } + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + } + + _updateStyle() { + this._menuButton.updateStyle(); + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + + _updateMenuHeight(){ + this._menuButton.updateHeight(); + } + + _updatePinnedApps(){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadPinnedApps(); + + //If the active category is Pinned Apps, redisplay the new Pinned Apps + const activeCategory = this._menuButton.MenuLayout?.activeCategoryType; + if(!activeCategory) + return; + if(activeCategory === Constants.CategoryType.PINNED_APPS || activeCategory === Constants.CategoryType.HOME_SCREEN) + this._menuButton.displayPinnedApps(); + } + + _updateExtraPinnedApps(){ + let layout = this._settings.get_enum('menu-layout'); + if(layout == Constants.MenuLayout.UNITY || layout == Constants.MenuLayout.MINT || layout == Constants.MenuLayout.BRISK){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadExtraPinnedApps(); + } + } + + _updateHotCornerManager() { + if (this.isPrimary) { + let hotCornerAction = this._settings.get_enum('hot-corners'); + if (hotCornerAction === Constants.HotCornerAction.DEFAULT) { + this._hotCornerManager.restoreDefaultHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.DISABLED) { + this._hotCornerManager.disableHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU) { + this._hotCornerManager.modifyHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.CUSTOM) { + this._hotCornerManager.modifyHotCorners(); + } + } + } + + _updateHotKeyBinder() { + if (this.isPrimary) { + const RunnerHotKey = this._settings.get_enum('runner-menu-hotkey'); + const HotKey = this._settings.get_enum('menu-hotkey'); + const EnableStandaloneRunnerMenu = this._settings.get_boolean('enable-standlone-runner-menu'); + + this._keybindingManager.unbind('ToggleArcMenu'); + this._keybindingManager.unbind('ToggleRunnerMenu'); + this._menuHotKeybinder.disableHotKey(); + this._menuKeyBindingKey = null; + this._runnerKeyBindingKey = null; + + if(EnableStandaloneRunnerMenu){ + if(!this.runnerMenu){ + this.runnerMenu = new StandaloneRunner(this._settings); + this.runnerMenu.initiate(); + } + + if(RunnerHotKey === Constants.RunnerHotKey.CUSTOM){ + this._keybindingManager.bind('ToggleRunnerMenu', 'toggle-runner-menu', () => this._onHotkey(() => this.toggleStandaloneRunner())); + this._runnerKeyBindingKey = this._settings.get_strv('toggle-runner-menu').toString(); + } + else if(RunnerHotKey === Constants.RunnerHotKey.SUPER_L){ + this._menuHotKeybinder.enableHotKey(() => this.toggleStandaloneRunner()); + } + } + else if(this.runnerMenu){ + this.runnerMenu.destroy(); + this.runnerMenu = null; + } + + if(HotKey === Constants.HotKey.CUSTOM){ + this._keybindingManager.bind('ToggleArcMenu', 'toggle-arcmenu', () => this._onHotkey(() => this.toggleMenus())); + this._menuKeyBindingKey = this._settings.get_strv('toggle-arcmenu').toString(); + } + else if(HotKey === Constants.HotKey.SUPER_L){ + this._menuHotKeybinder.disableHotKey(); + this._menuHotKeybinder.enableHotKey(() => this.toggleMenus()); + } + + if(this._menuKeyBindingKey){ + this._menuKeyBindingKey = Gtk.accelerator_parse(this._menuKeyBindingKey)[0]; + } + if(this._runnerKeyBindingKey){ + this._runnerKeyBindingKey = Gtk.accelerator_parse(this._runnerKeyBindingKey)[0]; + } + } + } + + _onHotkey(callback) { + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + callback(); + else + this._onHotkeyRelease(callback); + } + + _onHotkeyRelease(callback) { + let activeMenu = this._settingsControllers[this.currentMonitorIndex]._menuButton.getActiveMenu() || ((this.runnerMenu && this.runnerMenu.arcMenu.isOpen) ? this.runnerMenu.arcMenu : null); + let focusPanel; + + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL) + focusPanel = this.panel; + else + focusPanel = this.panel._allDocks[0].dash; + + let focusTarget = activeMenu ? + (activeMenu.actor || activeMenu) : focusPanel; + + this.disconnectKeyRelease(); + + this.keyInfo = { + pressId: focusTarget.connect('key-press-event', () => this.disconnectKeyRelease()), + releaseId: focusTarget.connect('key-release-event', (actor, event) => { + this.disconnectKeyRelease(); + + if (this._menuKeyBindingKey === event.get_key_symbol()) { + callback(); + } + + if (this._runnerKeyBindingKey === event.get_key_symbol()) { + callback(); + } + }), + target: focusTarget + }; + + focusTarget.grab_key_focus(); + } + + disconnectKeyRelease() { + if (this.keyInfo && this.keyInfo.target) { + this.keyInfo.target.disconnect(this.keyInfo.pressId); + this.keyInfo.target.disconnect(this.keyInfo.releaseId); + this.keyInfo = 0; + } + } + + // Place the menu button to main panel as specified in the settings + _setButtonPosition() { + if (this._isButtonEnabled()) { + this._removeMenuButtonFromMainPanel(); + this._addMenuButtonToMainPanel(); + this._setMenuPositionAlignment(); + } + } + + _setMenuPositionAlignment(){ + this._menuButton.setMenuPositionAlignment(); + } + + // Change the menu button appearance as specified in the settings + _setButtonAppearance() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + this._menuButton.container.set_width(-1); + this._menuButton.container.set_height(-1); + menuButtonWidget.actor.show(); + switch (this._settings.get_enum('menu-button-appearance')) { + case Constants.MenuButtonAppearance.TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.showPanelText(); + break; + case Constants.MenuButtonAppearance.ICON_TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-left: 5px;'); + break; + case Constants.MenuButtonAppearance.TEXT_ICON: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-right: 5px;'); + menuButtonWidget.showPanelIcon(); + break; + case Constants.MenuButtonAppearance.NONE: + menuButtonWidget.actor.hide(); + this._menuButton.container.set_width(0); + this._menuButton.container.set_height(0); + break; + case Constants.MenuButtonAppearance.ICON: /* falls through */ + default: + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + } + this._setMenuButtonArrow(); + } + } + _setMenuButtonArrow() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + if (this._settings.get_boolean('enable-menu-button-arrow')) { + menuButtonWidget.hideArrowIcon(); + menuButtonWidget.showArrowIcon(); + } else { + menuButtonWidget.hideArrowIcon(); + } + } + } + + // Update the text of the menu button as specified in the settings + _setButtonText() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + // Update the text of the menu button + let menuButtonWidget = this._menuButton.menuButtonWidget; + let label = menuButtonWidget.getPanelLabel(); + + let customTextLabel = this._settings.get_string('custom-menu-button-text'); + label.set_text(customTextLabel); + } + } + + // Update the icon of the menu button as specified in the settings + _setButtonIcon() { + let path = this._settings.get_string('custom-menu-button-icon'); + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + + let iconString = Utils.getMenuButtonIcon(this._settings, path); + stIcon.set_gicon(Gio.icon_new_for_string(iconString)); + } + + // Update the icon of the menu button as specified in the settings + _setButtonIconSize() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let size = iconSize; + stIcon.icon_size = size; + } + } + + _setButtonIconPadding() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let padding = this._settings.get_int('button-padding'); + if(padding > -1) + this._menuButton.style = "-natural-hpadding: " + (padding * 2 ) + "px; -minimum-hpadding: " + padding + "px;"; + else + this._menuButton.style = null; + + let parent = this._menuButton.get_parent(); + if(!parent) + return; + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(this._menuButton); + } + + parent.remove_child(this._menuButton); + parent.insert_child_at_index(this._menuButton, actorIndex); + } + } + + // Get the current position of the menu button and its associated position order + _getMenuPosition() { + let offset = this._settings.get_int('menu-button-position-offset'); + switch (this._settings.get_enum('position-in-panel')) { + case Constants.MenuPosition.CENTER: + return [offset, 'center']; + case Constants.MenuPosition.RIGHT: + // get number of childrens in rightBox (without arcmenu) + let n_children = Main.panel._rightBox.get_n_children(); + n_children -= Main.panel.statusArea.ArcMenu !== undefined; + // position where icon should go, + // offset = 0, icon should be last + // offset = 1, icon should be second last + const order = Math.clamp(n_children - offset, 0, n_children); + return [order, 'right']; + case Constants.MenuPosition.LEFT: + default: + return [offset, 'left']; + } + } + + _configureActivitiesButton(){ + let isActivitiesButtonPresent = Main.panel.statusArea.activities && Main.panel.statusArea.activities.container && Main.panel._leftBox.contains(Main.panel.statusArea.activities.container); + let showActivities = this._settings.get_boolean('show-activities-button'); + + let container = Main.panel.statusArea.activities.container; + let parent = container.get_parent(); + let index = 0; + if(this._settings.get_enum('position-in-panel') === Constants.MenuPosition.LEFT && + this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && + this._settings.get_int('menu-button-position-offset') == 0) + index = 1; + + if(showActivities && !isActivitiesButtonPresent){ + parent ? parent.remove_child(container) : null; + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, index); + } + else if(!showActivities && isActivitiesButtonPresent) + Main.panel._leftBox.remove_child(Main.panel.statusArea.activities.container); + } + + // Check if the activities button is present on the main panel + _isActivitiesButtonPresent() { + return (this._activitiesButton && + this._activitiesButton.container && + Main.panel._leftBox.contains(this._activitiesButton.container)); + } + + // Add or restore the activities button on the main panel + _addActivitiesButtonToMainPanel() { + if (!this._isActivitiesButtonPresent()) { + // Retsore the activities button at the default position + let parent = this._activitiesButton.container.get_parent(); + if(!parent) + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, 0); + } + } + + // Add the menu button to the main panel + _addMenuButtonToMainPanel() { + let [position, box] = this._getMenuPosition(); + this.panel.addToStatusArea('ArcMenu', this._menuButton, position, box); + } + + // Remove the menu button from the main panel + _removeMenuButtonFromMainPanel() { + this.panel.menuManager.removeMenu(this._menuButton.arcMenu); + this.panel.menuManager.removeMenu(this._menuButton.arcMenuContextMenu); + this.panel.statusArea['ArcMenu'] = null; + } + + // Enable the menu button + enableButton(index) { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.DASH){ + this.dashIndex = index; + this.reEstablishDash(); + } + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + this._addMenuButtonToMainPanel(); + } + + this._menuButton.initiate(); + } + + reEstablishDash(){ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + if(!DashToDock){ + global.log("ArcMenu Error - Failed to place ArcMenu in Dash-to-Dock"); + return; + } + + const DashContainer = DashToDock._dashContainer; + + DashToDock.arcMenuEnabled = true; + this.oldShowAppsIcon = DashToDock._showAppsIcon; + + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.menuButtonAdjustedActor; + DashContainer.add_child(DashToDock._showAppsIcon); + + this._setButtonIcon(); + const IconSize = DashToDock.iconSize; + this._menuButton.menuButtonWidget.icon.setIconSize(IconSize); + + DashToDock.updateShowAppsButton(); + + this.hoverID = this.menuButtonAdjustedActor.child.connect('notify::hover', () => { + DashToDock._syncLabel(this.menuButtonAdjustedActor, null); + }); + + this.hidingID = Main.overview.connect('hiding', () => { + DashToDock._labelShowing = false; + this.menuButtonAdjustedActor.hideLabel(); + }); + + if(this.isPrimary){ + this.oldDashOnDestroy = this.panel._deleteDocks; + this.panel._deleteDocks = () => { + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + const AllDocks = this.panel._allDocks; + + if(!AllDocks.length) + return; + + AllDocks.forEach(dock => { + let dash = dock.dash; + if(dash._dashContainer.contains(dash._showAppsIcon)) + dash._dashContainer.remove_child(dash._showAppsIcon); + dash._showAppsIcon = this.oldShowAppsIcon; + dash._dashContainer.add_child(dash._showAppsIcon); + dash.arcMenuEnabled = false; + }); + + this.oldDashOnDestroy.call(this.panel, ...arguments); + this.panel._deleteDocks = this.oldDashOnDestroy; + }; + } + } + + _disableButton() { + this._removeMenuButtonFromMainPanel(); + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + + _isButtonEnabled() { + return this.panel.statusArea['ArcMenu'] !== null; + } + + destroy() { + if(this.runnerMenu){ + this.runnerMenu.destroy(); + } + this.settingsChangeIds.forEach(id => this._settings.disconnect(id)); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.panel === null || this.panel._allDocks.length === 0){ + this._menuButton.destroy(); + } + else{ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + const DashContainer = DashToDock._dashContainer; + if(this.panel._allDocks[this.dashIndex] && DashToDock && DashToDock.arcMenuEnabled){ + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + if(this.panel._allDocks[this.dashIndex]){ + DashToDock.arcMenuEnabled = false; + if(DashContainer.contains(DashToDock._showAppsIcon)) + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.oldShowAppsIcon; + DashContainer.add_child(DashToDock._showAppsIcon); + this.panel._deleteDocks = this.oldDashOnDestroy; + DashToDock.updateShowAppsButton(); + } + } + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + } + else if(this.panel == undefined) + this._menuButton.destroy(); + else if (this._isButtonEnabled()) { + this._disableButton(); + } + + if(this.isPrimary){ + this.disconnectKeyRelease(); + this._menuHotKeybinder.destroy(); + this._keybindingManager.destroy(); + this._hotCornerManager.destroy(); + } + this._settings = null; + this._activitiesButton = null; + this._menuButton = null; + delete global.toggleArcMenu; + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/extension.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/extension.js new file mode 100644 index 0000000..d101a31 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/extension.js @@ -0,0 +1,307 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {GLib, Gio, St} = imports.gi; +const Constants = Me.imports.constants; +const Controller = Me.imports.controller; +const Config = imports.misc.config; +const ShellVersion = parseFloat(Config.PACKAGE_VERSION); + +const Main = imports.ui.main; +const Util = imports.misc.util; +const Utils = Me.imports.utils; + +// Initialize panel button variables +let settings; +let settingsControllers; +let extensionChangedId; +let dockToggleID; +let dockExtension; +let enableTimeoutID; + +// Initialize menu language translations +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +// Enable the extension +function enable() { + if (ShellVersion < 3.39 && ShellVersion >= 3.36) + throw new Error(`ArcMenu v${Me.metadata.version} does not work on GNOME Shell version ${ShellVersion}. Please visit https://extensions.gnome.org/extension/3628/arcmenu/ and download ArcMenu v17`); + else if (ShellVersion < 3.36) + throw new Error(`GNOME Shell version ${ShellVersion} is not supported. Please visit https://extensions.gnome.org/extension/1228/arc-menu/ which supports GNOME Shell versions 3.14 - 3.34`); + + enableTimeoutID = GLib.timeout_add(0, 300, () => { + if(imports.gi.Meta.is_wayland_compositor()) + Me.metadata.isWayland = true; + else + Me.metadata.isWayland = false; + + settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + settings.connect('changed::multi-monitor', () => _multiMonitorChanged()); + settings.connect('changed::arc-menu-placement', () => _placementChanged()); + settingsControllers = []; + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + let avaliablePlacementArray = settings.get_default_value('available-placement').deep_unpack(); + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + + _enableButtons(); + + // dash to panel might get enabled after Arc-Menu + extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === 'dash-to-panel@jderose9.github.com') { + _disconnectDtpSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + setAvaliablePlacement(Constants.ArcMenuPlacement.DTP, isEnabled); + + if(isEnabled && (arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP)){ + _connectDtpSignals(); + _enableButtons(); + } + } + + if ((extension.uuid === "dash-to-dock@micxgx.gmail.com" || extension.uuid === "ubuntu-dock@ubuntu.com")) { + _disconnectDtdSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!_getDockExtensions() || !isEnabled) + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, false); + else{ + _connectDtdSignals(); + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, true); + } + _disableButtons(); + _enableButtons(); + } + } + }); + + // listen to dash to panel / dash to dock if they are compatible and already enabled + _connectDtdSignals(); + _connectDtpSignals(); + enableTimeoutID = null; + return GLib.SOURCE_REMOVE; + }); +} + +function disable() { + if(enableTimeoutID){ + GLib.source_remove(enableTimeoutID); + enableTimeoutID = null; + } + if(extensionChangedId){ + Main.extensionManager.disconnect(extensionChangedId); + extensionChangedId = null; + } + + _disconnectDtpSignals(); + _disconnectDtdSignals(); + + _disableButtons(); + settingsControllers = null; + + settings.run_dispose(); + settings = null; +} + +function setAvaliablePlacement(placement, state){ + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + if(avaliablePlacementArray[placement] !== state){ + avaliablePlacementArray[placement] = state; + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + } +} + +function _connectDtpSignals() { + if(global.dashToPanel) + global.dashToPanel._amPanelsCreatedId = global.dashToPanel.connect('panels-created', () => _enableButtons()); +} + +function _disconnectDtpSignals() { + if(global.dashToPanel?._amPanelsCreatedId){ + global.dashToPanel.disconnect(global.dashToPanel._amPanelsCreatedId); + delete global.dashToPanel._amPanelsCreatedId; + } +} + +function _connectDtdSignals(){ + dockExtension = _getDockExtensions(); + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + dockToggleID = dock.connect("toggled",() => { + _disableButtons(); + _enableButtons(); + }); + } +} + +function _disconnectDtdSignals() { + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + if(dock && dockToggleID){ + dock.disconnect(dockToggleID); + dockToggleID = null; + } + } +} + +function _placementChanged() { + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + _disconnectDtdSignals(); + _disconnectDtpSignals(); + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + _connectDtpSignals(); + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + _connectDtdSignals(); + + _disableButtons(); + _enableButtons(); +} + +function _multiMonitorChanged() { + _disableButtons(); + _enableButtons(); +} + +function _getDockExtensions(){ + let dashToDock = Main.extensionManager.lookup("dash-to-dock@micxgx.gmail.com"); + let ubuntuDash = Main.extensionManager.lookup("ubuntu-dock@ubuntu.com"); + let dock; + if(dashToDock?.stateObj?.dockManager) + dock = dashToDock; + if(ubuntuDash?.stateObj?.dockManager) + dock = ubuntuDash; + return dock; +} + +function _enableButtons() { + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = false; + + let multiMonitor = settings.get_boolean('multi-monitor'); + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + dockExtension = _getDockExtensions(); + + if(arcMenuPlacement == Constants.ArcMenuPlacement.DASH && dockExtension){ + avaliablePlacementArray[Constants.ArcMenuPlacement.DASH] = true; + + let dock = dockExtension.stateObj.dockManager; + if(dock?._allDocks.length){ + let docksLength = multiMonitor ? dock._allDocks.length : 1; + for(var index = 0; index < docksLength; index++){ + if(!dock._allDocks[index].dash.arcMenuEnabled){ + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, dock, + index, Constants.ArcMenuPlacement.DASH); + settingsController.monitorIndex = dock._allDocks[index].dash._monitorIndex; + settingsController.enableButton(index); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + } + } + else{ + let isDtPLoaded = false; + let panelArray = [Main.panel]; + if(global.dashToPanel && global.dashToPanel.panels){ + panelArray = global.dashToPanel.panels.map(pw => pw); + isDtPLoaded = true; + } + + let panelLength = multiMonitor ? panelArray.length : 1; + for(var index = 0; index < panelLength; index++){ + let panel = isDtPLoaded ? panelArray[index].panel : panelArray[index]; + let panelParent = panelArray[index]; + + let isPrimaryStandAlone = isDtPLoaded ? ('isPrimary' in panelParent && panelParent.isPrimary) && panelParent.isStandalone : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && isPrimaryStandAlone){ + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + panel = Main.panel; + } + + if(isDtPLoaded) + avaliablePlacementArray[Constants.ArcMenuPlacement.DTP] = true; + else + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + + if (panel.statusArea['ArcMenu']) + continue; + else if (settingsControllers[index]) + _disableButton(settingsControllers[index], 1); + + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, panel, + index, Constants.ArcMenuPlacement.PANEL); + + settingsController.monitorIndex = panelParent.monitor?.index; + + if(isDtPLoaded) + panel._amDestroyId = panel.connect('destroy', () => extensionChangedId ? _disableButton(settingsController, 1) : null); + + settingsController.enableButton(); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + + if(!Utils.getArraysEqual(settings.get_value('available-placement').deep_unpack(), avaliablePlacementArray)) + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); +} + +function _disableButtons(){ + for (let i = settingsControllers.length - 1; i >= 0; --i) { + let sc = settingsControllers[i]; + _disableButton(sc, 1); + } +} + +function _disableButton(controller, remove) { + if(controller.panel._amDestroyId){ + controller.panel.disconnect(controller.panel._amDestroyId); + delete controller.panel._amDestroyId; + } + + controller.destroy(); + + if(remove) + settingsControllers.splice(settingsControllers.indexOf(controller), 1); +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/helper.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/helper.js new file mode 100644 index 0000000..9dbc4d2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/helper.js @@ -0,0 +1,227 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gio, GObject, Gtk, Meta, Shell} = imports.gi; +const Constants = Me.imports.constants; +const Main = imports.ui.main; +const Util = imports.misc.util; + +const MUTTER_SCHEMA = 'org.gnome.mutter'; + +var MenuHotKeybinder = class { + constructor() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + + this._mutterSettings = new Gio.Settings({ 'schema': MUTTER_SCHEMA }); + + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + + this._overlayKeyChangedID = this._mutterSettings.connect('changed::overlay-key', () => { + if(!this._ignoreHotKeyChangedEvent) + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + }); + + this._mainStartUpComplete = Main.layoutManager.connect('startup-complete', () => this._setHotKey()); + } + + enableHotKey(menuToggler){ + this._menuToggler = menuToggler; + + this._ignoreHotKeyChangedEvent = true; + + this._mutterSettings.set_string('overlay-key', Constants.SUPER_L); + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + this.hotKeyEnabled = true; + if(!Main.layoutManager._startingUp) + this._setHotKey(); + this._ignoreHotKeyChangedEvent = false; + } + + disableHotKey(){ + this._ignoreHotKeyChangedEvent = true; + this._mutterSettings.set_value('overlay-key', this._oldOverlayKey); + if(this.overlayKeyID){ + global.display.disconnect(this.overlayKeyID); + this.overlayKeyID = null; + } + if(this.defaultOverlayKeyID){ + GObject.signal_handler_unblock(global.display, this.defaultOverlayKeyID); + this.defaultOverlayKeyID = null; + } + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + } + + _setHotKey(){ + if(this.hotKeyEnabled){ + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + //Find signal ID in Main.js that connects 'overlay-key' to global.display and toggles Main.overview + let [bool,signal_id, detail] = GObject.signal_parse_name('overlay-key', global.display, true); + this.defaultOverlayKeyID = GObject.signal_handler_find(global.display, GObject.SignalMatchType.ID, signal_id, detail, null, null, null); + + //If signal ID found, block it and connect new 'overlay-key' to toggle ArcMenu. + if(this.defaultOverlayKeyID){ + GObject.signal_handler_block(global.display, this.defaultOverlayKeyID); + this.overlayKeyID = global.display.connect('overlay-key', () => { + this._menuToggler(); + }); + } + else + global.log("ArcMenu Error - Failed to set Super_L hotkey"); + } + } + + destroy() { + if(this._overlayKeyChangedID){ + this._mutterSettings.disconnect(this._overlayKeyChangedID); + this._overlayKeyChangedID = null; + } + this.disableHotKey(); + if (this._mainStartUpComplete) { + Main.layoutManager.disconnect(this._mainStartUpComplete); + this._mainStartUpComplete = null; + } + } +}; + +var KeybindingManager = class { + constructor(settings) { + this._settings = settings; + this._keybindings = new Map(); + } + + bind(keybindingNameKey, keybindingValueKey, keybindingHandler) { + if (!this._keybindings.has(keybindingNameKey)) { + this._keybindings.set(keybindingNameKey, keybindingValueKey); + + Main.wm.addKeybinding(keybindingValueKey, ExtensionUtils.getSettings(), + Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP, + keybindingHandler); + } + } + + unbind(keybindingNameKey) { + if (this._keybindings.has(keybindingNameKey)) { + let keybindingValueKey = this._keybindings.get(keybindingNameKey); + Main.wm.removeKeybinding(keybindingValueKey); + this._keybindings.delete(keybindingNameKey); + } + } + + unbindAll() { + this._keybindings.forEach((value, key) => { + Main.wm.removeKeybinding(value); + this._keybindings.delete(key); + }); + } + + destroy() { + this.unbindAll(); + } +}; + +var HotCornerManager = class { + constructor(settings, menuToggler) { + this._settings = settings; + this._menuToggler = menuToggler; + this._hotCornersChangedId = Main.layoutManager.connect('hot-corners-changed', () => this._setCustomHotCorners()); + } + + _setCustomHotCorners() { + let hotCornerAction = this._settings.get_enum('hot-corners'); + + if(hotCornerAction === Constants.HotCornerAction.DISABLED) + this.disableHotCorners(); + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU || hotCornerAction === Constants.HotCornerAction.CUSTOM) + this.modifyHotCorners(); + } + + _getHotCorners() { + return Main.layoutManager.hotCorners; + } + + restoreDefaultHotCorners() { + Main.layoutManager._updateHotCorners(); + } + + disableHotCorners() { + let hotCorners = this._getHotCorners(); + hotCorners.forEach((corner) => { + if(corner){ + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { }; + } + }); + } + + modifyHotCorners() { + let hotCorners = this._getHotCorners(); + let hotCornerAction = this._settings.get_enum('hot-corners'); + + hotCorners.forEach((corner) => { + if (corner) { + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { + corner._pressureBarrier._isTriggered = true; + if(corner._ripples) + corner._ripples.playAnimation(corner._x, corner._y); + else + corner._rippleAnimation(); + if(hotCornerAction == Constants.HotCornerAction.TOGGLE_ARCMENU) + this._menuToggler(); + else if(hotCornerAction == Constants.HotCornerAction.CUSTOM){ + let cmd = this._settings.get_string('custom-hot-corner-cmd'); + if(cmd == "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(cmd == "ArcMenu_RunCommand") + Main.openRunDialog(); + else + Util.spawnCommandLine(this._settings.get_string('custom-hot-corner-cmd')); + } + corner._pressureBarrier._reset(); + }; + } + }); + } + + destroy() { + if (this._hotCornersChangedId>0) { + Main.layoutManager.disconnect(this._hotCornersChangedId); + this._hotCornersChangedId = 0; + } + + this.restoreDefaultHotCorners(); + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f06173f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..11c483b Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9cb7eaf Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..dd97be3 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..178df95 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7018c94 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..c08d48e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..99db3f1 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..b9d0c76 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0d4495f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..6158e6b Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ee7d15e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7b2cd8b Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..04eb49e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..25f1be6 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0f4968c Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..77836ed Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9c35974 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..49572c0 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..95fa04f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8a9f45d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef7005a Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..eb02f6c Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8b0241e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..22605ab Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..151addf Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9f4b060 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..defd162 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f048587 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ac057e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9dc0b4d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef34524 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ce757e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..68ad6a2 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/.keep b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/.keep new file mode 100644 index 0000000..e69de29 diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic.svg new file mode 100644 index 0000000..b0037ad --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg new file mode 100644 index 0000000..b87c15f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg @@ -0,0 +1 @@ + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg new file mode 100644 index 0000000..ba04343 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg new file mode 100644 index 0000000..27aa967 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg @@ -0,0 +1,1412 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg new file mode 100644 index 0000000..43e74e7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg new file mode 100644 index 0000000..7e35c7b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H: 2.5 x + 1/2 x + 1x + 1x + + 1x + + 1x + + + + + + + + + + + H: 2.5 x + + 1/2 x + + 1x + + 1x + + + + 1x + + + + 1x + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic.svg new file mode 100644 index 0000000..985702d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg new file mode 100644 index 0000000..56c7967 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg @@ -0,0 +1,287 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg new file mode 100644 index 0000000..0a1afe7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg @@ -0,0 +1,330 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg new file mode 100644 index 0000000..0687ab4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg @@ -0,0 +1,312 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg new file mode 100644 index 0000000..e26d0b1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg @@ -0,0 +1,328 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg new file mode 100644 index 0000000..2955da8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg new file mode 100644 index 0000000..077fcc7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg @@ -0,0 +1,202 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg new file mode 100644 index 0000000..ff230a7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg @@ -0,0 +1,45 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg new file mode 100644 index 0000000..46b2317 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg @@ -0,0 +1,87 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg new file mode 100644 index 0000000..013cc7c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg @@ -0,0 +1,227 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg new file mode 100644 index 0000000..02caa74 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg @@ -0,0 +1,65 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg new file mode 100644 index 0000000..c969ff2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg new file mode 100644 index 0000000..2eeaae6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg new file mode 100644 index 0000000..447e292 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg new file mode 100644 index 0000000..78c769b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg @@ -0,0 +1,159 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg new file mode 100644 index 0000000..24067fd --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg @@ -0,0 +1,163 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg new file mode 100644 index 0000000..eab2c5c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg new file mode 100644 index 0000000..fc8dd05 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg new file mode 100644 index 0000000..020a8e3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg @@ -0,0 +1,322 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg new file mode 100644 index 0000000..501012f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg @@ -0,0 +1,297 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg new file mode 100644 index 0000000..ba4c27e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg @@ -0,0 +1,290 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg new file mode 100644 index 0000000..1e85ea4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg new file mode 100644 index 0000000..1d75e16 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg new file mode 100644 index 0000000..15e9d51 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg @@ -0,0 +1,76 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg new file mode 100644 index 0000000..49311b4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg new file mode 100644 index 0000000..8a69a7b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg @@ -0,0 +1,384 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg new file mode 100644 index 0000000..47fae59 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg new file mode 100644 index 0000000..e146519 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg @@ -0,0 +1,298 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg new file mode 100644 index 0000000..13d524c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg @@ -0,0 +1,37 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg new file mode 100644 index 0000000..8f94a84 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg @@ -0,0 +1,438 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg new file mode 100644 index 0000000..2d04fcf --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg @@ -0,0 +1,307 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg new file mode 100644 index 0000000..a2e9833 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg @@ -0,0 +1,610 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg new file mode 100644 index 0000000..fae1077 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg @@ -0,0 +1,208 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg new file mode 100644 index 0000000..fdd6224 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg new file mode 100644 index 0000000..5ccb02c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg @@ -0,0 +1,295 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg new file mode 100644 index 0000000..7acd64d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg new file mode 100644 index 0000000..04f57e3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg @@ -0,0 +1,210 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg new file mode 100644 index 0000000..ba1c723 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg @@ -0,0 +1,99 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg new file mode 100644 index 0000000..830e664 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg @@ -0,0 +1,543 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg new file mode 100644 index 0000000..b5219b3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg @@ -0,0 +1,793 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg new file mode 100644 index 0000000..ff813d5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg @@ -0,0 +1,504 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg new file mode 100644 index 0000000..022435a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg new file mode 100644 index 0000000..75ed8b9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg @@ -0,0 +1,392 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg new file mode 100644 index 0000000..f29c05d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg @@ -0,0 +1,86 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg new file mode 100644 index 0000000..ff8584d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg @@ -0,0 +1,52 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets new file mode 100644 index 0000000..f2c8e16 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets @@ -0,0 +1,52 @@ +ArcMenu Style//rgba(53,53,53,0.987)//rgb(223,223,223)//rgb(32,32,32)//rgb(21,83,158)//rgba(255,255,255,1)//rgb(32,32,32)//9//1//5//12//24//false// +Simply Dark//rgba(28, 28, 28, 0.98)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Blue//rgb(25,31,34)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Light Blue//rgb(255,255,255)//rgb(51,51,51)//rgb(235,235,235)//rgba(189,230,251,0.9)//rgba(89,89,89,1)//rgba(189,230,251,0.9)//9//1//5//12//24//true// +Silk Desert//rgba(50,52,73,0.820946)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Breeze//rgb(237,237,243)//rgb(36,36,40)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(36,36,40)//rgb(210,210,215)//9//1//0//0//0//false// +Breeze Dark//rgb(49,53,61)//rgb(237,237,243)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(237,237,243)//rgb(65,69,73)//9//1//0//0//0//false// +Dark Blue 2//rgb(50,52,61)//rgb(211,217,227)//rgba(211,217,227,0.2)//rgb(81,149,226)//rgba(255,255,255,1)//rgba(211,217,227,0.5)//9//1//4//0//0//false// +Dark Orange//rgb(51,51,51)//rgb(226,224,221)//rgba(174,167,159,0.2)//rgb(233,84,32)//rgba(255,255,255,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Light Orange//rgb(246,246,245)//rgb(76,76,76)//rgba(51,51,51,0.2)//rgb(233,84,32)//rgba(114,114,114,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Blue Orange//rgb(44,62,80)//rgb(189,195,199)//rgba(189,195,199,0.2)//rgb(231,76,60)//rgba(227,233,237,1)//rgba(189,195,199,0.5)//9//1//4//0//0//false// +Light Purple//rgb(237,245,252)//rgb(39,45,45)//rgba(39,45,45,0.2)//rgba(144,112,164,0.5)//rgba(77,83,83,1)//rgba(144,112,164,0.5)//9//1//6//0//0//false// +Dark Green//rgb(27,34,36)//rgb(243,243,243)//rgba(46,149,130,0.2)//rgb(46,149,130)//rgba(255,255,255,1)//rgba(46,149,130,0.35)//9//1//6//0//0//true// +Gray//rgb(142,142,142)//rgb(255,255,255)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Terminal Green//rgba(28, 28, 28, 0.98)//rgb(17,164,40)//rgb(63,62,64)//rgba(17,164,40,0.641892)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Sky Clear//rgba(64,145,191,0.756757)//rgb(243,243,243)//rgb(63,62,64)//rgba(135,64,191,0.253378)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Ubi Purple//rgba(174,64,191,0.523649)//rgb(243,243,243)//rgb(63,62,64)//rgba(189,191,64,0.763514)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Shade//rgb(46,52,54)//rgb(186,189,182)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Red Shade//rgba(191,64,74,0.753378)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Tilk Blue//rgba(74,179,228,0.716216)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Green Blue//rgb(87,121,89)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Gray Blue//rgb(136,138,133)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Pastel//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 2//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 3//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 4//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 2//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 3//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 4//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Yellow Shade//rgb(196,160,0)//rgb(46,52,54)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Adapta//rgb(250,251,252)//rgb(34,45,50)//rgb(81,84,86)//rgba(0,150,136,0.121711)//rgba(72,83,88,1)//rgb(0,150,136)//11//0//8//12//24//true// +Adapta Nokto//rgb(38,50,56)//rgb(205,215,218)//rgb(38,50,56)//rgba(125,131,134,0.207237)//rgba(243,253,255,1)//rgb(0,188,212)//11//0//8//12//24//true// +Arc//rgb(245,246,247)//rgb(55,54,68)//rgba(82,148,226,0.903915)//rgba(56,55,68,0.0782918)//rgba(93,92,106,1)//rgb(82,148,226)//11//0//8//12//24//true// +Arc Dark//rgb(56,60,74)//rgb(188,195,205)//rgba(82,148,226,0.903915)//rgba(188,195,205,0.188612)//rgba(226,233,243,1)//rgb(82,148,226)//11//0//8//12//24//true// +Pop!_OS Dark//rgb(69,63,63)//rgb(188,185,183)//rgb(68,61,58)//rgba(250,164,26,0.885135)//rgba(226,223,221,1)//rgb(50,128,138)//11//0//8//12//24//true// +Pop!_OS//rgb(250,251,252)//rgb(87,79,74)//rgba(188,185,183,0.722973)//rgba(250,164,26,0.885135)//rgba(125,117,112,1)//rgb(72,185,199)//11//0//8//12//24//true// +McOS CTLina//rgba(243,243,243,0.841549)//rgb(32,32,32)//rgba(243,243,243,0.841549)//rgb(203,204,207)//rgba(70,70,70,1)//rgb(61,140,248)//11//0//8//12//24//true// +McOS CTLina Dark//rgba(47,47,46,0.873239)//rgb(198,194,194)//rgb(44,45,44)//rgb(37,87,214)//rgba(236,232,232,1)//rgb(37,87,214)//11//0//8//12//24//true// +Android Dark Blue//rgb(63,62,64)//rgb(243,243,243)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(255,255,255,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Blue//rgb(255,255,255)//rgb(63,62,64)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(101,100,102,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Green//rgb(255,255,255)//rgb(63,62,64)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(101,100,102,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Green//rgb(46,52,54)//rgb(243,243,243)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(255,255,255,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Yaru//rgb(46,52,54)//rgb(243,243,243)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(255,255,255,1)//rgb(189,86,53)//11//0//4//12//24//true// +Android Light Yaru//rgb(255,255,255)//rgb(63,62,64)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(101,100,102,1)//rgb(189,86,53)//11//0//4//12//24//true// +Adapta 4k Dark//rgb(49,59,67)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Adapta 4k Light//rgb(255,255,255)//rgb(46,52,54)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(84,90,92,1)//rgb(4,149,90)//11//1//4//12//24//true// +Neon Yellow Punk//rgb(49,59,67)//rgb(237,250,12)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(248,255,109,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Blue//rgba(49,59,67,0.841216)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Jade//rgba(24,81,58,0.875)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Amber//rgba(84,34,18,0.881757)//rgb(243,243,243)//rgb(247,186,36)//rgba(247,186,36,0.472973)//rgba(255,255,255,1)//rgb(247,186,36)//11//1//4//12//24//true// +Elegant Purple Haze//rgba(41,1,31,0.881757)//rgb(243,243,243)//rgba(112,8,67,0.425676)//rgba(112,8,67,0.425676)//rgba(255,255,255,1)//rgb(176,52,139)//11//0//4//12//24//true// diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuButton.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuButton.js new file mode 100644 index 0000000..ba9c387 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuButton.js @@ -0,0 +1,875 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, GObject, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com'; +var DASH_TO_DOCK_UUID = 'dash-to-dock@micxgx.gmail.com'; +var UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +var MenuButton = GObject.registerClass(class Arc_Menu_MenuButton extends PanelMenu.Button{ + _init(settings, arcMenuPlacement, panel, dashIndex) { + super._init(0.5, null, true); + this._settings = settings; + this._panel = panel; + this.menu.destroy(); + this.menu = null; + this.add_style_class_name('arc-menu-panel-menu'); + this.arcMenuPlacement = arcMenuPlacement; + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + let menuManagerParent; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) + menuManagerParent = this._panel; + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + menuManagerParent = this; + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this, 0.5, St.Side.TOP); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.arcMenuContextMenu = new ArcMenuContextMenu(this, 0.5, St.Side.TOP); + this.arcMenuContextMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(menuManagerParent); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + this.menuManager.addMenu(this.arcMenuContextMenu); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this); + this.subMenuManager._changeMenu = (menu) => {}; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget = new MW.MenuButtonWidget(); + this.x_expand = false; + this.y_expand = false; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this._delegate = this; + this.menuButtonWidget = new MW.DashMenuButtonWidget(this, this._settings); + this.dash = this._panel._allDocks[dashIndex]; + this.style_class = 'dash-item-container'; + this.child = this.menuButtonWidget.actor; + this.icon = this.menuButtonWidget.icon; + this.label = this.menuButtonWidget.label; + this.container.showLabel = () => this.menuButtonWidget.showLabel(); + this.container.hideLabel = () => this.menuButtonWidget.hideLabel(); + this.container.toggleButton = this.menuButtonWidget.actor; + this.toggleButton = this.menuButtonWidget.actor; + this.container.setDragApp = () => {}; + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + } + + //Add Menu Button Widget to Button + this.add_child(this.menuButtonWidget.actor); + } + + initiate(){ + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + //Dash to Panel Integration + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 1) { + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.syncWithDashToPanel(); + } + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 2) { + this.dashToPanel = null; + this.arcMenuContextMenu.removeExtensionSettings(); + this.updateArrowSide(St.Side.TOP); + if(this.dtpPostionChangedID>0 && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = 0; + } + } + }); + if(this.dashToPanel && this.dashToPanel.stateObj){ + this.syncWithDashToPanel(); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + //Dash to Dock Integration + this.dtdPostionChangedID = this._panel._settings.connect('changed::dock-position', ()=> { + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side); + }); + } + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => { + this.updateHeight(); + }); + + this._startupCompleteId = Main.layoutManager.connect('startup-complete', () => { + this.updateHeight(); + }); + + this.initiateRecentlyInstalledApps(); + this.setMenuPositionAlignment(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + setDragApp(){ + } + + handleDragOver(source, _actor, _x, _y, _time) { + return imports.ui.dnd.DragMotionResult.NO_DROP; + } + + acceptDrop(source, _actor, _x, _y, _time) { + return false; + } + + syncWithDashToPanel(){ + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + this.extensionSettingsItem = Utils.getSettings('org.gnome.shell.extensions.dash-to-panel', DASH_TO_PANEL_UUID); + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + let dashToPanelPositionSettings = 'panel-positions' + try{ + this.extensionSettingsItem.get_string(dashToPanelPositionSettings); + } catch(e){ + dashToPanelPositionSettings = 'panel-position' + } + this.dtpPostionChangedID = this.extensionSettingsItem.connect('changed::' + dashToPanelPositionSettings, ()=> { + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + }); + if(global.dashToPanel && global.dashToPanel.panels){ + global.dashToPanel.panels.forEach(p => { + if(p.panel === this._panel){ + this.dtpPanel = p; + } + }); + } + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._menuInForcedLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._menuInForcedLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + setMenuPositionAlignment(){ + let layout = this._settings.get_enum('menu-layout'); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + let arrowAlignment = (this._settings.get_int('menu-position-alignment') / 100); + if(layout != Constants.MenuLayout.RUNNER){ + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + this.arcMenu._boxPointer.setSourceAlignment(.5); + } + else if(this.dashToPanel && this.dashToPanel.stateObj){ + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + else{ + this.updateArrowSide(St.Side.TOP, false); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(layout != Constants.MenuLayout.RUNNER){ + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + } + + updateArrowSide(side, setAlignment = true){ + let arrowAlignment; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.updateArrowIconSide(side); + if(side === St.Side.RIGHT || side === St.Side.LEFT) + arrowAlignment = 1.0; + else + arrowAlignment = 0.5; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + arrowAlignment = 0.5; + + this.arcMenuContextMenu._arrowSide = side; + this.arcMenuContextMenu._boxPointer._arrowSide = side; + this.arcMenuContextMenu._boxPointer._userArrowSide = side; + this.arcMenuContextMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenuContextMenu._arrowAlignment = arrowAlignment; + this.arcMenuContextMenu._boxPointer._border.queue_repaint(); + + this.arcMenu._arrowSide = side; + this.arcMenu._boxPointer._arrowSide = side; + this.arcMenu._boxPointer._userArrowSide = side; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = arrowAlignment; + this.arcMenu._boxPointer._border.queue_repaint(); + + if(setAlignment) + this.setMenuPositionAlignment(); + } + + forceMenuLocation(){ + let layout = this._settings.get_enum('menu-layout'); + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + return; + + if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + if(!this._menuInForcedLocation) + return; + this.arcMenu.sourceActor = this; + this.arcMenu.focusActor = this; + this.arcMenu._boxPointer.setPosition(this, 0.5); + this.setMenuPositionAlignment(); + this._menuInForcedLocation = false; + return; + } + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + if(!this.dummyWidget){ + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + } + + if(!this._menuInForcedLocation){ + this.arcMenu.sourceActor = this.dummyWidget; + this.arcMenu.focusActor = this.dummyWidget; + this.arcMenu._boxPointer.setPosition(this.dummyWidget, 0.5); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + this._menuInForcedLocation = true; + } + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let rect = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY; + if(forcedMenuLocation === Constants.ForcedMenuLocation.TOP_CENTERED) + positionY = rect.y + this.rise; + else if(forcedMenuLocation === Constants.ForcedMenuLocation.BOTTOM_CENTERED) + positionY = rect.y + rect.height - this.rise; + this.dummyWidget.set_position(positionX, positionY); + } + + updateStyle(){ + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let layout = this._settings.get_enum('menu-layout'); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let gapAdjustment = this._settings.get_int('gap-adjustment'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + this.arcMenuContextMenu.actor.set_style_class_name(null); + this.arcMenuContextMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenuContextMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(layout === Constants.MenuLayout.RAVEN){ + this.MenuLayout?.updateStyle(); + return; + } + + if(removeMenuArrow){ + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px; -boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = "margin:0px;"; + } + else if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + this.arcMenu.actor.style = "-boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = null; + } + + this.MenuLayout?.updateStyle(); + } + + vfunc_event(event){ + if (event.type() === Clutter.EventType.BUTTON_PRESS){ + if(event.get_button() == 1){ + this.toggleMenu(); + } + else if(event.get_button() == 3){ + this.arcMenuContextMenu.toggle(); + } + } + else if(event.type() === Clutter.EventType.TOUCH_BEGIN){ + this.toggleMenu(); + } + else if(event.type() === Clutter.EventType.ENTER && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + else if(event.type() === Clutter.EventType.LEAVE && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + return Clutter.EVENT_PROPAGATE; + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + this.forceMenuLocation(); + let layout = this._settings.get_enum('menu-layout'); + if(layout === Constants.MenuLayout.GNOME_OVERVIEW){ + if(this._settings.get_boolean('gnome-dash-show-applications')){ + Main.overview._overview._controls._toggleAppsPage(); + } + else + Main.overview.toggle(); + } + else if(!this.arcMenu.isOpen){ + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + this.MenuLayout.updateLocation(); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(this.dtpPanel){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpPanel.intellihide._revealPanel(true); + this.dtpPanel.intellihide.revealAndHold(1); + } + else if(!this.dtpPanel.panelBox.visible){ + this.dtpPanel.panelBox.visible = true; + this.dtpNeedsHiding = true; + } + } + else if(this._panel === Main.panel && !Main.layoutManager.panelBox.visible){ + Main.layoutManager.panelBox.visible = true; + this.mainPanelNeedsHiding = true; + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.dash.getDockState() === 0){ + this.dash._removeAnimations(); + this.dash._animateIn(0, 0); + } + } + this.arcMenu.toggle(); + if(this.arcMenu.isOpen && this.MenuLayout){ + if(this.MenuLayout.activeMenuItem && this.MenuLayout.layoutProperties.SupportsCategoryOnHover) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else if(this.arcMenuContextMenu.isOpen) + return this.arcMenuContextMenu; + else + return null; + } + + toggleArcMenuContextMenu(){ + if(this.arcMenuContextMenu.isOpen) + this.arcMenuContextMenu.toggle(); + } + + updateHeight(){ + let layout = this._settings.get_enum('menu-layout'); + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor); + + if(height > monitorWorkArea.height){ + height = (monitorWorkArea.height * 8) / 10; + } + + if(!(layout == Constants.MenuLayout.SIMPLE || layout == Constants.MenuLayout.SIMPLE_2 || layout == Constants.MenuLayout.RUNNER) && this.MenuLayout) + this.mainBox.style = `height: ${height}px`; + if(this.MenuLayout?.updateWidth) + this.MenuLayout.updateWidth(true); + } + + _onDestroy(){ + if (this._monitorsChangedId){ + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = null; + } + if (this._startupCompleteId){ + Main.layoutManager.disconnect(this._startupCompleteId); + this._startupCompleteId = null; + } + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + if(this.tooltipShowingID){ + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if(this.tooltipHidingID){ + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.extensionChangedId){ + Main.extensionManager.disconnect(this.extensionChangedId); + this.extensionChangedId = null; + } + if(this.dtpPostionChangedID && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = null; + } + if(this.dtdPostionChangedID && this._panel._settings){ + this._panel._settings.disconnect(this.dtdPostionChangedID); + this.dtdPostionChangedID = null; + } + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.arcMenuContextMenu) + this.arcMenuContextMenu.destroy(); + if(this.dummyWidget) + this.dummyWidget.destroy(); + + super._onDestroy(); + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout && this.MenuLayout.updateLocation) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + //Avoid Super L hotkey conflicts with Pop Shell extension by + //setting 'overlay-key' mode to Shell.ActionMode.ALL. + let hotKeyPos = this._settings.get_enum('menu-hotkey'); + if(hotKeyPos === Constants.HotKey.SUPER_L) + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.ALL); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.setActiveStylePseudoClass(true); + this.add_style_pseudo_class('active'); + + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + + if(this.dtpPanel && !this.dtpNeedsRelease){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpNeedsRelease = true; + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.hideLabel(); + if(this.dash._autohideIsEnabled || this.dash._intellihideIsEnabled){ + this.dtdNeedsHiding = true; + this.dash._autohideIsEnabled = false; + this.dash._intellihideIsEnabled = false; + } + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtpPanel && this.dtpNeedsRelease && !this.dtpNeedsHiding){ + this.dtpNeedsRelease = false; + this.dtpPanel.intellihide?.release(1); + } + if(this.dtpPanel && this.dtpNeedsHiding){ + this.dtpNeedsHiding = false; + this.dtpPanel.panelBox.visible = false; + } + if(this.mainPanelNeedsHiding){ + Main.layoutManager.panelBox.visible = false; + this.mainPanelNeedsHiding = false; + } + this.menuButtonWidget.setActiveStylePseudoClass(false); + this.remove_style_pseudo_class('active'); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtdNeedsHiding){ + let dtdSettings = Utils.getSettings('org.gnome.shell.extensions.dash-to-dock', DASH_TO_DOCK_UUID); + if(dtdSettings){ + this.dash._autohideIsEnabled = dtdSettings.get_boolean('autohide'); + this.dash._intellihideIsEnabled = dtdSettings.get_boolean('intellihide'); + } + this.dash._box.sync_hover(); + this.dash._updateDashVisibility(); + this.dtdNeedsHiding = false; + } + + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + if(!this.menuButtonWidget.actor.hover) + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + } + } +}); + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this._menuButton.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this._menuButton.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this._menuButton.contextMenuManager.activeMenu) + this._menuButton.contextMenuManager.activeMenu.toggle(); + if(this._menuButton.subMenuManager.activeMenu) + this._menuButton.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; + +var ArcMenuContextMenu = class Arc_Menu_ArcMenuContextMenu extends PopupMenu.PopupMenu { + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + this.extensionSettingsItem = false; + + this.actor.add_style_class_name('panel-menu'); + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + + this.addMenuItem(this.createQuickLinkItem(_("ArcMenu Settings"), Constants.PrefsVisiblePage.MAIN)); + + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + let item = new PopupMenu.PopupMenuItem(_("Settings Quick Links:"), { + activate: false, + reactive: false + }); + item.add_style_class_name("margin-box arcmenu-menu-item"); + this.addMenuItem(item); + + this.addMenuItem(this.createQuickLinkItem(_("Change Menu Layout"), Constants.PrefsVisiblePage.MENU_LAYOUT)); + this.addMenuItem(this.createQuickLinkItem(_("Layout Tweaks"), Constants.PrefsVisiblePage.LAYOUT_TWEAKS)); + this.addMenuItem(this.createQuickLinkItem(_("Customize Menu"), Constants.PrefsVisiblePage.CUSTOMIZE_MENU)); + this.addMenuItem(this.createQuickLinkItem(_("Button Appearance"), Constants.PrefsVisiblePage.BUTTON_APPEARANCE)); + + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + this.addMenuItem(this.createQuickLinkItem(_("About"), Constants.PrefsVisiblePage.ABOUT)); + } + + addExtensionSettings(arcMenuPlacement){ + if(!this.extensionSettingsItem){ + let extensionCommand, extensionName; + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + extensionName = _("Dash to Panel Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_PANEL_UUID; + } + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + let dashToDock = Main.extensionManager.lookup(DASH_TO_DOCK_UUID); + let ubuntuDash = Main.extensionManager.lookup(UBUNTU_DOCK_UUID); + if(dashToDock && dashToDock.stateObj && dashToDock.stateObj.dockManager){ + extensionName = _("Dash to Dock Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_DOCK_UUID; + } + if(ubuntuDash && ubuntuDash.stateObj && ubuntuDash.stateObj.dockManager){ + extensionName = _("Ubuntu Dock Settings"); + extensionCommand = 'gnome-control-center ubuntu'; + } + } + + let item = new PopupMenu.PopupMenuItem(_(extensionName)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + Util.spawnCommandLine(extensionCommand); + }); + this.addMenuItem(item, 1); + this.extensionSettingsItem = true; + } + } + + removeExtensionSettings(){ + let children = this._getMenuItems(); + children[1].destroy(); + this.extensionSettingsItem = false; + } + + createQuickLinkItem(title, prefsVisiblePage){ + let item = new PopupMenu.PopupMenuItem(_(title)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + this._settings.set_int('prefs-visible-page', prefsVisiblePage); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + }); + return item; + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js new file mode 100644 index 0000000..c38431f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js @@ -0,0 +1,3693 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const {Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Shell, St} = imports.gi; +const AccountsService = imports.gi.AccountsService; +const AppFavorites = imports.ui.appFavorites; +const BoxPointer = imports.ui.boxpointer; +const Constants = Me.imports.constants; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const _SystemActions = imports.misc.systemActions; +const SystemActions = _SystemActions.getDefault(); +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; +const { loadInterfaceXML } = imports.misc.fileUtils; + +const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration'); +const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface); + +Gio._promisify(Gio._LocalFilePrototype, 'query_info_async', 'query_info_finish'); +Gio._promisify(Gio._LocalFilePrototype, 'set_attributes_async', 'set_attributes_finish'); + +const INDICATOR_ICON_SIZE = 18; +const USER_AVATAR_SIZE = 28; + +function activatePowerOption(powerType, arcMenu){ + arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + if(powerType === Constants.PowerType.POWER_OFF) + SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.RESTART) + SystemActions.activateRestart ? SystemActions.activateRestart() : SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.LOCK) + SystemActions.activateLockScreen(); + else if(powerType === Constants.PowerType.LOGOUT) + SystemActions.activateLogout(); + else if(powerType === Constants.PowerType.SUSPEND) + SystemActions.activateSuspend(); + else if(powerType === Constants.PowerType.HYBRID_SLEEP) + Utils.activateHybridSleep(); + else if(powerType === Constants.PowerType.HIBERNATE) + Utils.activateHibernate(); +} + +var ApplicationContextItems = GObject.registerClass({ + Signals: { + 'close-context-menu': { }, + }, + +}, class Arc_Menu_ApplicationContextItems extends St.BoxLayout{ + _init(actor, app, menuLayout){ + super._init({ + vertical: true, + x_expand: true, + y_expand: true, + style_class: 'margin-box', + }); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.sourceActor = actor; + this.layout = this._settings.get_enum('menu-layout'); + + this.discreteGpuAvailable = false; + this._switcherooNotifyId = global.connect('notify::switcheroo-control', + () => this._updateDiscreteGpuAvailable()); + this._updateDiscreteGpuAvailable(); + } + + set path(path){ + this._path = path; + } + + _updateDiscreteGpuAvailable() { + this._switcherooProxy = global.get_switcheroo_control(); + if (this._switcherooProxy) { + let prop = this._switcherooProxy.get_cached_property('HasDualGpu'); + this.discreteGpuAvailable = prop?.unpack() ?? false; + } else { + this.discreteGpuAvailable = false; + } + } + + closeMenus(){ + this.close(); + this._menuLayout.arcMenu.toggle(); + } + + close(){ + this.emit('close-context-menu'); + } + + rebuildItems(){ + this.destroy_all_children(); + if(this._app instanceof Shell.App){ + this.appInfo = this._app.get_app_info(); + let actions = this.appInfo.list_actions(); + + let windows = this._app.get_windows().filter( + w => !w.skip_taskbar + ); + + if (windows.length > 0){ + let item = new PopupMenu.PopupMenuItem(_("Current Windows:"), { + reactive: false, + can_focus: false + }); + item.actor.add_style_class_name('inactive'); + this.add_child(item); + + windows.forEach(window => { + let title = window.title ? window.title + : this._app.get_name(); + let item = this._appendMenuItem(title); + item.connect('activate', () => { + this.closeMenus(); + Main.activateWindow(window); + }); + }); + this._appendSeparator(); + } + + if (!this._app.is_window_backed()) { + if (this._app.can_open_new_window() && !actions.includes('new-window')) { + let newWindowItem = this._appendMenuItem(_("New Window")); + newWindowItem.connect('activate', () => { + this.closeMenus(); + this._app.open_new_window(-1); + }); + } + if (this.discreteGpuAvailable && this._app.state == Shell.AppState.STOPPED) { + const appPrefersNonDefaultGPU = this.appInfo.get_boolean('PrefersNonDefaultGPU'); + const gpuPref = appPrefersNonDefaultGPU + ? Shell.AppLaunchGpu.DEFAULT + : Shell.AppLaunchGpu.DISCRETE; + + this._onGpuMenuItem = this._appendMenuItem(appPrefersNonDefaultGPU + ? _('Launch using Integrated Graphics Card') + : _('Launch using Discrete Graphics Card')); + + this._onGpuMenuItem.connect('activate', () => { + this.closeMenus(); + this._app.launch(0, -1, gpuPref); + }); + } + + for (let i = 0; i < actions.length; i++) { + let action = actions[i]; + let item; + if(action === "empty-trash-inactive"){ + item = new PopupMenu.PopupMenuItem(this.appInfo.get_action_name(action), {reactive:false, can_focus:false}); + item.actor.add_style_class_name('inactive'); + this._appendSeparator(); + this.add_child(item); + } + else if(action === "empty-trash"){ + this._appendSeparator(); + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + else{ + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + + item.connect('activate', (emitter, event) => { + this.closeMenus(); + this._app.launch_action(action, event.get_time(), -1); + }); + } + + //If Trash Can, we don't want to add the rest of the entries below. + if(this.appInfo.get_string('Id') === "ArcMenu_Trash") + return false; + + let desktopIcons = Main.extensionManager.lookup("desktop-icons@csoriano"); + let desktopIconsNG = Main.extensionManager.lookup("ding@rastersoft.com"); + if((desktopIcons && desktopIcons.stateObj) || (desktopIconsNG && desktopIconsNG.stateObj)){ + this._appendSeparator(); + let fileDestination = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP); + let src = Gio.File.new_for_path(this.appInfo.get_filename()); + let dst = Gio.File.new_for_path(GLib.build_filenamev([fileDestination, src.get_basename()])); + let exists = dst.query_exists(null); + if(exists) { + let item = this._appendMenuItem(_("Delete Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + dst.delete(null); + } catch (e) { + log(`Failed to delete shortcut: ${e.message}`); + } + } + this.close(); + }); + } + else { + let item = this._appendMenuItem(_("Create Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + // copy_async() isn't introspectable :-( + src.copy(dst, Gio.FileCopyFlags.OVERWRITE, null, null); + this._markTrusted(dst); + } catch (e) { + log(`Failed to copy to desktop: ${e.message}`); + } + } + this.close(); + }); + } + } + + let canFavorite = global.settings.is_writable('favorite-apps'); + if (canFavorite) { + this._appendSeparator(); + let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._app.get_id()); + if (isFavorite) { + let item = this._appendMenuItem(_("Remove from Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.removeFavorite(this._app.get_id()); + this.close(); + }); + } else { + let item = this._appendMenuItem(_("Add to Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.addFavorite(this._app.get_id()); + this.close(); + }); + } + } + + let pinnedApps = this._settings.get_strv('pinned-app-list'); + let pinnedAppID = []; + + //filter pinnedApps list by every 3rd entry in list. 3rd entry contains an appID or command + for(let i = 2; i < pinnedApps.length; i += 3){ + pinnedAppID.push(pinnedApps[i]); + } + let isAppPinned = pinnedAppID.find((element) => { + return element == this._app.get_id(); + }); + + //if app is pinned and menulayout has PinnedApps category, show Unpin from ArcMenu entry + if(isAppPinned && this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app.get_id()){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + else if(this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Pin to ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + pinnedApps.push(this.appInfo.get_display_name()); + pinnedApps.push(''); + pinnedApps.push(this._app.get_id()); + this._settings.set_strv('pinned-app-list',pinnedApps); + }); + } + + if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { + this._appendSeparator(); + let item = this._appendMenuItem(_("Show Details")); + item.connect('activate', () => { + let id = this._app.get_id(); + let args = GLib.Variant.new('(ss)', [id, '']); + Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => { + let bus = Gio.DBus.get_finish(res); + bus.call('org.gnome.Software', + '/org/gnome/Software', + 'org.gtk.Actions', 'Activate', + GLib.Variant.new('(sava{sv})', + ['details', [args], null]), + null, 0, -1, null, null); + this.closeMenus(); + }); + }); + } + } + } + else if(this._path){ + let newWindowItem = this._appendMenuItem(_("Open Folder Location")); + newWindowItem.connect('activate', () => { + let file = Gio.File.new_for_path(this._path); + let context = global.create_app_launch_context(Clutter.get_current_event().get_time(), -1) + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + this.closeMenus(); + }); + } + else if(this._menuLayout.hasPinnedApps && this.sourceActor instanceof PinnedAppsMenuItem) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', () => { + this.close(); + let pinnedApps = this._settings.get_strv('pinned-app-list'); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + } + + //_markTrusted function borrowed from + //https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/apps-menu + async _markTrusted(file) { + let modeAttr = Gio.FILE_ATTRIBUTE_UNIX_MODE; + let trustedAttr = 'metadata::trusted'; + let queryFlags = Gio.FileQueryInfoFlags.NONE; + let ioPriority = GLib.PRIORITY_DEFAULT; + + try { + let info = await file.query_info_async(modeAttr, queryFlags, ioPriority, null); + + let mode = info.get_attribute_uint32(modeAttr) | 0o100; + info.set_attribute_uint32(modeAttr, mode); + info.set_attribute_string(trustedAttr, 'yes'); + await file.set_attributes_async(info, queryFlags, ioPriority, null); + + // Hack: force nautilus to reload file info + info = new Gio.FileInfo(); + info.set_attribute_uint64( + Gio.FILE_ATTRIBUTE_TIME_ACCESS, GLib.get_real_time()); + try { + await file.set_attributes_async(info, queryFlags, ioPriority, null); + } catch (e) { + log(`Failed to update access time: ${e.message}`); + } + } catch (e) { + log(`Failed to mark file as trusted: ${e.message}`); + } + } + + _appendSeparator() { + let separator = new ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.add_child(separator); + } + + _appendMenuItem(labelText) { + let item = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.label = new St.Label({ + text: _(labelText), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + item.add_child(this.label); + this.add_child(item); + return item; + } +}); + +var ApplicationContextMenu = class Arc_Menu_ApplicationContextMenu extends PopupMenu.PopupMenu { + constructor(actor, app, menuLayout){ + super(actor, 0.0, St.Side.TOP); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.layout = this._settings.get_enum('menu-layout'); + this._boxPointer.setSourceAlignment(.20); + this._boxPointer._border.queue_repaint(); + this.blockSourceEvents = true; + Main.uiGroup.add_child(this.actor); + this._menuLayout.contextMenuManager.addMenu(this); + this.contextMenuItems = new ApplicationContextItems(actor, app, menuLayout); + this.contextMenuItems.connect('close-context-menu', () => this.toggle()); + this.contextMenuItems._delegate = this.contextMenuItems; + this.box.add_child(this.contextMenuItems); + this.sourceActor = actor; + this.sourceActor.connect("destroy", ()=> { + if(this.isOpen) + this.close(); + Main.uiGroup.remove_child(this.actor); + this.contextMenuItems.destroy(); + this.destroy(); + }); + } + + centerBoxPointerPosition(){ + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + rightBoxPointerPosition(){ + this._arrowSide = St.Side.LEFT; + this._boxPointer._arrowSide = St.Side.LEFT; + this._boxPointer._userArrowSide = St.Side.LEFT; + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + set path(path){ + this.contextMenuItems.path = path; + } + + open(animate){ + if(this._menuLayout.searchResults && this.sourceActor !== this._menuLayout.searchResults.getTopResult()) + this._menuLayout.searchResults.getTopResult()?.remove_style_pseudo_class('active'); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.sourceActor.tooltip){ + this.sourceActor.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + super.open(animate); + } + + close(animate){ + super.close(animate); + if(this.sourceActor instanceof ArcMenuButtonItem) + this.sourceActor.sync_hover(); + else{ + this.sourceActor.active = false; + } + + this.sourceActor.sync_hover(); + this.sourceActor.hovered = this.sourceActor.hover; + } + + rebuildItems(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(customStyle){ + this.actor.style_class = 'arc-menu-boxpointer'; + this.actor.add_style_class_name('arc-menu'); + } + else{ + this.actor.style_class = 'popup-menu-boxpointer'; + this.actor.add_style_class_name('popup-menu'); + } + + this.contextMenuItems.rebuildItems(); + } + + _onKeyPress(actor, event) { + return Clutter.EVENT_PROPAGATE; + } +}; + +var ArcMenuPopupBaseMenuItem = GObject.registerClass({ + Properties: { + 'active': GObject.ParamSpec.boolean('active', 'active', 'active', + GObject.ParamFlags.READWRITE, + false), + 'hovered': GObject.ParamSpec.boolean('hovered', 'hovered', 'hovered', + GObject.ParamFlags.READWRITE, + false), + 'sensitive': GObject.ParamSpec.boolean('sensitive', 'sensitive', 'sensitive', + GObject.ParamFlags.READWRITE, + true), + }, + Signals: { + 'activate': { param_types: [Clutter.Event.$gtype] }, + }, + +}, class Arc_Menu_PopupBaseMenuItem extends St.BoxLayout{ + _init(menuLayout, params){ + params = imports.misc.params.parse(params, { + reactive: true, + activate: true, + hover: true, + style_class: null, + can_focus: true, + }); + super._init({ style_class: 'popup-menu-item arcmenu-menu-item', + reactive: params.reactive, + track_hover: params.reactive, + can_focus: params.can_focus, + accessible_role: Atk.Role.MENU_ITEM + }); + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this.hasContextMenu = false; + this._delegate = this; + this._menuLayout = menuLayout; + this.arcMenu = this._menuLayout.arcMenu; + this.shouldShow = true; + this._parent = null; + this._active = false; + this._activatable = params.reactive && params.activate; + this._sensitive = true; + + this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' }); + this.add_child(this._ornamentLabel); + + this.x_align = Clutter.ActorAlign.FILL; + this.x_expand = true; + + if (!this._activatable) + this.add_style_class_name('popup-inactive-menu-item'); + + if (params.style_class) + this.add_style_class_name(params.style_class); + + if (params.reactive && params.hover) + this.bind_property('hover', this, 'hovered', GObject.BindingFlags.SYNC_CREATE); + + if(params.hover) + this.actor.connect('notify::hover', this._onHover.bind(this)); + + this.arcMenuOpenStateChangeID = this.arcMenu.connect('open-state-changed', (menu, open) =>{ + if(!open) + this.cancelPopupTimeout(); + }); + + let textureCache = St.TextureCache.get_default(); + let iconThemeChangedId = textureCache.connect('icon-theme-changed', this._updateIcon.bind(this)); + this.connect('destroy', () => { + textureCache.disconnect(iconThemeChangedId); + this._onDestroy(); + }); + } + + _updateIcon() { + if(!this._iconBin || !this.createIcon) + return; + + let icon = this.createIcon(); + this._iconBin.set_child(icon); + } + + get actor() { + return this; + } + + get active(){ + return this._active; + } + + set active(active) { + if(this.isDestroyed) + return; + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + if(this._menuLayout.activeMenuItem !== this) + this._menuLayout.activeMenuItem = this; + this.remove_style_class_name('selected'); + this.add_style_pseudo_class('active'); + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_pseudo_class('active'); + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + set hovered(hover) { + let hoverChanged = hover != this.hovered; + if(hoverChanged){ + let isActiveStyle = this.get_style_pseudo_class()?.includes('active') + if(hover && !isActiveStyle){ + this.add_style_class_name('selected'); + } + else{ + this.remove_style_class_name('selected'); + } + } + } + + setShouldShow(){ + //If a saved shortcut link is a desktop app, check if currently installed. + //Do NOT display if application not found. + if(this._command.endsWith(".desktop") && !Shell.AppSystem.get_default().lookup_app(this._command)){ + this.shouldShow = false; + } + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = this.description; + if(this._app) + description = this._app.get_description(); + Utils.createTooltip(this._menuLayout, this, this.label, description, this._displayType ? this._displayType : -1); + } + } + + vfunc_button_press_event(){ + let event = Clutter.get_current_event(); + this.pressed = false; + if(event.get_button() == 1){ + this._menuLayout._blockActivateEvent = false; + this.pressed = true; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + } + else if(event.get_button() == 3){ + this.pressed = true; + } + this.active = true; + return Clutter.EVENT_PROPAGATE; + } + + vfunc_button_release_event(){ + let event = Clutter.get_current_event(); + if(event.get_button() == 1 && !this._menuLayout._blockActivateEvent && this.pressed){ + this.pressed = false; + this.activate(event); + if(!(this instanceof CategoryMenuItem) && !(this instanceof ArcMenuButtonItem)) + this.active = false; + return Clutter.EVENT_STOP; + } + if(event.get_button() == 3 && this.pressed){ + this.pressed = false; + if(this.hasContextMenu) + this.popupContextMenu(); + else if(!(this instanceof CategoryMenuItem && !(this instanceof ArcMenuButtonItem))){ + this.active = false; + this.hovered = true; + } + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_key_focus_in() { + super.vfunc_key_focus_in(); + if(!this.actor.hover) + this._menuLayout._keyFocusIn(this.actor); + this.active = true; + } + + vfunc_key_focus_out() { + if(this.contextMenu && this.contextMenu.isOpen){ + return; + } + super.vfunc_key_focus_out(); + this.active = false; + } + + activate(event) { + this.emit('activate', event); + } + + vfunc_key_press_event(keyEvent) { + if (!this._activatable) + return super.vfunc_key_press_event(keyEvent); + + let state = keyEvent.modifier_state; + + // if user has a modifier down (except capslock and numlock) + // then don't handle the key press here + state &= ~Clutter.ModifierType.LOCK_MASK; + state &= ~Clutter.ModifierType.MOD2_MASK; + state &= Clutter.ModifierType.MODIFIER_MASK; + + if (state) + return Clutter.EVENT_PROPAGATE; + + let symbol = keyEvent.keyval; + if ( symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter) { + this.activate(Clutter.get_current_event()); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_touch_event(event){ + if(event.type == Clutter.EventType.TOUCH_END && !this._menuLayout._blockActivateEvent && this.pressed){ + this.remove_style_pseudo_class('active'); + this.activate(Clutter.get_current_event()); + this.pressed = false; + return Clutter.EVENT_STOP; + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && !this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = true; + this._menuLayout._blockActivateEvent = false; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + this.add_style_pseudo_class('active'); + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = false; + this._menuLayout._blockActivateEvent = false; + this._menuLayout.contextMenuManager.activeMenu.toggle(); + } + return Clutter.EVENT_PROPAGATE; + } + + contextMenuTimeOut(){ + this._popupTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 600, () => { + this.pressed = false; + this._popupTimeoutId = null; + if(this.hasContextMenu && this._menuLayout.arcMenu.isOpen && !this._menuLayout._blockActivateEvent) { + this.popupContextMenu(); + this._menuLayout.contextMenuManager.ignoreRelease(); + } + return GLib.SOURCE_REMOVE; + }); + } + + cancelPopupTimeout(){ + if(this._popupTimeoutId){ + GLib.source_remove(this._popupTimeoutId); + this._popupTimeoutId = null; + } + } + + _onDestroy(){ + this.isDestroyed = true; + if(this.arcMenuOpenStateChangeID){ + this.arcMenu.disconnect(this.arcMenuOpenStateChangeID); + this.arcMenuOpenStateChangeID = null; + } + } +}); + +var ArcMenuSeparator = GObject.registerClass( +class Arc_Menu_Separator extends PopupMenu.PopupBaseMenuItem { + _init(separatorLength, separatorAlignment, text) { + super._init({ + style_class: 'popup-separator-menu-item', + reactive: false, + can_focus: false, + }); + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + this.remove_child(this._ornamentLabel); + this.reactive = true; + this.label = new St.Label({ + text: text || '', + style: 'font-weight: bold' + }); + this.add_child(this.label); + this.label_actor = this.label; + + this.label.add_style_pseudo_class = () => { return false; }; + + this.label.connect('notify::text', + this._syncLabelVisibility.bind(this)); + this._syncLabelVisibility(); + + this._separator = new St.Widget({ + style_class: 'popup-separator-menu-item-separator separator-color-style', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(this._separator); + if(separatorAlignment === Constants.SeparatorAlignment.HORIZONTAL){ + this.style = "padding: 0px 5px;" + if(separatorLength === Constants.SeparatorStyle.SHORT) + this._separator.style = "margin: 5px 45px;"; + else if(separatorLength === Constants.SeparatorStyle.MEDIUM) + this._separator.style = "margin: 5px 15px;"; + else if(separatorLength === Constants.SeparatorStyle.LONG) + this._separator.style = "margin: 0px 5px;"; + else if(separatorLength === Constants.SeparatorStyle.MAX) + this._separator.style = "margin: 0px; padding: 0px;"; + else if(separatorLength === Constants.SeparatorStyle.HEADER_LABEL){ + this._separator.style = "margin: 0px 20px 0px 10px;"; + this.style = "padding: 5px 15px;" + } + } + else if(separatorAlignment === Constants.SeparatorAlignment.VERTICAL){ + if(separatorLength === Constants.SeparatorStyle.ALWAYS_SHOW){ + this.style = "padding: 8px 4px;" + } + else{ + this._syncVisibility(); + this.vertSeparatorChangedID = this._settings.connect('changed::vert-separator', this._syncVisibility.bind(this)); + this.style = "padding: 0px 4px;" + } + + this._separator.style = "margin: 0px; width: 1px; height: -1px;"; + this.remove_child(this.label); + this.x_expand = this._separator.x_expand = true; + this.x_align = this._separator.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = this._separator.y_expand = true; + this.y_align = this._separator.y_align = Clutter.ActorAlign.FILL; + } + + this.connect('destroy', () => { + if(this.vertSeparatorChangedID){ + this._settings.disconnect(this.vertSeparatorChangedID); + this.vertSeparatorChangedID = null; + } + }); + } + + _syncLabelVisibility() { + this.label.visible = this.label.text != ''; + } + + _syncVisibility() { + this._separator.visible = this._settings.get_boolean('vert-separator'); + } +}); + +var ActivitiesMenuItem = GObject.registerClass(class Arc_Menu_ActivitiesMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _("Activities Overview"), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + icon_name: 'view-fullscreen-symbolic', + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + activate(event) { + this._menuLayout.arcMenu.toggle(); + Main.overview.show(); + super.activate(event); + } +}); + +var Tooltip = class Arc_Menu_Tooltip{ + constructor(menuLayout, sourceActor, title, description) { + this._menuButton = menuLayout.menuButton; + this._settings = this._menuButton._settings; + this.sourceActor = sourceActor; + if(this.sourceActor.tooltipLocation) + this.location = this.sourceActor.tooltipLocation; + else + this.location = Constants.TooltipLocation.BOTTOM; + let descriptionLabel; + this.actor = new St.BoxLayout({ + vertical: true, + style_class: 'dash-label tooltip-menu-item', + opacity: 0 + }); + + if(title){ + this.titleLabel = new St.Label({ + text: _(title), + style: description ? "font-weight: bold;" : null, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this.titleLabel); + } + + if(description){ + descriptionLabel = new St.Label({ + text: description, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(descriptionLabel); + } + + global.stage.add_child(this.actor); + + this.actor.connect('destroy',()=>{ + if(this.destroyID){ + this.sourceActor.disconnect(this.destroyID); + this.destroyID = null; + } + if(this.activeID){ + this.sourceActor.disconnect(this.activeID); + this.activeID = null; + } + + if(this.hoverID){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.toggleID){ + this._settings.disconnect(this.toggleID); + this.toggleID = null; + } + }) + this.activeID = this.sourceActor.connect('notify::active', ()=> this.setActive(this.sourceActor.active)); + this.destroyID = this.sourceActor.connect('destroy',this.destroy.bind(this)); + this.hoverID = this.sourceActor.connect('notify::hover', this._onHover.bind(this)); + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + this.toggleID = this._settings.connect('changed::disable-tooltips', this.disableTooltips.bind(this)); + } + + setActive(active){ + if(!active) + this.hide(); + } + + disableTooltips() { + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + } + + _onHover() { + if(this._useTooltips){ + if(this.sourceActor.hover){ + if(this._menuButton.tooltipShowing){ + this.show(); + this._menuButton.activeTooltip = this.actor; + } + else{ + this._menuButton.tooltipShowingID = GLib.timeout_add(0, 750, () => { + this.show(); + this._menuButton.tooltipShowing = true; + this._menuButton.activeTooltip = this.actor; + this._menuButton.tooltipShowingID = null; + return GLib.SOURCE_REMOVE; + }); + } + if(this._menuButton.tooltipHidingID){ + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + } + else { + this.hide(); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + this._menuButton.tooltipHidingID = GLib.timeout_add(0, 750, () => { + this._menuButton.tooltipShowing = false; + this._menuButton.activeTooltip = null; + this._menuButton.tooltipHidingID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + } + + show() { + if(this._useTooltips){ + this.actor.opacity = 0; + this.actor.show(); + + let [stageX, stageY] = this.sourceActor.get_transformed_position(); + + let itemWidth = this.sourceActor.allocation.x2 - this.sourceActor.allocation.x1; + let itemHeight = this.sourceActor.allocation.y2 - this.sourceActor.allocation.y1; + + let labelWidth = this.actor.get_width(); + let labelHeight = this.actor.get_height(); + + let x, y; + let gap = 5; + + switch (this.location) { + case Constants.TooltipLocation.BOTTOM_CENTERED: + y = stageY + itemHeight + gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.TOP_CENTERED: + y = stageY - labelHeight - gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.BOTTOM: + y = stageY + itemHeight + gap; + x = stageX + gap; + break; + } + + // keep the label inside the screen + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + if (x - monitor.x < gap) + x += monitor.x - x + gap; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + else if (y - monitor.y < gap) + y += monitor.y - y + gap; + else if (y + labelHeight > monitor.y + monitor.height - gap) + y -= y + labelHeight - (monitor.y + monitor.height) + gap; + + this.actor.set_position(x, y); + this.actor.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + } + + hide() { + if(this._useTooltips){ + this.actor.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.actor.hide() + }); + } + } + + destroy() { + if (this._menuButton.tooltipShowingID) { + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + if (this._menuButton.tooltipHidingID) { + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + if(this.toggleID>0){ + this._settings.disconnect(this.toggleID); + this.toggleID = 0; + } + if(this.hoverID>0){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = 0; + } + if(this._menuButton.activeTooltip = this.actor) + this._menuButton.activeTooltip = null; + + global.stage.remove_child(this.actor); + this.actor.destroy(); + } +}; + +var ArcMenuButtonItem = GObject.registerClass( + class Arc_Menu_ArcMenuButtonItem extends ArcMenuPopupBaseMenuItem { + _init(menuLayout, tooltipText, iconName, gicon) { + super._init(menuLayout); + this.style_class = 'popup-menu-item arc-menu-button'; + this._settings = this._menuLayout._settings; + this._menuLayout = menuLayout; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.iconName = iconName; + this.gicon = gicon; + this.toggleMenuOnClick = true; + + if(tooltipText){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, tooltipText); + this.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + this.tooltip.hide(); + } + + if(this.iconName !== null){ + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + } + } + + createIcon(overrideIconSize){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this.gicon ? this.gicon : Gio.icon_new_for_string(this.iconName), + icon_size: overrideIconSize ? overrideIconSize : iconSize, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER + }); + } + + setIconSize(size){ + if(!this._iconBin) + return; + this._iconBin.set_child(this.createIcon(size)); + } + + activate(event){ + if(this.toggleMenuOnClick) + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +// Settings Button +var SettingsButton = GObject.registerClass(class Arc_Menu_SettingsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Settings"), 'emblem-system-symbolic'); + } + activate(event) { + super.activate(event); + Util.spawnCommandLine('gnome-control-center'); + } +}); + +// Runner Layout Tweaks Button +var RunnerTweaksButton = GObject.registerClass(class Arc_Menu_RunnerTweaksButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Configure Runner"), 'emblem-system-symbolic'); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + } + activate(event) { + super.activate(event); + this._menuLayout._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.RUNNER_TWEAKS); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + } +}); + +//'Insider' layout Pinned Apps hamburger button +var PinnedAppsButton = GObject.registerClass(class Arc_Menu_PinnedAppsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Pinned Apps"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.togglePinnedAppsMenu(); + } +}); + +//'Windows' layout extras hamburger button +var ExtrasButton = GObject.registerClass(class Arc_Menu_ExtrasButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Extras"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleExtrasMenu(); + } +}); + +//"Leave" Button with popupmenu that shows lock, power off, restart, etc +var LeaveButton = GObject.registerClass(class Arc_Menu_LeaveButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Leave"), 'system-shutdown-symbolic'); + this.toggleMenuOnClick = false; + this._menuLayout = menuLayout; + this.menuButton = menuLayout.menuButton; + this._settings = menuLayout._settings; + this._createLeaveMenu(); + } + + _createLeaveMenu(){ + this.leaveMenu = new PopupMenu.PopupMenu(this, 0.5 , St.Side.BOTTOM); + this.leaveMenu.blockSourceEvents = true; + let section = new PopupMenu.PopupMenuSection(); + this.leaveMenu.addMenuItem(section); + + let box = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + box._delegate = box; + + section.actor.add_child(box); + + box.add_child(this._menuLayout.createLabelRow(_("Session"))); + + this.lockItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOCK); + box.add_child(this.lockItem); + + let logOutItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOGOUT); + box.add_child(logOutItem); + + box.add_child(this._menuLayout.createLabelRow(_("System"))); + + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + let sleepItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HYBRID_SLEEP); + box.insert_child_at_index(sleepItem, 4); + } + }); + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + let hibernateItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HIBERNATE); + box.insert_child_at_index(hibernateItem, 5); + } + }); + + let suspendItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.SUSPEND); + box.add_child(suspendItem); + + let restartItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.RESTART); + box.add_child(restartItem); + + let powerOffItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.POWER_OFF); + box.add_child(powerOffItem); + + this._menuLayout.subMenuManager.addMenu(this.leaveMenu); + this.leaveMenu.actor.hide(); + Main.uiGroup.add_child(this.leaveMenu.actor); + this.leaveMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.active = false; + this.sync_hover(); + this.hovered = this.hover; + } + }); + } + + _onDestroy(){ + Main.uiGroup.remove_child(this.leaveMenu.actor); + this.leaveMenu.destroy(); + } + + activate(event) { + super.activate(event); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.leaveMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.leaveMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.leaveMenu.toggle(); + } +}); + +//'Unity' layout categories hamburger button +var CategoriesButton = GObject.registerClass(class Arc_Menu_CategoriesButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Categories"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleCategoriesMenu(); + } +}); + +var PowerButton = GObject.registerClass(class Arc_Menu_PowerButton extends ArcMenuButtonItem { + _init(menuLayout, powerType) { + super._init(menuLayout, Constants.PowerOptions[powerType].TITLE, Constants.PowerOptions[powerType].IMAGE); + this.powerType = powerType; + } + activate(event) { + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PowerMenuItem = GObject.registerClass(class Arc_Menu_PowerMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, type) { + super._init(menuLayout); + this.powerType = type; + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(Constants.PowerOptions[this.powerType].TITLE), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: Gio.icon_new_for_string(Constants.PowerOptions[this.powerType].IMAGE), + style_class: 'popup-menu-icon', + icon_size: iconSize, + }); + } + + activate(){ + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PlasmaMenuItem = GObject.registerClass(class Arc_Menu_PlasmaMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, title, iconPath) { + super._init(menuLayout); + this.remove_child(this._ornamentLabel); + this._menuLayout = menuLayout; + this.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.vertical = true; + this.name = "arc-menu-plasma-button"; + this.iconPath = iconPath; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(title), + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label.x_align = this.label.y_align = Clutter.ActorAlign.CENTER; + this.label.y_expand = true; + + this._iconBin.x_align = this._iconBin.y_align = Clutter.ActorAlign.CENTER; + this._iconBin.y_expand = true; + + this.label.get_clutter_text().set_line_wrap(true); + this.add_child(this.label); + this.actor.connect('notify::hover', this._onHover.bind(this)); + } + + createIcon(){ + return new St.Icon({ + gicon: Gio.icon_new_for_string(this.iconPath), + style_class: 'popup-menu-icon', + icon_size: Constants.MEDIUM_ICON_SIZE + }); + } + + _onHover(){ + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = null; + Utils.createTooltip(this._menuLayout, this, this.label, description, Constants.DisplayType.LIST); + } + let shouldHover = this._settings.get_boolean('plasma-enable-hover'); + if(shouldHover && this.actor.hover && !this.isActive){ + this.activate(Clutter.get_current_event()); + } + } + + set active(active) { + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + this.add_style_class_name('selected'); + this._menuLayout.activeMenuItem = this; + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + setActive(active){ + if(active){ + this.isActive = true; + this.set_style_pseudo_class("active-item"); + } + else{ + this.isActive = false; + this.set_style_pseudo_class(null); + } + } + + activate(event){ + this._menuLayout.searchBox.clearWithoutSearchChangeEvent(); + this._menuLayout.clearActiveItem(); + this.setActive(true); + super.activate(event); + } +}); + +var PlasmaCategoryHeader = GObject.registerClass(class Arc_Menu_PlasmaCategoryHeader extends St.BoxLayout{ + _init(menuLayout) { + super._init({ + style_class: "popup-menu-item", + style: 'padding: 0px;', + reactive: true, + track_hover:true, + can_focus: true, + accessible_role: Atk.Role.MENU_ITEM + }); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this.backButton = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.backButton.x_expand = false; + this.backButton.x_align = Clutter.ActorAlign.CENTER; + this.label = new St.Label({ + text: _("Applications"), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + style: 'font-weight: bold' + }); + + this.backButton.add_child(this.label); + + this.add_child(this.backButton); + this.backButton.connect("activate", () => this._menuLayout.displayCategories() ); + + this.categoryLabel = new St.Label({ + text: '', + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.categoryLabel); + } + + setActiveCategory(categoryText){ + if(categoryText){ + this.categoryLabel.text = _(categoryText); + this.categoryLabel.show(); + } + else + this.categoryLabel.hide(); + } +}); + +var AllAppsButton = GObject.registerClass(class Arc_Menu_AllAppsButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-next-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("All Apps"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.insert_child_at_index(this._label, 0); + } + + activate(event){ + super.activate(event); + this._menuLayout.displayAllApps(); + } +}); + +var BackButton = GObject.registerClass(class Arc_Menu_BackButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-previous-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("Back"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this._label); + } + + activate(event){ + super.activate(event); + this._menuLayout.setDefaultMenuView(); + } +}); + +// Menu item to go back to category view +var BackMenuItem = GObject.registerClass(class Arc_Menu_BackMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + let backLabel = new St.Label({ + text: _("Back"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-previous-symbolic', + icon_size: iconSize, + }); + } + + activate(event) { + if(this._layout === Constants.MenuLayout.ARCMENU){ + //If the current page is inside a category and + //previous page was the categories page, + //go back to categories page + if(this._menuLayout.previousCategoryType === Constants.CategoryType.CATEGORIES_LIST && (this._menuLayout.activeCategoryType <= 4 || this._menuLayout.activeCategoryType instanceof GMenu.TreeDirectory)) + this._menuLayout.displayCategories(); + else + this._menuLayout.setDefaultMenuView(); + } + else if(this._layout === Constants.MenuLayout.TOGNEE) + this._menuLayout.setDefaultMenuView(); + super.activate(event); + } +}); + +// Menu item to view all apps +var ViewAllPrograms = GObject.registerClass(class Arc_Menu_ViewAllPrograms extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + let backLabel = new St.Label({ + text: _("All Applications"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + this._updateIcon(); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-next-symbolic', + icon_size: iconSize, + x_align: Clutter.ActorAlign.START + }); + } + + activate(event) { + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this._menuLayout.displayCategories(); + else + this._menuLayout.displayAllApps(); + super.activate(event); + } +}); + +var ShortcutMenuItem = GObject.registerClass(class Arc_Menu_ShortcutMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + if(this._settings.get_enum('shortcut-icon-type') === Constants.CategoryIconType.FULL_COLOR) + this.add_style_class_name('regular-icons'); + else + this.add_style_class_name('symbolic-icons'); + this._command = command; + this._displayType = displayType; + this.isContainedInCategory = isContainedInCategory; + this.iconName = icon; + + //Check for default commands-------- + if(this._command == "ArcMenu_Software"){ + let softwareManager = Utils.findSoftwareManager(); + this._command = softwareManager ? softwareManager : 'ArcMenu_unfound.desktop'; + } + else if(this._command === "ArcMenu_Trash"){ + this.trash = new Me.imports.placeDisplay.Trash(this); + this._command = "ArcMenu_Trash"; + this._app = this.trash.getApp(); + } + if(!this._app) + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + + if(this._app && icon === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this.iconName = appIcon.gicon.to_string(); + } + } + //------------------------------------- + + this.hasContextMenu = this._app ? true : false; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(name), y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.layout = this._settings.get_enum('menu-layout'); + if(this.layout === Constants.MenuLayout.PLASMA && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + else if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.remove_child(this.label); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + this.setShouldShow(); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + iconSizeEnum = this._settings.get_enum('button-item-icon-size'); + defaultIconSize = LayoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + } + else if(this._displayType === Constants.DisplayType.GRID){ + iconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(iconSizeEnum, defaultIconStyle); + } + + return new St.Icon({ + icon_name: this.iconName, + gicon: Gio.icon_new_for_string(this.iconName), + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this._app && this.contextMenu == undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID || this.layout === Constants.MenuLayout.UNITY || this.layout === Constants.MenuLayout.AZ) + this.contextMenu.centerBoxPointerPosition(); + else if(this.layout === Constants.MenuLayout.MINT || this.layout === Constants.MenuLayout.TOGNEE) + this.contextMenu.rightBoxPointerPosition(); + if(this._path) + this.contextMenu.path = this._path; + } + if(this.contextMenu !== undefined){ + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen){ + this.contextMenu.rebuildItems(); + } + this.contextMenu.toggle(); + } + } + + activate(event) { + if(this._command === "ArcMenu_LogOut") + activatePowerOption(Constants.PowerType.LOGOUT, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Lock") + activatePowerOption(Constants.PowerType.LOCK, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_PowerOff") + activatePowerOption(Constants.PowerType.POWER_OFF, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Restart") + activatePowerOption(Constants.PowerType.RESTART, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Suspend") + activatePowerOption(Constants.PowerType.SUSPEND, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_HybridSleep") + activatePowerOption(Constants.PowerType.HYBRID_SLEEP, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Hibernate") + activatePowerOption(Constants.PowerType.HIBERNATE, this._menuLayout.arcMenu); + + else{ + this._menuLayout.arcMenu.toggle(); + if(this._command === "ArcMenu_ActivitiesOverview") + Main.overview.show(); + else if(this._command === "ArcMenu_RunCommand") + Main.openRunDialog(); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(this._app) + this._app.open_new_window(-1); + else + Util.spawnCommandLine(this._command); + } + } +}); + +// Menu item which displays the current user +var UserMenuItem = GObject.registerClass(class Arc_Menu_UserMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, displayType) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._settings = this._menuLayout._settings; + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + this.iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + this.iconSize = Utils.getIconSize(IconSizeEnum, USER_AVATAR_SIZE); + } + + this.userMenuIcon = new UserMenuIcon(menuLayout, this.iconSize, false); + + this.add_child(this.userMenuIcon.actor); + this.label = this.userMenuIcon.label; + if(this._displayType !== Constants.DisplayType.BUTTON) + this.add_child(this.label); + } + + activate(event) { + Util.spawnCommandLine("gnome-control-center user-accounts"); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var UserMenuIcon = class Arc_Menu_UserMenuIcon{ + constructor(menuLayout, size, hasTooltip) { + this._menuLayout = menuLayout; + this.iconSize = size; + + let username = GLib.get_user_name(); + this._user = AccountsService.UserManager.get_default().get_user(username); + + this.actor = new St.Bin({ + style_class: 'menu-user-avatar user-icon', + track_hover: true, + reactive: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label = new St.Label({ + text: GLib.get_real_name(), + y_align: Clutter.ActorAlign.CENTER + }); + + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + + this._userLoadedId = this._user.connect('notify::is-loaded', this._onUserChanged.bind(this)); + this._userChangedId = this._user.connect('changed', this._onUserChanged.bind(this)); + this.actor.connect('destroy', this._onDestroy.bind(this)); + if(hasTooltip) + this.actor.connect('notify::hover',this._onHover.bind(this)); + + this._onUserChanged(); + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, GLib.get_real_name()); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + this.tooltip._onHover(); + } + } + + _onUserChanged() { + if (this._user.is_loaded) { + this.label.set_text(this._user.get_real_name()); + if(this.tooltip) + this.tooltip.titleLabel.text = this._user.get_real_name(); + + let iconFile = this._user.get_icon_file(); + if (iconFile && !GLib.file_test(iconFile ,GLib.FileTest.EXISTS)) + iconFile = null; + + if (iconFile) { + this.actor.child = null; + this.actor.add_style_class_name('user-avatar'); + this.actor.style = 'background-image: url("%s");'.format(iconFile) + "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + } + else { + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + this.actor.child = new St.Icon({ + icon_name: 'avatar-default-symbolic', + icon_size: this.iconSize, + style: "padding: 5px; width: " + this.iconSize + "px; height: " + this.iconSize + "px;" + }); + } + } + } + + _onDestroy() { + if (this._userLoadedId) { + this._user.disconnect(this._userLoadedId); + this._userLoadedId = null; + } + if (this._userChangedId) { + this._user.disconnect(this._userChangedId); + this._userChangedId = null; + } + } +}; + +// Menu pinned apps item class +var PinnedAppsMenuItem = GObject.registerClass({ + Signals: { 'saveSettings': {}, }, +}, class Arc_Menu_PinnedAppsMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._menuButton = menuLayout.menuButton; + this._settings = this._menuLayout._settings; + this._command = command; + this._iconString = this._iconPath = icon; + this._name = name; + this._displayType = displayType; + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + this.hasContextMenu = true; + this.gridLocation = [-1, -1]; + this.isContainedInCategory = isContainedInCategory; + + //Modifiy the Default Pinned Apps--------------------- + if(this._name == "ArcMenu Settings"){ + this._name = _("ArcMenu Settings"); + } + else if(this._name == "Terminal"){ + this._name = _("Terminal"); + } + else if(this._name == "Files"){ + this._name = _("Files"); + } + if(this._iconPath === "ArcMenu_ArcMenuIcon" || this._iconPath === Me.path + '/media/icons/arc-menu-symbolic.svg'){ + this._iconString = this._iconPath = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + //------------------------------------------------------- + + if(this._app && this._iconPath === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this._iconString = appIcon.gicon ? appIcon.gicon.to_string() : appIcon.fallback_icon_name; + if(!this._iconString) + this._iconString = ""; + } + } + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(this._name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + if(this._displayType === Constants.DisplayType.LIST && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this._draggable = DND.makeDraggable(this.actor); + this._draggable._animateDragEnd = (eventTime) => { + this._draggable._animationInProgress = true; + this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime); + }; + this.isDraggableApp = true; + this._draggable.connect('drag-begin', this._onDragBegin.bind(this)); + this._draggable.connect('drag-end', this._onDragEnd.bind(this)); + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.setShouldShow(); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this.contextMenu == undefined){ + let app = this._app ? this._app : this._command; + this.contextMenu = new ApplicationContextMenu(this.actor, app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + _onDragBegin() { + this.isDragging = true; + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + if(this.contextMenu && this.contextMenu.isOpen) + this.contextMenu.toggle(); + + this.cancelPopupTimeout(); + + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this) + }; + DND.addDragMonitor(this._dragMonitor); + this._parentBox = this.actor.get_parent(); + let p = this._parentBox.get_transformed_position(); + this.posX = p[0]; + this.posY = p[1]; + + this.actor.opacity = 55; + this.get_allocation_box(); + this.rowHeight = this.height; + this.rowWidth = this.width; + } + + _onDragMotion(dragEvent) { + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + this.xIndex = Math.floor((this._draggable._dragX - this.posX) / (this.rowWidth + layoutManager.column_spacing)); + this.yIndex = Math.floor((this._draggable._dragY - this.posY) / (this.rowHeight + layoutManager.row_spacing)); + + if(this.xIndex === this.gridLocation[0] && this.yIndex === this.gridLocation[1]){ + return DND.DragMotionResult.CONTINUE; + } + else{ + this.gridLocation = [this.xIndex, this.yIndex]; + } + + this._parentBox.remove_child(this); + let children = this._parentBox.get_children(); + let childrenCount = children.length; + let columns = layoutManager.gridColumns; + let rows = Math.floor(childrenCount / columns); + if(this.yIndex >= rows) + this.yIndex = rows; + if(this.yIndex < 0) + this.yIndex = 0; + if(this.xIndex >= columns - 1) + this.xIndex = columns - 1; + if(this.xIndex < 0) + this.xIndex = 0; + + if(((this.xIndex + 1) + (this.yIndex * columns)) > childrenCount) + this.xIndex = Math.floor(childrenCount % columns); + + this._parentBox.remove_all_children(); + + let x = 0, y = 0; + for(let i = 0; i < children.length; i++){ + if(this.xIndex === x && this.yIndex === y) + [x, y] = this.gridLayoutIter(x, y, columns); + layoutManager.attach(children[i], x, y, 1, 1); + [x, y] = this.gridLayoutIter(x, y, columns); + } + layoutManager.attach(this, this.xIndex, this.yIndex, 1, 1); + } + return DND.DragMotionResult.CONTINUE; + } + + _onDragEnd() { + if (this._dragMonitor) { + DND.removeDragMonitor(this._dragMonitor); + this._dragMonitor = null; + } + this.actor.opacity = 255; + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + let x = 0, y = 0; + let columns = layoutManager.gridColumns; + let orderedList = []; + let children = this._parentBox.get_children(); + for(let i = 0; i < children.length; i++){ + orderedList.push(this._parentBox.layout_manager.get_child_at(x, y)); + [x, y] = this.gridLayoutIter(x, y, columns); + } + this._menuLayout.pinnedAppsArray = orderedList; + } + this.emit('saveSettings'); + } + + getDragActor() { + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let icon = new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + style_class: 'popup-menu-icon', + icon_size: this._iconBin.get_child().icon_size + }); + let iconColor = this._settings.get_string('menu-foreground-color'); + if(customStyle) + icon.style = `color: ${iconColor};`; + return icon; + } + + getDragActorSource() { + return this.actor; + } + + gridLayoutIter(x, y, columns){ + x++; + if(x === columns){ + y++; + x = 0; + } + return [x, y]; + } + + activate(event) { + if(this._app) + this._app.open_new_window(-1); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else + Util.spawnCommandLine(this._command); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var ApplicationMenuItem = GObject.registerClass(class Arc_Menu_ApplicationMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, app, displayType, metaInfo, isContainedInCategory) { + super._init(menuLayout); + this._app = app; + this._menuLayout = menuLayout; + this.metaInfo = metaInfo; + this._settings = this._menuLayout._settings; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._displayType = displayType; + this.hasContextMenu = true; + this.isSearchResult = this.metaInfo ? true : false; + this.isContainedInCategory = isContainedInCategory; + + if(this._app){ + let disableRecentAppsIndicator = this._settings.get_boolean("disable-recently-installed-apps") + if(!disableRecentAppsIndicator){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + this.isRecentlyInstalled = recentApps.some((appIter) => appIter === this._app.get_id()); + } + } + + this._iconBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._app ? this._app.get_name() : this.metaInfo['name'], + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.description = this._app ? this._app.get_description() : this.metaInfo['description']; + + let searchResultsDescriptionsSetting = this._settings.get_boolean("show-search-result-details"); + let appsShowDescriptionsSetting = this._settings.get_boolean("apps-show-extra-details"); + this.searchResultsDescriptions = searchResultsDescriptionsSetting && this.isSearchResult; + this.appsShowDescriptions = appsShowDescriptionsSetting && !this.isSearchResult; + + if(this.description && (this.searchResultsDescriptions || this.appsShowDescriptions) && this._displayType === Constants.DisplayType.LIST){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionText = this.description.split('\n')[0]; + this.descriptionLabel = new St.Label({ + text: descriptionText, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + labelBox.add_child(this.descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this.label_actor = this.label; + + if(this.isRecentlyInstalled){ + this._indicator = new St.Label({ + text: _('New'), + style_class: "arc-menu-menu-item-text-indicator", + style: "border-radius: 15px; margin: 0px; padding: 0px 10px;", + x_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.hoverID = this.connect("notify::hover", () => this.removeIndicator()); + this.keyFocusInID = this.connect("key-focus-in", () => this.removeIndicator()); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + this._iconBin.x_align = Clutter.ActorAlign.CENTER; + + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory || this.isSearchResult ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + return this.metaInfo ? this.metaInfo['createIcon'](iconSize) : this._app.create_icon_texture(iconSize); + } + + removeIndicator(){ + if(this.isRecentlyInstalled){ + this.isRecentlyInstalled = false; + let recentApps = this._settings.get_strv('recently-installed-apps'); + let index = recentApps.indexOf(this._app.get_id()); + if(index > -1){ + recentApps.splice(index, 1); + } + this._settings.set_strv('recently-installed-apps', recentApps); + + this._indicator.hide(); + this._menuLayout.setRecentlyInstalledIndicator(); + } + } + + popupContextMenu(){ + this.removeIndicator(); + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activateSearchResult(provider, metaInfo, terms, event){ + this._menuLayout.arcMenu.toggle(); + if(provider.activateResult){ + provider.activateResult(metaInfo.id, terms); + if (metaInfo.clipboardText) + St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, metaInfo.clipboardText); + } + else{ + if (metaInfo.id.endsWith('.desktop')) { + let app = Shell.AppSystem.get_default().lookup_app(metaInfo.id); + if (app.can_open_new_window()) + app.open_new_window(-1); + else + app.activate(); + } + else{ + this._menuLayout.arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + SystemActions.activateAction(metaInfo.id); + } + } + } + + activate(event) { + this.removeIndicator(); + + if(this.metaInfo){ + this.activateSearchResult(this.provider, this.metaInfo, this.resultsView.terms, event); + return Clutter.EVENT_STOP; + } + else + this._app.open_new_window(-1); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _onDestroy(){ + if(this.hoverID){ + this.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.keyFocusInID){ + this.disconnect(this.keyFocusInID); + this.keyFocusInID = null; + } + } +}); + +// Menu Category item class +var CategoryMenuItem = GObject.registerClass(class Arc_Menu_CategoryMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, category, displayType) { + super._init(menuLayout); + this.appList = []; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._layout = this._settings.get_enum('menu-layout'); + this._category = category; + this._name = ""; + this._horizontalFlip = this._settings.get_boolean('enable-horizontal-flip'); + this._displayType = displayType; + this.layoutProps = this._menuLayout.layoutProperties; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._name, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + + if(this.isRecentlyInstalled) + this.setRecentlyInstalledIndicator(true); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.remove_child(this.label); + } + + this.label_actor = this.label; + this._menuLayout._oldX = -1; + this._menuLayout._oldY = -1; + this.connect('motion-event', this._onMotionEvent.bind(this)); + this.connect('enter-event', this._onEnterEvent.bind(this)); + this.connect('leave-event', this._onLeaveEvent.bind(this)); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + + let defaultIconSize = this.layoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + let defaultIconSize = this.layoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + let icon = new St.Icon({ + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + icon.gicon = gicon; + else if(iconName) + icon.icon_name = iconName; + else + icon.fallback_icon_name = fallbackIconName; + + return icon; + } + + setRecentlyInstalledIndicator(shouldShow){ + if(this._displayType === Constants.DisplayType.BUTTON) + return; + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + else if(this._indicator && this.contains(this._indicator)) + this.remove_child(this._indicator); + } + + displayAppList(){ + this._menuLayout.searchBox?.clearWithoutSearchChangeEvent(); + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, null); + } + + activate(event) { + this.displayAppList(); + if(this.layoutProps.SupportsCategoryOnHover) + this._menuLayout.setActiveCategory(this, true); + super.activate(event); + } + + _onEnterEvent(actor, event) { + if(this._menuLayout.navigatingCategoryLeaveEventID){ + GLib.source_remove(this._menuLayout.navigatingCategoryLeaveEventID); + this._menuLayout.navigatingCategoryLeaveEventID = null; + } + } + + _onLeaveEvent(actor, event) { + if(!this._menuLayout.navigatingCategoryLeaveEventID){ + this._menuLayout.navigatingCategoryLeaveEventID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { + this._menuLayout.navigatingCategory = null; + this._menuLayout.navigatingCategoryLeaveEventID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + + _onMotionEvent(actor, event) { + if(this.layoutProps.SupportsCategoryOnHover && this._settings.get_boolean('activate-on-hover')){ + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategoryType !== this._category && this._menuLayout.navigatingCategory === this) + this.activate(Clutter.get_current_event()); + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } + } + + _isInTriangle([x, y]){ + let [posX, posY] = this._menuLayout.navigatingCategory.get_transformed_position(); + + //the mouse is still in the active category + if (this._menuLayout.navigatingCategory === this){ + this._menuLayout._oldX = x; + this._menuLayout._oldY = y; + return true; + } + + if(!this._menuLayout.navigatingCategory) + return false; + + let width = this._menuLayout.navigatingCategory.width; + let height = this._menuLayout.navigatingCategory.height; + + let maxX = this._horizontalFlip ? posX : posX + width; + let maxY = posY + height; + + let distance = Math.abs(maxX - this._menuLayout._oldX); + let point1 = [this._menuLayout._oldX, this._menuLayout._oldY] + let point2 = [maxX, posY - distance]; + let point3 = [maxX, maxY + distance]; + + let area = Utils.areaOfTriangle(point1, point2, point3); + let a1 = Utils.areaOfTriangle([x, y], point2, point3); + let a2 = Utils.areaOfTriangle(point1, [x, y], point3); + let a3 = Utils.areaOfTriangle(point1, point2, [x, y]); + return area === a1 + a2 + a3; + } +}); + +var SimpleMenuItem = GObject.registerClass(class Arc_Menu_SimpleMenuItem extends CategoryMenuItem{ + _init(menuLayout, category) { + super._init(menuLayout, category); + this.subMenu = new PopupMenu.PopupMenu(this.actor,.5,St.Side.LEFT); + this.subMenu.connect("open-state-changed", (menu, open) => { + if(!open){ + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + }); + + Main.uiGroup.add_child(this.subMenu.actor); + this.section = new PopupMenu.PopupMenuSection(); + this.subMenu.addMenuItem(this.section); + + this.applicationsScrollBox = this._menuLayout._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this._menuLayout.subMenuManager.addMenu(this.subMenu); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.applicationsScrollBox.style = 'max-height: 25em;'; + this.applicationsBox._delegate = this.applicationsBox; + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.section.actor.add_child(this.applicationsScrollBox); + + if(this.subMenu._keyPressId) + this.actor.disconnect(this.subMenu._keyPressId); + this.applicationsScrollBox.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Right: + case Clutter.KEY_Left: + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + } + return Clutter.EVENT_STOP; + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.actor.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + } + return Clutter.EVENT_STOP; + case Clutter.KEY_Left: + case Clutter.KEY_Right: + case Clutter.KEY_Return: + if(!this.subMenu.isOpen){ + let navigateFocus = true; + this.activate(event, navigateFocus); + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + return Clutter.EVENT_STOP; + } + else{ + return Clutter.EVENT_PROPAGATE; + } + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.updateStyle(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.subMenu.actor.hide(); + if(customStyle){ + this.subMenu.actor.style_class = 'arc-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('arc-menu'); + } + else + { + this.subMenu.actor.style_class = 'popup-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('popup-menu'); + } + } + + displayAppList(){ + this._menuLayout.activeCategory = this._name; + } + + activate(event, navigateFocus = true) { + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + this.subMenu.toggle(); + if(navigateFocus) + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + this._menuLayout.setActiveCategory(this, true); + } + + _onMotionEvent(actor, event) { + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategory !== this._name && this._menuLayout.navigatingCategory === this){ + let navigateFocus = false; + this.activate(event, navigateFocus); + } + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } +}); +// SubMenu Category item class +var CategorySubMenuItem = GObject.registerClass(class Arc_Menu_CategorySubMenuItem extends PopupMenu.PopupSubMenuMenuItem{ + _init(menuLayout, category) { + super._init('', true); + this.add_style_class_name("arcmenu-menu-item"); + this.add_style_class_name('margin-box'); + this._category = category; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._name = ""; + this.isSimpleMenuItem = false; + this._active = false; + this.applicationsMap = new Map(); + this.appList = []; + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + this.icon.gicon = gicon; + else if(iconName) + this.icon.icon_name = iconName; + else + this.icon.fallback_icon_name = fallbackIconName; + + this.label.text = this._name; + + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + this.icon.icon_size = iconSize; + + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._menuLayout._blockActivateEvent = true; + this._menuLayout.onPan(action, this.menu.actor); + }); + panAction.connect('gesture-cancel',(action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + panAction.connect('gesture-end', (action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + this.menu.actor.add_action(panAction); + + this.menu.actor.style = 'max-height: 250px;'; + this.menu.actor.overlay_scrollbars = true; + this.menu.actor.style_class = 'popup-sub-menu ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'); + this.menu._needsScrollbar = () => this._needsScrollbar(); + + this.menu.connect('open-state-changed', () => { + if(!this.menu.isOpen){ + let scrollbar= this.menu.actor.get_vscroll_bar().get_adjustment(); + scrollbar.set_value(0); + } + }); + this.menu.box.style_class = 'margin-box'; + } + + setRecentlyInstalledIndicator(shouldShow){ + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this._indicator); + } + else if(this._indicator && this.actor.contains(this._indicator)) + this.actor.remove_child(this._indicator); + } + + _needsScrollbar() { + let topMenu = this.menu; + let [, topNaturalHeight] = topMenu.actor.get_preferred_height(-1); + let topThemeNode = topMenu.actor.get_theme_node(); + + let topMaxHeight = topThemeNode.get_max_height(); + let needsScrollbar = topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight; + if(needsScrollbar) + this.menu.actor.style = 'min-height:150px; max-height: 250px;'; + else + this.menu.actor.style = 'max-height: 250px;'; + + this.menu.actor.vscrollbar_policy = St.PolicyType.AUTOMATIC; + + if (needsScrollbar) + this.menu.actor.add_style_pseudo_class('scrolled'); + else + this.menu.actor.remove_style_pseudo_class('scrolled'); + + return needsScrollbar; + } + + loadMenu(){ + let children = this.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let item = children[i]; + this.menu.box.remove_child(item); + } + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + for (let i = 0; i < appList.length; i++) { + let app = appList[i]; + let item = this.applicationsMap.get(app); + if(item.actor.get_parent()){ + item.actor.get_parent().remove_child(item.actor); + } + if (!item.actor.get_parent()) { + this.menu.box.add_child(item.actor); + } + } + } + + _setOpenState(open){ + if(this.isSimpleMenuItem && open){ + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + } + else if(open) + this.loadMenu(); + + this.setSubmenuShown(open); + } +}); + +// Place Info class +var PlaceInfo = class Arc_Menu_PlaceInfo { + constructor(file, name, icon) { + this.file = file; + this.name = name ? name : this._getFileName(); + this.icon = icon ? icon : null; + this.gicon = icon ? null : this.getIcon(); + } + + launch(timestamp) { + let context = global.create_app_launch_context(timestamp, -1); + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(this._getFileName()), e.message); + reject(e); + } + }); + }); + } + + getIcon() { + try { + let info = this.file.query_info('standard::symbolic-icon', 0, null); + return info.get_symbolic_icon(); + + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!this.file.is_native()) { + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + return this.file.get_basename(); + } + } + } + + destroy(){ + } +}; +Signals.addSignalMethods(PlaceInfo.prototype); + +// Menu Place Shortcut item class +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._info = info; + this._settings = menuLayout._settings; + this.isContainedInCategory = isContainedInCategory; + this.hasContextMenu = true; + + this.label = new St.Label({ + text: _(info.name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = this.y_expand = false; + this.x_align = this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + this.add_child(this.label); + } + + this._changedId = this._info.connect('changed', this._propertiesChanged.bind(this)); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: this._info.gicon ? this._info.gicon : this._info.icon, + icon_size: iconSize, + }); + } + + _onDestroy() { + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = null; + } + if(this._info) + this._info.destroy(); + super._onDestroy(); + } + + popupContextMenu(){ + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this.createIcon(); + if(this.label) + this.label.text = info.name; + } +}); + +var SearchBox = GObject.registerClass({ +Signals: { + 'search-changed': { param_types: [GObject.TYPE_STRING] }, + 'entry-key-focus-in': { }, + 'entry-key-press': { param_types: [Clutter.Event.$gtype] }, +},}, +class Arc_Menu_SearchBox extends St.Entry { + _init(menuLayout) { + super._init({ + hint_text: _("Search…"), + track_hover: true, + can_focus: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + name: "ArcSearchEntry" + }); + this.searchResults = menuLayout.searchResults; + this._settings = menuLayout._settings; + this.triggerSearchChangeEvent = true; + + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.EXTRA_SMALL_ICON_SIZE); + + this._findIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-find-symbolic', + icon_size: iconSize + }); + + this._clearIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-clear-symbolic', + icon_size: iconSize + }); + + this.set_primary_icon(this._findIcon); + + this._text = this.get_clutter_text(); + this._textChangedId = this._text.connect('text-changed', this._onTextChanged.bind(this)); + this._keyPressId = this._text.connect('key-press-event', this._onKeyPress.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-in', this._onKeyFocusIn.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-out', this._onKeyFocusOut.bind(this)); + this._searchIconClickedId = this.connect('secondary-icon-clicked', () => this.clear()); + this.connect('destroy', this._onDestroy.bind(this)); + } + + updateStyle(removeBorder){ + let style = this.style; + this.style = style.replace("border-width: 0;", ""); + if(removeBorder) + this.style += 'border-width: 0;'; + } + + get entryBox(){ + return this; + } + + get actor(){ + return this; + } + + getText() { + return this.get_text(); + } + + setText(text) { + this.set_text(text); + } + + clearWithoutSearchChangeEvent(){ + this.triggerSearchChangeEvent = false; + this.set_text(''); + this.triggerSearchChangeEvent = true; + } + + hasKeyFocus() { + return this.contains(global.stage.get_key_focus()); + } + + clear() { + this.set_text(''); + } + + isEmpty() { + return this.get_text() == ''; + } + + _onKeyFocusOut(){ + if(!this.isEmpty()){ + this.add_style_pseudo_class('focus'); + return Clutter.EVENT_STOP; + } + } + + _onTextChanged() { + let searchString = this.get_text(); + if(!this.isEmpty()){ + if(!this.hasKeyFocus()) + this.grab_key_focus(); + if (!this.searchResults.getTopResult()?.has_style_pseudo_class("active")) + this.searchResults.getTopResult()?.add_style_pseudo_class("active") + this.add_style_pseudo_class('focus'); + this.set_secondary_icon(this._clearIcon); + } + else{ + if(!this.hasKeyFocus()) + this.remove_style_pseudo_class('focus'); + this.set_secondary_icon(null); + } + + if(this.triggerSearchChangeEvent) + this.emit('search-changed', searchString); + } + + _onKeyPress(actor, event) { + let symbol = event.get_key_symbol(); + if (symbol == Clutter.KEY_Return || + symbol == Clutter.KEY_KP_Enter) { + if (!this.isEmpty()) { + if (this.searchResults.getTopResult()) { + this.searchResults.getTopResult().activate(event); + } + } + return Clutter.EVENT_STOP; + } + this.emit('entry-key-press', event); + return Clutter.EVENT_PROPAGATE; + } + + _onKeyFocusIn() { + this.add_style_pseudo_class('focus'); + this.emit('entry-key-focus-in'); + return Clutter.EVENT_PROPAGATE; + } + + _onDestroy() { + if (this._textChangedId) { + this._text.disconnect(this._textChangedId); + this._textChangedId = null; + } + if (this._keyPressId) { + this._text.disconnect(this._keyPressId); + this._keyPressId = null; + } + if (this._keyFocusInId) { + this._text.disconnect(this._keyFocusInId); + this._keyFocusInId = null; + } + if(this._searchIconClickedId){ + this.disconnect(this._searchIconClickedId); + this._searchIconClickedId = null; + } + } +}); + +/** + * This class is responsible for the appearance of the menu button. + */ +var MenuButtonWidget = class Arc_Menu_MenuButtonWidget{ + constructor() { + this.actor = new St.BoxLayout({ + style_class: 'panel-status-menu-box', + pack_start: false + }); + this._arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + this._arrowIcon.add_style_class_name('arc-menu-arrow'); + + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + reactive: true, + }); + this._label = new St.Label({ + text: _("Applications"), + y_expand: true, + style_class: 'arc-menu-text', + y_align: Clutter.ActorAlign.CENTER, + }); + + this.actor.add_child(this._icon); + this.actor.add_child(this._label); + this.actor.add_child(this._arrowIcon); + } + + setActiveStylePseudoClass(enable){ + if(enable){ + this._arrowIcon.add_style_pseudo_class('active'); + this._icon.add_style_pseudo_class('active'); + this._label.add_style_pseudo_class('active'); + } + else{ + this._arrowIcon.remove_style_pseudo_class('active'); + this._icon.remove_style_pseudo_class('active'); + this._label.remove_style_pseudo_class('active'); + } + } + + updateArrowIconSide(side){ + let iconName; + switch (side) { + case St.Side.TOP: + iconName = 'pan-down-symbolic'; + break; + case St.Side.RIGHT: + iconName = 'pan-start-symbolic'; + break; + case St.Side.BOTTOM: + iconName = 'pan-up-symbolic'; + break; + case St.Side.LEFT: + iconName = 'pan-end-symbolic'; + break; + } + this._arrowIcon.icon_name = iconName; + } + + getPanelLabel() { + return this._label; + } + + getPanelIcon() { + return this._icon; + } + + showArrowIcon() { + if (!this.actor.contains(this._arrowIcon)) { + this.actor.add_child(this._arrowIcon); + } + } + + hideArrowIcon() { + if (this.actor.contains(this._arrowIcon)) { + this.actor.remove_child(this._arrowIcon); + } + } + + showPanelIcon() { + if (!this.actor.contains(this._icon)) { + this.actor.add_child(this._icon); + } + } + + hidePanelIcon() { + if (this.actor.contains(this._icon)) { + this.actor.remove_child(this._icon); + } + } + + showPanelText() { + if (!this.actor.contains(this._label)) { + this.actor.add_child(this._label); + } + } + + hidePanelText() { + this._label.style = ''; + if (this.actor.contains(this._label)) { + this.actor.remove_child(this._label); + } + } + + setPanelTextStyle(style){ + this._label.style = style; + } +}; + +var DashMenuButtonWidget = class Arc_Menu_DashMenuButtonWidget{ + constructor(menuButton, settings) { + this._menuButton = menuButton; + this._settings = settings; + this.actor = new St.Button({ + style_class: 'show-apps', + track_hover: true, + can_focus: true, + toggle_mode: false, + reactive: false + }); + this.actor._delegate = this; + this.icon = new imports.ui.iconGrid.BaseIcon(_("ArcMenu"), + { setSizeManually: true, + showLabel: false, + createIcon: this._createIcon.bind(this) }); + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + icon_size: 15, + track_hover:true, + reactive: true + }); + this.icon._delegate = this.actor; + this._labelText = _("ArcMenu"); + this.label = new St.Label({ style_class: 'dash-label' }); + this.label.hide(); + Main.layoutManager.addChrome(this.label); + this.label_actor = this.label; + this.actor.set_child(this.icon); + + this.child = this.actor; + } + showLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.actor.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1; + let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let x, y, xOffset, yOffset; + + let position = this._menuButton._panel._settings.get_enum('dock-position'); + this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); + let labelOffset = node.get_length('-x-offset'); + switch (position) { + case St.Side.LEFT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = stageX + this.actor.get_width() + xOffset; + break; + case St.Side.RIGHT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = Math.round(stageX) - labelWidth - xOffset; + break; + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + case St.Side.BOTTOM: + yOffset = labelOffset; + y = stageY - labelHeight - yOffset; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + } + + // keep the label inside the screen border + // Only needed fot the x coordinate. + + // Leave a few pixel gap + let gap = 5; + let monitor = Main.layoutManager.findMonitorForActor(this.actor); + if (x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + + this.label.remove_all_transitions(); + this.label.set_position(x, y); + this.label.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD + }); + } + hideLabel() { + this.label.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.label.hide() + }); + } + _createIcon(size) { + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + icon_size: size, + reactive: true + }); + let path = this._settings.get_string('custom-menu-button-icon'); + let iconString = Utils.getMenuButtonIcon(this._settings, path); + this._icon.set_gicon(Gio.icon_new_for_string(iconString)); + + return this._icon; + } + getPanelIcon() { + return this._icon; + } +}; + +var WorldClocksSection = GObject.registerClass(class Arc_Menu_WorldClocksSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this._clock = new imports.gi.GnomeDesktop.WallClock(); + this._clockNotifyId = 0; + + this._locations = []; + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._grid = new St.Widget({ style_class: 'world-clocks-grid', + x_expand: true, + layout_manager: layout }); + layout.hookup_style(this._grid); + + this.add_child(this._grid); + + this._clocksApp = null; + this._clocksProxy = new ClocksProxy( + Gio.DBus.session, + 'org.gnome.clocks', + '/org/gnome/clocks', + this._onProxyReady.bind(this), + null /* cancellable */, + Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES); + + this._clockSettings = new Gio.Settings({ + schema_id: 'org.gnome.shell.world-clocks', + }); + this.clocksChangedID = this._clockSettings.connect('changed', this._clocksChanged.bind(this)); + this._clocksChanged(); + + this._appSystem = Shell.AppSystem.get_default(); + this.syncID = this._appSystem.connect('installed-changed', + this._sync.bind(this)); + this._sync(); + } + + _onDestroy(){ + if(this.syncID){ + this._appSystem.disconnect(this.syncID); + this.syncID = null; + } + if(this.clocksChangedID){ + this._clockSettings.disconnect(this.clocksChangedID); + this.clocksChangedID = null; + } + if(this.clocksProxyID){ + this._clocksProxy.disconnect(this.clocksProxyID); + this.clocksProxyID = null; + } + if (this._clockNotifyId){ + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = null; + } + } + + activate(event) { + super.activate(event); + if (this._clocksApp){ + this._clocksApp.activate(); + } + } + + _sync() { + this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); + this.visible = this._clocksApp != null; + } + + _clocksChanged() { + this._grid.destroy_all_children(); + this._locations = []; + + let world = imports.gi.GWeather.Location.get_world(); + let clocks = this._clockSettings.get_value('locations').deep_unpack(); + for (let i = 0; i < clocks.length; i++) { + let l = world.deserialize(clocks[i]); + if (l && l.get_timezone() != null) + this._locations.push({ location: l }); + } + + this._locations.sort((a, b) => { + return a.location.get_timezone().get_offset() - + b.location.get_timezone().get_offset(); + }); + + let layout = this._grid.layout_manager; + let title = this._locations.length == 0 + ? _("Add world clocks…") + : _("World Clocks"); + let header = new St.Label({ x_align: Clutter.ActorAlign.START, + text: title }); + header.style = "font-weight: bold;"; + layout.attach(header, 0, 0, 2, 1); + this.label_actor = header; + + let localOffset = GLib.DateTime.new_now_local().get_utc_offset(); + + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i].location; + + let name = l.get_city_name() || l.get_name(); + let label = new St.Label({ text: name, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true }); + label.style = "font-weight: normal; font-size: 0.9em;"; + let time = new St.Label(); + time.style = "font-feature-settings: \"tnum\"; font-size: 1.2em;"; + let otherOffset = this._getTimeAtLocation(l).get_utc_offset(); + let offset = (otherOffset - localOffset) / GLib.TIME_SPAN_HOUR; + let fmt = Math.trunc(offset) == offset ? '%s%.0f' : '%s%.1f'; + let prefix = offset >= 0 ? '+' : '-'; + let tz = new St.Label({ text: fmt.format(prefix, Math.abs(offset)), + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER }); + tz.style = "font-feature-settings: \"tnum\"; font-size: 0.9em;"; + if (this._grid.text_direction == Clutter.TextDirection.RTL) { + layout.attach(tz, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(label, 2, i + 1, 1, 1); + } else { + layout.attach(label, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(tz, 2, i + 1, 1, 1); + } + + this._locations[i].actor = time; + } + + if (this._grid.get_n_children() > 1) { + if (!this._clockNotifyId) { + this._clockNotifyId = + this._clock.connect('notify::clock', this._updateLabels.bind(this)); + } + this._updateLabels(); + } else { + if (this._clockNotifyId) + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = 0; + } + } + + _getTimeAtLocation(location) { + let tz = GLib.TimeZone.new(location.get_timezone().get_tzid()); + return GLib.DateTime.new_now(tz); + } + + _updateLabels() { + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i]; + let now = this._getTimeAtLocation(l.location); + l.actor.text = Util.formatTime(now, { timeOnly: true }); + } + } + + _onProxyReady(proxy, error) { + if (error) { + log(`Failed to create GNOME Clocks proxy: ${error}`); + return; + } + + this.clocksProxyID = this._clocksProxy.connect('g-properties-changed', + this._onClocksPropertiesChanged.bind(this)); + this._onClocksPropertiesChanged(); + } + + _onClocksPropertiesChanged() { + if (this._clocksProxy.g_name_owner == null) + return; + + this._clockSettings.set_value('locations', + new GLib.Variant('av', this._clocksProxy.Locations)); + } +}); + +var WeatherSection = GObject.registerClass(class Arc_Menu_WeatherSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this.x_align = Clutter.ActorAlign.FILL; + this._weatherClient = new imports.misc.weather.WeatherClient(); + + let box = new St.BoxLayout({ + vertical: true, + x_expand: true, + }); + + this.add_child(box); + + let titleBox = new St.BoxLayout({ }); + let label = new St.Label({ + x_align: Clutter.ActorAlign.START, + x_expand: true, + y_align: Clutter.ActorAlign.END, + text: _('Weather'), + }) + label.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(label); + box.add_child(titleBox); + + this._titleLocation = new St.Label({ + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.END, + }); + this._titleLocation.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(this._titleLocation); + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._forecastGrid = new St.Widget({ + style_class: 'weather-grid', + layout_manager: layout, + }); + layout.hookup_style(this._forecastGrid); + box.add_child(this._forecastGrid); + + this.syncID = this._weatherClient.connect('changed', this._sync.bind(this)); + this._sync(); + + } + _onDestroy(){ + if(this.syncID){ + this._weatherClient.disconnect(this.syncID); + this.syncID = null; + } + this._weatherClient = null; + } + vfunc_map() { + this._weatherClient.update(); + super.vfunc_map(); + } + + activate(event) { + super.activate(event); + this._weatherClient.activateApp(); + } + + _getInfos() { + let forecasts = this._weatherClient.info.get_forecast_list(); + + let now = GLib.DateTime.new_now_local(); + let current = GLib.DateTime.new_from_unix_local(0); + let infos = []; + for (let i = 0; i < forecasts.length; i++) { + const [valid, timestamp] = forecasts[i].get_value_update(); + if (!valid || timestamp === 0) + continue; // 0 means 'never updated' + + const datetime = GLib.DateTime.new_from_unix_local(timestamp); + if (now.difference(datetime) > 0) + continue; // Ignore earlier forecasts + + if (datetime.difference(current) < GLib.TIME_SPAN_HOUR) + continue; // Enforce a minimum interval of 1h + + if (infos.push(forecasts[i]) == 5) + break; // Use a maximum of five forecasts + + current = datetime; + } + return infos; + } + + _addForecasts() { + let layout = this._forecastGrid.layout_manager; + + let infos = this._getInfos(); + if (this._forecastGrid.text_direction == Clutter.TextDirection.RTL) + infos.reverse(); + + let col = 0; + infos.forEach(fc => { + const [valid_, timestamp] = fc.get_value_update(); + let timeStr = Util.formatTime(new Date(timestamp * 1000), { + timeOnly: true + }); + const [, tempValue] = fc.get_value_temp(imports.gi.GWeather.TemperatureUnit.DEFAULT); + const tempPrefix = tempValue >= 0 ? ' ' : ''; + + let time = new St.Label({ + text: timeStr, + x_align: Clutter.ActorAlign.CENTER, + }); + time.style = "font-size: 0.8em;" + let icon = new St.Icon({ + style_class: 'weather-forecast-icon', + icon_name: fc.get_symbolic_icon_name(), + x_align: Clutter.ActorAlign.CENTER, + x_expand: true, + }); + let temp = new St.Label({ + text: '%s%.0f°'.format(tempPrefix, tempValue), + x_align: Clutter.ActorAlign.CENTER, + }); + + temp.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + time.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + + layout.attach(time, col, 0, 1, 1); + layout.attach(icon, col, 1, 1, 1); + layout.attach(temp, col, 2, 1, 1); + col++; + }); + } + + _setStatusLabel(text) { + let layout = this._forecastGrid.layout_manager; + let label = new St.Label({ text }); + layout.attach(label, 0, 0, 1, 1); + } + + _updateForecasts() { + this._forecastGrid.destroy_all_children(); + + if (!this._weatherClient.hasLocation) { + this._setStatusLabel(_("Select a location…")); + return; + } + + let info = this._weatherClient.info; + let loc = info.get_location(); + if (loc.get_level() !== imports.gi.GWeather.LocationLevel.CITY && loc.has_coords()) { + let world = imports.gi.GWeather.Location.get_world(); + loc = world.find_nearest_city(...loc.get_coords()); + } + this._titleLocation.text = loc.get_name(); + + if (this._weatherClient.loading) { + this._setStatusLabel(_("Loading…")); + return; + } + + if (info.is_valid()) { + this._addForecasts(); + return; + } + + if (info.network_error()) + this._setStatusLabel(_("Go online for weather information")); + else + this._setStatusLabel(_("Weather information is currently unavailable")); + } + + _sync() { + this.visible = this._weatherClient.available; + + if (!this.visible) + return; + + this._titleLocation.visible = this._weatherClient.hasLocation; + + this._updateForecasts(); + } +}); + +function _isToday(date) { + let now = new Date(); + return now.getYear() == date.getYear() && + now.getMonth() == date.getMonth() && + now.getDate() == date.getDate(); +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js new file mode 100644 index 0000000..a0c1d16 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js @@ -0,0 +1,456 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.buttonPressEventID = global.stage.connect("button-press-event", () => { + if(this.arcMenu.isOpen && this.backButton.visible){ + let event = Clutter.get_current_event(); + if(event.get_button() === 8){ + this.backButton.activate(event); + } + } + }); + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'left-panel' + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + this.leftBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBox.add_child(separator); + + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(this.backButton.actor); + + this.viewProgramsButton = new MW.ViewAllPrograms(this); + this.navigateBox.add_child(this.viewProgramsButton.actor); + this.leftBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 5px 10px 0px 10px;"; + this.leftBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length > 0){ + this.placesShortcuts = true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length > 0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw = true; + if(shouldDraw){ + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px; padding: 0px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + this.extraCategoriesLinksBox = new St.BoxLayout({ + vertical: true + }); + this.extraCategoriesLinksBox.hide(); + this.extraCategoriesSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + + let extraCategoriesLinksLocation = this._settings.get_enum('arcmenu-extra-categories-links-location'); + if(extraCategoriesLinksLocation === Constants.MenuItemLocation.TOP) + this.leftBox.insert_child_below(this.extraCategoriesLinksBox, this.applicationsScrollBox); + else + this.navigateBox.insert_child_above(this.extraCategoriesLinksBox, this.navigateBox.get_child_at_index(0)); + this.extraCategoriesLinksBox.add_child(this.extraCategoriesSeparator); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + _createExtraCategoriesLinks(){ + this.showExtraCategoriesLinksBox = false; + let extraCategories = this._settings.get_value("arcmenu-extra-categories-links").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + //Don't create extra categories quick links if + //the default menu view is the categories list + if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + return; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.ALL_PROGRAMS && shouldShow && defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + shouldShow = false; + if(shouldShow){ + let extraCategoryItem = this.categoryDirectories.get(categoryEnum); + if(!extraCategoryItem) + continue; + + this.showExtraCategoriesLinksBox = true; + if(extraCategoryItem.get_parent()) + extraCategoryItem.get_parent().remove_child(extraCategoryItem); + + this.extraCategoriesLinksBox.insert_child_below(extraCategoryItem, this.extraCategoriesSeparator); + } + } + if(this.showExtraCategoriesLinksBox) + this.extraCategoriesLinksBox.show(); + else + this.extraCategoriesLinksBox.hide(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.hasPinnedApps = true; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + this._createExtraCategoriesLinks(); + } + + displayPinnedApps(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS){ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayAllApps(showBackButton = true){ + super.displayAllApps(); + this.viewProgramsButton.actor.hide(); + + if(showBackButton){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + } + else{ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.backButton.actor.hide(); + } + } + + displayCategories(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else{ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.displayPinnedApps(); + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this.displayFrequentApps(); + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + this.displayAllApps(false); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let isContainedInCategory = false; + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST, null, isContainedInCategory); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + displayRecentFiles(){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + super.displayRecentFiles(); + } + + _clearActorsFromBox(box){ + //keep track of the previous category for the back button. + this.previousCategoryType = this.activeCategoryType; + super._clearActorsFromBox(box); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.buttonPressEventID){ + global.stage.disconnect(this.buttonPressEventID); + this.buttonPressEventID = null; + } + super.destroy() + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js new file mode 100644 index 0000000..dce09de --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js @@ -0,0 +1,285 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 4, + RowSpacing: 4, + VerticalMainBox: true, + DefaultMenuWidth: 460, + DefaultIconGridStyle: 'LargeRectIconGrid', + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBoxStyle = "margin: 0px 0px 10px 0px; spacing: 0px; background-color: rgba(186, 196,201, 0.1); padding: 11px 5px;"+ + "border-color:rgba(186, 196,201, 0.2); border-bottom-width: 1px;"; + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.topBoxStyle + }); + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 5px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.subMainBox.add_child(this.topBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 12px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "margin: 0px 15px; spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.x_expand = true; + this.user.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + + let filesButton = new MW.ShortcutMenuItem(this, _("Files"), "system-file-manager", "org.gnome.Nautilus.desktop", Constants.DisplayType.BUTTON); + if(filesButton.shouldShow) + this.actionsBox.add_child(filesButton.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton) + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton) + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.IconGridSize = 42; + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + setDefaultMenuView(){ + this.setGridLayout(Constants.DisplayType.GRID, 4, 4); + this.layoutProperties.IconGridSize = 42; + super.setDefaultMenuView(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 3); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 4, 4, false); + } + + updateStyle(){ + super.updateStyle(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + const RoundBottomBorder = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + const RoundTopBorder = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + RoundBottomBorder; + this.topBox.style = this.topBoxStyle + RoundTopBorder; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.layoutProperties.IconGridSize = 26; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.subMainBox.insert_child_at_index(this.allAppsButton, 1); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.subMainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.subMainBox.contains(this.backButton)) + this.subMainBox.remove_child(this.backButton); + if(this.subMainBox.contains(this.allAppsButton)) + this.subMainBox.remove_child(this.allAppsButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.style = 'padding: 0px 15px 10px 15px;' + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.leaveButton.destroy(); + this.backButton.destroy(); + this.allAppsButton.destroy(); + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js new file mode 100644 index 0000000..af9d2c4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js @@ -0,0 +1,1128 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, GMenu, Gtk, Shell, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const appSys = Shell.AppSystem.get_default(); +const ArcSearch = Me.imports.search; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MenuLayouts = Me.imports.menulayouts; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const Utils = Me.imports.utils; + +//This class handles the core functionality of all the menu layouts. +//Each menu layout extends this class. +var BaseLayout = class { + constructor(menuButton, layoutProperties){ + this.menuButton = menuButton; + this._settings = menuButton._settings; + this.mainBox = menuButton.mainBox; + this.contextMenuManager = menuButton.contextMenuManager; + this.subMenuManager = menuButton.subMenuManager; + this.arcMenu = menuButton.arcMenu; + this.section = menuButton.section; + this.layout = this._settings.get_enum('menu-layout'); + this.layoutProperties = layoutProperties; + this._focusChild = null; + this.shouldLoadPinnedApps = true; + this.hasPinnedApps = false; + + if(this.layoutProperties.Search){ + this.searchResults = new ArcSearch.SearchResults(this); + this.searchBox = new MW.SearchBox(this); + this._searchBoxChangedId = this.searchBox.connect('search-changed', this._onSearchBoxChanged.bind(this)); + this._searchBoxKeyPressId = this.searchBox.connect('entry-key-press', this._onSearchBoxKeyPress.bind(this)); + } + + this._mainBoxKeyPressId = this.mainBox.connect('key-press-event', this._onMainBoxKeyPress.bind(this)); + + this._tree = new GMenu.Tree({ menu_basename: 'applications.menu' }); + this._treeChangedId = this._tree.connect('changed', () => this.reloadApplications()); + + this._gnomeFavoritesReloadID = AppFavorites.getAppFavorites().connect('changed', () => { + if(this.categoryDirectories){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem) + this._loadGnomeFavorites(categoryMenuItem); + } + }); + + this.mainBox.vertical = this.layoutProperties.VerticalMainBox; + + this.createLayout(); + this.updateStyle(); + } + + createLayout(){ + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.activeCategoryType = -1; + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.applicationsGrid = new St.Widget({ + x_expand: true, + x_align: this.layoutProperties.DisplayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.applicationsGrid); + } + + setDefaultMenuView(){ + if(this.layoutProperties.Search){ + this.searchBox.clearWithoutSearchChangeEvent(); + this.searchResults.setTerms([]); + } + + this._clearActorsFromBox(); + this.resetScrollBarPosition(); + } + + getColumnsFromActor(actor){ + let gridIconWidth = this.getActorWidthFromStyleClass(actor.name); + return this.getBestFitColumns(gridIconWidth); + } + + getColumnsFromGridIconSizeSetting(){ + let gridIconWidth; + let iconSizeEnum = this._settings.get_enum("menu-item-grid-icon-size"); + + if(iconSizeEnum === Constants.GridIconSize.DEFAULT) + gridIconWidth = this.getActorWidthFromStyleClass(this.layoutProperties.DefaultIconGridStyle); + else{ + Constants.GridIconInfo.forEach((info) => { + if(iconSizeEnum === info.ENUM){ + gridIconWidth = info.SIZE; + return; + } + }); + } + return this.getBestFitColumns(gridIconWidth); + } + + getBestFitColumns(gridIconWidth){ + let width = this.layoutProperties.MenuWidth; + let spacing = this.layoutProperties.ColumnSpacing; + let columns = Math.floor(width / (gridIconWidth + spacing)); + return columns; + } + + getActorWidthFromStyleClass(name){ + let size; + + Constants.GridIconInfo.forEach((info) => { + if(name === info.NAME){ + size = info.SIZE; + return; + } + }); + return size; + } + + resetScrollBarPosition(){ + let appsScrollBoxAdj; + + if(this.applicationsScrollBox){ + appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.categoriesScrollBox){ + appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.shortcutsScrollBox){ + appsScrollBoxAdj = this.shortcutsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.actionsScrollBox){ + appsScrollBoxAdj = this.actionsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + } + + reloadApplications(){ + //Don't reload applications if the menu is open. + //Instead, reload on menu-closed event. + //Prevents the menu from jumping to its default view + //when reloadApplications() is called. + if(this.arcMenu.isOpen){ + if(!this._menuClosedID){ + this._menuClosedID = this.arcMenu.connect('menu-closed', () => { + this.reloadApplications(); + if(this._menuClosedID){ + this.arcMenu.disconnect(this._menuClosedID); + this._menuClosedID = null; + } + }); + } + return; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(this.layoutProperties.Search){ + this.searchBox.updateStyle(this._settings.get_boolean('disable-searchbox-border')) + customStyle ? this.searchResults.setStyle('arc-menu-status-text') : this.searchResults.setStyle(''); + if(customStyle){ + this.searchBox.remove_style_class_name('default-search-entry'); + this.searchBox.add_style_class_name('arc-search-entry'); + } + else{ + this.searchBox.remove_style_class_name('arc-search-entry'); + this.searchBox.add_style_class_name('default-search-entry'); + } + } + } + + loadCategories(displayType = Constants.DisplayType.LIST){ + this.applicationsMap = new Map(); + this._tree.load_sync(); + let root = this._tree.get_root_directory(); + let iter = root.iter(); + let nextType; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.DIRECTORY) { + let dir = iter.get_directory(); + if (!dir.get_is_nodisplay()) { + let categoryId = dir.get_menu_id(); + let categoryMenuItem; + if(displayType === Constants.DisplayType.SIMPLE_CATEGORY) + categoryMenuItem = new MW.SimpleMenuItem(this, dir); + else if(displayType === Constants.DisplayType.SUBMENU_CATEGORY) + categoryMenuItem = new MW.CategorySubMenuItem(this, dir); + else + categoryMenuItem = new MW.CategoryMenuItem(this, dir, displayType); + this.categoryDirectories.set(categoryId, categoryMenuItem); + let foundRecentlyInstallApp = this._loadCategory(categoryId, dir); + categoryMenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + //Sort the App List Alphabetically + categoryMenuItem.appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + } + } + } + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.ALL_PROGRAMS); + if(categoryMenuItem){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + //Show Recently Installed Indicator on All Programs category + if(value.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + categoryMenuItem.appList = appList; + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem){ + this._loadGnomeFavorites(categoryMenuItem); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + if(categoryMenuItem){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this.hasPinnedApps = true; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + if(categoryMenuItem){ + this._loadRecentFiles(categoryMenuItem); + } + + } + + _loadCategory(categoryId, dir, submenuItem) { + let iter = dir.iter(); + let nextType; + let foundRecentlyInstallApp = false; + let isLayoutSimple2 = this.layout === Constants.MenuLayout.SIMPLE_2; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.ENTRY) { + let entry = iter.get_entry(); + let id; + try { + id = entry.get_desktop_file_id(); + } catch (e) { + continue; + } + let app = appSys.lookup_app(id); + if (!app) + app = new Shell.App({ app_info: entry.get_app_info() }); + if (app.get_app_info().should_show()){ + let item = this.applicationsMap.get(app); + if (!item) { + let isContainedInCategory = true; + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType, null, isContainedInCategory); + } + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled && item.isRecentlyInstalled) + foundRecentlyInstallApp = true; + if(!submenuItem){ + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(app); + this.applicationsMap.set(app, item); + } + else{ + submenuItem.applicationsMap.set(app, item); + } + } + } + else if (nextType == GMenu.TreeItemType.DIRECTORY) { + let subdir = iter.get_directory(); + if (!subdir.get_is_nodisplay()){ + if(this._settings.get_boolean('enable-sub-menus') && this.layoutProperties.DisplayType === Constants.DisplayType.LIST && !isLayoutSimple2){ + let submenuItem = this.applicationsMap.get(subdir); + if (!submenuItem) { + submenuItem = new MW.CategorySubMenuItem(this, subdir); + submenuItem._setParent(this.arcMenu); + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(subdir); + this.applicationsMap.set(subdir, submenuItem); + } + let recentlyInstallApp = this._loadCategory(categoryId, subdir, submenuItem); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + submenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + } + else{ + let recentlyInstallApp = this._loadCategory(categoryId, subdir); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + } + } + } + } + return foundRecentlyInstallApp; + } + + setRecentlyInstalledIndicator(){ + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.setRecentlyInstalledIndicator(false); + for(let i = 0; i < categoryMenuItem.appList.length; i++){ + let item = this.applicationsMap.get(categoryMenuItem.appList[i]); + if(!item) + continue; + if(item instanceof MW.CategorySubMenuItem){ + item.setRecentlyInstalledIndicator(false); + for(let menuItem of item.applicationsMap.values()){ + if(menuItem.isRecentlyInstalled){ + item.setRecentlyInstalledIndicator(true); + break; + } + } + } + if(item.isRecentlyInstalled){ + categoryMenuItem.setRecentlyInstalledIndicator(true); + break; + } + } + } + } + } + + displayCategories(categoriesBox){ + if(!categoriesBox){ + categoriesBox = this.applicationsBox; + } + this._clearActorsFromBox(categoriesBox); + + this._futureActiveItem = false; + + for(let categoryMenuItem of this.categoryDirectories.values()){ + if(categoryMenuItem.get_parent()) + continue; + categoriesBox.add_child(categoryMenuItem.actor); + if(!this._futureActiveItem){ + this._futureActiveItem = categoryMenuItem; + } + } + + this.activeMenuItem = this._futureActiveItem; + } + + _loadGnomeFavorites(categoryMenuItem){ + let appList = AppFavorites.getAppFavorites().getFavorites(); + + //Show Recently Installed Indicator on GNOME favorites category + for(let i = 0; i < appList.length; i++){ + let item = this.applicationsMap.get(appList[i]); + if(item && item.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + } + + categoryMenuItem.appList = appList; + if(this.activeCategoryType === Constants.CategoryType.FAVORITES) + categoryMenuItem.displayAppList(); + } + + _loadRecentFiles(){ + if(!this.recentFilesManager) + this.recentFilesManager = new RecentFilesManager(); + } + + displayRecentFiles(box = this.applicationsBox, callback){ + const homeRegExp = new RegExp('^(' + GLib.get_home_dir() + ')'); + this._clearActorsFromBox(box); + this._futureActiveItem = false; + + this.recentFilesManager.filterRecentFiles(recentFile => { + let file = Gio.File.new_for_uri(recentFile.get_uri()); + let filePath = file.get_path(); + let name = recentFile.get_display_name(); + let icon = Gio.content_type_get_symbolic_icon(recentFile.get_mime_type()).to_string(); + let isContainedInCategory = true; + + let placeMenuItem = this.createMenuItem([name, icon, filePath], Constants.DisplayType.LIST, isContainedInCategory); + placeMenuItem._path = file.get_parent()?.get_path() // can be null + placeMenuItem.style = "padding-right: 15px;"; + placeMenuItem.description = recentFile.get_uri_display().replace(homeRegExp, '~'); + placeMenuItem.fileUri = recentFile.get_uri(); + + placeMenuItem._removeBtn = new MW.ArcMenuButtonItem(this, null, 'edit-delete-symbolic'); + placeMenuItem._removeBtn.toggleMenuOnClick = false; + placeMenuItem._removeBtn.x_align = Clutter.ActorAlign.END; + placeMenuItem._removeBtn.x_expand = true; + placeMenuItem._removeBtn.add_style_class_name("arcmenu-small-button"); + placeMenuItem._removeBtn.setIconSize(14); + placeMenuItem._removeBtn.connect('activate', () => { + try { + let recentManager = this.recentFilesManager.getRecentManager(); + recentManager.remove_item(placeMenuItem.fileUri); + } catch(err) { + log(err); + } + + placeMenuItem.cancelPopupTimeout(); + placeMenuItem.contextMenu?.close(); + box.remove_child(placeMenuItem); + placeMenuItem.destroy(); + }); + + placeMenuItem.add_child(placeMenuItem._removeBtn); + box.add_child(placeMenuItem); + + if(!this._futureActiveItem){ + this._futureActiveItem = placeMenuItem; + this.activeMenuItem = this._futureActiveItem; + } + + if(callback) + callback(); + }); + } + + _displayPlaces() { + var SHORTCUT_TRANSLATIONS = [_("Home"), _("Documents"), _("Downloads"), _("Music"), _("Pictures"), _("Videos"), _("Computer"), _("Network")]; + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem) + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadExtraPinnedApps(pinnedAppsArray, separatorIndex){ + let pinnedApps = pinnedAppsArray; + //if the extraPinnedApps array is empty, create a default list of apps. + if(!pinnedApps.length || !Array.isArray(pinnedApps)){ + pinnedApps = this._createExtraPinnedAppsList(); + } + + for(let i = 0;i < pinnedApps.length; i += 3){ + if(i === separatorIndex * 3 && i !== 0) + this._addSeparator(); + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2]], Constants.DisplayType.BUTTON, isContainedInCategory); + placeMenuItem.actor.x_expand = false; + placeMenuItem.actor.y_expand = false; + placeMenuItem.actor.y_align = Clutter.ActorAlign.CENTER; + placeMenuItem.actor.x_align = Clutter.ActorAlign.CENTER; + this.actionsBox.add_child(placeMenuItem.actor); + } + } + + createMenuItem(menuItemArray, displayType, isContainedInCategory){ + let placeInfo, placeMenuItem; + let command = menuItemArray[2]; + let app = Shell.AppSystem.get_default().lookup_app(command); + + if(command === "ArcMenu_Home"){ + let homePath = GLib.get_home_dir(); + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(homePath), _("Home")); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Computer"){ + placeInfo = new PlaceDisplay.RootInfo(); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Network"){ + placeInfo = new PlaceDisplay.PlaceInfo('network', Gio.File.new_for_uri('network:///'), _('Network'),'network-workgroup-symbolic'); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Software"){ + let software = Utils.findSoftwareManager(); + if(software) + placeMenuItem = new MW.ShortcutMenuItem(this, _("Software"), 'system-software-install-symbolic', software, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Trash"){ + placeMenuItem = new MW.ShortcutMenuItem(this, _("Trash"), '', "ArcMenu_Trash", displayType, isContainedInCategory); + } + else if(command === Constants.ArcMenuSettingsCommand || command === "ArcMenu_Suspend" || command === "ArcMenu_LogOut" || command === "ArcMenu_PowerOff" + || command === "ArcMenu_Lock" || command === "ArcMenu_Restart" || command === "ArcMenu_HybridSleep" || command === "ArcMenu_Hibernate" || app){ + + placeMenuItem = new MW.ShortcutMenuItem(this, menuItemArray[0], menuItemArray[1], menuItemArray[2], displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Recent"){ + let uri = "recent:///"; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_uri(uri), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command.startsWith("ArcMenu_")){ + let path = command.replace("ArcMenu_",''); + + if(path === "Documents") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS; + else if(path === "Downloads") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOWNLOAD; + else if(path === "Music") + path = imports.gi.GLib.UserDirectory.DIRECTORY_MUSIC; + else if(path === "Pictures") + path = imports.gi.GLib.UserDirectory.DIRECTORY_PICTURES; + else if(path === "Videos") + path = imports.gi.GLib.UserDirectory.DIRECTORY_VIDEOS; + + path = GLib.get_user_special_dir(path); + if (path !== null){ + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + } + else{ + let path = command; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0]), (menuItemArray[1] !== "ArcMenu_Folder") ? Gio.icon_new_for_string(menuItemArray[1]) : null); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + return placeMenuItem; + } + + loadPinnedApps(){ + let pinnedApps = this._settings.get_strv('pinned-app-list'); + + this.pinnedAppsArray = null; + this.pinnedAppsArray = []; + + let categoryMenuItem = this.categoryDirectories ? this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS) : null; + let isContainedInCategory = categoryMenuItem ? true : false; + + for(let i = 0; i < pinnedApps.length; i += 3){ + if(i === 0 && pinnedApps[0] === "ArcMenu_WebBrowser") + this._updatePinnedAppsWebBrowser(pinnedApps); + + let pinnedAppsMenuItem = new MW.PinnedAppsMenuItem(this, pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2], this.layoutProperties.DisplayType, isContainedInCategory); + pinnedAppsMenuItem.connect('saveSettings', ()=> { + let array = []; + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + array.push(this.pinnedAppsArray[i]._name); + array.push(this.pinnedAppsArray[i]._iconPath); + array.push(this.pinnedAppsArray[i]._command); + } + this._settings.set_strv('pinned-app-list',array); + }); + this.pinnedAppsArray.push(pinnedAppsMenuItem); + } + + if(categoryMenuItem){ + categoryMenuItem.appList = null; + categoryMenuItem.appList = []; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + } + + _updatePinnedAppsWebBrowser(pinnedApps){ + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + if(pinnedApps[0] === "ArcMenu_WebBrowser"){ + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + + this._app = appSys.lookup_app(browserName); + if(this._app){ + pinnedApps[0] = this._app.get_name(); + pinnedApps[1] = ''; + pinnedApps[2] = this._app.get_id(); + } + else{ + pinnedApps.splice(0,3); + } + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + } + } + + displayPinnedApps(){ + this._clearActorsFromBox(); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + placesAddSeparator(id){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this._sections[id].add_child(separator); + } + + _redisplayPlaces(id) { + if(this._sections[id].get_n_children() > 0){ + this.bookmarksShorctus = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this._sections[id].destroy_all_children(); + } + this._createPlaces(id); + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + if(this.placesManager.get('network').length > 0) + this.networkDevicesShorctus = true; + if(this.placesManager.get('devices').length > 0) + this.externalDevicesShorctus=true; + if(this.placesManager.get('bookmarks').length > 0) + this.bookmarksShorctus = true; + + if(this._settings.get_boolean('show-bookmarks')){ + if(id === 'bookmarks' && places.length > 0){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + //create a separator if bookmark and software shortcut are both shown + if(this.bookmarksShorctus && this.softwareShortcuts){ + this.placesAddSeparator(id); + } + } + } + if(this._settings.get_boolean('show-external-devices')){ + if(id === 'devices'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if((this.externalDevicesShorctus && !this.networkDevicesShorctus) && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + if(id === 'network'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if(this.networkDevicesShorctus && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + } + } + + setActiveCategory(category, setActive = true){ + this._futureActiveItem = category; + this.activeMenuItem = category; + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + + _clearActorsFromBox(box){ + this.recentFilesManager?.cancelCurrentQueries(); + if(!box){ + box = this.applicationsBox; + this.activeCategoryType = -1; + } + let parent = box.get_parent(); + if(parent instanceof St.ScrollView){ + let scrollBoxAdj = parent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = box.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + box.remove_child(actor); + } + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + this.activeCategoryType = category; + grid.remove_all_children(); + let count = 0; + let top = -1; + let left = 0; + this._futureActiveItem = false; + let currentCharacter; + let alphabetizeAllPrograms = this._settings.get_boolean("alphabetize-all-programs") && this.layoutProperties.DisplayType === Constants.DisplayType.LIST; + let rtl = this.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + let columns = -1; + + for (let i = 0; i < apps.length; i++) { + let app = apps[i]; + let item; + let shouldShow = true; + + if(category === Constants.CategoryType.PINNED_APPS || category === Constants.CategoryType.HOME_SCREEN){ + item = app; + if(!item.shouldShow) + shouldShow = false; + } + else{ + item = this.applicationsMap.get(app); + if (!item) { + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType); + this.applicationsMap.set(app, item); + } + } + + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + + if(shouldShow){ + if(columns === -1){ + if(grid.layout_manager.forceGridColumns) + columns = grid.layout_manager.forceGridColumns; + else if(this.layoutProperties.DisplayType === Constants.DisplayType.GRID) + columns = this.getColumnsFromActor(item); + else + columns = 1; + grid.layout_manager.gridColumns = columns; + } + + if(!rtl && (count % columns === 0)){ + top++; + left = 0; + } + else if(rtl && (left === 0)){ + top++; + left = columns; + } + + if(alphabetizeAllPrograms && category === Constants.CategoryType.ALL_PROGRAMS){ + if(currentCharacter !== app.get_name().charAt(0).toLowerCase()){ + currentCharacter = app.get_name().charAt(0).toLowerCase(); + + let label = this._createLabelWithSeparator(currentCharacter.toUpperCase()); + grid.layout_manager.attach(label, left, top, 1, 1); + top++; + } + } + + grid.layout_manager.attach(item, left, top, 1, 1); + item.gridLocation = [left, top]; + + if(item instanceof MW.CategorySubMenuItem){ + top++; + grid.layout_manager.attach(item.menu.actor, left, top, 1, 1); + } + + if(!rtl) + left++; + else if(rtl) + left--; + count++; + + if(!this._futureActiveItem && grid === this.applicationsGrid){ + this._futureActiveItem = item; + } + } + } + if(this.applicationsBox && !this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + if(this._futureActiveItem) + this.activeMenuItem = this._futureActiveItem; + } + + displayAllApps(){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + } + + get activeMenuItem() { + return this._activeMenuItem; + } + + set activeMenuItem(item) { + let itemChanged = item !== this._activeMenuItem; + if(itemChanged){ + this._activeMenuItem = item; + if(this.arcMenu.isOpen && item && this.layoutProperties.SupportsCategoryOnHover) + item.grab_key_focus(); + else if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + if(this.layout === Constants.MenuLayout.LAUNCHER && !this.layoutProperties.StandaloneRunner && item) + this.createActiveSearchItemPanel(item); + } + } + + _onSearchBoxChanged(searchBox, searchString) { + if(searchBox.isEmpty()){ + this.searchResults.hide(); + this.setDefaultMenuView(); + } + else{ + this._clearActorsFromBox(); + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.show(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms(searchString.split(/\s+/)); + } + } + + _onSearchBoxKeyPress(searchBox, event) { + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_Up) + return Clutter.EVENT_PROPAGATE; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + let cursorPosition = this.searchBox.clutter_text.get_cursor_position(); + + if(cursorPosition === Constants.CaretPosition.END && symbol === Clutter.KEY_Right) + cursorPosition = Constants.CaretPosition.END; + else if(cursorPosition === Constants.CaretPosition.START && symbol === Clutter.KEY_Left) + cursorPosition = Constants.CaretPosition.START; + else + cursorPosition = Constants.CaretPosition.MIDDLE; + + if(cursorPosition === Constants.CaretPosition.END || cursorPosition === Constants.CaretPosition.START){ + let navigateActor = this.activeMenuItem; + if(this.searchResults.hasActiveResult()){ + navigateActor = this.searchResults.getTopResult(); + if(navigateActor.has_style_pseudo_class("active")){ + navigateActor.grab_key_focus(); + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + navigateActor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + if(!navigateActor) + return Clutter.EVENT_PROPAGATE; + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + return Clutter.EVENT_PROPAGATE; + default: + return Clutter.EVENT_PROPAGATE; + } + } + + _onMainBoxKeyPress(actor, event) { + if (event.has_control_modifier()) { + if(this.searchBox) + this.searchBox.grab_key_focus(); + return Clutter.EVENT_PROPAGATE; + } + + let symbol = event.get_key_symbol(); + let unicode = Clutter.keysym_to_unicode(symbol); + + switch (symbol) { + case Clutter.KEY_BackSpace: + if(this.searchBox && !this.searchBox.hasKeyFocus() && !this.searchBox.isEmpty()){ + this.searchBox.grab_key_focus(); + let newText = this.searchBox.getText().slice(0, -1); + this.searchBox.setText(newText); + } + return Clutter.EVENT_PROPAGATE; + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down) + direction = St.DirectionType.DOWN; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT + if (symbol === Clutter.KEY_Up) + direction = St.DirectionType.UP; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + if(this.layoutProperties.Search && this.searchBox.hasKeyFocus() && this.searchResults.hasActiveResult() && this.searchResults.get_parent()){ + if(this.searchResults.getTopResult().has_style_pseudo_class("active")){ + this.searchResults.getTopResult().actor.grab_key_focus(); + return actor.navigate_focus(global.stage.key_focus, direction, false); + } + this.searchResults.getTopResult().actor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + else if(global.stage.key_focus === this.mainBox && symbol === Clutter.KEY_Up){ + return actor.navigate_focus(global.stage.key_focus, direction, true); + } + else if(global.stage.key_focus === this.mainBox){ + this.activeMenuItem.grab_key_focus(); + return Clutter.EVENT_STOP; + } + + return actor.navigate_focus(global.stage.key_focus, direction, false); + case Clutter.KEY_Tab: + case Clutter.KEY_KP_Tab: + case Clutter.KEY_KP_Enter: + case Clutter.KEY_Return: + case Clutter.KEY_Escape: + return Clutter.EVENT_PROPAGATE; + default: + if (unicode !== 0 && this.searchBox) { + global.stage.set_key_focus(this.searchBox.clutter_text); + let synthEvent = event.copy(); + synthEvent.set_source(this.searchBox.clutter_text); + this.searchBox.clutter_text.event(synthEvent, false); + } + } + return Clutter.EVENT_PROPAGATE; + } + + destroy(){ + if(this.recentFilesManager){ + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + } + + if(this._treeChangedId){ + this._tree.disconnect(this._treeChangedId); + this._treeChangedId = null; + this._tree = null; + } + + if(this.applicationsBox){ + if(this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.remove_child(this.applicationsGrid); + } + + if(this.network){ + this.network.destroy(); + this.networkMenuItem.destroy(); + } + + if(this.computer){ + this.computer.destroy(); + this.computerMenuItem.destroy(); + } + + if(this.placesManager){ + for(let id in this._sections){ + this._sections[id].get_children().forEach((child) =>{ + child.destroy(); + }); + }; + if(this.placeManagerUpdatedID){ + this.placesManager.disconnect(this.placeManagerUpdatedID); + this.placeManagerUpdatedID = null; + } + this.placesManager.destroy(); + this.placesManager = null + } + + if(this._searchBoxChangedId){ + this.searchBox?.disconnect(this._searchBoxChangedId); + this._searchBoxChangedId = null;; + } + if(this._searchBoxKeyPressId){ + this.searchBox?.disconnect(this._searchBoxKeyPressId); + this._searchBoxKeyPressId = null; + } + if(this._searchBoxKeyFocusInId){ + this.searchBox?.disconnect(this._searchBoxKeyFocusInId); + this._searchBoxKeyFocusInId = null; + } + + if(this.searchBox) + this.searchBox.destroy(); + + if(this.searchResults){ + this.searchResults.setTerms([]); + this.searchResults.destroy(); + this.searchResults = null; + } + + if (this._mainBoxKeyPressId) { + this.mainBox.disconnect(this._mainBoxKeyPressId); + this._mainBoxKeyPressId = null; + } + + if(this._gnomeFavoritesReloadID){ + AppFavorites.getAppFavorites().disconnect(this._gnomeFavoritesReloadID); + this._gnomeFavoritesReloadID = null; + } + + if(this.pinnedAppsArray){ + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + this.pinnedAppsArray[i].destroy(); + } + this.pinnedAppsArray = null; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.mainBox.destroy_all_children(); + } + + _createScrollBox(params){ + let scrollBox = new St.ScrollView(params); + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._blockActivateEvent = true; + this.onPan(action, scrollBox); + }); + panAction.connect('gesture-cancel',(action) => this.onPanEnd(action, scrollBox)); + panAction.connect('gesture-end', (action) => this.onPanEnd(action, scrollBox)); + scrollBox.add_action(panAction); + + scrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); + scrollBox.clip_to_allocation = true; + + return scrollBox; + } + + _createLabelWithSeparator(headerLabel){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.HEADER_LABEL, Constants.SeparatorAlignment.HORIZONTAL, headerLabel); + return separator; + } + + createLabelRow(title){ + let labelRow = new PopupMenu.PopupMenuItem(_(title), { + hover: false, + can_focus: false + }); + labelRow.actor.add_style_pseudo_class = () => { return false;}; + labelRow.label.style = 'font-weight: bold;'; + return labelRow; + } + + _keyFocusIn(actor) { + if (this._focusChild == actor) + return; + this._focusChild = actor; + Utils.ensureActorVisibleInScrollView(actor); + } + + onPan(action, scrollbox) { + let [dist_, dx_, dy] = action.get_motion_delta(0); + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + adjustment.value -= dy; + return false; + } + + onPanEnd(action, scrollbox) { + let velocity = -action.get_velocity(0)[2]; + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + let endPanValue = adjustment.value + velocity * 2; + adjustment.value = endPanValue; + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js new file mode 100644 index 0000000..fefdcd6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js @@ -0,0 +1,206 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus70' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.actionsBox.style = "padding: 5px 0px 0px 0px;" + this.leftBox.add_child(this.actionsBox); + + //create new section for Power, Lock, Logout, Suspend Buttons + this.sessionBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.sessionBox.style = "spacing: 6px;"; + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.sessionBox.add_child(powerButton); + } + } + this.leftBox.add_child(this.sessionBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + let pinnedApps = this._settings.get_strv('brisk-shortcuts-list'); + + for(let i = 0;i < pinnedApps.length; i += 3){ + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i],pinnedApps[i+1], pinnedApps[i+2]], Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem){ + this.actionsBox.add_child(placeMenuItem.actor); + } + } + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js new file mode 100644 index 0000000..46107c5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js @@ -0,0 +1,184 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * Budgie.js Layout Created By: MagneFire https://gitlab.com/MagneFire + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-bottom: 6px;"; + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel-plus70', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + // Disable horizontal scrolling, hide vertical scrollbar, but allow vertical scrolling. + this.applicationsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + if(this._settings.get_boolean('enable-activities-shortcut')){ + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(this.activities.actor); + this.leftBox.add_child(this.activitiesBox); + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-top: 6px;"; + this.mainBox.add_child(separator); + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px; margin: 0; spacing: 0;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js new file mode 100644 index 0000000..e0d862c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive: true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js new file mode 100644 index 0000000..79de6aa --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox= new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive:true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;" + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js new file mode 100644 index 0000000..1b3f548 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultMenuWidth: 650, + DefaultIconGridStyle: "MediumRectIconGrid", + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 10px 15px;"; + + this.topBox.add_child(this.searchBox.actor); + this.mainBox.insert_child_at_index(this.topBox, 0); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px; background-color:rgba(186, 196,201, 0.1); padding: 12px 25px;"+ + "border-color: rgba(186, 196,201, 0.2); border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true, + style: 'padding: 0px 25px;' + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 5, + column_homogeneous: true + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + layout.forceGridColumns = 2; + this.shortcutsBox.add_child(this.shortcutsGrid); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.actionsBox.add_child(this.user.actor); + + this.quickLinksBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER, + vertical: false, + style: 'spacing: 10px;' + }); + let path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Downloads")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + let settingsButton = new MW.SettingsButton(this); + this.quickLinksBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.quickLinksBox.add_child(this.leaveButton.actor); + + this.actionsBox.add_child(this.quickLinksBox); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton); + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton); + this.frequentAppsHeader = this._createNavigationButtons(_("Frequent"), null); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + + this.disableFrequentAppsID = this._settings.connect("changed::eleven-disable-frequent-apps", () => this.setDefaultMenuView()); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + loadFrequentApps(){ + this.frequentAppsList = []; + + if(this._settings.get_boolean("eleven-disable-frequent-apps")) + return; + + let labelRow = this.createLabelRow(_("Frequent")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + + if(mostUsed.length < 1) + return; + + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + + const MaxItems = 8; + if(this.frequentAppsList.length > MaxItems) + this.frequentAppsList.splice(MaxItems); + } + + setDefaultMenuView(){ + this.layoutProperties.IconGridSize = 34; + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + super.setDefaultMenuView(); + this.loadFrequentApps(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 5); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0, false); + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + + if(this.frequentAppsList.length > 0 && !this._settings.get_boolean("eleven-disable-frequent-apps")){ + this.activeCategory = _("Frequent"); + this.setGridLayout(Constants.DisplayType.GRID, 2, 0); + this._displayAppList(this.frequentAppsList, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + } + else if(this.applicationsBox.contains(this.shortcutsBox)){ + this.applicationsBox.remove_child(this.shortcutsBox); + } + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.applicationsBox.insert_child_at_index(this.allAppsButton, 0); + } + else if(category === Constants.CategoryType.HOME_SCREEN){ + this.applicationsBox.insert_child_at_index(this.frequentAppsHeader, 2); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.mainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.mainBox.contains(this.backButton)) + this.mainBox.remove_child(this.backButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.label.style = 'padding: 15px 0px;'; + navButton.style = 'padding: 0px 25px;' + if(ButtonClass) + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.backButton.destroy(); + this.allAppsButton.destroy(); + if(this.disableFrequentAppsID){ + this._settings.disconnect(this.disableFrequentAppsID); + this.disableFrequentAppsID = null; + } + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js new file mode 100644 index 0000000..8b66793 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js @@ -0,0 +1,161 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(activities.actor); + this.leftBox.add_child(this.activitiesBox); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js new file mode 100644 index 0000000..e298283 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js @@ -0,0 +1,337 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + PinnedAppsColumns: 1, + DefaultMenuWidth: 525, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.pinnedAppsButton = new MW.PinnedAppsButton(this); + this.pinnedAppsButton.actor.y_expand = true; + this.pinnedAppsButton.actor.y_align= Clutter.ActorAlign.START; + this.pinnedAppsButton.actor.margin = 5; + this.actionsBox.add_child(this.pinnedAppsButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + settingsButton.actor.expand = false; + settingsButton.actor.margin = 5; + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.leaveButton.actor.expand = false; + this.leaveButton.actor.margin = 5; + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + let userMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + vertical: false, + }) + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.user.label.x_align = Clutter.ActorAlign.CENTER; + this.user.label.style = "margin-left: 10px;" + userMenuBox.add_child(this.user.actor); + userMenuBox.add_child(this.user.label); + this.subMainBox.add_child(userMenuBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 10px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor( this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createPinnedAppsMenu(); + this.setDefaultMenuView(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + super.loadPinnedApps(); + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + } + + _createPinnedAppsMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.pinnedAppsMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.pinnedAppsMenu.blockSourceEvents = true; + this.section = new PopupMenu.PopupMenuSection(); + this.pinnedAppsMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.togglePinnedAppsMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + headerBox.add_child(this.createLabelRow(_("Pinned Apps"))); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + + this.leftPanelPopup.add_child(this.pinnedAppsScrollBox); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 0, + row_spacing: 0 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.forceGridColumns = 1; + layout.hookup_style(this.pinnedAppsGrid); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.displayPinnedApps(); + this.subMenuManager.addMenu(this.pinnedAppsMenu); + this.pinnedAppsMenu.actor.hide(); + Main.uiGroup.add_child(this.pinnedAppsMenu.actor); + this.pinnedAppsMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.pinnedAppsButton.tooltip){ + this.pinnedAppsButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.pinnedAppsButton.active = false; + this.pinnedAppsButton.sync_hover(); + this.pinnedAppsButton.hovered = this.pinnedAppsButton.hover; + } + }); + } + + togglePinnedAppsMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.pinnedAppsMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.pinnedAppsMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.pinnedAppsButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.pinnedAppsMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base: 0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.pinnedAppsMenu.toggle(); + if(this.pinnedAppsMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + this.activeMenuItem = this.applicationsGrid.layout_manager.get_child_at(0, 0); + if(!this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + this._clearActorsFromBox(this.pinnedAppsBox); + this.layoutProperties.GridColumns = 1; + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + this.updateStyle(); + this.layoutProperties.GridColumns = 5; + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js new file mode 100644 index 0000000..7dbeccc --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const MORE_PROVIDERS_POP_UP = -1; +const MAX_VISIBLE_PROVIDERS = 4; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + MenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.activeResult = null; + this.searchProvidersBoxStyle = "padding: 0px 15px; margin-bottom: 10px; height: 50px; background-color: rgba(186, 196, 201, 0.1); border-color:rgba(186, 196, 201, 0.2); border-bottom-width: 1px;" + this.themeNodeBorderRadius = ""; + this.searchProvidersBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.searchProvidersBoxStyle + this.themeNodeBorderRadius + }); + this.searchProvidersBox.clip_to_allocation = true; + this.mainBox.add_child(this.searchProvidersBox); + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px;"; + this.searchTermsChangedID = this.searchResults.connect('have-results', () => { + this.searchResultsChangedEvent(); + }); + this.searchNoResultsID = this.searchResults.connect('no-results', () => { + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + }) + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.subMainBox.style = "width:750px; spacing: 8px;"; + + this.searchResultDetailsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + style: 'width: 415px; spacing: 20px;' + }); + + this.searchResultDetailsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.searchResultDetailsScrollBox.add_actor(this.searchResultDetailsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.mainBox.add_child(this.searchBox); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.arcMenu.box.style = "padding-top: 0px;"; + this.hasPinnedApps = true; + this.loadPinnedApps(); + this.loadCategories(); + + this.moreItem = this.createProviderMenuItem(_("More"), MORE_PROVIDERS_POP_UP); + let arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + arrowIcon.y_expand = false; + this.moreItem.add_child(arrowIcon); + this._createMoreProvidersMenu(); + + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + super.loadPinnedApps(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.FREQUENT_APPS, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.FREQUENT_APPS, categoryMenuItem); + + super.loadCategories(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.moveProvidersMenuItems = []; + this.moreProvidersBox.remove_all_children(); + this.searchResults.setProvider(Constants.CategoryType.SEARCH_RESULTS); + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + this.displayPinnedApps(); + this.searchProvidersBox.remove_all_children(); + let allProvidersItem = this.createProviderMenuItem(_("All"), Constants.CategoryType.SEARCH_RESULTS); + this.searchProvidersBox.add_child(allProvidersItem); + let searchProviders = this.searchResults.getProviders(); + + let currentItems = 1; + for(let provider of searchProviders){ + provider = provider.appInfo ? provider : _("Applications"); + let item = this.createProviderMenuItem(provider, provider.appInfo ? null : Constants.CategoryType.ALL_PROGRAMS); + + if(currentItems < MAX_VISIBLE_PROVIDERS) + this.searchProvidersBox.add_child(item); + else{ + this.moveProvidersMenuItems.push(item); + item.moreIndex = currentItems - MAX_VISIBLE_PROVIDERS; + item.x_expand = true; + item.x_align = Clutter.ActorAlign.FILL; + this.moreProvidersBox.add_child(item); + } + + currentItems++; + } + + this.searchProvidersBox.add_child(this.moreItem); + + this.activeProvider = allProvidersItem; + this.activeProvider.add_style_class_name("active-item"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + createProviderMenuItem(provider, providerEnum){ + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + + let providerMenuItem = new MW.ArcMenuPopupBaseMenuItem(this); + providerMenuItem.name = "arc-menu-launcher-button"; + providerMenuItem.x_expand = false; + providerMenuItem.remove_child(providerMenuItem._ornamentLabel); + providerMenuItem.x_align = Clutter.ActorAlign.START; + providerMenuItem.style = 'padding: 10px 14px; margin: 0px;'; + providerMenuItem.provider = provider; + let label = new St.Label({ + text: _(providerName), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + }); + providerMenuItem.label = label; + providerMenuItem.add_child(label); + + providerMenuItem.connect("activate", () => this.activateProviderMenuItem(providerMenuItem, providerEnum)); + return providerMenuItem; + } + + activateProviderMenuItem(providerMenuItem, providerEnum){ + if(providerEnum && providerEnum === MORE_PROVIDERS_POP_UP){ + this.moreItem.add_style_class_name("active-item"); + this.toggleMoreProvidersMenu(); + } + else{ + if(this.activeProvider) + this.activeProvider.remove_style_class_name("active-item"); + + if(this.moreProvidersMenu.isOpen) + this.moreProvidersMenu.toggle(); + + this.moreItem.remove_style_class_name("active-item"); + this.moreItem.active = false; + + let potentialMovedItem = this.searchProvidersBox.get_child_at_index(MAX_VISIBLE_PROVIDERS); + + if(potentialMovedItem.wasMoved) + this.moveProviderMenuItem(potentialMovedItem, this.searchProvidersBox, this.moreProvidersBox, true); + + if(providerMenuItem.get_parent() === this.moreProvidersBox) + this.moveProviderMenuItem(providerMenuItem, this.moreProvidersBox, this.searchProvidersBox, false); + + this.activeProvider = providerMenuItem; + providerMenuItem.add_style_class_name("active-item"); + + this.displayProviderPage(providerMenuItem.provider, providerEnum); + this.searchResults.setProvider(providerMenuItem.provider.appInfo ? providerMenuItem.provider.appInfo.get_id() : providerEnum); + + if(!this.searchBox.isEmpty()){ + this._clearActorsFromBox(); + let searchString = this.searchBox.get_text(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms([]); + + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.setTerms(searchString.split(/\s+/)); + this.searchResults.highlightDefault(true); + this.activeProvider.grab_key_focus(); + } + } + } + + moveProviderMenuItem(menuItem, currentBox, newBox, wasMoved){ + let expand = wasMoved ? true : false; + let align = wasMoved ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.START; + let index = wasMoved ? menuItem.moreIndex : MAX_VISIBLE_PROVIDERS; + + currentBox.remove_child(menuItem); + newBox.insert_child_at_index(menuItem, index); + menuItem.x_expand = expand; + menuItem.x_align = align; + menuItem.wasMoved = !wasMoved; + } + + displayProviderPage(provider, providerEnum){ + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + if(providerEnum){ + if(providerEnum === Constants.CategoryType.SEARCH_RESULTS) + this.displayPinnedApps(); + if(providerEnum === Constants.CategoryType.ALL_PROGRAMS) + this.displayFrequentApps(); + return; + } + this._clearActorsFromBox(); + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + let providerIcon = provider.appInfo ? provider.appInfo.get_icon() : Gio.icon_new_for_string(''); + + this.setSearchHintText(providerName); + + let providerBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let icon = new St.Icon({ + icon_size: 76, + gicon: providerIcon, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let label = new St.Label({ + text: _("Search") + " " + _(providerName), + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: false, + y_align: Clutter.ActorAlign.START, + }); + providerBox.add_child(icon); + providerBox.add_child(label); + this.applicationsBox.add_child(providerBox); + } + + _createMoreProvidersMenu(){ + this.moreProvidersMenu = new PopupMenu.PopupMenu(this.moreItem, 0.5, St.Side.TOP); + this.moreProvidersMenu.connect('open-state-changed', (menu, open) => { + if(!open) + this.moreItem.remove_style_class_name("active-item"); + }); + + this.section = new PopupMenu.PopupMenuSection(); + this.moreProvidersMenu.addMenuItem(this.section); + + this.moreProvidersBox = new St.BoxLayout({ + vertical: true + }); + + this.moreProvidersScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'vfade', + overlay_scrollbars: true, + reactive: true + }); + this.moreProvidersScrollBox._delegate = this.moreProvidersBoxScrollBox; + this.moreProvidersScrollBox.add_actor(this.moreProvidersBox); + this.moreProvidersScrollBox.clip_to_allocation = true; + + this.moreProvidersScrollBox.style = "max-height: 350px;"; + this.section.actor.add_child(this.moreProvidersScrollBox); + this.subMenuManager.addMenu(this.moreProvidersMenu); + this.moreProvidersMenu.actor.hide(); + Main.uiGroup.add_child(this.moreProvidersMenu.actor); + } + + toggleMoreProvidersMenu(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.moreProvidersMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.moreProvidersMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + + this.moreProvidersMenu.toggle(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + this.setSearchHintText(_("Applications")); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + let label = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(categoryMenuItem.appList, Constants.CategoryType.FREQUENT_APPS, this.applicationsGrid); + } + + setSearchHintText(providerName){ + this.searchBox.hint_text = _("Search") + " " + _(providerName) + "…"; + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.searchProvidersBox.style = this.searchProvidersBoxStyle + this.themeNodeBorderRadius; + if(removeMenuArrow) + this.arcMenu.box.style = "padding-top: 0px; margin: 0px;"; + else + this.arcMenu.box.style = "padding-top: 0px;"; + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayPinnedApps() { + super._clearActorsFromBox(); + let label = this.createLabelRow(_("Pinned Apps")); + this.searchBox.hint_text = _("Search…"); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + searchResultsChangedEvent(){ + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.add_child(this.searchResultDetailsScrollBox); + if(this.activeResult === this.searchResults.getTopResult()) + return; + + this.activeResult = this.searchResults.getTopResult(); + if(!this.activeResult || this.activeResult === null){ + return; + } + + this.createActiveSearchItemPanel(this.searchResults.getTopResult()); + } + + createActiveSearchItemPanel(activeResult){ + if(!activeResult) + return; + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + return; + if(!activeResult.provider || activeResult === this.activeResultMenuItem) + return; + this.activeCategoryType = -1; + this.searchResultDetailsBox.destroy_all_children(); + + if(!activeResult.metaInfo) + return; + + let app = activeResult.app ? activeResult.app : null; + let path = activeResult._path ? activeResult._path : null; + + this.activeResultMenuItem = new MW.ApplicationMenuItem(this, app, Constants.DisplayType.GRID, activeResult.metaInfo); + this.activeResultMenuItem.name = "ExtraLargeIconGrid"; + this.activeResultMenuItem.provider = activeResult.provider; + this.activeResultMenuItem.resultsView = activeResult.resultsView; + this.activeResultMenuItem._path = path; + this.activeResultMenuItem.x_expand = false; + this.activeResultMenuItem.x_align = Clutter.ActorAlign.CENTER; + let iconSize = 76; + let icon = activeResult.metaInfo ?activeResult.metaInfo['createIcon'](iconSize) : app.create_icon_texture(iconSize); + this.activeResultMenuItem._iconBin.set_child(icon); + if(!this.activeResultMenuItem._iconBin.get_child()){ + let icon = new St.Icon({ + icon_size: iconSize, + gicon: activeResult.provider.appInfo.get_icon() + }); + this.activeResultMenuItem._iconBin.set_child(icon); + } + this.searchResultDetailsBox.add_child(this.activeResultMenuItem); + this.searchResultContextItems = new MW.ApplicationContextItems(this.activeResultMenuItem, app, this); + this.searchResultContextItems.path = path; + this.searchResultContextItems.rebuildItems(); + this.searchResultDetailsBox.add_child(this.searchResultContextItems); + } + + destroy(){ + this.arcMenu.box.style = null; + + if(this.searchTermsChangedID){ + this.searchResults.disconnect(this.searchTermsChangedID); + this.searchTermsChangedID = null; + } + + if(this.searchNoResultsID){ + this.searchResults.disconnect(this.searchNoResultsID); + this.searchNoResultsID = null; + } + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js new file mode 100644 index 0000000..3185f2d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js @@ -0,0 +1,250 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + //Stores the Pinned Icons on the left side + this.actionsScrollBox = new St.ScrollView({ + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'small-vfade' + }); + this.actionsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + this.actionsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsScrollBox.add_actor(this.actionsBox); + this.actionsScrollBox.clip_to_allocation = true; + + this.actionsScrollBox.style = "padding: 21px 0px; width: 62px; margin: 0px 10px 10px 20px; background-color:rgba(186, 196,201, 0.1); border-color:rgba(186, 196,201, 0.2); border-width: 1px; border-radius: 5px;"; + this.actionsBox.style = "spacing: 10px;"; + //check if custom ArcMenu is enabled + if( this._settings.get_boolean('enable-custom-arc-menu')) + this.actionsBox.add_style_class_name('arc-menu'); + + this.mainBox.add_child(this.actionsScrollBox); + this.rightMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.rightMenuBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + else + this.rightMenuBox.style = "margin-top: 10px;"; + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.rightMenuBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + + this.categoriesScrollBox.add_actor( this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + _addSeparator(){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + super.loadExtraPinnedApps(this._settings.get_strv('mint-pinned-app-list'), this._settings.get_int('mint-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + this._app = appSys.lookup_app(browserName); + if(this._app){ + let appIcon = this._app.create_icon_texture(25); + let iconName = ''; + if(appIcon.icon_name) + iconName = appIcon.icon_name; + else if(appIcon.gicon) + iconName = appIcon.gicon.to_string(); + pinnedApps.push(this._app.get_name(), iconName, this._app.get_id()); + } + else{ + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + } + pinnedApps.push(_("Terminal"), "utilities-terminal", "org.gnome.Terminal.desktop"); + pinnedApps.push(_("Settings"), "emblem-system-symbolic", "gnome-control-center.desktop"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('mint-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js new file mode 100644 index 0000000..2135cc5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js @@ -0,0 +1,453 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 450, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.leftTopBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + vertical: false, + y_align: Clutter.ActorAlign.CENTER, + style: "padding-left: 10px; margin-left: 0.4em" + }); + this.rightTopBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + style_class: 'popup-menu-item', + style: "padding: 0px; margin: 0px; spacing: 0px;" + }); + + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_expand = false; + this.user.actor.y_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.leftTopBox.add_child(this.user.actor); + this.rightTopBox.add_child(this.user.label); + this.user.label.style = "padding-left: 0.4em; margin: 0px 10px 0px 15px; font-weight: bold;"; + this.user.label.y_expand = false; + this.user.label.x_expand = true; + this.user.label.x_align = Clutter.ActorAlign.START; + this.rightTopBox.add_child(this.searchBox.actor); + + this.topBox.add_child(this.leftTopBox); + this.topBox.add_child(this.rightTopBox); + + this.searchBarLocation = this._settings.get_enum('searchbar-default-top-location'); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? 'margin-box' : 'margin-box small-vfade', + overlay_scrollbars: true, + reactive:true, + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBoxContainer = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.navigateBox = new St.BoxLayout({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 6px;", + }); + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_homogeneous: true, + column_spacing: 10, + row_spacing: 10 + }); + this.grid = new St.Widget({ + layout_manager: layout + }); + layout.hookup_style(this.grid); + this.navigateBox.add_child(this.grid); + + this.pinnedAppsButton = new MW.PlasmaMenuItem(this, _("Pinned Apps"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'); + this.pinnedAppsButton.connect("activate", () => this.displayPinnedApps() ); + this.grid.layout_manager.attach(this.pinnedAppsButton, 0, 0, 1, 1); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + + this.applicationsButton = new MW.PlasmaMenuItem(this, _("Applications"), 'preferences-desktop-apps-symbolic'); + this.applicationsButton.connect("activate", () => this.displayCategories() ); + this.grid.layout_manager.attach(this.applicationsButton, 1, 0, 1, 1); + + this.computerButton = new MW.PlasmaMenuItem(this, _("Computer"), 'computer-symbolic'); + this.computerButton.connect("activate", () => this.displayComputerCategory() ); + this.grid.layout_manager.attach(this.computerButton, 2, 0, 1, 1); + + this.leaveButton = new MW.PlasmaMenuItem(this, _("Leave"), 'system-shutdown-symbolic'); + this.leaveButton.connect("activate", () => this.displayPowerItems() ); + this.grid.layout_manager.attach(this.leaveButton, 3, 0, 1, 1); + + this.categoryHeader = new MW.PlasmaCategoryHeader(this); + this.categoryHeader.add_style_class_name('margin-box'); + + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 3px 10px 5px 10px;"; + this.topBox.style = 'padding-top: 0.5em;' + + this.navigateBoxContainer.add_child(this.navigateBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.y_expand = false; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.START; + this.mainBox.add_child(this.navigateBoxContainer); + this.mainBox.add_child(this.applicationsScrollBox); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + + this.mainBox.add_child(this.topBox); + } + else if(this.searchBarLocation === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 3px 10px 10px 10px;"; + + this.mainBox.add_child(this.topBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + this.mainBox.add_child(this.applicationsScrollBox); + this.navigateBoxContainer.y_expand = true; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.END; + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.add_child(this.navigateBox); + this.mainBox.add_child(this.navigateBoxContainer); + } + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + this.updateWidth(); + this._createPowerItems(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + categoryMenuItem.appList.push(mostUsed[i]); + let item = this.applicationsMap.get(mostUsed[i]); + if (!item) { + item = new MW.ApplicationMenuItem(this, mostUsed[i], this.layoutProperties.DisplayType); + this.applicationsMap.set(mostUsed[i], item); + } + } + } + } + + _clearActorsFromBox(box){ + this.categoryHeader.setActiveCategory(null); + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + super._clearActorsFromBox(box); + } + + clearActiveItem(){ + this.pinnedAppsButton.setActive(false); + this.computerButton.setActive(false); + this.applicationsButton.setActive(false); + this.leaveButton.setActive(false); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum === Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayComputerCategory(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.applicationsBox.add_child(this.applicationShortcuts[i]); + } + this.applicationsBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.applicationsBox.add_child(this.directoryShortcuts[i]); + } + this.applicationsBox.add_child(this.externalDevicesBox); + this.activeMenuItem = this.applicationShortcuts[0]; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + displayPinnedApps(){ + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + super.displayPinnedApps(); + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let isContainedInCategory = false; + let directory = directoryShortcutsList[i]; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createPowerItems(){ + this.lock = new MW.PowerMenuItem(this, Constants.PowerType.LOCK); + this.logOut = new MW.PowerMenuItem(this, Constants.PowerType.LOGOUT); + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + this.sleep = new MW.PowerMenuItem(this, Constants.PowerType.HYBRID_SLEEP); + } + }); + + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + this.hibernate = new MW.PowerMenuItem(this, Constants.PowerType.HIBERNATE); + } + }); + this.suspend = new MW.PowerMenuItem(this, Constants.PowerType.SUSPEND); + this.restart = new MW.PowerMenuItem(this, Constants.PowerType.RESTART); + this.powerOff = new MW.PowerMenuItem(this, Constants.PowerType.POWER_OFF); + } + + displayPowerItems(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Session"))); + this.applicationsBox.add_child(this.lock); + this.applicationsBox.add_child(this.logOut); + this.applicationsBox.add_child(this.createLabelRow(_("System"))); + this.applicationsBox.add_child(this.suspend); + if(this.sleep) + this.applicationsBox.insert_child_at_index(this.sleep, 4); + + if(this.hibernate) + this.applicationsBox.insert_child_at_index(this.hibernate, 5); + this.applicationsBox.add_child(this.restart); + this.applicationsBox.add_child(this.powerOff); + this.activeMenuItem = this.lock; + } + + displayCategories(){ + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this._clearActorsFromBox(this.applicationsBox); + + this.categoryHeader.setActiveCategory(null); + this._insertCategoryHeader(); + + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.applicationsBox.add_child(categoryMenuItem.actor); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.clearActiveItem(); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + this.displayPinnedApps(); + } + + _insertCategoryHeader(){ + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM) + this.mainBox.insert_child_at_index(this.categoryHeader, 1); + else + this.mainBox.insert_child_at_index(this.categoryHeader, 2); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._insertCategoryHeader(); + this.categoryHeader.setActiveCategory(this.activeCategory); + this._displayAppList(appList, category, this.applicationsGrid); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this._insertCategoryHeader(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.categoryHeader.setActiveCategory(this.activeCategory); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.clearActiveItem(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.sleep) + this.sleep.destroy(); + if(this.hibernate) + this.hibernate.destroy(); + + this.lock.destroy(); + this.logOut.destroy(); + this.suspend.destroy(); + this.restart.destroy(); + this.powerOff.destroy(); + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js new file mode 100644 index 0000000..2630ef5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js @@ -0,0 +1,395 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 410, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + SupportsCategoryOnHover: true, + DefaultCategoryIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.ravenPositionChangedID = this._settings.connect('changed::raven-position', () => this._updatePosition()); + + this.dummyCursor = new St.Widget({ width: 1, height: 0, opacity: 0}); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.actionsBoxContainer = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + this.actionsBoxContainer.add_child(this.actionsBox); + this.actionsBox.style = "spacing: 5px;"; + this.actionsBoxContainerStyle = "margin: 0px 0px 0px 0px; spacing: 10px; background-color: rgba(186, 196,201, 0.1); padding: 5px 5px;"+ + "border-color: rgba(186, 196,201, 0.2);"; + + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + //Sub Main Box -- stores left and right box + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.subMainBox.add_child(this.topBox); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 25px 10px 10px 10px;"; + this.topBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + x_align: Clutter.ActorAlign.FILL, + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.weatherBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: true + }); + + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.x_expand = true; + this._clocksItem.x_align = Clutter.ActorAlign.FILL; + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + + this.weatherBox.add_child(this._clocksItem); + this.weatherBox.add_child(this._weatherItem); + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this._updatePosition(); + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.weatherBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _updatePosition(){ + let ravenPosition = this._settings.get_enum('raven-position'); + if(this.mainBox.contains(this.actionsBoxContainer)){ + this.mainBox.remove_child(this.actionsBoxContainer); + } + if(ravenPosition === Constants.RavenPosition.LEFT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 0); + this.actionsBoxContainer.style = "border-right-width: 1px;" + this.actionsBoxContainerStyle; + } + else if(ravenPosition === Constants.RavenPosition.RIGHT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 1); + this.actionsBoxContainer.style = "border-left-width: 1px;" + this.actionsBoxContainerStyle; + } + } + + updateLocation(){ + let ravenPosition = this._settings.get_enum('raven-position'); + + let alignment = ravenPosition === Constants.RavenPosition.LEFT ? 0 : 1; + this.arcMenu._boxPointer.setSourceAlignment(alignment); + this.arcMenu._arrowAlignment = alignment; + + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + let positionX = ravenPosition === Constants.RavenPosition.LEFT ? monitorWorkArea.x : monitorWorkArea.x + monitorWorkArea.width - 1; + let positionY = this.arcMenu._arrowSide === St.Side.BOTTOM ? monitorWorkArea.y + monitorWorkArea.height : monitorWorkArea.y; + + this.dummyCursor.set_position(positionX, positionY); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let screenHeight = monitorWorkArea.height; + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderWidth = themeNode.get_length('-arrow-border-width'); + + let height = Math.round((screenHeight - borderWidth * 2) / scaleFactor); + this.mainBox.style = `height: ${height}px;`; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + updateStyle(){ + super.updateStyle(); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px;"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.updateLocation(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.BUTTON); + this.displayCategories(); + } + + displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.actionsBox.add_child(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + let actors = this.weatherBox.get_children(); + for (let i = 0; i < actors.length; i++) { + this.weatherBox.remove_child(actors[i]); + } + if(this._settings.get_boolean('enable-clock-widget-raven')){ + this.weatherBox.add_child(this._clocksItem); + } + if(this._settings.get_boolean('enable-weather-widget-raven')){ + this.weatherBox.add_child(this._weatherItem); + } + if(!this.subMainBox.contains(this.weatherBox)) + this.subMainBox.add_child(this.weatherBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.subMainBox.contains(this.weatherBox)){ + this.subMainBox.remove_child(this.weatherBox); + } + + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + let label = this._createLabelWithSeparator(this.activeCategory); + + if(grid === this.applicationsGrid){ + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label.actor, 0); + } + else{ + label.actor.style += "padding-left: 10px; padding-top: 20px;"; + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + if(this.ravenPositionChangedID){ + this._settings.disconnect(this.ravenPositionChangedID); + this.ravenPositionChangedID = null; + } + + this.arcMenu.actor.style = null; + this.arcMenu.box.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js new file mode 100644 index 0000000..d0cb17d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js @@ -0,0 +1,229 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP) + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + y_align: Clutter.ActorAlign.FILL, + y_expand: true, + vertical: true, + style_class: 'right-panel margin-box' + }); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0){ + this.placesShortcuts=true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length>0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw=true; + if(shouldDraw){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.mainBox.add_child(horizonalFlip ? this.rightBox : this.subMainBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.mainBox.add_child(verticalSeparator); + this.mainBox.add_child(horizonalFlip ? this.subMainBox: this.rightBox); + horizonalFlip ? this.rightBox.style += "margin-right: 0px" : this.rightBox.style += "margin-left: 0px" + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js new file mode 100644 index 0000000..7386301 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js @@ -0,0 +1,208 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton, isStandalone) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + StandaloneRunner: isStandalone + }); + } + + createLayout(){ + super.createLayout(); + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0.5); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: false, + style: "margin: 5px 0px 0px 0px;" + }); + + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + this.runnerTweaksButton = new MW.RunnerTweaksButton(this); + this.runnerTweaksButton.actor.x_expand = false; + this.runnerTweaksButton.actor.y_expand = true; + this.runnerTweaksButton.actor.y_align = this.searchBox.y_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.x_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.style = "margin: 0px 6px;"; + + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.runnerTweaksButton); + this.mainBox.add_child(this.topBox); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: false, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + reactive:true + }); + + this.mainBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "margin: 5px 6px 0px 16px;" + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.activeMenuItem = null; + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + this.activeMenuItem = null; + super.setDefaultMenuView(); + if(this._settings.get_boolean("runner-show-frequent-apps")) + this.displayFrequentApps(); + } + + displayFrequentApps(){ + let labelRow = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_actor(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + /** + * if button is hidden, menu should appear on current monitor, unless preference is to always show on primary monitor + * @returns index of monitor where menu should appear + */ + _getMonitorIndexForPlacement() { + if (this.layoutProperties.StandaloneRunner) { + return this._settings.get_boolean('runner-hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + } + else if (this._settings.get_enum('menu-button-appearance') === Constants.MenuButtonAppearance.NONE) + return this._settings.get_boolean('hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + else + return Main.layoutManager.findIndexForActor(this.menuButton); + } + + updateLocation(){ + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + + let rect = Main.layoutManager.getWorkAreaForMonitor(this._getMonitorIndexForPlacement()); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + (this._settings.get_boolean('runner-use-theme-gap') ? this.rise : 0); + if(this._settings.get_enum('runner-position') == 1) + positionY = Math.round(rect.y + (rect.height / 2) - 125); + this.dummyCursor.set_position(positionX, positionY); + + if(!this.topBox) + return; + + this._runnerWidth = this._settings.get_int("runner-menu-width"); + this._runnerHeight = this._settings.get_int("runner-menu-height"); + this._runnerFontSize = this._settings.get_int("runner-font-size"); + this.mainBox.style = `max-height: ${this._runnerHeight}px;`; + if(this._runnerFontSize > 0){ + this.mainBox.style += `font-size: ${this._runnerFontSize}pt;` + this.searchBox.style += `font-size: ${this._runnerFontSize}pt;` + } + else{ + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + } + this.topBox.style = `width: ${this._runnerWidth}px; margin: 5px 0px 0px 0px;`; + this.applicationsScrollBox.style = `width: ${this._runnerWidth}px;`; + } + + updateStyle(){ + super.updateStyle(); + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + } + + loadCategories(){ + } + + destroy(){ + this.arcMenu.actor.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js new file mode 100644 index 0000000..0e971e4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js @@ -0,0 +1,159 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GMenu, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.section = this.menuButton.section; + let actors = this.section.actor.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + this.section.actor.remove_child(actor); + } + this.section.actor.add_child(this.mainBox); + + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + updateStyle(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.updateStyle(); + } + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.SimpleMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SIMPLE_CATEGORY); + } + + displayCategories(){ + super.displayCategories(this.mainBox); + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + let children = categoryMenuItem.applicationsBox.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.applicationsBox.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.applicationsBox); + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + if(!categoryMenuItem.applicationsBox.contains(this.applicationsGrid)) + categoryMenuItem.applicationsBox.add_child(this.applicationsGrid); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js new file mode 100644 index 0000000..ec5b2cf --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js @@ -0,0 +1,179 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + this.arcMenu.actor.style = 'max-height: ' + (this.arcMenu.actor.height + 250) + 'px;'; + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + let actors = this.mainBox.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + } + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategorySubMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SUBMENU_CATEGORY); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem._setParent(this.arcMenu); + categoryMenuItem.isSimpleMenuItem = true; + } + } + + displayCategories(){ + this._clearActorsFromBox(); + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.arcMenu.addMenuItem(categoryMenuItem); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + super._clearActorsFromBox(this.mainBox); + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + this._clearActorsFromBox(); + this.applicationsGrid.remove_all_children(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + + let children = categoryMenuItem.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.menu.box.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.menu.box, () => categoryMenuItem._needsScrollbar()); + if(!categoryMenuItem.menu.box.contains(this.applicationsGrid)) + categoryMenuItem.menu.box.add_child(this.applicationsGrid); + + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + let box = categoryMenuItem.menu.box; + if(!box.contains(this.applicationsGrid)) + box.add_child(this.applicationsGrid); + } + + destroy(){ + this.arcMenu.actor.style = null; + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js new file mode 100644 index 0000000..9d279ee --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js @@ -0,0 +1,290 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * tognee Layout Created By: tognee https://gitlab.com/tognee + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 290, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + // The "Left Box" + // Contains the app list and the searchbar + this.appBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + this.appBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL)); + this.navigateBox.add_child(this.backButton.actor); + this.appBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + + // The "Right Box" + // Contains some useful shortcuts + this.quickBox = new St.BoxLayout({ + vertical: true, + style: "margin: 0px 1px;", + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.subMainBox.add_child(horizonalFlip ? this.appBox : this.quickBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.quickBox : this.appBox); + + this.placesShortcuts= this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0; + this.softwareShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack().length>0; + + this.shortcutsBox = new St.BoxLayout({ + vertical: true, + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + style: "spacing: 5px; padding-bottom: 5px;" + }); + + this.shortcutsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + this.shortcutsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.quickBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //check to see if should draw separator + if(this.placesShortcuts && this.softwareShortcuts){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.BUTTON, isContainedInCategory); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + // Bottom Section for Power etc... + this.actionsScrollBox = new St.ScrollView({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.actionsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.actionsScrollBox.clip_to_allocation = true; + + //create new section for Leave Button + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 3px;" + }); + this.actionsScrollBox.add_actor(this.actionsBox); + + let leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(leaveButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.insert_child_at_index(separator, 0); + this.quickBox.add_child(this.actionsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 175px minimum limit for the menu width + menuWidth = Math.max(175, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _displayPlaces() { + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.BUTTON, isContainedInCategory); + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayPinnedApps(){ + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + this.navigateBox.show(); + } + + displayAllApps(){ + this.navigateBox.hide(); + super.displayAllApps() + } + + displayCategories(){ + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this.navigateBox.hide(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view-tognee'); + + if(defaultMenuView === Constants.DefaultMenuViewTognee.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuViewTognee.ALL_PROGRAMS) + this.displayAllApps(); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.navigateBox.show(); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.navigateBox.show(); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(searchBox.isEmpty()){ + this.navigateBox.hide(); + } + else if(!searchBox.isEmpty()){ + this.navigateBox.show(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js new file mode 100644 index 0000000..290a169 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js @@ -0,0 +1,1286 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Prefs = Me.imports.prefs; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var TweaksPage = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_TweaksPage extends Gtk.Box { + _init(settings, layoutName) { + this._settings = settings; + this.addResponse = false; + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.layoutNameLabel = new Gtk.Label({ + label: "" + _(layoutName) + "", + use_markup: true, + xalign: 0, + hexpand: true, + halign: Gtk.Align.CENTER + }) + + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + }); + backButton.halign = Gtk.Align.START; + backButton.connect('clicked', ()=> { + this.emit('response', -20); + }); + this.headerBox = new Gtk.Grid({ + hexpand: true, + halign: Gtk.Align.FILL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + }); + + this.headerBox.attach(backButton, 0, 0, 1, 1); + this.headerBox.attach(this.layoutNameLabel, 0, 0, 1, 1); + this.mainScrollWindow = new Gtk.ScrolledWindow(); + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.append(this.headerBox); + this.mainScrollWindow.set_child(this.mainBox); + this.mainScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.append(this.mainScrollWindow); + this._createLayout(); + } + + setActiveLayout(menuLayout, layoutName){ + if(layoutName) + this.layoutNameLabel.label = "" + _(layoutName) + ""; + let children = [...this.mainBox]; + for(let child of children){ + this.mainBox.remove(child); + } + this._createLayout(menuLayout); + } + + _createLayout(menuLayout) { + if(!menuLayout) + menuLayout = this._settings.get_enum('menu-layout'); + + if(menuLayout == Constants.MenuLayout.ARCMENU) + this._loadArcMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.BRISK) + this._loadBriskMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WHISKER) + this._loadWhiskerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_MENU) + this._loadGnomeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.MINT) + this._loadMintMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEMENTARY) + this._loadElementaryTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_OVERVIEW) + this._loadGnomeOverviewTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE_2) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.REDMOND) + this._loadRedmondMenuTweaks() + else if(menuLayout == Constants.MenuLayout.UNITY) + this._loadUnityTweaks(); + else if(menuLayout == Constants.MenuLayout.RAVEN) + this._loadRavenTweaks(); + else if(menuLayout == Constants.MenuLayout.BUDGIE) + this._loadBudgieMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.INSIDER) + this._loadInsiderMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.RUNNER) + this._loadRunnerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.CHROMEBOOK) + this._loadChromebookTweaks(); + else if(menuLayout == Constants.MenuLayout.TOGNEE) + this._loadTogneeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.PLASMA) + this._loadPlasmaMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WINDOWS) + this._loadWindowsTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEVEN) + this._loadElevenTweaks(); + else + this._loadPlaceHolderTweaks(); + } + + _createActivateOnHoverRow(){ + let activateOnHoverRow = new PW.FrameBoxRow(); + let activateOnHoverLabel = new Gtk.Label({ + label: _("Category Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let activateOnHoverCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + activateOnHoverCombo.append_text(_("Mouse Click")); + activateOnHoverCombo.append_text(_("Mouse Hover")); + if(this._settings.get_boolean('activate-on-hover')) + activateOnHoverCombo.set_active(1); + else + activateOnHoverCombo.set_active(0); + activateOnHoverCombo.connect('changed', (widget) => { + if(widget.get_active()==0) + this._settings.set_boolean('activate-on-hover',false); + if(widget.get_active()==1) + this._settings.set_boolean('activate-on-hover',true); + }); + + activateOnHoverRow.add(activateOnHoverLabel); + activateOnHoverRow.add(activateOnHoverCombo); + return activateOnHoverRow; + } + _createAvatarShapeRow(){ + let avatarStyleRow = new PW.FrameBoxRow(); + let avatarStyleLabel = new Gtk.Label({ + label: _('Avatar Icon Shape'), + xalign:0, + hexpand: true, + }); + let avatarStyleCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + avatarStyleCombo.append_text(_("Circular")); + avatarStyleCombo.append_text(_("Square")); + avatarStyleCombo.set_active(this._settings.get_enum('avatar-style')); + avatarStyleCombo.connect('changed', (widget) => { + this._settings.set_enum('avatar-style', widget.get_active()); + this._settings.set_boolean('reload-theme', true); + }); + avatarStyleRow.add(avatarStyleLabel); + avatarStyleRow.add(avatarStyleCombo); + return avatarStyleRow; + } + _createSearchBarLocationRow(bottomDefault){ + let searchBarLocationSetting = bottomDefault ? 'searchbar-default-bottom-location' : 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting )); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + return searchbarLocationRow; + } + _createFlipHorizontalRow(){ + let horizontalFlipRow = new PW.FrameBoxRow(); + let horizontalFlipLabel = new Gtk.Label({ + label: _("Flip Layout Horizontally"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let horizontalFlipSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + horizontalFlipSwitch.set_active(this._settings.get_boolean('enable-horizontal-flip')); + horizontalFlipSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-horizontal-flip', widget.get_active()); + }); + horizontalFlipRow.add(horizontalFlipLabel); + horizontalFlipRow.add(horizontalFlipSwitch); + return horizontalFlipRow; + } + _disableAvatarRow(){ + let disableAvatarRow = new PW.FrameBoxRow(); + let disableAvatarLabel = new Gtk.Label({ + label: _('Disable User Avatar'), + xalign:0, + hexpand: true, + }); + let disableAvatarSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableAvatarSwitch.set_active(this._settings.get_boolean('disable-user-avatar')); + disableAvatarSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('disable-user-avatar', widget.get_active()); + }); + disableAvatarRow.add(disableAvatarLabel); + disableAvatarRow.add(disableAvatarSwitch); + return disableAvatarRow; + } + + _loadElevenTweaks(){ + let elevenTweaksFrame = new PW.FrameBox(); + let disableFrequentAppsRow = new PW.FrameBoxRow(); + let disableFrequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let disableFrequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableFrequentAppsSwitch.set_active(this._settings.get_boolean('eleven-disable-frequent-apps')); + disableFrequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('eleven-disable-frequent-apps', widget.get_active()); + }); + disableFrequentAppsRow.add(disableFrequentAppsLabel); + disableFrequentAppsRow.add(disableFrequentAppsSwitch); + elevenTweaksFrame.add(disableFrequentAppsRow); + this.mainBox.append(elevenTweaksFrame); + } + + _loadGnomeOverviewTweaks(){ + let gnomeOverviewTweaksFrame = new PW.FrameBox(); + let appsGridRow = new PW.FrameBoxRow(); + let appsGridLabel = new Gtk.Label({ + label: _("Show Applications Grid"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appsGridSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appsGridSwitch.set_active(this._settings.get_boolean('gnome-dash-show-applications')); + appsGridSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('gnome-dash-show-applications', widget.get_active()); + }); + appsGridRow.add(appsGridLabel); + appsGridRow.add(appsGridSwitch); + gnomeOverviewTweaksFrame.add(appsGridRow); + this.mainBox.append(gnomeOverviewTweaksFrame); + } + + _loadWindowsTweaks(){ + let windowsTweaksFrame = new PW.FrameBox(); + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let frequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + frequentAppsSwitch.set_active(this._settings.get_boolean('windows-disable-frequent-apps')); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + windowsTweaksFrame.add(frequentAppsRow); + + let pinnedAppsRow = new PW.FrameBoxRow(); + let pinnedAppsLabel = new Gtk.Label({ + label: _("Disable Pinned Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let pinnedAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + pinnedAppsSwitch.set_active(this._settings.get_boolean('windows-disable-pinned-apps')); + pinnedAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-pinned-apps', widget.get_active()); + }); + pinnedAppsRow.add(pinnedAppsLabel); + pinnedAppsRow.add(pinnedAppsSwitch); + windowsTweaksFrame.add(pinnedAppsRow); + + this.mainBox.append(windowsTweaksFrame); + } + + _loadPlasmaMenuTweaks(){ + let plasmaMenuTweaksFrame = new PW.FrameBox(); + + let searchBarLocationSetting = 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + plasmaMenuTweaksFrame.add(searchbarLocationRow); + + let hoverRow = new PW.FrameBoxRow(); + let hoverLabel = new Gtk.Label({ + label: _("Activate on Hover"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hoverSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + hoverSwitch.set_active(this._settings.get_boolean('plasma-enable-hover')); + hoverSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('plasma-enable-hover', widget.get_active()); + }); + hoverRow.add(hoverLabel); + hoverRow.add(hoverSwitch); + plasmaMenuTweaksFrame.add(hoverRow); + + let foregroundColorRow = new PW.FrameBoxRow(); + let foregroundColorLabel = new Gtk.Label({ + label: _('Selected Button Border Color'), + xalign:0, + hexpand: true, + }); + let foregroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-color')); + foregroundColorChooser.set_rgba(color); + foregroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-color', foregroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + foregroundColorRow.add(foregroundColorLabel); + foregroundColorRow.add(foregroundColorChooser); + plasmaMenuTweaksFrame.add(foregroundColorRow); + + let backgroundColorRow = new PW.FrameBoxRow(); + let backgroundColorLabel = new Gtk.Label({ + label: _('Selected Button Background Color'), + xalign:0, + hexpand: true, + }); + let backgroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-background-color')); + backgroundColorChooser.set_rgba(color); + backgroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-background-color',backgroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + backgroundColorRow.add(backgroundColorLabel); + backgroundColorRow.add(backgroundColorChooser); + plasmaMenuTweaksFrame.add(backgroundColorRow); + + this.mainBox.append(plasmaMenuTweaksFrame); + + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true + }); + resetButton.set_sensitive(true); + resetButton.connect('clicked', ()=> { + let foregroundColor = this._settings.get_default_value('plasma-selected-color').unpack(); + let backgroundColor = this._settings.get_default_value('plasma-selected-background-color').unpack(); + let hoverEnabled = this._settings.get_default_value('plasma-enable-hover').unpack(); + let showDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this._settings.reset('searchbar-default-top-location'); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + hoverSwitch.set_active(hoverEnabled); + color.parse(foregroundColor); + foregroundColorChooser.set_rgba(color); + color.parse(backgroundColor); + backgroundColorChooser.set_rgba(color); + descriptionsSwitch.set_active(showDescriptions); + this._settings.reset('plasma-selected-color'); + this._settings.reset('plasma-selected-background-color'); + this._settings.reset('plasma-enable-hover'); + this._settings.reset('apps-show-extra-details'); + this._settings.set_boolean('reload-theme', true); + }); + this.mainBox.append(resetButton); + } + _loadBriskMenuTweaks(){ + let briskMenuTweaksFrame = new PW.FrameBox(); + briskMenuTweaksFrame.add(this._createActivateOnHoverRow()); + briskMenuTweaksFrame.add(this._createSearchBarLocationRow()); + briskMenuTweaksFrame.add(this._createFlipHorizontalRow()); + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_max_content_height(100); + pinnedAppsScrollWindow.set_min_content_height(100); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('brisk-shortcuts-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('brisk-shortcuts-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Brisk Menu Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + + this.mainBox.append(briskMenuTweaksFrame); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + } + _loadChromebookTweaks(){ + let chromeBookTweaksFrame = new PW.FrameBox(); + chromeBookTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(chromeBookTweaksFrame); + } + _loadElementaryTweaks(){ + let elementaryTweaksFrame = new PW.FrameBox(); + elementaryTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(elementaryTweaksFrame); + } + _loadBudgieMenuTweaks(){ + let budgieMenuTweaksFrame = new PW.FrameBox(); + budgieMenuTweaksFrame.add(this._createActivateOnHoverRow()); + budgieMenuTweaksFrame.add(this._createSearchBarLocationRow()); + budgieMenuTweaksFrame.add(this._createFlipHorizontalRow()); + + let enableActivitiesRow = new PW.FrameBoxRow(); + let enableActivitiesLabel = new Gtk.Label({ + label: _('Enable Activities Overview Shortcut'), + xalign:0, + hexpand: true, + }); + let enableActivitiesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableActivitiesSwitch.set_active(this._settings.get_boolean('enable-activities-shortcut')); + enableActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-activities-shortcut', widget.get_active()); + }); + enableActivitiesRow.add(enableActivitiesLabel); + enableActivitiesRow.add(enableActivitiesSwitch); + budgieMenuTweaksFrame.add(enableActivitiesRow); + + this.mainBox.append(budgieMenuTweaksFrame); + } + _loadRunnerMenuTweaks(){ + let runnerMenuTweaksFrame = new PW.FrameBox(); + let runnerPositionRow = new PW.FrameBoxRow(); + let runnerPositionLabel = new Gtk.Label({ + label: _('Position'), + xalign:0, + hexpand: true, + }); + let runnerPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + runnerPositionCombo.append_text(_("Top")); + runnerPositionCombo.append_text(_("Centered")); + runnerPositionCombo.set_active(this._settings.get_enum('runner-position')); + runnerPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('runner-position', widget.get_active()); + }); + runnerPositionRow.add(runnerPositionLabel); + runnerPositionRow.add(runnerPositionCombo); + runnerMenuTweaksFrame.add(runnerPositionRow); + + let runnerWidthRow = new PW.FrameBoxRow(); + let runnerWidthLabel = new Gtk.Label({ + label: _("Width"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerWidthScale.add_mark(500, Gtk.PositionType.TOP, _("Default")); + runnerWidthScale.set_value(this._settings.get_int('runner-menu-width')); + runnerWidthScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-width', widget.get_value()); + }); + runnerWidthRow.add(runnerWidthLabel); + runnerWidthRow.add(runnerWidthScale); + runnerMenuTweaksFrame.add(runnerWidthRow); + + let runnerHeightRow = new PW.FrameBoxRow(); + let runnerHeightLabel = new Gtk.Label({ + label: _("Height"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerHeightScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerHeightScale.add_mark(400, Gtk.PositionType.TOP, _("Default")); + runnerHeightScale.set_value(this._settings.get_int('runner-menu-height')); + runnerHeightScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-height', widget.get_value()); + }); + + runnerHeightRow.add(runnerHeightLabel); + runnerHeightRow.add(runnerHeightScale); + runnerMenuTweaksFrame.add(runnerHeightRow); + + let runnerFontSizeRow = new PW.FrameBoxRow(); + let runnerFontSizeLabel = new Gtk.Label({ + label: _("Font Size"), + hexpand: true, + use_markup: true, + xalign: 0 + }); + let runnerFontSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 30, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + + runnerFontSizeScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); + runnerFontSizeScale.set_value(this._settings.get_int('runner-font-size')); + runnerFontSizeScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-font-size', widget.get_value()); + }); + runnerFontSizeRow.add(runnerFontSizeLabel); + runnerFontSizeRow.add(runnerFontSizeScale); + runnerMenuTweaksFrame.add(runnerFontSizeRow); + + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Show Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let frequentAppsSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-show-frequent-apps')) + frequentAppsSwitch.set_active(true); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-show-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + runnerMenuTweaksFrame.add(frequentAppsRow); + + let inheritThemeGapRow = new PW.FrameBoxRow(); + let inheritThemeGapLabel = new Gtk.Label({ + label: _("Inherit Shell Theme Popup Gap"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let inheritThemeGapSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-use-theme-gap')) + inheritThemeGapSwitch.set_active(true); + inheritThemeGapSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-use-theme-gap', widget.get_active()); + }); + inheritThemeGapRow.add(inheritThemeGapLabel); + inheritThemeGapRow.add(inheritThemeGapSwitch); + runnerMenuTweaksFrame.add(inheritThemeGapRow); + + this.mainBox.append(runnerMenuTweaksFrame); + } + _loadUnityTweaks(){ + let pinnedAppsFrame = new PW.FrameBox(); + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.UNITY); + this.mainBox.append(widgetFrame); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('unity-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('unity-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Unity Layout Buttons") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Button Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('unity-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('unity-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadRavenTweaks(){ + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let ravenPositionRow = new PW.FrameBoxRow(); + let ravenPositionLabel = new Gtk.Label({ + label: _('Position on Monitor'), + xalign:0, + hexpand: true, + }); + let ravenPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + ravenPositionCombo.append_text(_("Left")); + ravenPositionCombo.append_text(_("Right")); + let ravenPosition = this._settings.get_enum('raven-position'); + ravenPositionCombo.set_active(ravenPosition); + ravenPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('raven-position', widget.get_active()); + }); + ravenPositionRow.add(ravenPositionLabel); + ravenPositionRow.add(ravenPositionCombo); + generalTweaksFrame.add(ravenPositionRow); + generalTweaksFrame.add(this._createActivateOnHoverRow()); + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.RAVEN); + this.mainBox.append(widgetFrame); + } + _loadMintMenuTweaks(){ + let mintMenuTweaksFrame = new PW.FrameBox(); + mintMenuTweaksFrame.add(this._createActivateOnHoverRow()); + mintMenuTweaksFrame.add(this._createSearchBarLocationRow()); + mintMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(mintMenuTweaksFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Mint Layout Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('mint-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('mint-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + this.mainBox.append(pinnedAppsScrollWindow); + + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Shortcut Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('mint-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('mint-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadPinnedApps(array,frame, savePinnedAppsButton, scrollWindow) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(scrollWindow); + frameRow._name = array[i]; + frameRow._icon = Prefs.getIconPath([array[i], array[i+1], array[i+2]]); + frameRow._cmd = array[i+2]; + frameRow.saveButton = savePinnedAppsButton; + frameRow.hasEditButton = true; + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + frameRow.add(frameLabel); + + Prefs.checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: frame, + buttons: [savePinnedAppsButton], + modifyButton: true, + changeButton: true + }); + + buttonBox.connect('change', ()=> { + let dialog = new Prefs.AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.OTHER); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + let icon = Prefs.getIconPath(newPinnedApps); + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new Prefs.AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.OTHER, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(buttonBox); + frame.add(frameRow); + } + } + _loadWhiskerMenuTweaks(){ + let whiskerMenuTweaksFrame = new PW.FrameBox(); + whiskerMenuTweaksFrame.add(this._createActivateOnHoverRow()); + whiskerMenuTweaksFrame.add(this._createAvatarShapeRow()); + whiskerMenuTweaksFrame.add(this._createSearchBarLocationRow()); + whiskerMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(whiskerMenuTweaksFrame); + } + _loadRedmondMenuTweaks(){ + let redmondMenuTweaksFrame = new PW.FrameBox(); + redmondMenuTweaksFrame.add(this._createSearchBarLocationRow()); + + redmondMenuTweaksFrame.add(this._createFlipHorizontalRow()); + redmondMenuTweaksFrame.add(this._createAvatarShapeRow()); + redmondMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(redmondMenuTweaksFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + + } + _loadInsiderMenuTweaks(){ + let insiderMenuTweaksFrame = new PW.FrameBox(); + insiderMenuTweaksFrame.add(this._createAvatarShapeRow()); + this.mainBox.append(insiderMenuTweaksFrame); + } + _loadGnomeMenuTweaks(){ + let gnomeMenuTweaksFrame = new PW.FrameBox(); + gnomeMenuTweaksFrame.add(this._createActivateOnHoverRow()); + gnomeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(gnomeMenuTweaksFrame); + } + _loadPlaceHolderTweaks(){ + let placeHolderFrame = new PW.FrameBox(); + let placeHolderRow = new PW.FrameBoxRow(); + let placeHolderLabel = new Gtk.Label({ + label: _("Nothing Yet!"), + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + placeHolderRow.add(placeHolderLabel); + placeHolderFrame.add(placeHolderRow); + this.mainBox.append(placeHolderFrame); + } + _loadTogneeMenuTweaks(){ + let togneeMenuTweaksFrame = new PW.FrameBox(); + let searchBarBottomDefault = true; + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END + }); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view-tognee')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view-tognee', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + togneeMenuTweaksFrame.add(defaultLeftBoxRow); + togneeMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + togneeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(togneeMenuTweaksFrame); + } + _loadArcMenuTweaks(){ + let arcMenuTweaksFrame = new PW.FrameBox(); + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + defaultLeftBoxCombo.append_text(_("Pinned Apps")); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("Frequent Apps")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + arcMenuTweaksFrame.add(defaultLeftBoxRow); + + let searchBarBottomDefault = true; + arcMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + arcMenuTweaksFrame.add(this._createFlipHorizontalRow()); + arcMenuTweaksFrame.add(this._createAvatarShapeRow()); + arcMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(arcMenuTweaksFrame); + + let extraCategoriesFrame = new PW.FrameBox(); + let extraCategoriesRow = new PW.FrameBoxRow(); + let extraCategoriesButtonRow = new PW.FrameBoxRow(); + let extraCategoriesLocationRow = new PW.FrameBoxRow(); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Categories Quick Links") + "" + + "\n" + '' + _("Display quick links of extra categories on the home page") + "" + + "\n" + '' + _("See Customize Menu -> Extra Categories") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + let extraCategoriesLinksBox = new Prefs.MenuSettingsCategoriesPage(this._settings, "arcmenu-extra-categories-links"); + extraCategoriesLinksBox.categoriesFrame.unparent(); + extraCategoriesLinksBox.buttonRow.unparent(); + extraCategoriesRow.add(extraCategoriesLinksBox.categoriesFrame); + extraCategoriesLinksBox.categoriesFrame.hexpand = true; + extraCategoriesLinksBox.categoriesFrame.halign = Gtk.Align.FILL; + extraCategoriesButtonRow.add(extraCategoriesLinksBox.buttonRow); + extraCategoriesFrame.add(extraCategoriesRow); + extraCategoriesFrame.add(extraCategoriesButtonRow); + + this.mainBox.append(extraCategoriesFrame); + + let extraCategoriesLocationFrame = new PW.FrameBox(); + let extraCategoriesLocationLabel = new Gtk.Label({ + label: _("Quick Links Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let extraCategoriesLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + extraCategoriesLocationCombo.append_text(_("Bottom")); + extraCategoriesLocationCombo.append_text(_("Top")); + extraCategoriesLocationCombo.set_active(this._settings.get_enum('arcmenu-extra-categories-links-location')); + extraCategoriesLocationCombo.connect('changed', (widget) => { + this._settings.set_enum('arcmenu-extra-categories-links-location' , widget.get_active()); + }); + + extraCategoriesLocationRow.add(extraCategoriesLocationLabel); + extraCategoriesLocationRow.add(extraCategoriesLocationCombo); + extraCategoriesLocationFrame.add(extraCategoriesLocationRow); + this.mainBox.append(extraCategoriesLocationFrame); + } + _createWidgetsRows(layout){ + let weatherWidgetSetting = 'enable-weather-widget-raven'; + let clockWidgetSetting = 'enable-clock-widget-raven'; + if(layout == Constants.MenuLayout.RAVEN){ + weatherWidgetSetting = 'enable-weather-widget-raven'; + clockWidgetSetting = 'enable-clock-widget-raven'; + } + else{ + weatherWidgetSetting = 'enable-weather-widget-unity'; + clockWidgetSetting = 'enable-clock-widget-unity'; + } + + let widgetFrame = new PW.FrameBox(); + let weatherWidgetRow = new PW.FrameBoxRow(); + let weatherWidgetLabel = new Gtk.Label({ + label: _("Enable Weather Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let weatherWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + weatherWidgetSwitch.set_active(this._settings.get_boolean(weatherWidgetSetting)); + weatherWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(weatherWidgetSetting, widget.get_active()); + }); + + weatherWidgetRow.add(weatherWidgetLabel); + weatherWidgetRow.add(weatherWidgetSwitch); + widgetFrame.add(weatherWidgetRow); + + let clockWidgetRow = new PW.FrameBoxRow(); + let clockWidgetLabel = new Gtk.Label({ + label: _("Enable Clock Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clockWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + clockWidgetSwitch.set_active(this._settings.get_boolean(clockWidgetSetting)); + clockWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(clockWidgetSetting, widget.get_active()); + }); + + clockWidgetRow.add(clockWidgetLabel); + clockWidgetRow.add(clockWidgetSwitch); + widgetFrame.add(clockWidgetRow); + + return widgetFrame; + } +}); diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js new file mode 100644 index 0000000..b29a5bb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js @@ -0,0 +1,445 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + VerticalMainBox: true, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: 'padding-bottom: 10px; padding-right: 15px;' + }); + + this.mainBox.add_child(this.topBox); + this.categoriesButton = new MW.CategoriesButton(this); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.actor.y_align = Clutter.ActorAlign.CENTER; + this.searchBox.actor.y_expand = true; + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 15px 0px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.categoriesButton.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 5px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.widgetBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: false, + style_class: 'datemenu-displays-box' + }); + + this.widgetBox.style = "margin: 0px; spacing: 10px; padding: 10px 50px;"; + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; width: 350px; padding: 10px; margin: 0px"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px"; + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID, isContainedInCategory); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this._createCategoriesMenu(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _addSeparator(){ + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.ALWAYS_SHOW, Constants.SeparatorAlignment.VERTICAL); + this.actionsBox.add_child(verticalSeparator); + } + + loadExtraPinnedApps(){ + this.actionsContainerBox.remove_child(this.actionsBox); + this.actionsBox.destroy_all_children(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px; padding: 5px 0px;"; + this.actionsContainerBox.add_child(this.actionsBox); + + super.loadExtraPinnedApps(this._settings.get_strv('unity-pinned-app-list'), this._settings.get_int('unity-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + pinnedApps.push(_("Downloads"), "ArcMenu_Downloads", "ArcMenu_Downloads"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('unity-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + _createCategoriesMenu(){ + this.categoriesMenu = new PopupMenu.PopupMenu(this.categoriesButton.actor, 0.5, St.Side.TOP); + this.categoriesMenu.blockSourceEvents = true; + this.categoriesMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.categoriesButton.tooltip){ + this.categoriesButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.categoriesButton.active = false; + this.categoriesButton.sync_hover(); + this.categoriesButton.hovered = this.categoriesButton.hover; + } + }); + this.section = new PopupMenu.PopupMenuSection(); + this.categoriesMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + this.leftPanelPopup.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(350 / scaleFactor); + this.leftPanelPopup.style = `max-height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this._displayCategories(); + this.subMenuManager.addMenu(this.categoriesMenu); + this.categoriesMenu.actor.hide(); + Main.uiGroup.add_child(this.categoriesMenu.actor); + } + + toggleCategoriesMenu(){ + let appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.categoriesMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.categoriesMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.categoriesButton.tooltip.hide(); + + this.categoriesMenu.toggle(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + _displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.categoriesBox.add_actor(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.subMainBox.remove_child(this.actionsContainerBox); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + this.widgetBox.remove_all_children(); + if(this._settings.get_boolean('enable-clock-widget-unity')) + this.widgetBox.add_child(this._clocksItem); + if(this._settings.get_boolean('enable-weather-widget-unity')) + this.widgetBox.add_child(this._weatherItem); + if(!this.subMainBox.contains(this.widgetBox)) + this.subMainBox.add_child(this.widgetBox); + this.subMainBox.add_child(this.actionsContainerBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.categoriesMenu.isOpen) + this.categoriesMenu.toggle(); + if(this.subMainBox.contains(this.widgetBox)){ + this.subMainBox.remove_child(this.widgetBox); + } + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + let label = this._createLabelWithSeparator(this.activeCategory); + if(grid === this.applicationsGrid) + this.applicationsBox.insert_child_at_index(label.actor, 0); + else + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + + super.destroy(); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js new file mode 100644 index 0000000..ab4958e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js @@ -0,0 +1,187 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.actionsBox.style = "spacing: 6px; margin: 0px 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.actor.x_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + else{ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js new file mode 100644 index 0000000..047bd63 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.LIST, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 300, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.extrasButton = new MW.ExtrasButton(this); + this.extrasButton.actor.y_expand = true; + this.extrasButton.actor.y_align= Clutter.ActorAlign.START; + this.actionsBox.add_child(this.extrasButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade' + }); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true, + x_expand: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 10 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.pinnedAppsGrid); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 0px 10px;"; + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.subMainBox.add_child(this.searchBox.actor); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createExtrasMenu(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.pinnedAppsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView){ + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + this.pinnedAppsGrid.layout_manager.forceGridColumns = this.getColumnsFromGridIconSizeSetting(); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let directory = directoryShortcutsList[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createExtrasMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.extrasMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.section = new PopupMenu.PopupMenuSection(); + this.extrasMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.toggleExtrasMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + + this.computerScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + reactive:true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + + this.leftPanelPopup.add_child(this.computerScrollBox); + + this.computerBox = new St.BoxLayout({ + vertical: true + }); + this.computerScrollBox.add_actor(this.computerBox); + + this.computerBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.computerBox.add_child(this.applicationShortcuts[i]); + } + this.computerBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.computerBox.add_child(this.directoryShortcuts[i]); + } + this.computerBox.add_child(this.externalDevicesBox); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.subMenuManager.addMenu(this.extrasMenu); + this.extrasMenu.actor.hide(); + Main.uiGroup.add_child(this.extrasMenu.actor); + this.extrasMenu.connect('open-state-changed', (menu, open) => { + if(!open){ + this.extrasButton.active = false; + this.extrasButton.sync_hover(); + this.extrasButton.hovered = this.extrasButton.hover; + } + else{ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.extrasButton.tooltip){ + this.extrasButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + }); + } + + toggleExtrasMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.extrasMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.extrasMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.extrasButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.extrasMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base:0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.extrasMenu.toggle(); + if(this.extrasMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + + this.displayAllApps(); + if(!this._settings.get_boolean('windows-disable-pinned-apps')){ + if(!this.mainBox.contains(this.pinnedAppsScrollBox)) + this.mainBox.add_child(this.pinnedAppsScrollBox); + this.displayPinnedApps(); + } + + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + + displayAllApps(){ + this._clearActorsFromBox(); + let label = this._createLabelWithSeparator(_("Frequent")); + this.activeMenuItemSet = false; + + if(!this._settings.get_boolean('windows-disable-frequent-apps')){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + this.frequentAppsList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + const MaxItems = 8; + if(this.frequentAppsList.length > 0){ + this.applicationsBox.add_child(label.actor); + for (let i = 0; i < this.frequentAppsList.length && i < MaxItems; i++) { + let item = this.frequentAppsList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!this.activeMenuItemSet){ + this._frequentActiveItem = item; + this.activeMenuItemSet = true; + } + } + } + } + + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + super._clearActorsFromBox(this.pinnedAppsBox); + this.pinnedAppsGrid.remove_all_children(); + let label = this.createLabelRow(_("Pinned Apps")); + label.remove_child(label._ornamentLabel); + this.pinnedAppsBox.add_child(label); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.HOME_SCREEN, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/metadata.json b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/metadata.json new file mode 100644 index 0000000..f6d4800 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/metadata.json @@ -0,0 +1,15 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Application menu for GNOME Shell\n\nFeatures include: various menu layouts, built in GNOME search, quick access to system shortcuts, and much more!\n\nCommon solutions for ERROR message:\n - Restart your GNOME session after updating ArcMenu.\n - Install one of the following packages: 'gir1.2-gmenu-3.0' or 'gnome-menus'\n\nGeneral Help:\n - Visit https://gitlab.com/arcmenu/ArcMenu/-/wikis/home\n\nPlease report all bugs or issues at https://gitlab.com/arcmenu/ArcMenu", + "extension-id": "arcmenu", + "gettext-domain": "arcmenu", + "name": "ArcMenu", + "settings-schema": "org.gnome.shell.extensions.arcmenu", + "shell-version": [ + "40", + "41" + ], + "url": "https://gitlab.com/arcmenu/ArcMenu", + "uuid": "arcmenu@arcmenu.com", + "version": 27 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js new file mode 100644 index 0000000..4e58333 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js @@ -0,0 +1,764 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from places-menu extension + * (https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/places-menu) + * and Dash to Dock extension 'location.js' file to implement a trash shortcut + * (https://github.com/micheleg/dash-to-dock/blob/master/locations.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {St, Gio, GLib, Shell } = imports.gi; +const Clutter = imports.gi.Clutter; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const GObject = imports.gi.GObject; +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const ShellMountOperation = imports.ui.shellMountOperation; +const Signals = imports.signals; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const BACKGROUND_SCHEMA = 'org.gnome.desktop.background'; +const Hostname1Iface = ' \ + \ + \ + \ +'; +const Hostname1 = Gio.DBusProxy.makeProxyWrapper(Hostname1Iface); + +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem2 extends MW.ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info) { + super._init(menuLayout); + this._info = info; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ text: info.name, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER }); + + this.add_child(this.label); + + if (info.isRemovable()) { + this.style = "padding-right: 15px;"; + this._ejectButton = new MW.ArcMenuButtonItem(this._menuLayout, null, 'media-eject-symbolic'); + this._ejectButton.add_style_class_name("arcmenu-small-button") + this._ejectButton.setIconSize(14); + this._ejectButton.x_align = Clutter.ActorAlign.END; + this._ejectButton.x_expand = true; + this._ejectButton.connect('activate', info.eject.bind(info)); + this.add_child(this._ejectButton); + } + + this._changedId = info.connect('changed', + this._propertiesChanged.bind(this)); + this.actor.connect('destroy',()=>{ + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = 0; + } + }); + + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + let defaultIconSize = this._menuLayout.layoutProperties.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this._info.icon, + icon_size: iconSize + }); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this._iconBin.set_child(this.createIcon()); + this.label.text = info.name; + } +}); + +var PlaceInfo = class Arc_Menu_PlaceInfo2 { + constructor() { + this._init.apply(this, arguments); + } + + _init(kind, file, name, icon) { + this.kind = kind; + this.file = file; + this.name = name || this._getFileName(); + this.icon = icon ? new Gio.ThemedIcon({ name: icon }) : this.getIcon(); + } + + destroy() { + } + + isRemovable() { + return false; + } + + async _ensureMountAndLaunch(context, tryMount) { + try { + await this._launchDefaultForUri(this.file.get_uri(), context, null); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_MOUNTED)) { + Main.notifyError(_('Failed to launch “%s”').format(this.name), e.message); + return; + } + + let source = { + get_icon: () => this.icon + }; + let op = new ShellMountOperation.ShellMountOperation(source); + try { + await this._mountEnclosingVolume(0, op.mountOp, null); + + if (tryMount) + this._ensureMountAndLaunch(context, false); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED)) + Main.notifyError(_('Failed to mount volume for “%s”').format(this.name), e.message); + } finally { + op.close(); + } + } + } + + launch(timestamp) { + let launchContext = global.create_app_launch_context(timestamp, -1); + this._ensureMountAndLaunch(launchContext, true); + } + + getIcon() { + this.file.query_info_async('standard::symbolic-icon', 0, 0, null, + (file, result) => { + try { + let info = file.query_info_finish(result); + this.icon = info.get_symbolic_icon(); + this.emit('changed'); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return; + throw e; + } + }); + + // return a generic icon for this kind for now, until we have the + // icon from the query info above + switch (this.kind) { + case 'network': + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + case 'devices': + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + case 'special': + case 'bookmarks': + default: + if (!this.file.is_native()) + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + else + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return this.file.get_basename(); + throw e; + } + } + + _launchDefaultForUri(uri, context, cancel) { + return new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(uri, context, cancel, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } + + _mountEnclosingVolume(flags, mountOp, cancel) { + return new Promise((resolve, reject) => { + this.file.mount_enclosing_volume(flags, mountOp, cancel, (o, res) => { + try { + this.file.mount_enclosing_volume_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } +} +Signals.addSignalMethods(PlaceInfo.prototype); + +var RootInfo = class Arc_Menu_RootInfo extends PlaceInfo { + _init() { + super._init('devices', Gio.File.new_for_path('/'), _('Computer')); + + let busName = 'org.freedesktop.hostname1'; + let objPath = '/org/freedesktop/hostname1'; + new Hostname1(Gio.DBus.system, busName, objPath, (obj, error) => { + if (error) + return; + + this._proxy = obj; + this._proxyID = this._proxy.connect('g-properties-changed', + this._propertiesChanged.bind(this)); + this._propertiesChanged(obj); + }); + + } + + getIcon() { + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + } + + _propertiesChanged(proxy) { + // GDBusProxy will emit a g-properties-changed when hostname1 goes down + // ignore it + if (proxy.g_name_owner) { + this.name = proxy.PrettyHostname || _('Computer'); + this.emit('changed'); + } + } + + destroy() { + if (this._proxyID) { + this._proxy.disconnect(this._proxyID); + this._proxy = 0; + } + if (this._proxy) { + this._proxy.run_dispose(); + this._proxy = null; + } + super.destroy(); + } +}; + + +var PlaceDeviceInfo = class Arc_Menu_PlaceDeviceInfo extends PlaceInfo { + _init(kind, mount) { + this._mount = mount; + super._init(kind, mount.get_root(), mount.get_name()); + } + + getIcon() { + return this._mount.get_symbolic_icon(); + } + + isRemovable() { + return this._mount.can_eject(); + } + + eject() { + let unmountArgs = [ + Gio.MountUnmountFlags.NONE, + (new ShellMountOperation.ShellMountOperation(this._mount)).mountOp, + null // Gio.Cancellable + ]; + + if (this._mount.can_eject()) + this._mount.eject_with_operation(...unmountArgs, + this._ejectFinish.bind(this)); + else + this._mount.unmount_with_operation(...unmountArgs, + this._unmountFinish.bind(this)); + } + + _ejectFinish(mount, result) { + try { + mount.eject_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _unmountFinish(mount, result) { + try { + mount.unmount_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _reportFailure(exception) { + let msg = _('Ejecting drive “%s” failed:').format(this._mount.get_name()); + Main.notifyError(msg, exception.message); + } +}; + +var PlaceVolumeInfo = class Arc_Menu_PlaceVolumeInfo extends PlaceInfo { + _init(kind, volume) { + this._volume = volume; + super._init(kind, volume.get_activation_root(), volume.get_name()); + } + + launch(timestamp) { + if (this.file) { + super.launch(timestamp); + return; + } + + this._volume.mount(0, null, null, (volume, result) => { + volume.mount_finish(result); + + let mount = volume.get_mount(); + this.file = mount.get_root(); + super.launch(timestamp); + }); + } + + getIcon() { + return this._volume.get_symbolic_icon(); + } +}; + +const DefaultDirectories = [ + GLib.UserDirectory.DIRECTORY_DOCUMENTS, + GLib.UserDirectory.DIRECTORY_PICTURES, + GLib.UserDirectory.DIRECTORY_MUSIC, + GLib.UserDirectory.DIRECTORY_DOWNLOAD, + GLib.UserDirectory.DIRECTORY_VIDEOS, +]; + +var PlacesManager = class Arc_Menu_PlacesManager { + constructor() { + this._places = { + special: [], + devices: [], + bookmarks: [], + network: [], + }; + + this._settings = new Gio.Settings({ schema_id: BACKGROUND_SCHEMA }); + this._showDesktopIconsChangedId = + this._settings.connect('changed::show-desktop-icons', + this._updateSpecials.bind(this)); + this._updateSpecials(); + + /* + * Show devices, code more or less ported from nautilus-places-sidebar.c + */ + this._volumeMonitor = Gio.VolumeMonitor.get(); + this._connectVolumeMonitorSignals(); + this._updateMounts(); + + this._bookmarksFile = this._findBookmarksFile(); + this._bookmarkTimeoutId = 0; + this._monitor = null; + + if (this._bookmarksFile) { + this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null); + this._monitor.connect('changed', () => { + if (this._bookmarkTimeoutId > 0) + return; + /* Defensive event compression */ + this._bookmarkTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 100, () => { + this._bookmarkTimeoutId = 0; + this._reloadBookmarks(); + return false; + }); + }); + + this._reloadBookmarks(); + } + } + + _connectVolumeMonitorSignals() { + const signals = [ + 'volume-added', + 'volume-removed', + 'volume-changed', + 'mount-added', + 'mount-removed', + 'mount-changed', + 'drive-connected', + 'drive-disconnected', + 'drive-changed' + ]; + + this._volumeMonitorSignals = []; + let func = this._updateMounts.bind(this); + for (let i = 0; i < signals.length; i++) { + let id = this._volumeMonitor.connect(signals[i], func); + this._volumeMonitorSignals.push(id); + } + } + + destroy() { + if (this._settings) + this._settings.disconnect(this._showDesktopIconsChangedId); + this._settings = null; + + for (let i = 0; i < this._volumeMonitorSignals.length; i++) + this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]); + + if (this._monitor) + this._monitor.cancel(); + if (this._bookmarkTimeoutId) + GLib.source_remove(this._bookmarkTimeoutId); + } + + _updateSpecials() { + this._places.special.forEach(p => p.destroy()); + this._places.special = []; + + let homePath = GLib.get_home_dir(); + + this._places.special.push(new PlaceInfo('special', + Gio.File.new_for_path(homePath), + _('Home'))); + + let specials = []; + let dirs = DefaultDirectories.slice(); + + if (this._settings.get_boolean('show-desktop-icons')) + dirs.push(GLib.UserDirectory.DIRECTORY_DESKTOP); + + for (let i = 0; i < dirs.length; i++) { + let specialPath = GLib.get_user_special_dir(dirs[i]); + if (specialPath == null || specialPath == homePath) + continue; + + let file = Gio.File.new_for_path(specialPath), info; + try { + info = new PlaceInfo('special', file); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + continue; + throw e; + } + + specials.push(info); + } + + specials.sort((a, b) => GLib.utf8_collate(a.name, b.name)); + this._places.special = this._places.special.concat(specials); + + this.emit('special-updated'); + } + + _updateMounts() { + let networkMounts = []; + let networkVolumes = []; + + this._places.devices.forEach(p => p.destroy()); + this._places.devices = []; + this._places.network.forEach(p => p.destroy()); + this._places.network = []; + + /* Add standard places */ + // this._places.devices.push(new RootInfo()); + /* this._places.network.push(new PlaceInfo('network', + Gio.File.new_for_uri('network:///'), + _('Network'), + 'network-workgroup-symbolic'));*/ + + /* first go through all connected drives */ + let drives = this._volumeMonitor.get_connected_drives(); + for (let i = 0; i < drives.length; i++) { + let volumes = drives[i].get_volumes(); + + for (let j = 0; j < volumes.length; j++) { + let identifier = volumes[j].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[j]); + } else { + let mount = volumes[j].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + } + + /* add all volumes that is not associated with a drive */ + let volumes = this._volumeMonitor.get_volumes(); + for (let i = 0; i < volumes.length; i++) { + if (volumes[i].get_drive() != null) + continue; + + let identifier = volumes[i].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[i]); + } else { + let mount = volumes[i].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + + /* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */ + let mounts = this._volumeMonitor.get_mounts(); + for (let i = 0; i < mounts.length; i++) { + if (mounts[i].is_shadowed()) + continue; + + if (mounts[i].get_volume()) + continue; + + let root = mounts[i].get_default_location(); + if (!root.is_native()) { + networkMounts.push(mounts[i]); + continue; + } + this._addMount('devices', mounts[i]); + } + + for (let i = 0; i < networkVolumes.length; i++) { + let mount = networkVolumes[i].get_mount(); + if (mount) { + networkMounts.push(mount); + continue; + } + this._addVolume('network', networkVolumes[i]); + } + + for (let i = 0; i < networkMounts.length; i++) { + this._addMount('network', networkMounts[i]); + } + + this.emit('devices-updated'); + this.emit('network-updated'); + } + + _findBookmarksFile() { + let paths = [ + GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']), + GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']), + ]; + + for (let i = 0; i < paths.length; i++) { + if (GLib.file_test(paths[i], GLib.FileTest.EXISTS)) + return Gio.File.new_for_path(paths[i]); + } + + return null; + } + + _reloadBookmarks() { + + this._bookmarks = []; + + let content = Shell.get_file_contents_utf8_sync(this._bookmarksFile.get_path()); + let lines = content.split('\n'); + + let bookmarks = []; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let components = line.split(' '); + let bookmark = components[0]; + + if (!bookmark) + continue; + + let file = Gio.File.new_for_uri(bookmark); + if (file.is_native() && !file.query_exists(null)) + continue; + + let duplicate = false; + for (let i = 0; i < this._places.special.length; i++) { + if (file.equal(this._places.special[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + for (let i = 0; i < bookmarks.length; i++) { + if (file.equal(bookmarks[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + let label = null; + if (components.length > 1) + label = components.slice(1).join(' '); + + bookmarks.push(new PlaceInfo('bookmarks', file, label)); + } + + this._places.bookmarks = bookmarks; + + this.emit('bookmarks-updated'); + } + + _addMount(kind, mount) { + let devItem; + + try { + devItem = new PlaceDeviceInfo(kind, mount); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(devItem); + } + + _addVolume(kind, volume) { + let volItem; + + try { + volItem = new PlaceVolumeInfo(kind, volume); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(volItem); + } + + get(kind) { + return this._places[kind]; + } +}; +Signals.addSignalMethods(PlacesManager.prototype); + +//Trash can class implemented from Dash to Dock https://github.com/micheleg/dash-to-dock/blob/master/locations.js +var Trash = class Arc_Menu_Trash { + constructor(menuItem) { + this._menuItem = menuItem; + let trashPath = GLib.get_home_dir() + '/.local/share/Trash/files/'; + this._file = Gio.file_new_for_path(trashPath); + try { + this._monitor = this._file.monitor_directory(0, null); + this._signalId = this._monitor.connect( + 'changed', + this._onTrashChange.bind(this) + ); + } catch (e) { + log(`Impossible to monitor trash: ${e}`); + } + this._lastEmpty = true; + this._empty = true; + this._schedUpdateId = 0; + this._updateTrash(); + } + + destroy() { + if (this._monitor) { + this._monitor.disconnect(this._signalId); + this._monitor.run_dispose(); + } + this._file.run_dispose(); + } + + _onTrashChange() { + if (this._schedUpdateId) { + GLib.source_remove(this._schedUpdateId); + } + this._schedUpdateId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 500, () => { + this._schedUpdateId = 0; + this._updateTrash(); + return GLib.SOURCE_REMOVE; + }); + } + + _updateTrash() { + try { + let children = this._file.enumerate_children('*', 0, null); + this._empty = children.next_file(null) == null; + children.close(null); + } catch (e) { + log(`Impossible to enumerate trash children: ${e}`) + return; + } + + this._ensureApp(); + } + + _ensureApp() { + if (this._trashApp == null || + this._lastEmpty != this._empty) { + let trashKeys = new GLib.KeyFile(); + trashKeys.set_string('Desktop Entry', 'Name', _('Trash')); + trashKeys.set_string('Desktop Entry', 'Id', 'ArcMenu_Trash'); + trashKeys.set_string('Desktop Entry', 'Icon', + this._empty ? 'user-trash-symbolic' : 'user-trash-full-symbolic'); + trashKeys.set_string('Desktop Entry', 'Type', 'Application'); + trashKeys.set_string('Desktop Entry', 'Exec', 'gio open trash:///'); + trashKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); + trashKeys.set_string('Desktop Entry', 'XdtdUri', 'trash:///'); + if (!this._empty) { + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash;'); + trashKeys.set_string('Desktop Action empty-trash', 'Name', _('Empty Trash')); + trashKeys.set_string('Desktop Action empty-trash', 'Exec', + 'dbus-send --print-reply --dest=org.gnome.Nautilus /org/gnome/Nautilus org.gnome.Nautilus.FileOperations.EmptyTrash'); + } + else{ + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash-inactive;'); + trashKeys.set_string('Desktop Action empty-trash-inactive', 'Name', _('Empty Trash')); + } + + let trashAppInfo = Gio.DesktopAppInfo.new_from_keyfile(trashKeys); + this._trashApp = new Shell.App({appInfo: trashAppInfo}); + this._lastEmpty = this._empty; + + this._menuItem._app = this._trashApp; + if(this._menuItem.contextMenu) + this._menuItem.contextMenu._app = this._trashApp; + let trashIcon = this._trashApp.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(this._menuItem._iconBin && trashIcon) + this._menuItem.iconName = trashIcon.gicon.to_string(); + this._menuItem._updateIcon(); + this.emit('changed'); + } + } + + getApp() { + this._ensureApp(); + return this._trashApp; + } +} +Signals.addSignalMethods(Trash.prototype); diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefs.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefs.js new file mode 100644 index 0000000..916491b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefs.js @@ -0,0 +1,6786 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const ByteArray = imports.byteArray; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const LayoutTweaks = Me.imports.menulayouts.tweaks; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/arcmenu/'; +const GSET = 'gnome-shell-extension-tool'; + +var MenuSettingsPinnedAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPinnedAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + + this.pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.pinnedAppsScrollWindow.set_min_content_height(300); + this.pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.frame = new PW.FrameBox(); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END, + vexpand: false, + valign: Gtk.Align.END + }); + this._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + this.pinnedAppsScrollWindow.set_child(this.frame); + this.mainBox.append(this.pinnedAppsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array = []; + for(let i = 0; i < newPinnedApps.length; i++){ + array.push(newPinnedApps[i]._name); + array.push(newPinnedApps[i]._icon); + array.push(newPinnedApps[i]._cmd); + } + this._loadPinnedApps(array); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addPinnedAppsFrameRow.add(addPinnedAppsFrameLabel); + addPinnedAppsFrameRow.add(addPinnedAppsButton); + addPinnedAppsFrame.add(addPinnedAppsFrameRow); + this.mainBox.append(addPinnedAppsFrame); + + let addCustomAppFrame = new PW.FrameBox(); + let addCustomAppFrameRow = new PW.FrameBoxRow(); + let addCustomAppFrameLabel = new Gtk.Label({ + label: _("Add Custom Shortcut"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addCustomAppButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addCustomAppButton.connect('clicked', ()=> { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps(newPinnedApps); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let x = 0; x < this.frame.count; x++) { + array.push(this.frame.get_index(x)._name); + array.push(this.frame.get_index(x)._icon); + array.push(this.frame.get_index(x)._cmd); + } + this._settings.set_strv('pinned-app-list',array); + this.saveButton.set_sensitive(false); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + _loadPinnedApps(array) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(this.pinnedAppsScrollWindow); + let iconString; + frameRow._name = array[i]; + frameRow._icon = array[i + 1]; + frameRow._cmd = array[i + 2]; + frameRow.saveButton = this.saveButton; + if(frameRow._icon === "ArcMenu_ArcMenuIcon"){ + frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + + checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + frameRow.add(frameLabel); + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.frame, + buttons: [this.saveButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)) + arcMenuImage.gicon = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon(); + else + arcMenuImage.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + frameRow.add(buttonBox); + this.frame.add(frameRow); + } + } +}); + +var AddAppsToPinnedListWindow = GObject.registerClass( + class Arc_Menu_AddAppsToPinnedListWindow extends PW.DialogWindow { + _init(settings, parent, dialogType) { + this._settings = settings; + this._dialogType = dialogType; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(_('Add to your Pinned Apps'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(_('Change Selected Pinned App'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(_('Select Application Shortcuts'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(_('Select Directory Shortcuts'), parent); + this.newPinnedAppsArray=[]; + this.addResponse = false; + } + + _createLayout(vbox) { + let searchBar = new Gtk.SearchEntry({ + placeholder_text: _("Search…") + }); + searchBar.connect('search-changed', ()=> { + this._loadCategories(); + let applist = Gio.app_info_get_all(); + + let pattern = searchBar.text; + let searchResults = []; + let res = []; + for (let i in applist) { + let app = applist[i]; + let match; + + match = app.get_name().toLowerCase() + " "; + let info = Gio.DesktopAppInfo.new(app.get_id()); + + if (info.get_display_name()) + match += info.get_display_name().toLowerCase() + " "; + if (info.get_executable()) + match += info.get_executable().toLowerCase() + " "; + if (info.get_keywords()) + match += info.get_keywords().toString().toLowerCase() + " "; + if (app.get_description()) + match += app.get_description().toLowerCase(); + + + let index = match.indexOf(pattern); + if (index != -1) { + searchResults.push([index, app]); + } + } + let arcMenuSettings = _("ArcMenu Settings").toLowerCase(); + let index = arcMenuSettings.indexOf(pattern); + let showArcMenuSettings = false; + if (index != -1) { + showArcMenuSettings = true; + } + + searchResults.sort(function(a,b) { + return a[0] > b[0]; + }); + res = searchResults.map(function(value,index) { return value[1]; }); + this.appsFrame.remove_all_children(); + this._loadCategories(res, showArcMenuSettings); + this.appsFrame.show(); + + }); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_min_content_width(650); + this.appsFrame = new PW.FrameBox(); + let addAppsButton; + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS + || this._dialogType == Constants.DiaglogType.DIRECTORIES){ + addAppsButton = new Gtk.Button({ + label: _("Add") + }); + + addAppsButton.connect('clicked', ()=> { + this.addResponse = true; + this.response(-10); + }); + addAppsButton.set_halign(Gtk.Align.END); + } + + pinnedAppsScrollWindow.set_child(this.appsFrame); + vbox.append(pinnedAppsScrollWindow); + if(this._dialogType == Constants.DiaglogType.DEFAULT){ + this._loadCategories(); + vbox.append(addAppsButton); + vbox.prepend(searchBar); + } + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Recent"), "document-open-recent-symbolic", "ArcMenu_Recent"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + this.appsFrame.add(frameRow); + } + vbox.append(addAppsButton); + } + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS){ + this._loadCategories(); + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + let defaultApplicationShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("ArcMenu Settings"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg', Constants.ArcMenuSettingsCommand]); + defaultApplicationShortcuts.push([_("Run Command..."), "system-run-symbolic", "ArcMenu_RunCommand"]); + defaultApplicationShortcuts.push([_("Show All Applications"), "view-fullscreen-symbolic", "ArcMenu_ShowAllApplications"]); + + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(frameRow._icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) { + this.newPinnedAppsArray.push(frameRow); + } + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Default Apps")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultApplicationShortcutsFrame); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + vbox.append(addAppsButton); + } + else{ + this._loadCategories(); + let defaultAppsWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + defaultAppsWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + defaultAppsWindow.set_min_content_width(500); + defaultAppsWindow.set_min_content_width(500); + + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + defaultAppsWindow.set_child(defaultApplicationShortcutsFrame); + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"]); + defaultApplicationShortcuts.push([_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"]); + defaultApplicationShortcuts.push([_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"]); + defaultApplicationShortcuts.push([_("Restart"), 'system-reboot-symbolic', "ArcMenu_Restart"]); + defaultApplicationShortcuts.push([_("Suspend"), "media-playback-pause-symbolic", "ArcMenu_Suspend"]); + defaultApplicationShortcuts.push([_("Hybrid Sleep"), Me.path + Constants.SleepIcon.PATH, "ArcMenu_HybridSleep"]); + defaultApplicationShortcuts.push([_("Hibernate"), "document-save-symbolic", "ArcMenu_Hibernate"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Presets")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultAppsWindow); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + } + } + + get_newPinnedAppsArray() { + return this.newPinnedAppsArray; + } + + get_response() { + return this.addResponse; + } + + _loadCategories(searchResults, showArcMenuSettings) { + let allApps = searchResults ? searchResults : Gio.app_info_get_all(); + allApps.sort((a, b) => { + let _a = a.get_display_name(); + let _b = b.get_display_name(); + return GLib.strcmp0(_a, _b); + }); + + let iter = -1; + if(searchResults) + iter = 0; + if(showArcMenuSettings) + iter = -1; + for(let i = iter; i < allApps.length; i++) { + if(i == -1 ? true : allApps[i].should_show()) { + let frameRow = new PW.FrameBoxRow(); + let icon; + if(i == -1){ + frameRow._name = _("ArcMenu Settings"); + icon = frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + frameRow._cmd = Constants.ArcMenuSettingsCommand; + } + else{ + frameRow._app = allApps[i]; + frameRow._name = allApps[i].get_display_name(); + frameRow._icon = ''; + if(allApps[i].get_icon()) + icon = allApps[i].get_icon().to_string(); + else + icon = "dialog-information"; + + frameRow._cmd = allApps[i].get_id(); + } + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS|| + this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + } + else{ + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + } + + this.appsFrame.add(frameRow); + } + } + } +}); + +var AddCustomLinkDialogWindow = GObject.registerClass( + class Arc_Menu_AddCustomLinkDialogWindow extends PW.DialogWindow { + _init(settings, parent, dialogType, isAppEdit=false, appArray=null) { + this._settings = settings; + this.newPinnedAppsArray=[]; + this.addResponse = false; + this.isAppEdit = isAppEdit; + this._dialogType = dialogType; + this.appArray = appArray; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(isAppEdit?_('Edit Shortcut'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(isAppEdit?_('Edit Custom Shortcut'):_('Add a Custom Shortcut'), parent); + } + + _createLayout(vbox) { + let mainFrame = new PW.FrameBox(); + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Shortcut Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let nameEntry = new Gtk.Entry(); + nameEntry.set_width_chars(35); + nameFrameRow.add(nameFrameLabel); + nameFrameRow.add(nameEntry); + nameEntry.grab_focus(); + mainFrame.add(nameFrameRow); + + let iconFrameRow = new PW.FrameBoxRow(); + let iconFrameLabel = new Gtk.Label({ + label: _("Icon:"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconEntry = new Gtk.Entry(); + iconEntry.set_width_chars(35); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Browse...') + }); + + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.set_filter(fileFilter); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + let iconFilepath = dialog.get_file().get_path(); + iconEntry.set_text(iconFilepath); + dialog.destroy(); + } + else if(response === Gtk.ResponseType.CANCEL) + dialog.destroy(); + }) + + dialog.show(); + }); + + iconFrameRow.add(iconFrameLabel); + iconFrameRow.add(fileChooserButton); + iconFrameRow.add(iconEntry); + mainFrame.add(iconFrameRow); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + iconEntry.set_text("ArcMenu_Folder"); + + let cmdFrameRow = new PW.FrameBoxRow(); + let cmdFrameLabel = new Gtk.Label({ + label: _('Terminal Command:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + cmdFrameLabel.label = _("Shortcut Path:"); + let cmdEntry = new Gtk.Entry(); + cmdEntry.set_width_chars(35); + cmdFrameRow.add(cmdFrameLabel); + cmdFrameRow.add(cmdEntry); + mainFrame.add(cmdFrameRow); + + let addButton = new Gtk.Button({ + label: this.isAppEdit ?_("Apply") :_("Add") + }); + + if(this.appArray!=null) { + nameEntry.text=this.appArray[0]; + iconEntry.text=this.appArray[1]; + cmdEntry.text=this.appArray[2]; + } + addButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(nameEntry.get_text()); + this.newPinnedAppsArray.push(iconEntry.get_text()); + this.newPinnedAppsArray.push(cmdEntry.get_text()); + this.addResponse = true; + this.response(-10); + }); + addButton.set_halign(Gtk.Align.END); + + vbox.append(mainFrame); + vbox.append(addButton); + } + + get_newPinnedAppsArray(){ + return this.newPinnedAppsArray; + } + + get_response(){ + return this.addResponse; + } +}); + +var GeneralPage = GObject.registerClass( + class Arc_Menu_GeneralPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let arcMenuPlacementHeader = new Gtk.Label({ + label: "" + _("Display Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(arcMenuPlacementHeader); + let menuPlacementFrame = new PW.FrameBox(); + this._createDisplayOnFrame(menuPlacementFrame, true); + this._settings.connect('changed::available-placement', ()=>{ + menuPlacementFrame.remove_all_children(); + this._createDisplayOnFrame(menuPlacementFrame, false); + menuPlacementFrame.show(); + }) + + this.mainBox.append(menuPlacementFrame); + + let hotCornerHeader = new Gtk.Label({ + label: "" + _("Hot Corner Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(hotCornerHeader); + + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Modify Hot Corner"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let modifyHotCornerButton = new PW.Button({ + icon_name: 'emblem-system-symbolic', + }); + modifyHotCornerButton.connect('clicked', ()=> { + let dialog = new ModifyHotCornerDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + dialog.destroy(); + }); + }); + let modifyHotCornerSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + modifyHotCornerSwitch.set_active(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerButton.set_sensitive(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('override-hot-corners',widget.get_active()); + modifyHotCornerButton.set_sensitive(widget.get_active()); + if(!widget.get_active()){ + this._settings.set_enum('hot-corners',Constants.HotCornerAction.DEFAULT); + } + }); + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(modifyHotCornerButton); + modifyHotCornerRow.add(modifyHotCornerSwitch); + modifyHotCornerFrame.add(modifyHotCornerRow); + this.mainBox.append(modifyHotCornerFrame); + + let menuHotkeyHeader = new Gtk.Label({ + label: "" + _("Hotkey Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuHotkeyHeader); + + let menuHotKeyFrame = this._createHotkeyFrame(true); + this.mainBox.append(menuHotKeyFrame); + + let runnerHeaderLabel = new Gtk.Label({ + label: "" + _("Standalone Runner Menu") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(runnerHeaderLabel); + + let runnerHotkeyFrame = this._createHotkeyFrame(false); + this.mainBox.append(runnerHotkeyFrame); + } + + _createHotkeyFrame(isMenuHotkey){ + let hotkeyFrame = new PW.FrameBox(); + let enableRunnerMenuSwitch, hotkeyEnumSetting, customHotkeySetting, primaryMonitorSetting; + if(isMenuHotkey){ + hotkeyEnumSetting = 'menu-hotkey'; + customHotkeySetting = 'toggle-arcmenu'; + primaryMonitorSetting = 'hotkey-open-primary-monitor'; + } + else{ + hotkeyEnumSetting = 'runner-menu-hotkey'; + customHotkeySetting = 'toggle-runner-menu'; + primaryMonitorSetting = 'runner-hotkey-open-primary-monitor'; + let enableRunnerMenuRow = new PW.FrameBoxRow(); + let enableRunnerMenuLabel = new Gtk.Label({ + label: _("Enable a standalone Runner menu"), + use_markup: true, + xalign: 0, + hexpand: true + }); + enableRunnerMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + enableRunnerMenuSwitch.set_active(this._settings.get_boolean('enable-standlone-runner-menu')); + enableRunnerMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-standlone-runner-menu', widget.get_active()); + if(!widget.get_active()){ + hotkeyFrame.removeChildrenAfterIndex(0); + } + else{ + hotkeyFrame.add(hotkeyRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 0) + hotkeyFrame.add(primaryMonitorRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 1){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + } + }); + enableRunnerMenuRow.add(enableRunnerMenuLabel); + enableRunnerMenuRow.add(enableRunnerMenuSwitch); + hotkeyFrame.add(enableRunnerMenuRow); + } + + let hotkeyActivationRow = new PW.FrameBoxRow(); + let hotkeyActivationLabel = new Gtk.Label({ + label: _("Hotkey Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotkeyActivationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotkeyActivationCombo.append_text(_("Key Release")); + hotkeyActivationCombo.append_text(_("Key Press")); + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + hotkeyActivationCombo.set_active(1); + else + hotkeyActivationCombo.set_active(0); + hotkeyActivationCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + this._settings.set_boolean('disable-hotkey-onkeyrelease',false); + if(widget.get_active() === 1) + this._settings.set_boolean('disable-hotkey-onkeyrelease',true); + }); + + hotkeyActivationRow.add(hotkeyActivationLabel); + hotkeyActivationRow.add(hotkeyActivationCombo); + + let primaryMonitorRow = new PW.FrameBoxRow(); + let primaryMonitorLabel = new Gtk.Label({ + label: _("Open on Primary Monitor"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let primaryMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + primaryMonitorSwitch.set_active(this._settings.get_boolean(primaryMonitorSetting)); + primaryMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(primaryMonitorSetting, widget.get_active()); + }); + primaryMonitorRow.add(primaryMonitorLabel); + primaryMonitorRow.add(primaryMonitorSwitch); + + + let hotkeyRow = new PW.FrameBoxRow(); + let hotkeyLabel = new Gtk.Label({ + label: isMenuHotkey ? _("Menu Hotkey") : _("Runner Hotkey"), + use_markup: true, + xalign: 0, + hexpand: true + }); + hotkeyRow.add(hotkeyLabel); + + let hotkeyCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + if(isMenuHotkey) + hotkeyCombo.append("NONE", _("None")); + hotkeyCombo.append("SUPER_L", _("Left Super Key")); + hotkeyCombo.append("CUSTOM", _("Custom Hotkey")); + hotkeyCombo.set_active(this._settings.get_enum(hotkeyEnumSetting)); + hotkeyCombo.connect('changed', (widget) => { + let removeIndex = isMenuHotkey ? 0 : 1; + if(widget.get_active_id() === "NONE"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + } + else if(widget.get_active_id() === "SUPER_L"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(primaryMonitorRow); + } + else if(widget.get_active_id() === "CUSTOM"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + hotkeyFrame.show(); + } + this._settings.set_enum(hotkeyEnumSetting, widget.get_active()); + }); + hotkeyRow.add(hotkeyCombo); + + hotkeyFrame.add(hotkeyRow); + + let customHotkeyRow = new PW.FrameBoxRow(); + let currentHotkeyLabel = new Gtk.Label( { + label: _("Current Hotkey"), + use_markup: true, + xalign: 0, + hexpand: false + }); + + let shortcutCell = new Gtk.ShortcutsShortcut({ + halign: Gtk.Align.START, + hexpand: true, + }); + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + + let modifyHotkeyButton = new Gtk.Button({ + label: _("Modify Hotkey"), + halign: Gtk.Align.END, + hexpand: false, + }); + customHotkeyRow.add(currentHotkeyLabel); + customHotkeyRow.add(shortcutCell); + customHotkeyRow.add(modifyHotkeyButton); + modifyHotkeyButton.connect('clicked', () => { + let dialog = new CustomHotkeyDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', () => { + let customHotKeyEnum = isMenuHotkey ? 2 : 1; + if(dialog.addResponse) { + this._settings.set_enum(hotkeyEnumSetting, 0); + this._settings.set_strv(customHotkeySetting, [dialog.resultsText]); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + shortcutCell.accelerator = dialog.resultsText; + dialog.destroy(); + } + else { + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + dialog.destroy(); + } + }); + }); + + if(hotkeyCombo.get_active_id() === "SUPER_L"){ + hotkeyFrame.add(primaryMonitorRow); + } + else if(hotkeyCombo.get_active_id() === "CUSTOM"){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + + if(!isMenuHotkey && !enableRunnerMenuSwitch.get_active()) + hotkeyFrame.removeChildrenAfterIndex(0); + return hotkeyFrame; + } + + _createDisplayOnFrame(menuPlacementFrame, setComboBox){ + let menuPlacementRow = new PW.FrameBoxRow(); + let menuPlacementLabel = new Gtk.Label({ + label: _("Display ArcMenu On"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuPlacementCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + let avaliablePlacement = this._settings.get_value('available-placement').deep_unpack(); + let dashExtensionName = _("Dash to Dock"); + let gnomeSettings = Gio.Settings.new("org.gnome.shell"); + let enabledExtensions = gnomeSettings.get_strv('enabled-extensions'); + if (enabledExtensions.includes('ubuntu-dock@ubuntu.com')) { + dashExtensionName = _("Ubuntu Dock"); + } + + menuPlacementCombo.append_text(_("Main Panel")); + menuPlacementCombo.append_text(_("Dash to Panel")); + menuPlacementCombo.append_text(dashExtensionName); + + menuPlacementRow.add(menuPlacementLabel); + menuPlacementRow.add(menuPlacementCombo); + menuPlacementFrame.add(menuPlacementRow); + + let dashToDockWarningRow = new PW.FrameBoxRow(); + let dashToDockWarningLabel = new Gtk.Label({ + label: _("Dash to Dock extension not running!") + "\n" + _("Enable Dash to Dock for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesRow = new PW.FrameBoxRow(); + let showActivitiesLabel = new Gtk.Label({ + label: _("Show Activities Button"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + showActivitiesSwitch.set_active(this._settings.get_boolean('show-activities-button')); + showActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('show-activities-button', widget.get_active()); + }); + showActivitiesRow.add(showActivitiesLabel); + showActivitiesRow.add(showActivitiesSwitch); + + let warningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let warningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + warningImageBox.append(warningImage); + + if(!avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + dashToDockWarningRow.add(warningImageBox); + } + dashToDockWarningRow.add(dashToDockWarningLabel); + + let panelWarningRow = new PW.FrameBoxRow(); + let panelWarningLabel = new Gtk.Label({ + label: avaliablePlacement[Constants.ArcMenuPlacement.DTP] ? _("Main Panel not found!") : + _("Dash to Panel extension not running!") + "\n" + _("Enable Dash to Panel for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + let panelWarningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let panelWarningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + panelWarningImageBox.append(panelWarningImage); + panelWarningRow.add(panelWarningImageBox); + panelWarningRow.add(panelWarningLabel); + + let menuPositionRow = new PW.FrameBoxRow(); + let menuPositionBoxLabel = new Gtk.Label({ + label: _("Position in Panel"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuPositionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + menuPositionCombo.append_text(_('Left')); + menuPositionCombo.append_text(_('Center')); + menuPositionCombo.append_text(_('Right')); + menuPositionCombo.set_active(this._settings.get_enum('position-in-panel')); + menuPositionCombo.connect('changed', (widget) => { + if(widget.get_active() === Constants.MenuPosition.LEFT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + else if(widget.get_active() === Constants.MenuPosition.CENTER){ + if(menuPlacementFrame.get_index(2) != menuPositionAdjustmentRow){ + menuPlacementFrame.insert(menuPositionAdjustmentRow, 2); + menuPlacementFrame.show(); + } + } + else if(widget.get_active() === Constants.MenuPosition.RIGHT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + this._settings.set_enum('position-in-panel', widget.get_active()); + }); + + menuPositionRow.add(menuPositionBoxLabel); + menuPositionRow.add(menuPositionCombo); + + let menuPositionAdjustmentRow = new PW.FrameBoxRow(); + let menuPositionAdjustmentLabel = new Gtk.Label({ + label: _("Menu Alignment"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alignmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 100, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + }); + alignmentScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Left")); + alignmentScale.add_mark(50, Gtk.PositionType.BOTTOM, _("Center")); + alignmentScale.add_mark(100, Gtk.PositionType.BOTTOM, _("Right")); + + alignmentScale.set_value(this._settings.get_int('menu-position-alignment')); + alignmentScale.connect('value-changed', (widget) => { + this._settings.set_int('menu-position-alignment', widget.get_value()); + }); + menuPositionAdjustmentRow.add(menuPositionAdjustmentLabel); + menuPositionAdjustmentRow.add(alignmentScale); + + let multiMonitorRow = new PW.FrameBoxRow(); + let multiMonitorLabel = new Gtk.Label({ + label: _("Display ArcMenu on all monitors"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let multiMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + multiMonitorSwitch.set_active(this._settings.get_boolean('multi-monitor')); + multiMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('multi-monitor', widget.get_active()); + }); + + multiMonitorRow.add(multiMonitorLabel); + multiMonitorRow.add(multiMonitorSwitch); + + menuPlacementCombo.connect('changed', (widget) => { + let placement = widget.get_active(); + this._settings.set_enum('arc-menu-placement', placement); + menuPlacementFrame.remove_all_children(); + menuPlacementFrame.add(menuPlacementRow); + if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.PANEL){ + if(avaliablePlacement[Constants.ArcMenuPlacement.PANEL] === false){ + menuPlacementFrame.add(panelWarningRow); + } + else{ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + menuPlacementFrame.show(); + } + else if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.DTP){ + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]){ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(panelWarningRow); + + menuPlacementFrame.show(); + } + else{ + if(avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(dashToDockWarningRow); + + menuPlacementFrame.show(); + } + }); + let placement = this._settings.get_enum('arc-menu-placement'); + if(setComboBox){ + if(placement == Constants.ArcMenuPlacement.PANEL && !avaliablePlacement[Constants.ArcMenuPlacement.PANEL]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.DTP); + else if(placement == Constants.ArcMenuPlacement.DTP && !avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.PANEL); + else + menuPlacementCombo.set_active(placement); + } + else + menuPlacementCombo.set_active(placement); + } +}); + +var ModifyHotCornerDialogWindow = GObject.registerClass( + class Arc_Menu_ModifyHotCornerDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + super._init(_('Modify Hot Corner'), parent); + this.set_default_size(600,250); + } + + _createLayout(vbox) { + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Hot Corner Action"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerActionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotCornerActionCombo.append_text(_("GNOME Default")); + hotCornerActionCombo.append_text(_("Disabled")); + hotCornerActionCombo.append_text(_("Open ArcMenu")); + hotCornerActionCombo.append_text(_("Custom")); + + let customHotCornerFrame = new PW.FrameBox(); + let customHeaderHotCornerRow = new PW.FrameBoxRow(); + + let customHeaderHotCornerLabel = new Gtk.Label({ + label: ""+_("Custom Hot Corner Action") + "\n" + _("Choose from a list of preset commands or use your own terminal command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + customHeaderHotCornerRow.add(customHeaderHotCornerLabel); + + let presetCustomHotCornerRow = new PW.FrameBoxRow(); + let presetCustomHotCornerLabel = new Gtk.Label({ + label: _("Preset commands"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerPresetsCombo = new Gtk.ComboBoxText({ + hexpand: true + }); + + hotCornerPresetsCombo.append_text(_("Show all Applications")); + hotCornerPresetsCombo.append_text(_("GNOME Terminal")); + hotCornerPresetsCombo.append_text(_("GNOME System Monitor")); + hotCornerPresetsCombo.append_text(_("GNOME Calculator")); + hotCornerPresetsCombo.append_text(_("GNOME gedit")); + hotCornerPresetsCombo.append_text(_("GNOME Screenshot")); + hotCornerPresetsCombo.append_text(_("GNOME Weather")); + hotCornerPresetsCombo.append_text(_("Run Command...")); + hotCornerPresetsCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + customHotCornerEntry.set_text("ArcMenu_ShowAllApplications"); + else if(widget.get_active() === 1) + customHotCornerEntry.set_text("gnome-terminal"); + else if(widget.get_active() === 2) + customHotCornerEntry.set_text("gnome-system-monitor"); + else if(widget.get_active() === 3) + customHotCornerEntry.set_text("gnome-calculator"); + else if(widget.get_active() === 4) + customHotCornerEntry.set_text("gedit"); + else if(widget.get_active() === 5) + customHotCornerEntry.set_text("gnome-screenshot"); + else if(widget.get_active() === 6) + customHotCornerEntry.set_text("gnome-weather"); + else if(widget.get_active() === 7) + customHotCornerEntry.set_text("ArcMenu_RunCommand"); + }); + presetCustomHotCornerRow.add(presetCustomHotCornerLabel); + presetCustomHotCornerRow.add(hotCornerPresetsCombo); + + let customHotCornerRow = new PW.FrameBoxRow(); + let customHotCornerLabel = new Gtk.Label({ + label: _("Terminal Command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let customHotCornerEntry = new Gtk.Entry({ + }); + customHotCornerEntry.set_text(this._settings.get_string('custom-hot-corner-cmd')); + customHotCornerEntry.connect('changed', (widget) => { + applyButton.set_sensitive(true); + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + }); + customHotCornerEntry.set_width_chars(40); + + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + customHotCornerRow.add(customHotCornerLabel); + customHotCornerRow.add(customHotCornerEntry); + + customHotCornerFrame.add(customHeaderHotCornerRow); + customHotCornerFrame.add(presetCustomHotCornerRow); + customHotCornerFrame.add(customHotCornerRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + }); + applyButton.connect('clicked', () => { + this._settings.set_string('custom-hot-corner-cmd',customHotCornerEntry.get_text()); + this._settings.set_enum('hot-corners',hotCornerActionCombo.get_active()); + applyButton.set_sensitive(false); + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + applyButton.set_sensitive(false); + + + let hotCornerAction = this._settings.get_enum('hot-corners'); + hotCornerActionCombo.set_active(hotCornerAction); + hotCornerActionCombo.connect('changed', (widget) => { + applyButton.set_sensitive(true); + if(widget.get_active()==Constants.HotCornerAction.CUSTOM){ + customHotCornerFrame.set_sensitive(true); + } + else{ + customHotCornerFrame.set_sensitive(false); + } + }); + + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(hotCornerActionCombo); + modifyHotCornerFrame.add(modifyHotCornerRow); + if(hotCornerActionCombo.get_active() == Constants.HotCornerAction.CUSTOM) + customHotCornerFrame.set_sensitive(true); + else + customHotCornerFrame.set_sensitive(false); + vbox.append(modifyHotCornerFrame); + vbox.append(customHotCornerFrame); + vbox.append(applyButton); + } + checkIfMatch(text){ + if(text === "ArcMenu_ShowAllApplications") + return 0; + else if(text === "gnome-terminal") + return 1; + else if(text === "gnome-system-monitor") + return 2; + else if(text === "gnome-calculator") + return 3; + else if(text === "gedit") + return 4; + else if(text === "gnome-screenshot") + return 5; + else if(text === "gnome-weather") + return 6; + else if(text === "ArcMenu_RunCommand") + return 7; + else + return -1; + } +}); + +var CustomHotkeyDialogWindow = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_CustomHotkeyDialogWindow extends Gtk.Window { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.keyEventController = new Gtk.EventControllerKey(); + + super._init({ + modal: true, + title: _("Set Custom Hotkey"), + transient_for: parent.get_root() + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + this.set_child(vbox); + this._createLayout(vbox); + this.add_controller(this.keyEventController); + this.set_size_request(500, 250); + } + + _createLayout(vbox) { + let hotkeyKey = ''; + + let modLabel = new Gtk.Label({ + label:_("Choose Modifiers"), + use_markup: true, + hexpand: true, + halign: Gtk.Align.START + }); + let modFrame = new PW.FrameBox(); + let modRow = new PW.FrameBoxRow(); + modRow.add(modLabel); + + let buttonBox = new Gtk.Box({ + hexpand: true, + halign: Gtk.Align.END, + spacing: 5 + }); + modRow.add(buttonBox); + let ctrlButton = new Gtk.ToggleButton({ + label: _("Ctrl") + }); + let superButton = new Gtk.ToggleButton({ + label: _("Super") + }); + let shiftButton = new Gtk.ToggleButton({ + label: _("Shift") + }); + let altButton = new Gtk.ToggleButton({ + label: _("Alt") + }); + ctrlButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + superButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + shiftButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + altButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + buttonBox.append(ctrlButton); + buttonBox.append(superButton); + buttonBox.append(shiftButton); + buttonBox.append(altButton); + modFrame.add(modRow); + vbox.append(modFrame); + + let keyFrame = new PW.FrameBox(); + let keyLabel = new Gtk.Label({ + label: _("Press any key"), + use_markup: true, + xalign: .5, + hexpand: true, + halign: Gtk.Align.CENTER + }); + vbox.append(keyLabel); + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/keyboard-symbolic.svg', 256, 72); + let keyboardImage = Gtk.Picture.new_for_pixbuf(pixbuf); + keyboardImage.hexpand = true; + keyboardImage.vexpand = true; + keyboardImage.halign = Gtk.Align.CENTER; + keyboardImage.valign = Gtk.Align.CENTER; + vbox.append(keyboardImage) + + let resultsRow = new PW.FrameBoxRow(); + let resultsLabel = new Gtk.Label({ + label: _("New Hotkey"), + use_markup: true, + xalign: .5, + hexpand: false, + halign: Gtk.Align.START + }); + let resultsWidget = new Gtk.ShortcutsShortcut({ + hexpand: true, + halign: Gtk.Align.END + }); + resultsRow.add(resultsLabel); + resultsRow.add(resultsWidget); + keyFrame.add(resultsRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + halign: Gtk.Align.END + }); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.emit("response", -10); + }); + applyButton.set_sensitive(false); + + this.keyEventController.connect('key-released', (controller, keyval, keycode, state) => { + this.resultsText = ""; + let key = keyval; + hotkeyKey = Gtk.accelerator_name(key, 0); + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += Gtk.accelerator_name(key,0); + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + + vbox.append(keyFrame); + vbox.append(applyButton); + } +}); + +function getIconPixbuf(filePath){ + if (GLib.file_test(filePath, GLib.FileTest.EXISTS)) + return GdkPixbuf.Pixbuf.new_from_file_at_size(filePath, 25, 25); + else + return null; +} + +var ButtonAppearancePage = GObject.registerClass( + class Arc_Menu_ButtonAppearancePage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + this.menuButtonColor = this._settings.get_string('menu-button-color'); + this.menuButtonHoverColor = this._settings.get_string('menu-button-hover-color'); + this.menuButtonActiveColor = this._settings.get_string('menu-button-active-color'); + this.menuButtonHoverBackgroundcolor = this._settings.get_string('menu-button-hover-backgroundcolor'); + this.menuButtonActiveBackgroundcolor = this._settings.get_string('menu-button-active-backgroundcolor'); + this._createLayout(this.mainBox); + } + + _createLayout(vbox) { + this.arcMenuPlacement = this._settings.get_enum('arc-menu-placement'); + let menuButtonAppearanceHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonAppearanceHeaderLabel); + + let menuButtonAppearanceFrame = new PW.FrameBox(); + let menuButtonAppearanceRow = new PW.FrameBoxRow(); + let menuButtonAppearanceLabel = new Gtk.Label({ + label: _('Appearance'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonAppearanceCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + menuButtonAppearanceCombo.append_text(_("Icon")); + menuButtonAppearanceCombo.append_text(_("Text")); + menuButtonAppearanceCombo.append_text(_("Icon and Text")); + menuButtonAppearanceCombo.append_text(_("Text and Icon")); + menuButtonAppearanceCombo.append_text(_("Hidden")); + menuButtonAppearanceCombo.set_active(this._settings.get_enum('menu-button-appearance')); + menuButtonAppearanceCombo.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + menuButtonAppearanceFrame.removeChildrenAfterIndex(0); + if(widget.get_active() === Constants.MenuButtonAppearance.NONE){ + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON_TEXT || widget.get_active() === Constants.MenuButtonAppearance.TEXT_ICON || + widget.get_active() === Constants.MenuButtonAppearance.TEXT){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + menuButtonAppearanceFrame.show(); + } + this._settings.set_enum('menu-button-appearance', widget.get_active()); + }); + + menuButtonAppearanceRow.add(menuButtonAppearanceLabel); + menuButtonAppearanceRow.add(menuButtonAppearanceCombo); + menuButtonAppearanceFrame.add(menuButtonAppearanceRow); + + let menuButtonArrowIconBoxRow = new PW.FrameBoxRow(); + let menuButtonArrowIconLabel = new Gtk.Label({ + label: _('Show Arrow'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let enableArrowIconSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableArrowIconSwitch.set_active(this._settings.get_boolean('enable-menu-button-arrow')); + enableArrowIconSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-menu-button-arrow', widget.get_active()); + this.resetButton.set_sensitive(true); + }); + + menuButtonArrowIconBoxRow.add(menuButtonArrowIconLabel); + menuButtonArrowIconBoxRow.add(enableArrowIconSwitch); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + + let menuButtonPaddingRow = new PW.FrameBoxRow(); + let menuButtonPadding = this._settings.get_int('button-padding'); + let menuButtonPaddingLabel = new Gtk.Label({ + label: _('Menu Button Padding'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let paddingScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, + upper: 25, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + paddingScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + paddingScale.add_mark(-1, Gtk.PositionType.TOP, _("Default")); + paddingScale.set_value(menuButtonPadding); + paddingScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('button-padding', paddingScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonPaddingRow.add(menuButtonPaddingLabel); + menuButtonPaddingRow.add(paddingScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + + ///// Row for menu button offset ///// + let menuButtonOffsetRow = new PW.FrameBoxRow(); + let menuButtonOffset = this._settings.get_int('menu-button-position-offset'); + let menuButtonOffsetLabel = new Gtk.Label({ + label: _('Menu Button Position'), + use_markup: true, + xalign: 0, + hexpand: true, + }); + let offsetScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 10, // arbitrary value + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + offsetScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); // offset 0 is default + offsetScale.add_mark(1, Gtk.PositionType.TOP, null); + offsetScale.add_mark(2, Gtk.PositionType.TOP, null); + offsetScale.set_value(menuButtonOffset); + offsetScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-position-offset', offsetScale.get_value()); + }); + menuButtonOffsetRow.add(menuButtonOffsetLabel); + menuButtonOffsetRow.add(offsetScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE && + (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP)) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + //////////////////// + + let menuButtonCustomTextBoxRow = new PW.FrameBoxRow(); + let menuButtonCustomTextLabel = new Gtk.Label({ + label: _('Text'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonCustomTextEntry = new Gtk.Entry({ halign: Gtk.Align.END }); + menuButtonCustomTextEntry.set_width_chars(30); + menuButtonCustomTextEntry.set_text(this._settings.get_string('custom-menu-button-text')); + menuButtonCustomTextEntry.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + let customMenuButtonText = widget.get_text(); + this._settings.set_string('custom-menu-button-text', customMenuButtonText); + }); + + menuButtonCustomTextBoxRow.add(menuButtonCustomTextLabel); + menuButtonCustomTextBoxRow.add(menuButtonCustomTextEntry); + if(this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.ICON && this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + vbox.append(menuButtonAppearanceFrame); + + let menuButtonIconHeaderLabel = new Gtk.Label({ + label: "" + _('Icon Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonIconHeaderLabel); + + let menuButtonIconFrame = new PW.FrameBox(); + let menuButtonIconRow = new PW.FrameBoxRow(); + let menuButtonIconLabel = new Gtk.Label({ + label: _('Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuButtonIconButton = new PW.Button({ + title: _("Browse Icons") + " ", + icon_name: 'icon-preview-symbolic', + hexpand: false, + }); + menuButtonIconButton.connect('clicked', () => { + let dialog = new ArcMenuIconsDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + dialog.destroy(); + }); + }); + + menuButtonIconRow.add(menuButtonIconLabel); + menuButtonIconRow.add(menuButtonIconButton); + menuButtonIconFrame.add(menuButtonIconRow); + + let menuButtonIconSizeRow = new PW.FrameBoxRow(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let menuButtonIconSizeLabel = new Gtk.Label({ + label: _('Icon Size'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonIconSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 14, + upper: 64, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonIconSizeScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonIconSizeScale.set_value(iconSize); + menuButtonIconSizeScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_double('custom-menu-button-icon-size', menuButtonIconSizeScale.get_value()); + }); + + menuButtonIconSizeRow.add(menuButtonIconSizeLabel); + menuButtonIconSizeRow.add(menuButtonIconSizeScale); + menuButtonIconFrame.add(menuButtonIconSizeRow); + + vbox.append(menuButtonIconFrame); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true, + valign: Gtk.Align.END, + vexpand: true + }); + + let menuButtonColorHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Styling') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonColorHeaderLabel); + + this.menuButtonIconColorFrame = new PW.FrameBox(); + + let[menuButtonColorSwitch, menuButtonColorChooser] = this.newColorChooserRow({ + color: this.menuButtonColor, + label: _("Color"), + settingColorName: 'menu-button-color', + settingOverrideName: 'override-menu-button-color', + }); + + let[menuButtonHoverColorSwitch, menuButtonHoverColorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverColor, + label: _("Hover Color"), + settingColorName: 'menu-button-hover-color', + settingOverrideName: 'override-menu-button-hover-color', + }); + + let[menuButtonActiveColorSwitch, menuButtonActiveColorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveColor, + label: _("Active Color"), + settingColorName: 'menu-button-active-color', + settingOverrideName: 'override-menu-button-active-color', + }); + + let[menuButtonHoverBackgroundcolorSwitch, menuButtonHoverBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverBackgroundcolor, + label: _("Hover Background Color"), + settingColorName: 'menu-button-hover-backgroundcolor', + settingOverrideName: 'override-menu-button-hover-background-color', + }); + + let[menuButtonActiveBackgroundcolorSwitch, menuButtonActiveBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveBackgroundcolor, + label: _("Active Background Color"), + settingColorName: 'menu-button-active-backgroundcolor', + settingOverrideName: 'override-menu-button-active-background-color', + }); + + let roundedCornersRow = new PW.FrameBoxRow(); + + let roundedCornersLabel = new Gtk.Label({ + label: _("Override Border Radius"), + xalign:0, + hexpand: true, + }); + let roundedCornersSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean('menu-button-override-border-radius') + }); + roundedCornersSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean('menu-button-override-border-radius', widget.get_active()) + this._settings.set_boolean('reload-theme', true); + menuButtonBorderRadiusRow.set_sensitive(widget.get_active()); + }); + + roundedCornersRow.add(roundedCornersLabel); + roundedCornersRow.add(roundedCornersSwitch); + + this.menuButtonIconColorFrame.add(roundedCornersRow); + + let menuButtonBorderRadiusRow = new PW.FrameBoxRow(); + let borderRadius = this._settings.get_int('menu-button-border-radius'); + let menuButtonBorderRadiusLabel = new Gtk.Label({ + label: _('Border Radius'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonBorderRadiusScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 20, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonBorderRadiusScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonBorderRadiusScale.set_value(borderRadius); + menuButtonBorderRadiusScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-border-radius', menuButtonBorderRadiusScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusLabel); + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusScale); + menuButtonBorderRadiusRow.set_sensitive(this._settings.get_boolean('menu-button-override-border-radius')); + this.menuButtonIconColorFrame.add(menuButtonBorderRadiusRow); + + vbox.append(this.menuButtonIconColorFrame); + + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + menuButtonAppearanceCombo.set_active(0); + menuButtonCustomTextEntry.set_text('Applications'); + paddingScale.set_value(-1); + menuButtonIconSizeScale.set_value(20); + let colorParse = new Gdk.RGBA(); + colorParse.parse('rgb(240,240,240)'); + menuButtonActiveColorChooser.set_rgba(colorParse); + menuButtonColorChooser.set_rgba(colorParse); + colorParse.parse('rgb(214,214,214)'); + menuButtonHoverColorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.1)'); + menuButtonHoverBackgroundcolorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.18)'); + menuButtonActiveBackgroundcolorChooser.set_rgba(colorParse); + enableArrowIconSwitch.set_active(false); + menuButtonColorSwitch.set_active(false); + menuButtonHoverColorSwitch.set_active(false); + menuButtonActiveColorSwitch.set_active(false); + menuButtonHoverBackgroundcolorSwitch.set_active(false); + menuButtonActiveBackgroundcolorSwitch.set_active(false); + roundedCornersSwitch.set_active(false); + menuButtonBorderRadiusScale.set_value(0); + offsetScale.set_value(0); + this._settings.reset('menu-button-icon'); + this._settings.reset('arc-menu-icon'); + this._settings.reset('distro-icon'); + this._settings.reset('custom-menu-button-icon'); + this._settings.reset('menu-button-hover-color'); + this._settings.reset('menu-button-active-color'); + this._settings.reset('menu-button-hover-backgroundcolor'); + this._settings.reset('menu-button-active-backgroundcolor'); + this._settings.reset('menu-button-color'); + this._settings.reset('override-menu-button-hover-color'); + this._settings.reset('override-menu-button-active-color'); + this._settings.reset('override-menu-button-hover-background-color'); + this._settings.reset('override-menu-button-active-background-color'); + this._settings.reset('override-menu-button-color'); + this._settings.reset('menu-button-override-border-radius'); + this._settings.reset('menu-button-border-radius'); + this._settings.reset('menu-button-position-offset'); + this._settings.set_boolean('reload-theme', true); + + this.resetButton.set_sensitive(false); + }); + vbox.append(this.resetButton); + } + + newColorChooserRow(params){ + let colorParse = new Gdk.RGBA(); + let colorRow = new PW.FrameBoxRow(); + let buttonsGrid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + + let colorLabel = new Gtk.Label({ + label: params.label, + xalign:0, + hexpand: true, + }); + let colorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean(params.settingOverrideName) + }); + colorSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean(params.settingOverrideName, widget.get_active()) + colorChooser.sensitive = widget.get_active(); + this._settings.set_boolean('reload-theme', true); + }); + + let colorChooser = new Gtk.ColorButton({ + use_alpha: true, + sensitive: colorSwitch.get_active() + }); + + colorParse.parse(params.color); + colorChooser.set_rgba(colorParse); + + colorChooser.connect('color-set', ()=>{ + this.resetButton.set_sensitive(true); + params.color = colorChooser.get_rgba().to_string(); + this._settings.set_string(params.settingColorName, params.color); + this._settings.set_boolean('reload-theme', true); + }); + + colorRow.add(colorLabel); + buttonsGrid.attach(colorSwitch, 0, 0, 1, 1); + buttonsGrid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 1, 0, 1, 1); + buttonsGrid.attach(colorChooser, 2, 0, 1, 1); + colorRow.add(buttonsGrid); + this.menuButtonIconColorFrame.add(colorRow); + return [colorSwitch, colorChooser]; + } + + checkIfResetButtonSensitive(){ + if( this._settings.get_string('menu-button-hover-backgroundcolor') != 'rgba(238,238,236,0.1)' || + this._settings.get_string('menu-button-active-backgroundcolor') != 'rgba(238,238,236,0.18)' || + this._settings.get_string('menu-button-active-color') != 'rgb(240,240,240)' || + this._settings.get_string('menu-button-hover-color') != 'rgb(214,214,214)' || + this._settings.get_string('menu-button-color') != 'rgb(240,240,240)' || + this._settings.get_double('custom-menu-button-icon-size') != 20 || + this._settings.get_int('button-padding') != -1 || + this._settings.get_enum('menu-button-icon') != 0 || + this._settings.get_int('arc-menu-icon') != 0 || + this._settings.get_string('custom-menu-button-text') != 'Applications' || + this._settings.get_enum('menu-button-appearance') != 0 || + this._settings.get_boolean('enable-menu-button-arrow') || + this._settings.get_boolean('override-menu-button-color') || + this._settings.get_boolean('override-menu-button-hover-color') || + this._settings.get_boolean('override-menu-button-active-color') || + this._settings.get_boolean('override-menu-button-hover-background-color') || + this._settings.get_boolean('override-menu-button-active-background-color') || + this._settings.get_boolean('menu-button-override-border-radius') || + this._settings.get_int('menu-button-border-radius') != 0 || + this._settings.get_int('menu-button-position-offset') != 0 ) + return true; + else + return false; + } +}); + +var ArcMenuIconsDialogWindow = GObject.registerClass( + class Arc_Menu_ArcMenuIconsDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + super._init(_('ArcMenu Icons'), parent); + this.set_default_size(550, 400); + } + + _createLayout(vbox){ + this.stack = new Gtk.Stack({ + halign: Gtk.Align.FILL, + hexpand: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let arcMenuIconsBox = new Gtk.ScrolledWindow(); + + let arcMenuIconsFlowBox = new PW.IconGrid(); + arcMenuIconsFlowBox.connect('child-activated', ()=> { + distroIconsBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = arcMenuIconsFlowBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.ARC_MENU); + this._settings.set_int('arc-menu-icon', selectedChildIndex); + }); + arcMenuIconsBox.set_child(arcMenuIconsFlowBox); + Constants.MenuIcons.forEach((icon)=>{ + let iconName = icon.PATH.replace("/media/icons/menu_button_icons/icons/", ''); + iconName = iconName.replace(".svg", ''); + let iconImage = new Gtk.Image({ + icon_name: iconName, + pixel_size: 36 + }); + arcMenuIconsFlowBox.add(iconImage); + }); + + let distroIconsBox = new PW.IconGrid(); + distroIconsBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = distroIconsBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.DISTRO_ICON); + this._settings.set_int('distro-icon', selectedChildIndex); + }); + Constants.DistroIcons.forEach((icon)=>{ + let iconImage; + if(icon.PATH === 'start-here-symbolic'){ + iconImage = new Gtk.Image({ + icon_name: 'start-here-symbolic', + pixel_size: 36 + }); + } + else{ + let iconName1 = icon.PATH.replace("/media/icons/menu_button_icons/distro_icons/", ''); + iconName1 = iconName1.replace(".svg", ''); + iconImage = new Gtk.Image({ + icon_name: iconName1, + pixel_size: 36 + }); + } + distroIconsBox.add(iconImage); + }); + + let customIconBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + let customIconFlowBox = new PW.IconGrid(); + customIconFlowBox.vexpand = false; + customIconFlowBox.homogeneous = false; + customIconFlowBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + let customIconPath = this._settings.get_string('custom-menu-button-icon'); + this._settings.set_string('custom-menu-button-icon', customIconPath) + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + }); + customIconBox.append(customIconFlowBox); + let customIconImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(this._settings.get_string('custom-menu-button-icon')), + pixel_size: 36 + }); + customIconFlowBox.add(customIconImage); + + let fileChooserFrame = new PW.FrameBox(); + fileChooserFrame.margin_top = 20; + fileChooserFrame.margin_bottom = 20; + fileChooserFrame.margin_start = 20; + fileChooserFrame.margin_end = 20; + let fileChooserRow = new PW.FrameBoxRow(); + let fileChooserLabel = new Gtk.Label({ + label: _('Browse for a Custom Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Select an Icon') + }); + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + + if(dialog.get_parent()) + dialog.unparent(); + dialog.set_filter(fileFilter); + + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + customIconImage.gicon = Gio.icon_new_for_string(dialog.get_file().get_path()); + this._settings.set_string('custom-menu-button-icon', dialog.get_file().get_path()); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + dialog.destroy(); + } + else + dialog.destroy(); + }) + + dialog.show(); + }); + + fileChooserRow.add(fileChooserLabel); + fileChooserRow.add(fileChooserButton); + fileChooserFrame.add(fileChooserRow); + customIconBox.append(fileChooserFrame); + + this.stack.add_titled(arcMenuIconsBox, 'ArcMenu Icons', _('ArcMenu Icons')); + this.stack.add_titled(distroIconsBox, 'Distro Icons', _('Distro Icons')); + this.stack.add_titled(customIconBox, 'Custom Icon', _('Custom Icon')); + + let stackSwitcher = new Gtk.StackSwitcher({ + stack: this.stack, + halign: Gtk.Align.CENTER + }); + + vbox.append(stackSwitcher); + vbox.append(this.stack); + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU){ + let children = arcMenuIconsFlowBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('arc-menu-icon')){ + arcMenuIconsFlowBox.select_child(arcMenuIconsFlowBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON){ + let children = distroIconsBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('distro-icon')){ + distroIconsBox.select_child(distroIconsBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM){ + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + } + + let distroInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + distroInfoButton.halign = Gtk.Align.START; + distroInfoButton.connect('clicked', ()=> { + let dialog = new DistroIconsDisclaimerWindow(this._settings, this); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + vbox.append(distroInfoButton); + } + + setVisibleChild(){ + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + } +}); + +var DistroIconsDisclaimerWindow = GObject.registerClass( + class Arc_Menu_DistroIconsDisclaimerWindow extends Gtk.MessageDialog { + _init(settings, parent) { + this._settings = settings; + super._init({ + text: "" + _("Legal disclaimer for Distro Icons...") + "", + use_markup: true, + message_type: Gtk.MessageType.OTHER, + transient_for: parent.get_root(), + modal: true, + buttons: Gtk.ButtonsType.OK + }); + + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + }); + this.get_content_area().append(vbox); + this._createLayout(vbox); + } + + _createLayout(vbox) { + let scrollWindow = new Gtk.ScrolledWindow({ + min_content_width: 500, + max_content_width: 500, + min_content_height: 400, + max_content_height: 400, + hexpand: false, + halign: Gtk.Align.START, + }); + scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + let frame = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + halign: Gtk.Align.START + }); + + let bodyLabel = new Gtk.Label({ + label: Constants.DistroIconsDisclaimer, + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true + }); + bodyLabel.set_size_request(500,-1); + + frame.append(bodyLabel); + scrollWindow.set_child(frame); + vbox.append(scrollWindow); + } +}); + +var MenuLayoutPage = GObject.registerClass( + class Arc_Menu_MenuLayoutPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + this._settings = settings; + + this.scrollBox = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_child(this.mainBox); + + let currentLayoutLabel = new Gtk.Label({ + label: "" + _("Current Menu Layout") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("Available Menu Layouts") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(currentLayoutLabel); + + let currentLayoutFrame = new PW.FrameBox(); + + let currentLayoutBoxLabel = new Gtk.Label({ + label: "" + this.getMenuLayoutName(this._settings.get_enum('menu-layout')) + "", + use_markup: true, + hexpand: true, + vexpand: true, + halign: Gtk.Align.CENTER, + valign: Gtk.Align.CENTER + }); + let currentLayoutBoxRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + currentLayoutBoxRow.activatable = true; + currentLayoutBoxRow._grid.row_spacing = 0; + currentLayoutBoxRow._grid.column_spacing = 0; + + let goNextImage = new Gtk.Image({ + icon_name: 'go-next-symbolic', + halign: Gtk.Align.END + }); + + currentLayoutFrame._listBox.connect('row-activated', () => { + this.displayLayoutTweaksPage(); + }); + + this.layoutsTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout'))); + this.layoutsTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + + let currentLayoutImagePath = this.getMenuLayoutImagePath(this._settings.get_enum('menu-layout')); + + let currentLayoutImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(currentLayoutImagePath), + pixel_size: 155, + hexpand: false, + halign: Gtk.Align.START, + valign: Gtk.Align.CENTER, + }); + let tweaksLabel = new Gtk.Label({ + label: this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')), + use_markup: true, + halign: Gtk.Align.END, + vexpand: true, + hexpand: true + }); + currentLayoutBoxRow._grid.attach(currentLayoutImage, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(currentLayoutBoxLabel, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(goNextImage, 0, 0, 1, 1); + currentLayoutFrame.add(currentLayoutBoxRow); + + this.mainBox.append(currentLayoutFrame); + this.mainBox.append(chooseNewLayoutLabel); + + this.stack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + this.layoutTilesBox = new Gtk.Grid({ + column_homogeneous: true, + column_spacing: 14, + row_spacing: 6, + hexpand: true, + halign: Gtk.Align.FILL, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.mainBox.append(this.layoutTilesBox); + this.stack.add_named(this.scrollBox, "LayoutsBox"); + this.stack.add_named(this.layoutsTweaksPage, "LayoutsTweaks") + let gridY = 0; + Constants.MenuStyles.STYLES.forEach((style) => { + let tile = new PW.LayoutTile(style.TITLE, style.IMAGE, style); + this.layoutTilesBox.attach(tile, 0, gridY, 1, 1); + let menuLayoutsBox = new MenuLayoutCategoryPage(this._settings, this, tile, style.TITLE); + gridY++; + menuLayoutsBox.connect('menu-layout-response', (dialog, response) => { + if(response === -10) { + this._settings.set_enum('menu-layout', dialog.index); + this._settings.set_boolean('reload-theme', true); + currentLayoutBoxLabel.label = "" + this.getMenuLayoutName(dialog.index) + ""; + tweaksLabel.label = this.getMenuLayoutTweaksName(dialog.index); + currentLayoutImage.gicon = Gio.icon_new_for_string(this.getMenuLayoutImagePath(dialog.index)); + this.stack.set_visible_child_name("LayoutsBox"); + this.scrollBox.vadjustment.set_value(this.scrollBox.vadjustment.get_lower()); + } + if(response === -20){ + this.stack.set_visible_child_name("LayoutsBox"); + } + }); + this.stack.add_named(menuLayoutsBox, "Layout_" + style.TITLE); + tile._listBox.connect('row-activated', ()=> { + this.stack.set_visible_child_name("Layout_" + style.TITLE); + menuLayoutsBox.enableSelectionMode(); + }); + }); + + this.append(this.stack); + } + + displayLayoutTweaksPage(){ + let layoutName = this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')); + this.layoutsTweaksPage.setActiveLayout(this._settings.get_enum('menu-layout'), layoutName); + this.stack.set_visible_child_name("LayoutsTweaks"); + } + + displayRunnerTweaksPage(){ + if(!this.runnerTweaksPage){ + let activeLayoutName = this.getMenuLayoutTweaksName(Constants.MenuLayout.RUNNER); + this.runnerTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, activeLayoutName); + this.stack.add_named(this.runnerTweaksPage, "RunnerTweaks") + this.runnerTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + this.runnerTweaksPage.setActiveLayout(Constants.MenuLayout.RUNNER); + } + this.stack.set_visible_child_name("RunnerTweaks"); + } + + getMenuLayoutName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _(style.TITLE); + } + } + } + } + + getMenuLayoutTweaksName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _("%s Layout Tweaks", style.TITLE).format(style.TITLE); + } + } + } + } + + getMenuLayoutImagePath(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return style.IMAGE; + } + } + } + } + +}); + +var MenuThemePage = GObject.registerClass( + class Arc_Menu_MenuThemePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.checkIfPresetMatch(); + + let overrideArcMenuHeaderLabel = new Gtk.Label({ + label: "" + _('Enable Custom Menu Theme') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(overrideArcMenuHeaderLabel); + + let overrideArcMenuFrame = new PW.FrameBox(); + let overrideArcMenuRow = new PW.FrameBoxRow(); + let overrideArcMenuLabel = new Gtk.Label({ + label: _("Override Menu Theme"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let overrideArcMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + overrideArcMenuSwitch.set_active(this._settings.get_boolean('enable-custom-arc-menu')); + overrideArcMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-custom-arc-menu',widget.get_active()); + this._settings.set_boolean('reload-theme', true); + if(widget.get_active()){ + this.mainBox.append(this.menuThemeCustomizationBox); + this.menuThemeCustomizationBox.show(); + this.append(this.buttonRow); + this.buttonRow.show(); + } + else{ + this.mainBox.remove(this.menuThemeCustomizationBox); + this.remove(this.buttonRow); + } + this.mainBox.show(); + }); + + this.menuThemeCustomizationBox = new OverrideArcMenuThemeWindow(this._settings, this.mainBox, this); + this.menuThemeCustomizationBox.connect('menu-theme-response', (dialog, response) => { + if(response === -10) { + this._settings.set_string('separator-color', dialog.separatorColor); + this._settings.set_boolean('vert-separator', dialog.verticalSeparator); + this._settings.set_string('menu-color', dialog.menuColor); + this._settings.set_string('menu-foreground-color', dialog.menuForegroundColor); + this._settings.set_string('border-color', dialog.borderColor); + this._settings.set_string('highlight-color', dialog.highlightColor ); + this._settings.set_string('highlight-foreground-color', dialog.highlightForegroundColor); + this._settings.set_int('menu-font-size', dialog.fontSize); + this._settings.set_int('menu-border-size', dialog.borderSize); + this._settings.set_int('menu-corner-radius', dialog.cornerRadius); + this._settings.set_int('menu-margin', dialog.menuMargin); + this._settings.set_int('menu-arrow-size', dialog.menuArrowSize); + this._settings.set_boolean('reload-theme', true); + this.presetName = dialog.presetName; + } + else{ + this.checkIfPresetMatch(); + } + }); + + overrideArcMenuRow.add(overrideArcMenuLabel); + overrideArcMenuRow.add(overrideArcMenuSwitch); + overrideArcMenuFrame.add(overrideArcMenuRow); + + this.mainBox.append(overrideArcMenuFrame); + if(overrideArcMenuSwitch.get_active()) + this.mainBox.append(this.menuThemeCustomizationBox); + else + this.remove(this.buttonRow); + } + + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < all_color_themes.length; i++){ + this.isEqual = true; + for(let l = 0; l < this.currentSettingsArray.length; l++){ + if(this.currentSettingsArray[l] !== all_color_themes[i][l + 1]){ + this.isEqual=false; + break; + } + } + if(this.isEqual){ + this.presetName = all_color_themes[i][0]; + break; + } + } + } +}); + +var MenuLayoutCategoryPage = GObject.registerClass({ + Signals: { + 'menu-layout-response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_MenuLayoutCategoryPage extends Gtk.ScrolledWindow { + _init(settings, parent, tile, title) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this.title = title; + this._parent = parent; + this._settings = settings; + this.index = this._settings.get_enum('menu-layout'); + this.layoutStyle = tile.layout; + + this._params = { + maxColumns: tile.layout.length > 3 ? 3 : tile.layout.length, + imageHeight: 155, + imageWidth: 155, + styles: tile.layout + }; + let layoutsFrame = new PW.FrameBox(); + let layoutsRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false, + }) + layoutsRow._grid.orientation = Gtk.Orientation.VERTICAL; + layoutsFrame.add(layoutsRow); + let buttonBox = new Gtk.Box({ + spacing: 10 + }); + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: false, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + let selectedBox = this._tileGrid.get_selected_children(); + this.index = selectedBox[0].get_child().layout; + this._tileGrid.unselect_all(); + applyButton.set_sensitive(false); + this.emit('menu-layout-response', -10); + }); + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + halign: Gtk.Align.START + }); + backButton.connect('clicked', ()=> { + this.emit('menu-layout-response', -20); + }); + buttonBox.append(backButton); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", this.title).format(this.title) + "", + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + buttonBox.append(chooseNewLayoutLabel); + buttonBox.append(applyButton); + applyButton.set_sensitive(false); + + this.mainBox.append(buttonBox); + this.mainBox.append(layoutsFrame); + this._tileGrid = new PW.TileGrid(this._params.maxColumns); + + this._params.styles.forEach((style) => { + this._addTile(style.TITLE, style.IMAGE, style.LAYOUT); + }); + + layoutsRow.add(this._tileGrid); + + this._tileGrid.connect('selected-children-changed', () => { + applyButton.set_sensitive(true); + }); + + this._tileGrid.set_selection_mode(Gtk.SelectionMode.NONE); + } + + + enableSelectionMode(){ + this._tileGrid.set_selection_mode(Gtk.SelectionMode.SINGLE); + } + + _addTile(name, image, layout) { + let tile = new PW.Tile(name, image, this._params.imageWidth, this._params.imageHeight, layout); + this._tileGrid.insert(tile, -1); + } +}); + +var MenuSettingsGeneralPage = GObject.registerClass( + class Arc_Menu_MenuSettingsGeneralPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.heightValue = this._settings.get_int('menu-height'); + this.widthValue = this._settings.get_int('menu-width-adjustment'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.menuWidth = this._settings.get_int('menu-width'); + this.forcedMenuLocation = this._settings.get_enum('force-menu-location'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.appDescriptions = this._settings.get_boolean('apps-show-extra-details'); + this.categoryIconType = this._settings.get_enum('category-icon-type'); + this.shortcutsIconType = this._settings.get_enum('shortcut-icon-type'); + + let menuSizeFrame = new PW.FrameBox(); + //find the greatest screen height of all monitors + //use that value to set Menu Height cap + let display = Gdk.Display.get_default(); + let monitors = display.get_monitors(); + let nMonitors = monitors.get_n_items(); + let greatestHeight = 0; + let scaleFactor = 1; + for (let i = 0; i < nMonitors; i++) { + let monitor = monitors.get_item(i); + let monitorHeight = monitor.get_geometry().height; + if(monitorHeight > greatestHeight){ + scaleFactor = monitor.get_scale_factor(); + greatestHeight = monitorHeight; + } + } + let monitorHeight = greatestHeight * scaleFactor; + monitorHeight = Math.round((monitorHeight * 8) / 10); + + let menuSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuSizeHeaderLabel); + + this.mainBox.append(menuSizeFrame); + let heightRow = new PW.FrameBoxRow(); + let heightLabel = new Gtk.Label({ + label: _('Height'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let hscale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: monitorHeight, + step_increment: 10, + page_increment: 10, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + hscale.set_value(this.heightValue); + hscale.connect('value-changed', () => { + this.heightValue = hscale.get_value(); + if(hSpinButton.value !== this.heightValue) + hSpinButton.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let hSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: monitorHeight, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + hSpinButton.set_value(this.heightValue); + hSpinButton.connect('value-changed', () => { + this.heightValue = hSpinButton.get_value(); + if(hscale.value !== this.heightValue) + hscale.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + heightRow.add(heightLabel); + heightRow.add(hscale); + heightRow.add(hSpinButton); + menuSizeFrame.add(heightRow); + + let menuWidthTwoPanelsHeaderRow = new PW.FrameBoxRow(); + let menuWidthTwoPanelsHeaderLabel = new Gtk.Label({ + label: _("Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + menuWidthTwoPanelsHeaderRow.add(menuWidthTwoPanelsHeaderLabel) + menuSizeFrame.add(menuWidthTwoPanelsHeaderRow); + + let menuWidthRow = new PW.FrameBoxRow(); + menuWidthRow._grid.margin_start = 25; + let menuWidthLabel = new Gtk.Label({ + label: _('Left-Panel'), + xalign:0, + hexpand: false, + }); + let menuWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuWidthScale.set_value(this.menuWidth); + menuWidthScale.connect('value-changed', () => { + this.menuWidth = menuWidthScale.get_value(); + if(menuWidthSpinButton.value !== this.menuWidth) + menuWidthSpinButton.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let menuWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + menuWidthSpinButton.set_value(this.menuWidth); + menuWidthSpinButton.connect('value-changed', () => { + this.menuWidth = menuWidthSpinButton.get_value(); + if(menuWidthScale.value !== this.menuWidth) + menuWidthScale.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + menuWidthRow.add(menuWidthLabel); + menuWidthRow.add(menuWidthScale); + menuWidthRow.add( menuWidthSpinButton); + menuSizeFrame.add(menuWidthRow); + + let rightPanelWidthRow = new PW.FrameBoxRow(); + rightPanelWidthRow._grid.margin_start = 25; + let rightPanelWidthLabel = new Gtk.Label({ + label: _('Right-Panel'), + xalign:0, + hexpand: false, + }); + let rightPanelWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + rightPanelWidthScale.set_value(this.rightPanelWidth); + rightPanelWidthScale.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthScale.get_value(); + if(rightPanelWidthSpinButton.value !== this.rightPanelWidth) + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let rightPanelWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + rightPanelWidthSpinButton.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthSpinButton.get_value(); + if(rightPanelWidthScale.value !== this.rightPanelWidth) + rightPanelWidthScale.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + rightPanelWidthRow.add(rightPanelWidthLabel); + rightPanelWidthRow.add(rightPanelWidthScale); + rightPanelWidthRow.add(rightPanelWidthSpinButton); + menuSizeFrame.add(rightPanelWidthRow); + + let otherWidthHeaderRow = new PW.FrameBoxRow(); + let otherWidthHeaderLabel = new Gtk.Label({ + label: _("Non-Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + otherWidthHeaderRow.add(otherWidthHeaderLabel) + menuSizeFrame.add(otherWidthHeaderRow); + + let widthRow = new PW.FrameBoxRow(); + widthRow._grid.margin_start = 25; + let widthLabel = new Gtk.Label({ + label: _('Width Offset'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let widthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -350, + upper: 600, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + widthScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Default")); + widthScale.set_value(this.widthValue); + widthScale.connect('value-changed', (widget) => { + this.widthValue = widget.get_value(); + if(widthSpinButton.value !== this.widthValue) + widthSpinButton.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let widthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: -350, upper: 600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + valign: Gtk.Align.START + }); + widthSpinButton.set_value(this.widthValue); + widthSpinButton.connect('value-changed', () => { + this.widthValue = widthSpinButton.get_value(); + if(widthScale.value !== this.widthValue) + widthScale.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + widthRow.add(widthLabel); + widthRow.add(widthScale); + widthRow.add(widthSpinButton); + menuSizeFrame.add(widthRow); + + let iconsSizeFrame = new PW.FrameBox(); + let menuItemSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Items Icon Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuItemSizeHeaderLabel); + + let gridIconsSizeRow = new PW.FrameBoxRow(); + let gridIconsSizeLabel = new Gtk.Label({ + label: _("Grid Icons"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.gridIconsSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + this.gridIconsSizeCombo.append("Default", _("Default")); + this.gridIconsSizeCombo.append("Small", _("Small") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Medium", _("Medium") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Large", _("Large") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Small Rect", _("Small") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Medium Rect", _("Medium") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Large Rect", _("Large") + " - " + _("Wide")); + this.gridIconsSizeCombo.set_active(this._settings.get_enum('menu-item-grid-icon-size')); + this.gridIconsSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + gridIconsSizeRow.add(gridIconsSizeLabel); + gridIconsSizeRow.add(this.gridIconsSizeCombo); + iconsSizeFrame.add(gridIconsSizeRow); + + [this.menuItemIconSizeCombo, this.menuItemIconSizeRow] = this.createIconSizeRow(_("Categories & Applications"), this._settings.get_enum('menu-item-icon-size')); + iconsSizeFrame.add(this.menuItemIconSizeRow); + [this.buttonIconSizeCombo, this.buttonIconSizeRow] = this.createIconSizeRow(_("Buttons"), this._settings.get_enum('button-item-icon-size')); + iconsSizeFrame.add(this.buttonIconSizeRow); + [this.quicklinksIconSizeCombo, this.quicklinksIconSizeRow] = this.createIconSizeRow(_("Quick Links"), this._settings.get_enum('quicklinks-item-icon-size')); + iconsSizeFrame.add(this.quicklinksIconSizeRow); + [this.miscIconSizeCombo, this.miscIconSizeRow] = this.createIconSizeRow(_("Misc"), this._settings.get_enum('misc-item-icon-size')); + iconsSizeFrame.add(this.miscIconSizeRow); + + this.mainBox.append(iconsSizeFrame); + + let generalHeaderLabel = new Gtk.Label({ + label: "" + _("General Settings") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(generalHeaderLabel); + + let generalSettingsFrame = new PW.FrameBox(); + let menuLocationRow = new PW.FrameBoxRow(); + let menuLocationLabel = new Gtk.Label({ + label: _('Override Menu Location'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let menuLocationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + menuLocationCombo.append_text(_("Off")); + menuLocationCombo.append_text(_("Top Centered")); + menuLocationCombo.append_text(_("Bottom Centered")); + menuLocationCombo.set_active(this._settings.get_enum('force-menu-location')); + menuLocationCombo.connect('changed', (widget) => { + this.forcedMenuLocation = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + menuLocationRow.add(menuLocationLabel); + menuLocationRow.add(menuLocationCombo); + generalSettingsFrame.add(menuLocationRow); + this.mainBox.append(generalSettingsFrame); + + let appDescriptionsRow = new PW.FrameBoxRow(); + let appDescriptionsLabel = new Gtk.Label({ + label: _("Show Application Descriptions"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appDescriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appDescriptionsSwitch.set_active(this.appDescriptions); + appDescriptionsSwitch.connect('notify::active', (widget) => { + this.appDescriptions = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appDescriptionsRow.add(appDescriptionsLabel); + appDescriptionsRow.add(appDescriptionsSwitch); + generalSettingsFrame.add(appDescriptionsRow); + + let categoryIconTypeRow = new PW.FrameBoxRow(); + let categoryIconTypeLabel = new Gtk.Label({ + label: _('Category Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let categoryIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + categoryIconTypeCombo.append_text(_("Full Color")); + categoryIconTypeCombo.append_text(_("Symbolic")); + categoryIconTypeCombo.set_active(this.categoryIconType); + categoryIconTypeCombo.connect('changed', (widget) => { + this.categoryIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + categoryIconTypeRow.add(categoryIconTypeLabel); + categoryIconTypeRow.add(categoryIconTypeCombo); + generalSettingsFrame.add(categoryIconTypeRow); + + let shortcutsIconTypeRow = new PW.FrameBoxRow(); + let shortcutsIconTypeLabel = new Gtk.Label({ + label: _('Shortcuts Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let shortcutsIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + shortcutsIconTypeCombo.append_text(_("Full Color")); + shortcutsIconTypeCombo.append_text(_("Symbolic")); + shortcutsIconTypeCombo.set_active(this.shortcutsIconType); + shortcutsIconTypeCombo.connect('changed', (widget) => { + this.shortcutsIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + shortcutsIconTypeRow.add(shortcutsIconTypeLabel); + shortcutsIconTypeRow.add(shortcutsIconTypeCombo); + generalSettingsFrame.add(shortcutsIconTypeRow); + + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + generalSettingsFrame.add(vertSeparatorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.heightValue = this._settings.get_default_value('menu-height').unpack(); + this.widthValue = this._settings.get_default_value('menu-width-adjustment').unpack(); + this.rightPanelWidth = this._settings.get_default_value('right-panel-width').unpack(); + this.menuWidth = this._settings.get_default_value('menu-width').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.appDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this.categoryIconType = 0; + this.shortcutsIconType = 1; + this.forcedMenuLocation = 0; + hscale.set_value(this.heightValue); + widthScale.set_value(this.widthValue); + menuWidthScale.set_value(this.menuWidth); + rightPanelWidthScale.set_value(this.rightPanelWidth); + vertSeparatorSwitch.set_active(this.verticalSeparator); + this.gridIconsSizeCombo.set_active(0); + this.menuItemIconSizeCombo.set_active(0); + this.buttonIconSizeCombo.set_active(0); + this.quicklinksIconSizeCombo.set_active(0); + this.miscIconSizeCombo.set_active(0); + appDescriptionsSwitch.set_active(this.appDescriptions); + menuLocationCombo.set_active(this.forcedMenuLocation); + categoryIconTypeCombo.set_active(0); + shortcutsIconTypeCombo.set_active(1); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('menu-height', this.heightValue); + this._settings.set_int('menu-width-adjustment', this.widthValue); + this._settings.set_int('right-panel-width', this.rightPanelWidth); + this._settings.set_int('menu-width', this.menuWidth); + this._settings.set_enum('force-menu-location', this.forcedMenuLocation); + this._settings.set_boolean('vert-separator', this.verticalSeparator); + this._settings.set_enum('menu-item-icon-size', this.menuItemIconSizeCombo.get_active()); + this._settings.set_enum('menu-item-grid-icon-size', this.gridIconsSizeCombo.get_active()); + this._settings.set_enum('button-item-icon-size', this.buttonIconSizeCombo.get_active()); + this._settings.set_enum('quicklinks-item-icon-size', this.quicklinksIconSizeCombo.get_active()); + this._settings.set_enum('misc-item-icon-size', this.miscIconSizeCombo.get_active()); + this._settings.set_boolean('reload-theme', true); + this._settings.set_boolean('apps-show-extra-details', this.appDescriptions); + this._settings.set_enum('category-icon-type', this.categoryIconType); + this._settings.set_enum('shortcut-icon-type', this.shortcutsIconType); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + createIconSizeRow(title, iconSizeEnum){ + let iconsSizeRow = new PW.FrameBoxRow(); + let iconsSizeLabel = new Gtk.Label({ + label: _(title), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + iconSizeCombo.append("Default", _("Default")); + iconSizeCombo.append("ExtraSmall", _("Extra Small")); + iconSizeCombo.append("Small", _("Small")); + iconSizeCombo.append("Medium", _("Medium")); + iconSizeCombo.append("Large", _("Large")); + iconSizeCombo.append("ExtraLarge", _("Extra Large")); + iconSizeCombo.set_active(iconSizeEnum); + iconSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + iconsSizeRow.add(iconsSizeLabel); + iconsSizeRow.add(iconSizeCombo); + return [iconSizeCombo, iconsSizeRow]; + } + + checkIfResetButtonSensitive(){ + return ( + this.heightValue !== this._settings.get_default_value('menu-height').unpack() || + this.widthValue !== this._settings.get_default_value('menu-width-adjustment').unpack() || + this.rightPanelWidth !== this._settings.get_default_value('right-panel-width').unpack() || + this.menuWidth !== this._settings.get_default_value('menu-width').unpack() || + this.forcedMenuLocation !== 0 || + this.verticalSeparator !== this._settings.get_default_value('vert-separator').unpack() || + this.gridIconsSizeCombo.get_active() !== 0 || + this.menuItemIconSizeCombo.get_active() !== 0 || + this.buttonIconSizeCombo.get_active() !== 0 || + this.quicklinksIconSizeCombo.get_active() !== 0 || + this.miscIconSizeCombo.get_active() !== 0 || + this.appDescriptions !== this._settings.get_default_value('apps-show-extra-details').unpack() || + this.categoryIconType !== 0 || + this.shortcutsIconType !== 1 ) ? true : false + } +}); + +var MenuSettingsFineTunePage = GObject.registerClass( + class Arc_Menu_MenuSettingsFineTunePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.gapAdjustment = this._settings.get_int('gap-adjustment'); + this.removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + this.disableSearchStyle = this._settings.get_boolean('disable-searchbox-border'); + this.alphabetizeAllPrograms = this._settings.get_boolean('alphabetize-all-programs') + this.multiLinedLabels = this._settings.get_boolean('multi-lined-labels'); + this.disableTooltips = this._settings.get_boolean('disable-tooltips'); + this.subMenus = this._settings.get_boolean('enable-sub-menus'); + this.showHiddenRecentFiles = this._settings.get_boolean('show-hidden-recent-files'); + + let searchStyleFrame = new PW.FrameBox(); + let searchStyleRow = new PW.FrameBoxRow(); + let searchStyleLabel = new Gtk.Label({ + label: _("Disable Searchbox Border"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let searchStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + searchStyleSwitch.set_active(this._settings.get_boolean('disable-searchbox-border')); + searchStyleSwitch.connect('notify::active', (widget) => { + this.disableSearchStyle = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + searchStyleRow.add(searchStyleLabel); + searchStyleRow.add(searchStyleSwitch); + searchStyleFrame.add(searchStyleRow); + this.mainBox.append(searchStyleFrame); + + let tweakStyleFrame = new PW.FrameBox(); + let tweakStyleRow = new PW.FrameBoxRow(); + let tweakStyleLabel = new Gtk.Label({ + label: _("Disable Menu Arrow"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let tweakStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tweakStyleSwitch.set_active(this._settings.get_boolean('remove-menu-arrow')); + tweakStyleSwitch.connect('notify::active', (widget) => { + this.removeMenuArrow = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tweakStyleRow.add(tweakStyleLabel); + tweakStyleRow.add(tweakStyleSwitch); + tweakStyleFrame.add(tweakStyleRow); + this.mainBox.append(tweakStyleFrame); + + let fadeEffectFrame = new PW.FrameBox(); + let fadeEffectRow = new PW.FrameBoxRow(); + let fadeEffectLabel = new Gtk.Label({ + label: _("Disable ScrollView Fade Effects"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fadeEffectSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + fadeEffectSwitch.set_active(this._settings.get_boolean('disable-scrollview-fade-effect')); + fadeEffectSwitch.connect('notify::active', (widget) => { + this.disableFadeEffect = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + fadeEffectRow.add(fadeEffectLabel); + fadeEffectRow.add(fadeEffectSwitch); + fadeEffectFrame.add(fadeEffectRow); + this.mainBox.append(fadeEffectFrame); + + let tooltipFrame = new PW.FrameBox(); + let tooltipRow = new PW.FrameBoxRow(); + let tooltipLabel = new Gtk.Label({ + label: _("Disable Tooltips"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let tooltipSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tooltipSwitch.set_active(this.disableTooltips); + tooltipSwitch.connect('notify::active', (widget) => { + this.disableTooltips = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tooltipRow.add(tooltipLabel); + tooltipRow.add(tooltipSwitch); + tooltipFrame.add(tooltipRow); + this.mainBox.append(tooltipFrame); + + let alphabetizeAllProgramsFrame = new PW.FrameBox(); + let alphabetizeAllProgramsRow = new PW.FrameBoxRow(); + let alphabetizeAllProgramsLabel = new Gtk.Label({ + label: _("Alphabetize 'All Programs' Category"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alphabetizeAllProgramsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + alphabetizeAllProgramsSwitch.set_active(this._settings.get_boolean('alphabetize-all-programs')); + alphabetizeAllProgramsSwitch.connect('notify::active', (widget) => { + this.alphabetizeAllPrograms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsLabel); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsSwitch); + alphabetizeAllProgramsFrame.add(alphabetizeAllProgramsRow); + this.mainBox.append(alphabetizeAllProgramsFrame); + + let subMenusFrame = new PW.FrameBox(); + let subMenusRow = new PW.FrameBoxRow(); + let subMenusLabel = new Gtk.Label({ + label: _('Category Sub Menus'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let subMenusSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + subMenusSwitch.set_active(this.subMenus); + subMenusSwitch.connect('notify::active', (widget) => { + this.subMenus = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + subMenusRow.add(subMenusLabel); + subMenusRow.add(subMenusSwitch); + subMenusFrame.add(subMenusRow); + this.mainBox.append(subMenusFrame); + + let hiddenFilesFrame = new PW.FrameBox(); + let hiddenFilesRow = new PW.FrameBoxRow(); + let hiddenFilesLabel = new Gtk.Label({ + label: _('Show Hidden Recent Files'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let hiddenFilesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + hiddenFilesSwitch.connect('notify::active', (widget) => { + this.showHiddenRecentFiles = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + hiddenFilesRow.add(hiddenFilesLabel); + hiddenFilesRow.add(hiddenFilesSwitch); + hiddenFilesFrame.add(hiddenFilesRow); + this.mainBox.append(hiddenFilesFrame); + + let multiLinedLabelFrame = new PW.FrameBox(); + let multiLinedLabelRow = new PW.FrameBoxRow(); + let multiLinedLabelLabel = new Gtk.Label({ + label: _("Multi-Lined Labels"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let multiLinedLabelSwitch = new Gtk.Switch({ halign: Gtk.Align.END, vexpand: false, valign: Gtk.Align.CENTER }); + multiLinedLabelSwitch.set_active(this._settings.get_boolean('multi-lined-labels')); + multiLinedLabelSwitch.connect('notify::active', (widget) => { + this.multiLinedLabels = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + let multiLinedLabelInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + multiLinedLabelInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Multi-Lined Labels"), + secondaryText: _('Enable/Disable multi-lined labels on large application icon layouts.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + multiLinedLabelRow.add(multiLinedLabelLabel); + multiLinedLabelRow.add(multiLinedLabelSwitch); + multiLinedLabelRow.add(multiLinedLabelInfoButton); + multiLinedLabelFrame.add(multiLinedLabelRow); + this.mainBox.append(multiLinedLabelFrame); + + let gapAdjustmentFrame = new PW.FrameBox(); + let gapAdjustmentRow = new PW.FrameBoxRow(); + let gapAdjustmentLabel = new Gtk.Label({ + label: _('Gap Adjustment'), + xalign:0, + hexpand: false, + }); + let gapAdjustmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, upper: 20, step_increment: 1, page_increment: 1, page_size: 0 + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT, + draw_value: true, + }); + gapAdjustmentScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + gapAdjustmentScale.set_value(this.gapAdjustment); + gapAdjustmentScale.connect('value-changed', () => { + this.gapAdjustment = gapAdjustmentScale.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let gapAdjustmentInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + gapAdjustmentInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Adjust the gap between the ArcMenu button and the menu."), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + gapAdjustmentRow.add(gapAdjustmentLabel); + gapAdjustmentRow.add(gapAdjustmentScale); + gapAdjustmentRow.add(gapAdjustmentInfoButton); + gapAdjustmentFrame.add(gapAdjustmentRow); + this.mainBox.append(gapAdjustmentFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.gapAdjustment = this._settings.get_default_value('gap-adjustment').unpack(); + this.removeMenuArrow = this._settings.get_default_value('remove-menu-arrow').unpack(); + this.disableSearchStyle = this._settings.get_default_value('disable-searchbox-border').unpack(); + this.alphabetizeAllPrograms = this._settings.get_default_value('alphabetize-all-programs').unpack(); + this.multiLinedLabels = this._settings.get_default_value('multi-lined-labels').unpack(); + this.subMenus = this._settings.get_default_value('enable-sub-menus').unpack(); + this.showHiddenRecentFiles = this._settings.get_default_value('show-hidden-recent-files').unpack(); + this.disableTooltips = this._settings.get_default_value('disable-tooltips').unpack(); + this.disableFadeEffect = this._settings.get_default_value('disable-scrollview-fade-effect').unpack(); + alphabetizeAllProgramsSwitch.set_active(this.alphabetizeAllPrograms); + gapAdjustmentScale.set_value(this.gapAdjustment); + searchStyleSwitch.set_active(this.disableSearchStyle); + tweakStyleSwitch.set_active(this.removeMenuArrow); + multiLinedLabelSwitch.set_active(this.multiLinedLabels); + tooltipSwitch.set_active(this.disableTooltips); + subMenusSwitch.set_active(this.subMenus); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + fadeEffectSwitch.set_active(this.disableFadeEffect); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('gap-adjustment', this.gapAdjustment); + this._settings.set_boolean('remove-menu-arrow', this.removeMenuArrow); + this._settings.set_boolean('disable-searchbox-border', this.disableSearchStyle); + this._settings.set_boolean('alphabetize-all-programs', this.alphabetizeAllPrograms); + this._settings.set_boolean('multi-lined-labels', this.multiLinedLabels); + this._settings.set_boolean('disable-scrollview-fade-effect', this.disableFadeEffect); + this._settings.set_boolean('disable-tooltips', this.disableTooltips); + this._settings.set_boolean('enable-sub-menus', this.subMenus); + this._settings.set_boolean('show-hidden-recent-files', this.showHiddenRecentFiles); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.subMenus !== this._settings.get_default_value('enable-sub-menus').unpack() || + this.disableTooltips !== this._settings.get_default_value('disable-tooltips').unpack() || + this.gapAdjustment !== this._settings.get_default_value('gap-adjustment').unpack() || + this.removeMenuArrow !== this._settings.get_default_value('remove-menu-arrow').unpack() || + this.disableSearchStyle !== this._settings.get_default_value('disable-searchbox-border').unpack()|| + this.alphabetizeAllPrograms !== this._settings.get_default_value('alphabetize-all-programs').unpack()|| + this.multiLinedLabels !== this._settings.get_default_value('multi-lined-labels').unpack() || + this.disableFadeEffect !== this._settings.get_default_value('disable-scrollview-fade-effect').unpack() || + this.showHiddenRecentFiles !== this._settings.get_default_value('show-hidden-recent-files').unpack()) ? true : false; + } +}); + +var MenuSettingsNewAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsNewAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableRecentApps = this._settings.get_boolean('disable-recently-installed-apps'); + this.indicatorColor = this._settings.get_string('indicator-color'); + this.indicatorTextColor = this._settings.get_string('indicator-text-color'); + + let recentAppsFrame = new PW.FrameBox(); + let recentAppsRow = new PW.FrameBoxRow(); + let recentAppsLabel = new Gtk.Label({ + label: _("Disable New Apps Tracker"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentAppsSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + + recentAppsSwitch.connect('notify::active', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + this.disableRecentApps = widget.get_active(); + + if(widget.get_active()){ + appIndicatorColorFrame.hide(); + recentlyInstalledInfoLabel.hide(); + clearRecentAppsFrame.hide(); + } + else{ + appIndicatorColorFrame.show(); + recentlyInstalledInfoLabel.show(); + clearRecentAppsFrame.show(); + this.mainBox.show(); + } + this._settings.set_boolean('disable-recently-installed-apps', widget.get_active()); + }); + + recentAppsSwitch.set_active(this._settings.get_boolean('disable-recently-installed-apps')); + + recentAppsRow.add(recentAppsLabel); + recentAppsRow.add(recentAppsSwitch); + recentAppsFrame.add(recentAppsRow); + this.mainBox.append(recentAppsFrame); + + let appIndicatorColorFrame = new PW.FrameBox(); + let recentlyInstalledInfoLabel = new Gtk.Label({ + label: "" + _("Customize New Apps Indicator") + "", + use_markup: true, + xalign: 0, + hexpand: true, + }); + this.mainBox.append(recentlyInstalledInfoLabel); + let appIndicatorColorRow = new PW.FrameBoxRow(); + let appIndicatorColorLabel = new Gtk.Label({ + label: _('Category Indicator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + appIndicatorColorChooser.connect('color-set', ()=>{ + this.indicatorColor = appIndicatorColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorColorRow.add(appIndicatorColorLabel); + appIndicatorColorRow.add(appIndicatorColorChooser); + appIndicatorColorFrame.add(appIndicatorColorRow); + + let appIndicatorTextColorRow = new PW.FrameBoxRow(); + let appIndicatorTextColorLabel = new Gtk.Label({ + label: _('App Indicator Label Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorTextColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + color = new Gdk.RGBA(); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + appIndicatorTextColorChooser.connect('color-set', ()=>{ + this.indicatorTextColor = appIndicatorTextColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorTextColorRow.add(appIndicatorTextColorLabel); + appIndicatorTextColorRow.add(appIndicatorTextColorChooser); + appIndicatorColorFrame.add(appIndicatorTextColorRow); + this.mainBox.append(appIndicatorColorFrame); + + let clearRecentAppsFrame = new PW.FrameBox(); + let clearRecentAppsRow = new PW.FrameBoxRow(); + let clearRecentAppsLabel = new Gtk.Label({ + label: _("Clear Apps Marked 'New'"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clearRecentAppsButton = new Gtk.Button({ + halign: Gtk.Align.END, + label: _("Clear All"), + }); + let sensitive = this._settings.get_strv('recently-installed-apps').length > 0; + clearRecentAppsButton.set_sensitive(sensitive); + clearRecentAppsButton.connect('clicked', (widget) => { + clearRecentAppsButton.set_sensitive(false); + this._settings.reset('recently-installed-apps'); + }); + clearRecentAppsRow.add(clearRecentAppsLabel); + clearRecentAppsRow.add(clearRecentAppsButton); + clearRecentAppsFrame.add(clearRecentAppsRow); + this.mainBox.append(clearRecentAppsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.disableRecentApps = this._settings.get_default_value('disable-recently-installed-apps').unpack(); + this.indicatorColor = this._settings.get_default_value('indicator-color').unpack(); + this.indicatorTextColor = this._settings.get_default_value('indicator-text-color').unpack(); + recentAppsSwitch.set_active(this.disableRecentApps); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('disable-recently-installed-apps', this.disableRecentApps); + this._settings.set_string('indicator-color', this.indicatorColor); + this._settings.set_string('indicator-text-color', this.indicatorTextColor); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.disableRecentApps !== this._settings.get_default_value('disable-recently-installed-apps').unpack() || + this.indicatorColor !== this._settings.get_default_value('indicator-color').unpack() || + this.indicatorTextColor !== this._settings.get_default_value('indicator-text-color').unpack() + ) ? true : false; + } +}); + +var MenuSettingsSearchOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsSearchOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.searchResultsDetails = this._settings.get_boolean('show-search-result-details'); + this.openWindowsSearchProvider = this._settings.get_boolean('search-provider-open-windows'); + this.recentFilesSearchProvider = this._settings.get_boolean('search-provider-recent-files'); + this.highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + this.maxSearchResults = this._settings.get_int('max-search-results'); + + let searchProvidersFrame = new PW.FrameBox(); + let searchProvidersLabel = new Gtk.Label({ + label: "" + _("Search Providers") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchProvidersLabel); + let openWindowsRow = new PW.FrameBoxRow(); + let openWindowsLabel = new Gtk.Label({ + label: _("Search for open windows across all workspaces"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let openWindowsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + openWindowsSwitch.connect('notify::active', (widget) => { + this.openWindowsSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + openWindowsRow.add(openWindowsLabel); + openWindowsRow.add(openWindowsSwitch); + searchProvidersFrame.add(openWindowsRow); + + let recentFilesRow = new PW.FrameBoxRow(); + let recentFilesLabel = new Gtk.Label({ + label: _("Search for recent files"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentFilesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + recentFilesSwitch.connect('notify::active', (widget) => { + this.recentFilesSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + recentFilesRow.add(recentFilesLabel); + recentFilesRow.add(recentFilesSwitch); + searchProvidersFrame.add(recentFilesRow); + this.mainBox.append(searchProvidersFrame); + + let searchOptionsFrame = new PW.FrameBox(); + let searchOptionsLabel = new Gtk.Label({ + label: "" + _("Search Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchOptionsLabel); + let descriptionsRow = new PW.FrameBoxRow(); + let descriptionsLabel = new Gtk.Label({ + label: _("Show descriptions of search results"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let descriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + descriptionsSwitch.set_active(this.searchResultsDetails); + descriptionsSwitch.connect('notify::active', (widget) => { + this.searchResultsDetails = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + descriptionsRow.add(descriptionsLabel); + descriptionsRow.add(descriptionsSwitch); + searchOptionsFrame.add(descriptionsRow); + + let highlightSearchResultRow = new PW.FrameBoxRow(); + let highlightSearchResultLabel = new Gtk.Label({ + label: _("Highlight search result terms"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let highlightSearchResultSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + highlightSearchResultSwitch.connect('notify::active', (widget) => { + this.highlightSearchResultTerms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + highlightSearchResultRow.add(highlightSearchResultLabel); + highlightSearchResultRow.add(highlightSearchResultSwitch); + searchOptionsFrame.add(highlightSearchResultRow); + + let maxSearchResultsRow = new PW.FrameBoxRow(); + let maxSearchResultsLabel = new Gtk.Label({ + label: _('Max Search Results'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let maxSearchResultsScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 2, + upper: 10, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + maxSearchResultsScale.set_value(this.maxSearchResults); + maxSearchResultsScale.connect('value-changed', (widget) => { + this.maxSearchResults = widget.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + maxSearchResultsRow.add(maxSearchResultsLabel); + maxSearchResultsRow.add(maxSearchResultsScale); + searchOptionsFrame.add( maxSearchResultsRow); + this.mainBox.append(searchOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.searchResultsDetails = this._settings.get_default_value('show-search-result-details').unpack(); + this.openWindowsSearchProvider = this._settings.get_default_value('search-provider-open-windows').unpack(); + this.recentFilesSearchProvider = this._settings.get_default_value('search-provider-recent-files').unpack(); + this.highlightSearchResultTerms = this._settings.get_default_value('highlight-search-result-terms').unpack(); + this.maxSearchResults = this._settings.get_default_value('max-search-results').unpack(); + descriptionsSwitch.set_active(this.searchResultsDetails); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + maxSearchResultsScale.set_value(this.maxSearchResults); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('show-search-result-details', this.searchResultsDetails); + this._settings.set_boolean('search-provider-open-windows', this.openWindowsSearchProvider); + this._settings.set_boolean('search-provider-recent-files', this.recentFilesSearchProvider); + this._settings.set_boolean('highlight-search-result-terms', this.highlightSearchResultTerms); + this._settings.set_int('max-search-results', this.maxSearchResults); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.searchResultsDetails !== this._settings.get_default_value('show-search-result-details').unpack() || + this.openWindowsSearchProvider !== this._settings.get_default_value('search-provider-open-windows').unpack() || + this.recentFilesSearchProvider !== this._settings.get_default_value('search-provider-recent-files').unpack() || + this.highlightSearchResultTerms !== this._settings.get_default_value('highlight-search-result-terms').unpack() || + this.maxSearchResults !== this._settings.get_default_value('max-search-results').unpack()) ? true : false; + } +}); + +var MenuSettingsCategoriesPage = GObject.registerClass( + class Arc_Menu_MenuSettingsCategoriesPage extends Gtk.Box { + _init(settings, settingType) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.settingType = settingType; + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.categoriesFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value(this.settingType).deep_unpack()); + this.mainBox.append(this.categoriesFrame); + + this.buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.categoriesFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value(this.settingType).deep_unpack()); + this.categoriesFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.categoriesFrame.count; i++) { + let frame = this.categoriesFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value(this.settingType, new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + this.buttonRow.append(this.resetButton); + this.buttonRow.append(this.saveButton); + this.append(this.buttonRow); + } + + getSensitive(){ + let defaultExtraCategories = this._settings.get_default_value(this.settingType).deep_unpack(); + let currentExtraCategories = this._settings.get_value(this.settingType).deep_unpack(); + return !Utils.getArraysEqual(defaultExtraCategories, currentExtraCategories); + } + + _createFrame(extraCategories){ + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let name = Constants.Categories[categoryEnum].NAME; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = extraCategories[i][0]; + frameRow._shouldShow = extraCategories[i][1]; + frameRow._name = Constants.Categories[categoryEnum].NAME; + frameRow._gicon = Gio.icon_new_for_string(Constants.Categories[categoryEnum].ICON); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.categoriesFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + this.categoriesFrame.add(frameRow); + } + } +}); + +var ColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent, themeName="") { + this._settings = settings; + this.addResponse = false; + this.themeName = themeName; + super._init(_('Color Theme Name'), parent); + } + + _createLayout(vbox) { + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + nameFrameRow.add(nameFrameLabel); + this.nameEntry = new Gtk.Entry(); + this.nameEntry.set_width_chars(35); + + nameFrameRow.add(this.nameEntry); + this.nameEntry.grab_focus(); + if(this.themeName!=""){ + this.nameEntry.set_text(this.themeName); + } + this.nameEntry.connect('changed',()=>{ + if(this.nameEntry.get_text().length > 0) + saveButton.set_sensitive(true); + else + saveButton.set_sensitive(false); + }); + + vbox.append(nameFrameRow); + let saveButton = new Gtk.Button({ + label: _("Save Theme"), + halign: Gtk.Align.END + }); + saveButton.set_sensitive(false); + saveButton.connect('clicked', ()=> { + this.themeName = this.nameEntry.get_text(); + this.addResponse=true; + this.response(-10); + }); + vbox.append(saveButton); + } + get_response(){ + return this.addResponse; + } +}); + +var ExportColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ExportColorThemeDialogWindow extends PW.DialogWindow { + + _init(settings, parent, themes=null) { + this._settings = settings; + this._themes = themes; + this.addResponse = false; + this.selectedThemes = []; + super._init(this._themes ? _('Select Themes to Import'): _('Select Themes to Export'), parent); + } + + _createLayout(vbox) { + vbox.spacing = 0; + this.checkButtonArray = []; + this.shouldToggle =true; + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + + let themesListButton = new Gtk.Button({ + label: this._themes ?_("Import"): _("Export"), + }); + + themesListButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + themesListButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + this.checkAllButton = new Gtk.CheckButton({ + margin_end: 23 + }); + + this.checkAllButton.set_halign(Gtk.Align.END); + this.checkAllButton.set_active(true); + this.checkAllButton.connect('toggled', () => { + let isActive = this.checkAllButton.get_active(); + if(this.shouldToggle){ + for(let i = 0; i< this.checkButtonArray.length; i++){ + this.checkButtonArray[i].set_active(isActive); + } + } + }); + let checkAllRow = new PW.FrameBoxRow(); + let checkAllLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + hexpand: true, + label: _("Select All"), + halign: Gtk.Align.END + }); + checkAllRow.add(checkAllLabel); + checkAllRow.add(this.checkAllButton); + vbox.append(checkAllRow); + vbox.append(themesListScrollWindow); + vbox.append(new PW.FrameBoxRow()); + vbox.append(themesListButton); + + this.color_themes = this._themes ? this._themes : this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', () => { + if(checkButton.get_active()){ + this.selectedThemes.push(theme); + } + else{ + this.shouldToggle = false; + this.checkAllButton.set_active(false); + this.shouldToggle = true; + let index= this.selectedThemes.indexOf(theme); + this.selectedThemes.splice(index,1); + } + }); + this.checkButtonArray.push(checkButton); + frameRow.add(checkButton); + this.mainFrame.add(frameRow); + checkButton.set_active(true); + } + } + get_response(){ + return this.addResponse; + } +}); + +var ManageColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ManageColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.selectedThemes = []; + super._init( _('Manage Presets'), parent); + } + + _createLayout(vbox) { + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + let buttonRow = new PW.FrameBoxRow(); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + applyButton.set_sensitive(false); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + vbox.append(themesListScrollWindow); + buttonRow.add(applyButton); + vbox.append(buttonRow); + + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.mainFrame, + buttons: [applyButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', () => { + let dialog = new ColorThemeDialogWindow(this._settings, this, theme[0]); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()) { + let index = frameRow.get_index(); + let array = [dialog.themeName, theme[1], theme[2], theme[3], theme[4], theme[5], + theme[6], theme[7], theme[8], theme[9], theme[10], theme[11], theme[12]]; + this.color_themes.splice(index,1,array); + theme = array; + frameLabel.label = dialog.themeName; + dialog.destroy(); + } + else + dialog.destroy(); + }); + applyButton.set_sensitive(true); + }); + buttonBox.connect('move-up', () => { + let index = frameRow.get_index(); + if(index > 0){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index - 1, 0, theme); + } + }); + + buttonBox.connect('move-down', () => { + let index = frameRow.get_index(); + if(index + 1 < this.mainFrame.count){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index + 1, 0, theme); + } + }); + + buttonBox.connect('delete', () => { + let index = frameRow.get_index(); + this.color_themes.splice(index, 1); + }); + + frameRow.add(buttonBox); + this.mainFrame.add(frameRow); + } + } + get_response(){ + return this.addResponse; + } +}); + +var OverrideArcMenuThemeWindow = GObject.registerClass({ + Signals: { + 'menu-theme-response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_OverrideArcMenuThemeWindow extends Gtk.Box { + _init(settings, parentBox, parentMainBox) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + }); + this.parentBox = parentBox; + this._parentMainBox = parentMainBox; + this._settings = settings; + this.addResponse = false; + this.heightValue = this._settings.get_int('menu-height'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.menuWidth = this._settings.get_int('menu-width'); + this.updatePresetComboBox = true; + this.shouldDeselect = true; + this._createLayout(this); + } + createIconList(store){ + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i= 0; i" + _('Menu Theme Presets') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(colorPresetHeaderLabel); + + this.colorPresetFrame = new PW.FrameBox(); + let colorPresetRow = new PW.FrameBoxRow(); + let colorPresetLabel = new Gtk.Label({ + label: _('Current Menu Theme Preset'), + xalign:0, + hexpand: true, + }); + let store = new Gtk.ListStore(); + store.set_column_types([GdkPixbuf.Pixbuf, GObject.TYPE_STRING]); + this.colorPresetCombo = new Gtk.ComboBox({ + model: store, + }); + + this.createIconList(store); + + let renderer = new Gtk.CellRendererPixbuf({xpad: 5}); + this.colorPresetCombo.pack_start(renderer, false); + this.colorPresetCombo.add_attribute(renderer, "pixbuf", 0); + renderer = new Gtk.CellRendererText(); + this.colorPresetCombo.pack_start(renderer, true); + this.colorPresetCombo.add_attribute(renderer, "text", 1); + + this.saveButton = new Gtk.Button({ + label: _("Save as Preset"), + hexpand: true, + halign: Gtk.Align.END + }); + this.checkIfPresetMatch(); + this.colorPresetCombo.connect('changed', (widget) => { + if(this.updatePresetComboBox){ + let index = widget.get_active(); + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Hightlight Foreground Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + if(index>=0){ + this.menuColor = this.color_themes[index][1]; + this.menuForegroundColor = this.color_themes[index][2]; + this.borderColor = this.color_themes[index][3]; + this.highlightColor = this.color_themes[index][4]; + this.highlightForegroundColor = this.color_themes[index][5]; + this.separatorColor = this.color_themes[index][6]; + this.fontSize = parseInt(this.color_themes[index][7]); + this.borderSize = parseInt(this.color_themes[index][8]); + this.cornerRadius = parseInt(this.color_themes[index][9]); + this.menuArrowSize = parseInt(this.color_themes[index][10]); + this.menuMargin = parseInt(this.color_themes[index][11]); + this.verticalSeparator = (this.color_themes[index][12] === 'true'); + + this.shouldDeselect = false; + this.presetName=this.color_themes[index][0]; + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + this.saveButton.set_sensitive(false); + applyButton.set_sensitive(true); + this.shouldDeselect = true; + resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + } + } + }); + colorPresetRow.add(colorPresetLabel); + colorPresetRow.add(this.colorPresetCombo); + this.colorPresetFrame.add(colorPresetRow); + + let presetsButtonRow = new PW.FrameBoxRow(); + + this.saveButton.connect('clicked', () => { + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + let dialog = new ColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let array = [dialog.themeName, this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + this.color_themes.push(array); + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + let manageButton = new Gtk.Button({ + label: _("Manage Presets") + }); + manageButton.connect('clicked', ()=> { + let dialog = new ManageColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response)=>{ + if(dialog.get_response()){ + this.color_themes = dialog.color_themes; + this._settings.set_value('color-themes',new GLib.Variant('aas',dialog.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + let addButton = new PW.Button({ + title: _("Browse Presets"), + icon_name: "browse-presets-symbolic", + hexpand: false + }); + addButton.connect('clicked', () => { + let settingsFile = Gio.File.new_for_path(Me.path + '/media/misc/ArcMenuDefaultPresets'); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + let colorThemes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + colorThemes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, colorThemes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + presetsButtonRow.add(manageButton); + presetsButtonRow.add(addButton); + presetsButtonRow.add(this.saveButton); + this.colorPresetFrame.add(presetsButtonRow); + vbox.append(this.colorPresetFrame); + + this._settings.connect("changed::color-themes", () => { + store.clear(); + this.createIconList(store); + this.colorPresetCombo.model = store; + this.colorPresetCombo.show(); + + this.checkIfPresetMatch(); + }); + + let menuSettingsHeaderLabel = new Gtk.Label({ + label: "" + _('Theme Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(menuSettingsHeaderLabel); + + let themeSettingsFrame = new PW.FrameBox(); + let themeSettingsFrameScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + themeSettingsFrameScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themeSettingsFrameScrollWindow.set_min_content_height(250); + themeSettingsFrameScrollWindow.set_child(themeSettingsFrame); + vbox.append(themeSettingsFrameScrollWindow); + + //ROW 1 - MENU BACKGROUND COLOR-------------------------------------- + let menuBackgroudColorRow = new PW.FrameBoxRow(); + let menuBackgroudColorLabel = new Gtk.Label({ + label: _('Menu Background Color'), + xalign:0, + hexpand: true, + }); + let menuBackgroudColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + menuBackgroudColorChooser.connect('color-set', () => { + this.menuColor = menuBackgroudColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuBackgroudColorRow.add(menuBackgroudColorLabel); + menuBackgroudColorRow.add(menuBackgroudColorChooser); + themeSettingsFrame.add(menuBackgroudColorRow); + + //ROW 2 - MENU FOREGROUND COLOR-------------------------------------- + let menuForegroundColorRow = new PW.FrameBoxRow(); + let menuForegroundColorLabel = new Gtk.Label({ + label: _('Menu Foreground Color'), + xalign:0, + hexpand: true, + }); + let menuForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + menuForegroundColorChooser.connect('color-set', () => { + this.menuForegroundColor = menuForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuForegroundColorRow.add(menuForegroundColorLabel); + menuForegroundColorRow.add(menuForegroundColorChooser); + themeSettingsFrame.add(menuForegroundColorRow); + + //ROW 3 - FONT SIZE-------------------------------------------------- + let fontSizeRow = new PW.FrameBoxRow(); + let fontSizeLabel = new Gtk.Label({ + label: _('Font Size'), + xalign:0, + hexpand: true, + }); + + let fontScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 8, upper: 14, step_increment: 1, page_increment: 1, page_size: 0 }), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + fontScale.set_format_value_func( (scale, value) => { + return value + "pt"; + }); + fontScale.set_value(this.fontSize); + fontScale.connect('value-changed', () => { + this.fontSize = fontScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + fontSizeRow.add(fontSizeLabel); + fontSizeRow.add(fontScale); + themeSettingsFrame.add(fontSizeRow); + + //ROW 4- Border Color------------------------------------------------- + let borderColorRow = new PW.FrameBoxRow(); + let borderColorLabel = new Gtk.Label({ + label: _('Border Color'), + xalign:0, + hexpand: true, + }); + let borderColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + borderColorChooser.connect('color-set', ()=>{ + this.borderColor = borderColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderColorRow.add(borderColorLabel); + borderColorRow.add(borderColorChooser); + themeSettingsFrame.add(borderColorRow); + + //ROW 5 - Border Size------------------------------------------------------- + let borderSizeRow = new PW.FrameBoxRow(); + let borderSizeLabel = new Gtk.Label({ + label: _('Border Size'), + xalign:0, + hexpand: true, + }); + let borderScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 4, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + borderScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + borderScale.set_value(this.borderSize); + borderScale.connect('value-changed', () => { + this.borderSize = borderScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderSizeRow.add(borderSizeLabel); + borderSizeRow.add(borderScale); + themeSettingsFrame.add(borderSizeRow); + + //ROW 6 - Active Item Background Color----------------------------------------------- + let itemColorRow = new PW.FrameBoxRow(); + let itemColorLabel = new Gtk.Label({ + label: _('Active Item Background Color'), + xalign:0, + hexpand: true, + }); + let itemColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + itemColorChooser.connect('color-set', () => { + this.highlightColor = itemColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemColorRow.add(itemColorLabel); + itemColorRow.add(itemColorChooser); + themeSettingsFrame.add(itemColorRow); + + //ROW 7 - Active Item Foreground Color----------------------------------------------- + let itemForegroundColorRow = new PW.FrameBoxRow(); + let itemForegroundColorLabel = new Gtk.Label({ + label: _('Active Item Foreground Color'), + xalign:0, + hexpand: true, + }); + let itemForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + itemForegroundColorChooser.connect('color-set', () => { + this.highlightForegroundColor = itemForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemForegroundColorRow.add(itemForegroundColorLabel); + itemForegroundColorRow.add(itemForegroundColorChooser); + themeSettingsFrame.add(itemForegroundColorRow); + + //ROW 8 - Corner Radius----------------------------------------------------- + let cornerRadiusRow = new PW.FrameBoxRow(); + let cornerRadiusLabel = new Gtk.Label({ + label: _('Corner Radius'), + xalign:0, + hexpand: true, + }); + let cornerScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + cornerScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + cornerScale.set_value(this.cornerRadius); + cornerScale.connect('value-changed', () => { + this.cornerRadius = cornerScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + cornerRadiusRow.add(cornerRadiusLabel); + cornerRadiusRow.add(cornerScale); + themeSettingsFrame.add(cornerRadiusRow); + + //ROW 9 - Menu Arrow Size------------------------------------------------------- + let menuMarginRow = new PW.FrameBoxRow(); + let menuMarginLabel = new Gtk.Label({ + label: _('Menu Arrow Size'), + xalign:0, + hexpand: true, + }); + let marginScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 30, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + marginScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + marginScale.set_value(this.menuMargin); + marginScale.connect('value-changed', () => { + this.menuMargin = marginScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuMarginRow.add(menuMarginLabel); + menuMarginRow.add(marginScale); + themeSettingsFrame.add(menuMarginRow); + + //ROW 10 - Menu Displacement------------------------------------------------------ + let menuArrowRow = new PW.FrameBoxRow(); + let menuArrowLabel = new Gtk.Label({ + label: _('Menu Displacement'), + xalign:0, + hexpand: true, + }); + let arrowScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + arrowScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + arrowScale.set_value(this.menuArrowSize); + arrowScale.connect('value-changed', () => { + this.menuArrowSize = arrowScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuArrowRow.add(menuArrowLabel); + menuArrowRow.add(arrowScale); + themeSettingsFrame.add(menuArrowRow); + + //ROW 11 - Vertical Separator------------------------------------------------------ + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ halign: Gtk.Align.END}); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + applyButton.set_sensitive(true); + resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + themeSettingsFrame.add(vertSeparatorRow); + + //ROW 12 - Separator Color------------------------------------------------------ + let separatorColorRow = new PW.FrameBoxRow(); + let separatorColorLabel = new Gtk.Label({ + label: _('Separator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let colorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + colorChooser.connect('color-set', ()=>{ + this.separatorColor = colorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + separatorColorRow.add(separatorColorLabel); + separatorColorRow.add(colorChooser); + themeSettingsFrame.add(separatorColorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this._parentMainBox.buttonRow = buttonRow; + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + valign: Gtk.Align.END, + vexpand: false + }); + resetButton.set_sensitive( this.checkIfResetButtonSensitive()); + resetButton.connect('clicked', ()=> { + this.separatorColor = this._settings.get_default_value('separator-color').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.menuColor = this._settings.get_default_value('menu-color').unpack(); + this.menuForegroundColor = this._settings.get_default_value('menu-foreground-color').unpack(); + this.borderColor = this._settings.get_default_value('border-color').unpack(); + this.highlightColor = this._settings.get_default_value('highlight-color').unpack(); + this.highlightForegroundColor = this._settings.get_default_value('highlight-foreground-color').unpack(); + this.fontSize = this._settings.get_default_value('menu-font-size').unpack(); + this.borderSize = this._settings.get_default_value('menu-border-size').unpack(); + this.cornerRadius = this._settings.get_default_value('menu-corner-radius').unpack(); + this.menuMargin = this._settings.get_default_value('menu-margin').unpack(); + this.menuArrowSize = this._settings.get_default_value('menu-arrow-size').unpack(); + + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + + resetButton.set_sensitive(false); + applyButton.set_sensitive(true); + }); + + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + applyButton.set_sensitive(false); + this.emit('menu-theme-response', -10); + }); + applyButton.set_sensitive(false); + + buttonRow.append(resetButton); + buttonRow.append(applyButton); + + this._parentMainBox.append(buttonRow); + } + get_response(){ + return this.addResponse; + } + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + let currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0;i < all_color_themes.length;i++){ + this.isEqual=true; + for(let l = 0; l { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('directory-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name, frame._icon, frame._cmd]); + } + this._settings.set_value('directory-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = _(applicationShortcuts[i][0]); + let editable = true; + if(applicationShortcuts[i][2].startsWith("ArcMenu_")){ + editable = false; + } + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + frameRow._name = applicationName; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._gicon = Gio.icon_new_for_string(getIconPath(applicationShortcuts[i])); + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.resetButton, this.saveButton], + modifyButton: editable, + deleteButton: true + }); + + if(editable){ + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + applicationIcon.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + } + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsShortcutApplicationsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsShortcutApplicationsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + let softwareShortcutsFrame = new PW.FrameBox(); + this.softwareShortcutsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.softwareShortcutsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.softwareShortcutsScrollWindow.set_min_content_height(300); + this.softwareShortcutsScrollWindow.set_child(softwareShortcutsFrame); + + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._loadPinnedApps(applicationShortcuts,softwareShortcutsFrame); + this.mainBox.append(this.softwareShortcutsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('application-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name,frame._icon, frame._cmd]); + } + this._settings.set_value('application-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + let iconString; + frameRow._name = applicationShortcuts[i][0]; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + checkIfValidShortcut(frameRow, softwareShortcutsLabel, applicationIcon); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.saveButton, this.resetButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + applicationIcon.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsPowerOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPowerOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.powerOptionsFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value("power-options").deep_unpack()); + this.mainBox.append(this.powerOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.powerOptionsFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value('power-options').deep_unpack()); + this.powerOptionsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.powerOptionsFrame.count; i++) { + let frame = this.powerOptionsFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value('power-options', new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultPowerOptions = this._settings.get_default_value("power-options").deep_unpack(); + let currentPowerOptions = this._settings.get_value("power-options").deep_unpack(); + return !Utils.getArraysEqual(defaultPowerOptions, currentPowerOptions); + } + + _createFrame(powerOptions){ + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let name = Constants.PowerOptions[powerType].TITLE; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = powerOptions[i][0]; + frameRow._shouldShow = powerOptions[i][1]; + frameRow._name = Constants.PowerOptions[powerType].TITLE; + frameRow._gicon = Gio.icon_new_for_string(Constants.PowerOptions[powerType].IMAGE); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let powerIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let powerImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + powerImageBox.append(dragImage); + powerImageBox.append(powerIcon); + frameRow.add(powerImageBox); + + let powerLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.powerOptionsFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(powerLabel); + frameRow.add(buttonBox); + this.powerOptionsFrame.add(frameRow); + } + } + }); + +var MiscPage = GObject.registerClass( + class Arc_Menu_MiscPage extends Gtk.ScrolledWindow { + _init(settings, parentBox) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let settingsHeaderLabel = new Gtk.Label({ + label: "" + _('Export or Import Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsHeaderLabel); + + let importFrame = new PW.FrameBox(); + let importRow = new PW.FrameBoxRow(); + let importLabel = new Gtk.Label({ + label: _("All ArcMenu Settings"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let settingsImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + settingsImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import All ArcMenu Settings"), + secondaryText: _('Importing settings from file may replace ALL saved settings.\nThis includes all saved pinned apps.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importButtonsRow = new PW.FrameBoxRow(); + let importButton = new Gtk.Button({ + label: _("Import from File"), + hexpand: true, + vexpand: true, + }); + importButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success_, pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + ); + }); + let exportButton = new Gtk.Button({ + label: _("Export to File"), + hexpand: true, + vexpand: true, + }); + exportButton.connect('clicked', ()=> { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE}, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + importRow.add(importLabel); + importRow.add(settingsImportInfoButton); + importButtonsRow.add(exportButton); + importButtonsRow.add(importButton); + importFrame.add(importRow); + importFrame.add(importButtonsRow); + this.mainBox.append(importFrame); + + let importColorPresetFrame = new PW.FrameBox(); + let importColorPresetRow = new PW.FrameBoxRow(); + let importColorPresetLabel = new Gtk.Label({ + label: _("Menu Theme Presets"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let colorThemesImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + colorThemesImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import Menu Theme Presets"), + secondaryText: _('Menu theme presets are located in the "Menu Theme" section'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importColorPresetButtonsRow = new PW.FrameBoxRow(); + let importColorPresetButton = new Gtk.Button({ + label: _("Import Theme Preset"), + hexpand: true, + vexpand: true, + }); + importColorPresetButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import Theme Preset'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + this.color_themes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + this.color_themes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, this.color_themes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + + dialog.destroy(); + } + else + dialog.destroy(); + }); + } + ); + }); + let exportColorPresetButton = new Gtk.Button({ + label: _("Export Theme Preset"), + hexpand: true, + vexpand: true, + }); + exportColorPresetButton.connect('clicked', ()=> { + let dialog = new ExportColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + this.selectedThemes = dialog.selectedThemes; + this._showFileChooser( + _('Export Theme Preset'), + { action: Gtk.FileChooserAction.SAVE }, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + for(let i = 0; i" + _('ArcMenu Settings Window Size') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsSizeHeaderLabel); + + let settingsSizeFrame = new PW.FrameBox(); + let settingsWidthRow = new PW.FrameBoxRow(); + let settingsWidthLabel = new Gtk.Label({ + label: _('Window Width'), + xalign:0, + hexpand: false, + }); + let settingsWidthScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 850, upper: 1800, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsWidthScale.set_value(this._settings.get_int("settings-width")); + settingsWidthScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-width", widget.get_value()) + }); + settingsWidthRow.add(settingsWidthLabel); + settingsWidthRow.add(settingsWidthScale); + settingsSizeFrame.add(settingsWidthRow); + + let settingsHeightRow = new PW.FrameBoxRow(); + let settingsHeightLabel = new Gtk.Label({ + label: _('Window Height'), + xalign:0, + hexpand: false, + }); + let settingsHeightScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: 1600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsHeightScale.set_value(this._settings.get_int("settings-height")); + settingsHeightScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-height", widget.get_value()) + }); + settingsHeightRow.add(settingsHeightLabel); + settingsHeightRow.add(settingsHeightScale); + settingsSizeFrame.add(settingsHeightRow); + + this.mainBox.append(settingsSizeFrame); + + let resetSettingsButton = new Gtk.Button({ + valign: Gtk.Align.END, + halign: Gtk.Align.START, + vexpand: true, + hexpand: false, + label: _("Reset all Settings"), + }); + let context = resetSettingsButton.get_style_context(); + context.add_class('suggested-action'); + resetSettingsButton.connect('clicked', (widget) => { + let dialog = new Gtk.MessageDialog({ + text: "" + _("Restore Default Settings?") + '\n' + _("All ArcMenu settings will be reset to the default value."), + use_markup: true, + buttons: Gtk.ButtonsType.YES_NO, + message_type: Gtk.MessageType.WARNING, + transient_for: this.get_root(), + modal: true + }); + dialog.connect('response', (widget, response) => { + if(response == Gtk.ResponseType.YES){ + GLib.spawn_command_line_sync('dconf reset -f /org/gnome/shell/extensions/arcmenu/'); + let children = [...parentBox.settingsFrameStack]; + for(let child of children){ + parentBox.settingsFrameStack.remove(child); + } + parentBox.populateSettingsFrameStack(); + } + dialog.destroy(); + }); + dialog.show(); + }); + + this.mainBox.append(resetSettingsButton); + } + _showFileChooser(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog({ + title: _(title), + transient_for: this.get_root(), + modal: true, + action: params.action, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + try { + acceptHandler(dialog.get_file().get_path()); + } catch(e) { + log('error from ArcMenu filechooser: ' + e); + } + } + dialog.destroy(); + }); + + dialog.show(); + } + }); + function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + return main; + }; + +var AboutPage = GObject.registerClass( + class Arc_Menu_AboutPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_start: 24, + margin_end: 24, + spacing: 0, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let releaseVersion; + if(Me.metadata.version) + releaseVersion = Me.metadata.version; + else + releaseVersion = 'unknown'; + + let commitVersion; + if(Me.metadata.commit) + commitVersion = Me.metadata.commit; + + let projectUrl = Me.metadata.url; + + let arcMenuImage = new Gtk.Image({ + margin_bottom: 5, + icon_name: 'arc-menu-logo', + pixel_size: 100, + }); + let arcMenuImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_top: 10, + margin_bottom: 10, + hexpand: false, + vexpand: false + }); + arcMenuImageBox.append(arcMenuImage); + + let extensionInfoFrame = new PW.FrameBox(); + + let arcMenuVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let versionText = new Gtk.Label({ + label: _('ArcMenu Version'), + }); + let versionInfo = new Gtk.Label({ + label: releaseVersion + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + arcMenuVersionRow.add(versionText); + arcMenuVersionRow.add(versionInfo); + extensionInfoFrame.add(arcMenuVersionRow); + + let commitRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let commitText = new Gtk.Label({ + label: _('Git Commit'), + }); + let commitInfo = new Gtk.Label({ + label: commitVersion ? commitVersion : '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + commitRow.add(commitText); + commitRow.add(commitInfo); + if(commitVersion){ + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(commitRow); + } + + let gnomeVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let gnomeVersionText = new Gtk.Label({ + label: _('GNOME Version'), + }); + let gnomeVersionInfo = new Gtk.Label({ + label: imports.misc.config.PACKAGE_VERSION + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + gnomeVersionRow.add(gnomeVersionText); + gnomeVersionRow.add(gnomeVersionInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(gnomeVersionRow); + + let osRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let osText = new Gtk.Label({ + label: _('OS'), + }); + let osInfoText; + let name = GLib.get_os_info("NAME"); + let prettyName = GLib.get_os_info("PRETTY_NAME"); + if(prettyName) + osInfoText = prettyName; + else + osInfoText = name; + let versionID = GLib.get_os_info("VERSION_ID"); + if(versionID) + osInfoText += "; Version ID: " + versionID; + let buildID = GLib.get_os_info("BUILD_ID"); + if(buildID) + osInfoText += "; " + "Build ID: " +buildID; + + let osInfo = new Gtk.Label({ + label: osInfoText, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + osRow.add(osText); + osRow.add(osInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(osRow); + + let windowingRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let windowingText = new Gtk.Label({ + label: _('Session Type'), + }); + let windowingLabel; + if(Me.metadata.isWayland) + windowingLabel = "Wayland"; + else + windowingLabel = "X11"; + + let windowingInfo = new Gtk.Label({ + label: windowingLabel, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + windowingRow.add(windowingText); + windowingRow.add(windowingInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(windowingRow); + + let arcMenuInfoBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + vexpand: false + }); + let arcMenuLabel = new Gtk.Label({ + label: '' + _('ArcMenu') + '', + use_markup: true, + vexpand: true, + valign: Gtk.Align.FILL + }); + + let projectDescriptionLabel = new Gtk.Label({ + label: _('Application Menu Extension for GNOME'), + hexpand: false, + vexpand: false, + margin_bottom: 5 + }); + let linksBox = new Gtk.Box({ + hexpand: false, + vexpand: false, + valign: Gtk.Align.END, + halign: Gtk.Align.CENTER, + margin_top: 0, + margin_bottom: 0, + margin_start: 0, + margin_end: 0, + spacing: 0, + }); + + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/donate-icon.svg', 150, 50); + let donateImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let donateLinkButton = new Gtk.LinkButton({ + child: donateImage, + uri: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url', + }); + + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/gitlab-icon.svg', 150, 50); + let gitlabImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let projectLinkButton = new Gtk.LinkButton({ + child: gitlabImage, + uri: projectUrl, + }); + + linksBox.append(projectLinkButton); + linksBox.append(donateLinkButton); + + this.creditsScrollWindow = new Gtk.ScrolledWindow({ + margin_top: 10, + margin_bottom: 0, + hexpand: false, + }); + this.creditsScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.creditsScrollWindow.set_max_content_height(200); + this.creditsScrollWindow.set_min_content_height(200); + this.creditsFrame = new PW.Notebook(); + this.creditsFrame.scrollable = true; + let developersPage = new PW.NotebookPage(_("Developers")); + this.creditsFrame.append_page(developersPage); + let translatorsPage = new PW.NotebookPage(_("Translators")); + this.creditsFrame.append_page(translatorsPage); + let contributorsPage = new PW.NotebookPage(_("Contributors")); + this.creditsFrame.append_page(contributorsPage ); + let artworkPage = new PW.NotebookPage(_("Artwork")); + this.creditsFrame.append_page(artworkPage); + this.creditsScrollWindow.set_child(this.creditsFrame); + let creditsLabel = new Gtk.Label({ + label: _(Constants.DEVELOPERS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + developersPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.TRANSLATORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + translatorsPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.CONTRIBUTORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + contributorsPage.append(creditsLabel); + contributorsPage.hexpand = false; + creditsLabel = new Gtk.Label({ + label: _(Constants.ARTWORK), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + artworkPage.append(creditsLabel); + arcMenuImageBox.append(arcMenuLabel); + arcMenuImageBox.append(projectDescriptionLabel); + + let gnuSofwareLabel = new Gtk.Label({ + label: _(Constants.GNU_SOFTWARE), + use_markup: true, + justify: Gtk.Justification.CENTER + }); + let gnuSofwareLabelBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + valign: Gtk.Align.END, + vexpand: true, + margin_top: 5, + margin_bottom: 10 + }); + gnuSofwareLabelBox.append(gnuSofwareLabel); + + this.mainBox.append(arcMenuImageBox); + this.mainBox.append(arcMenuInfoBox); + this.mainBox.append(extensionInfoFrame); + + this.mainBox.append(this.creditsScrollWindow) + this.mainBox.append(gnuSofwareLabelBox); + this.mainBox.append(linksBox); + } +}); + +function createSeparator(){ + let separatorRow = new Gtk.ListBoxRow({ + selectable: false, + activatable: false + }); + separatorRow.set_child(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + return separatorRow; +} + +var ArcMenuPreferencesWidget = GObject.registerClass( +class Arc_Menu_ArcMenuPreferencesWidget extends Gtk.Box { + _init() { + super._init(); + + this.leftHeaderBox = new Gtk.Box({ + hexpand: true, + visible: true + }); + + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.backButton = new Gtk.Button({ + child: new Gtk.Image({icon_name: 'go-previous-symbolic'}), + visible: true + }); + this.backButton.connect("clicked", () => { + this.leftHeaderBox.remove(this.backButton); + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + }); + + this.settingsFrameStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.CROSSFADE + }); + + this.settingsListStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let mainStackListBox = new PW.StackListBox(this, {width_request: 215}); + + let mainStackBox = mainStackListBox.scrollWindow; + mainStackListBox.addRow("General", _("General"), 'homescreen-symbolic'); + mainStackListBox.addRow("MenuLayout", _("Menu Layout"), 'menu-layouts-symbolic') + mainStackListBox.addRow("MenuTheme", _("Menu Theme"), 'menu-theme-symbolic'); + mainStackListBox.addRow("MenuSettingsGeneral", _("Customize Menu"), 'menu-settings-symbolic', "MenuSettings"); + mainStackListBox.addRow("ButtonAppearance", _("Button Appearance"), 'arc-menu-symbolic') + mainStackListBox.addRow("Misc", _("Misc"), 'misc-symbolic') + mainStackListBox.addRow("About", _("About"), 'info-circle-symbolic'); + mainStackListBox.setSeparatorIndices([1, 4, 5]); + + let menuSettingsStackListBox = new PW.StackListBox(this, {width_request: 215}); + let menuSettingsListBox = menuSettingsStackListBox.scrollWindow; + menuSettingsStackListBox.addRow("MenuSettingsGeneral", _("Menu Settings"), 'menu-settings-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPinnedApps", _("Pinned Apps"), 'pinned-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutDirectories", _("Directory Shortcuts"), 'folder-documents-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutApplications", _("Application Shortcuts"), 'preferences-desktop-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPowerOptions", _("Power Options"), 'gnome-power-manager-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsSearchOptions", _("Search Options"), 'preferences-system-search-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsCategories", _("Extra Categories"), 'categories-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsNewApps", _("New Apps Tracker"), 'preferences-system-notifications-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsFineTune", _("Fine-Tune"), 'fine-tune-symbolic'); + menuSettingsStackListBox.setSeparatorIndices([1, 4, 8]); + + this.settingsListStack.add_named(mainStackBox, "Main"); + this.settingsListStack.add_named(menuSettingsListBox, "MenuSettings"); + + let sidebar = new Gtk.StackSidebar(); + sidebar.set_stack(this.settingsListStack); + this.append(this.settingsListStack); + this.append(sidebar); + + this.append(this.settingsFrameStack); + this.populateSettingsFrameStack(); + } + + populateSettingsFrameStack(){ + this.settingsFrameStack.add_named(new GeneralPage(this._settings), "General"); + this.menuLayoutPage = new MenuLayoutPage(this._settings); + this.settingsFrameStack.add_named(this.menuLayoutPage, "MenuLayout"); + this.settingsFrameStack.add_named(new MenuThemePage(this._settings), "MenuTheme"); + + this.settingsFrameStack.add_named(new MenuSettingsGeneralPage(this._settings), "MenuSettingsGeneral"); + this.settingsFrameStack.add_named(new MenuSettingsPinnedAppsPage(this._settings), "MenuSettingsPinnedApps"); + + let menuSettingsPinnedAppsPage = this.settingsFrameStack.get_child_by_name("MenuSettingsPinnedApps"); + + if(this.pinnedAppsChangedID){ + this._settings.disconnect(this.pinnedAppsChangedID); + this.pinnedAppsChangedID = null; + } + this.pinnedAppsChangedID = this._settings.connect("changed::pinned-app-list", () =>{ + menuSettingsPinnedAppsPage.frame.remove_all_children(); + menuSettingsPinnedAppsPage._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + menuSettingsPinnedAppsPage.frame.show(); + }); + + this.settingsFrameStack.add_named(new MenuSettingsShortcutDirectoriesPage(this._settings), "MenuSettingsShortcutDirectories"); + this.settingsFrameStack.add_named(new MenuSettingsShortcutApplicationsPage(this._settings), "MenuSettingsShortcutApplications"); + this.settingsFrameStack.add_named(new MenuSettingsPowerOptionsPage(this._settings), "MenuSettingsPowerOptions"); + this.settingsFrameStack.add_named(new MenuSettingsSearchOptionsPage(this._settings), "MenuSettingsSearchOptions"); + this.settingsFrameStack.add_named(new MenuSettingsCategoriesPage(this._settings, "extra-categories"), "MenuSettingsCategories"); + this.settingsFrameStack.add_named(new MenuSettingsNewAppsPage(this._settings), "MenuSettingsNewApps"); + this.settingsFrameStack.add_named(new MenuSettingsFineTunePage(this._settings), "MenuSettingsFineTune"); + this.settingsFrameStack.add_named(new ButtonAppearancePage(this._settings), "ButtonAppearance"); + this.settingsFrameStack.add_named(new MiscPage(this._settings, this), "Misc"); + this.settingsFrameStack.add_named(new AboutPage(this._settings), "About"); + + this.show(); + + if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MAIN){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.CUSTOMIZE_MENU){ + this.settingsListStack.set_visible_child_name("MenuSettings"); + this.settingsListStack.get_child_by_name('MenuSettings').listBox.selectRowAtIndex(0); + if(!this.backButton.get_parent()) + this.leftHeaderBox.append(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MENU_LAYOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.BUTTON_APPEARANCE){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(4); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.LAYOUT_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayLayoutTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.RUNNER_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayRunnerTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.ABOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(6); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + this._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.MAIN); + } +}); + +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +function buildPrefsWidget() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); + if(!iconTheme.get_search_path().includes(Me.path + "/media/icons/prefs_icons")) + iconTheme.add_search_path(Me.path + "/media/icons/prefs_icons"); + let widget = new ArcMenuPreferencesWidget(); + widget.connect("realize", () => { + let window = widget.get_root(); + + window.default_width = this._settings.get_int('settings-width'); + window.default_height = this._settings.get_int('settings-height'); + + window.set_title(_("ArcMenu Settings")); + window.get_titlebar().pack_start(widget.leftHeaderBox); + }); + + widget.show(); + return widget; +} + +function checkIfValidShortcut(frameRow, label, icon){ + if(frameRow._cmd.endsWith(".desktop") && !Gio.DesktopAppInfo.new(frameRow._cmd)){ + icon.icon_name = 'warning-symbolic'; + label.label = "" + _("Invalid Shortcut") + " "+ _(label.label); + } +} + +function getIconPath(listing){ + let path, icon; + + if(listing[2]=="ArcMenu_Home") + path = GLib.get_home_dir(); + else if(listing[2].startsWith("ArcMenu_")){ + let string = listing[2]; + path = string.replace("ArcMenu_",''); + if(path === "Documents") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + else if(path === "Downloads") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + else if(path === "Music") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC); + else if(path === "Pictures") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); + else if(path === "Videos") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS); + else + path = null; + } + else if(listing[1] == listing[2]) + path = listing[2]; + else if(listing[1] == "ArcMenu_Folder"){ + path = listing[2]; + } + else + path = null; + + if(path){ + let file = Gio.File.new_for_path(path); + try { + let info = file.query_info('standard::symbolic-icon', 0, null); + icon = info.get_symbolic_icon(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!file.is_native()) { + icon = new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + icon = new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + return icon.to_string(); + } + else{ + if(listing[2]=="ArcMenu_Network") + return 'network-workgroup-symbolic'; + else if(listing[2]=="ArcMenu_Computer") + return 'drive-harddisk-symbolic'; + else + return listing[1]; + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js new file mode 100644 index 0000000..0700025 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js @@ -0,0 +1,793 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var Notebook = GObject.registerClass(class Arc_Menu_Notebook extends Gtk.Notebook{ + _init() { + super._init({ + margin_start: 0, + margin_end: 0 + }); + } + + append_page(notebookPage) { + Gtk.Notebook.prototype.append_page.call( + this, + notebookPage, + notebookPage.getTitleLabel() + ); + } +}); + +var NotebookPage = GObject.registerClass(class Arc_Menu_NotebookPage extends Gtk.Box { + _init(title) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + homogeneous: false + }); + this._title = new Gtk.Label({ + label: "" + title + "", + use_markup: true, + xalign: 0 + }); + } + + getTitleLabel() { + return this._title; + } +}); + +var Button = GObject.registerClass(class Arc_Menu_Button extends Gtk.Button { + _init(params) { + super._init(); + this._params = params; + this.halign = Gtk.Align.END; + this.valign = Gtk.Align.CENTER; + this.box = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 5 + }); + this.set_child(this.box); + + if (this._params.icon_name) { + let image = new Gtk.Image({ + icon_name: this._params.icon_name, + halign: Gtk.Align.CENTER + }); + this.box.append(image); + } + if (this._params.tooltip_text){ + this.set_tooltip_text(this._params.tooltip_text); + } + if (this._params.title){ + let label = new Gtk.Label({ + label: _(this._params.title), + use_markup: true, + xalign: 0 + }); + if(this._params.icon_first) + this.box.append(label); + else + this.box.prepend(label); + } + } +}); + +var DialogWindow = GObject.registerClass(class Arc_Menu_DialogWindow extends Gtk.Dialog { + _init(title, parent) { + super._init({ + title: title, + transient_for: parent.get_root(), + modal: true + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + vbox.insert_after(this.get_content_area(), null); + this._createLayout(vbox); + } + + _createLayout(vbox) { + throw "Not implemented!"; + } +}); + +var MessageDialog = GObject.registerClass(class Arc_Menu_MessageDialog extends Gtk.MessageDialog { + _init(params) { + super._init({ + transient_for: params.transient_for, + modal: true, + buttons: params.buttons + }); + this.set_size_request(300, 50); + this.grid = new Gtk.Grid({ + row_spacing: 10, + column_spacing: 24, + margin_top: 24, + margin_bottom: 0, + margin_start: 24, + margin_end: 24, + hexpand: false, + halign: Gtk.Align.CENTER + }); + this.grid.insert_after(this.get_content_area(), null); + let text = new Gtk.Label({ + label: "" + _(params.text) + "", + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(text, 1, 0, 1, 1); + + if(params.secondaryText){ + let secondayText = new Gtk.Label({ + label: _(params.secondaryText), + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(secondayText, 1, 1, 1, 1); + } + + if(params.iconName){ + let image = new Gtk.Image({ + icon_name: params.iconName, + pixel_size: 48 + }); + this.grid.attach(image, 0, 0, 1, 2); + } + } +}); + +var FrameBox = GObject.registerClass(class Arc_Menu_FrameBox extends Gtk.Frame { + _init(params) { + super._init(params); + this._listBox = new Gtk.ListBox(); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.count = 0; + this.children = []; + Gtk.Frame.prototype.set_child.call(this, this._listBox); + } + + add(boxRow) { + this._listBox.append(boxRow); + this.children.push(boxRow); + this.count++; + } + show() { + this._listBox.show(); + super.show(); + } + length() { + return this._listBox.length; + } + remove(boxRow){ + if(boxRow){ + this._listBox.remove(boxRow); + this.children = this.children.filter(e => e !== boxRow) + this.count = this.count -1; + } + } + removeChildrenAfterIndex(index){ + let childrenCount = this.count; + for(let i = childrenCount - 1; i > index; i--){ + let child = this._listBox.get_row_at_index(i); + if(child) this.remove(child); + } + this._listBox.show(); + } + remove_all_children() { + for(let i = 0; i < this.children.length; i++){ + let child = this.children[i]; + this._listBox.remove(child); + } + this.children = []; + this.count = 0; + this._listBox.show(); + } + get_index(index){ + return this._listBox.get_row_at_index(index); + } + insert(row, pos){ + this._listBox.insert(row, pos); + this.children.push(row); + this.count++; + } +}); + +var FrameBoxRow = GObject.registerClass(class Arc_Menu_FrameBoxRow extends Gtk.ListBoxRow { + _init(params) { + super._init(params); + this.selectable = false; + this.activatable = false; + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var FrameBoxDragRow = GObject.registerClass(class Arc_Menu_FrameBoxDragRow extends Gtk.ListBoxRow { + _init(scrolledWindow) { + super._init(); + + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + + let dragSource = new Gtk.DragSource({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dragSource); + + let dropTarget = new Gtk.DropTargetAsync({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dropTarget); + + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + dragSource.connect("drag-begin", (self, gdkDrag) => { + //get listbox parent + let listBox = self.get_widget().get_parent(); + //get widgets parent - the listBoxDragRow + listBox.dragRow = this; + + let alloc = self.get_widget().get_allocation(); + let dragWidget = self.get_widget().createDragRow(alloc); + listBox.dragWidget = dragWidget; + + let icon = Gtk.DragIcon.get_for_drag(gdkDrag); + icon.set_child(dragWidget); + + gdkDrag.set_hotspot(listBox.dragX, listBox.dragY); + }); + + dragSource.connect("prepare", (self, x, y) => { + //get listbox parent + this.set_state_flags(Gtk.StateFlags.NORMAL, true); + let listBox = self.get_widget().get_parent(); + //store drag start cursor location + listBox.dragX = x; + listBox.dragY = y; + return new Gdk.ContentProvider(Arc_Menu_FrameBoxDragRow); + }); + + dragSource.connect("drag-end", (self, gdkDrag, deleteData)=> { + deleteData = true; + let listBox = self.get_widget().get_parent(); + listBox.dragWidget = null; + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drag-enter", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + let widget = self.get_widget(); + + listBox.startIndex = widget.get_index(); + listBox.drag_highlight_row(widget); + + if(!scrolledWindow) + return true; + + let height = widget.get_height(); + let scrollHeight = scrolledWindow.get_height(); + let widgetLoc = widget.get_index() * height; + let value = scrolledWindow.vadjustment.value; + + if((widgetLoc + (height * 4)) > (value + scrollHeight)) + scrolledWindow.vadjustment.value += height; + else if((widgetLoc - (height * 2)) < value) + scrolledWindow.vadjustment.value -= height; + }); + + dropTarget.connect("drag-leave", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drop", (self, gdkDrop, x, y, selection, info, time)=> { + //get listbox parent + let listBox = this.get_parent(); + let index = this.get_index(); + if(index === listBox.dragRow.get_index()){ + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + } + listBox.remove(listBox.dragRow); + listBox.show(); + listBox.insert(listBox.dragRow, index); + this.resetButton?.set_sensitive(true); + this.saveButton.set_sensitive(true); + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + }); + } + + createDragRow(alloc){ + let dragWidget = new Gtk.ListBox(); + dragWidget.set_size_request(alloc.width, alloc.height); + + let dragRow = new FrameBoxRow(); + dragWidget.append(dragRow); + dragWidget.drag_highlight_row(dragRow); + + let image = new Gtk.Image( { + gicon: this._gicon, + pixel_size: 22 + }); + + let imageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: true, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + imageBox.append(dragImage); + imageBox.append(image); + + dragRow.add(imageBox); + + let label = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true, + label: _(this._name) + }); + dragRow.add(label); + let grid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }) + let editButton = new Button({ + icon_name: 'view-more-symbolic' + }); + grid.attach(editButton, 0, 0, 1, 1); + + if(this.hasSwitch){ + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + active: this.switchActive + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(modifyButton, 0, 0, 1, 1); + } + if(this.hasEditButton){ + let editButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(editButton, 0, 0, 1, 1); + } + dragRow.add(grid); + + return dragWidget; + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var EditEntriesBox = GObject.registerClass({ + Signals: { + 'modify': {}, + 'change': {}, + 'move-up': {}, + 'move-down': {}, + 'delete': {}, + }, +}, class Arc_Menu_EditEntriesBox extends Gtk.Grid{ + _init(params){ + super._init({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + let editPopover = new Gtk.Popover(); + let frameRow = params.frameRow; + let frame = params.frame; + let buttons = params.buttons; + + let modifyButton, deleteButton, changeButton; + + if(params.modifyButton){ + modifyButton = new Gtk.Button({ + label: _("Modify"), + has_frame: false + }); + modifyButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('modify'); + }); + } + + if(params.changeButton){ + changeButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + changeButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('change'); + }); + } + + let editButton = new Gtk.MenuButton({ + icon_name: 'view-more-symbolic', + popover: editPopover, + }); + + this.attach(editButton, 0, 0, 1, 1); + + let editPopoverBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + + editPopover.set_child(editPopoverBox); + + let moveUpButton = new Gtk.Button({ + label: _("Move Up"), + has_frame: false + }); + moveUpButton.connect('clicked', ()=> { + this.emit('move-up'); + let index = frameRow.get_index(); + if(index > 0){ + frame.remove(frameRow); + frame.insert(frameRow, index - 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + let moveDownButton = new Gtk.Button({ + label: _("Move Down"), + has_frame: false + }); + moveDownButton.connect('clicked', ()=> { + this.emit('move-down'); + let index = frameRow.get_index(); + if(index + 1 < frame.count) { + frame.remove(frameRow); + frame.insert(frameRow, index + 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + if(params.deleteButton){ + deleteButton = new Gtk.Button({ + label: _("Delete"), + has_frame: false, + }); + deleteButton.connect('clicked', ()=> { + this.emit('delete'); + frame.remove(frameRow); + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + } + + if(params.changeButton){ + this.insert_column(0); + this.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + this.insert_column(0); + this.attach(changeButton, 0, 0, 1, 1); + } + + if(params.modifyButton){ + editPopoverBox.append(modifyButton); + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + } + + editPopoverBox.append(moveUpButton); + editPopoverBox.append(moveDownButton); + + if(params.deleteButton){ + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + editPopoverBox.append(deleteButton); + } + } +}); + +var StackListBox = GObject.registerClass(class Arc_Menu_StackListBox extends Gtk.ListBox{ + _init(widget, params){ + super._init(params); + this.valign = Gtk.Align.FILL; + this.vexpand = true; + this.hexpand = false; + this.settingsFrameStack = widget.settingsFrameStack; + this.settingsListStack = widget.settingsListStack + this.connect("row-selected", (self, row) => { + if(row){ + let stackName = row.stackName; + this.settingsFrameStack.set_visible_child_name(stackName); + if(row.nextPage){ + if(widget.backButton.get_parent()) + widget.leftHeaderBox.remove(widget.backButton); + widget.leftHeaderBox.prepend(widget.backButton); + this.settingsListStack.set_visible_child_name(row.nextPage); + this.settingsListStack.get_child_by_name(row.nextPage).listBox.selectFirstRow(); + } + } + }); + this.scrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.scrollWindow.set_child(this); + this.scrollWindow.listBox = this; + } + + getRowAtIndex(index){ + return this.get_row_at_index(index).get_children()[0]; + } + + getSelectedRow(){ + return this.get_selected_row().get_children()[0]; + } + + selectFirstRow(){ + this.select_row(this.get_row_at_index(0)); + } + + selectRowAtIndex(index){ + this.select_row(this.get_row_at_index(index)); + } + + addRow(name, translateableName, iconName, nextPage){ + let row1 = new Gtk.ListBoxRow(); + this.append(row1); + + let row = new Gtk.Grid({ + margin_top: 12, + margin_bottom: 12, + margin_start: 12, + margin_end: 12, + column_spacing: 10 + }); + row1.set_child(row); + row1.stackName = name; + row1.translateableName = translateableName; + + let image = new Gtk.Image({ + icon_name: iconName + }); + + let label = new Gtk.Label({ + label: translateableName, + halign: Gtk.Align.START, + }); + row.attach(image, 0, 0, 1, 1); + row.attach(label, 1, 0, 1, 1); + + if(nextPage){ + row1.nextPage = nextPage; + let image2 = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + hexpand: true + }); + row.attach(image2, 2, 0, 1, 1); + } + } + + setSeparatorIndices(indexArray){ + this.set_header_func((_row, _before) =>{ + for(let i = 0; i < indexArray.length; i++){ + if(_row.get_index() === indexArray[i]){ + let sep = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL); + sep.show(); + _row.set_header(sep); + + } + } + }); + } +}); + +var TileGrid = GObject.registerClass(class Arc_Menu_TileGrid extends Gtk.FlowBox{ + _init(maxColumns) { + super._init({ + row_spacing: 5, + column_spacing: 5, + vexpand: true, + hexpand: true, + valign: Gtk.Align.CENTER, + halign: Gtk.Align.CENTER, + max_children_per_line: maxColumns, + homogeneous: true, + selection_mode: Gtk.SelectionMode.NONE + }); + } +}); + +var IconGrid = GObject.registerClass(class Arc_Menu_IconGrid extends Gtk.FlowBox{ + _init() { + super._init({ + max_children_per_line: 7, + row_spacing: 10, + column_spacing: 10, + vexpand: true, + hexpand: false, + valign: Gtk.Align.START, + halign: Gtk.Align.CENTER, + homogeneous: true, + selection_mode: Gtk.SelectionMode.SINGLE + }); + this.childrenCount = 0; + } + + add(widget){ + this.insert(widget, -1); + this.childrenCount++; + } +}); + +var Tile = GObject.registerClass(class Arc_Menu_Tile extends FrameBox{ + _init(name, file, width, height, layout) { + super._init({ + hexpand: true, + vexpand: false, + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER + }); + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.orientation = Gtk.Orientation.VERTICAL, + this.activatable = true; + this.name = name; + this.layout = layout; + this._image = new Gtk.Image({ + + gicon: Gio.icon_new_for_string(file), + pixel_size: width + }); + this._label = new Gtk.Label({ label: _(this.name) }); + + this.box._grid.attach(this._image, 0, 0, 1, 1); + this.box._grid.attach(this._label, 0, 1, 1, 1); + this._listBox.append(this.box); + } +}); + +var LayoutTile = GObject.registerClass(class Arc_Menu_LayoutTile extends FrameBox{ + _init(name, file, layout) { + super._init({ + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER, + hexpand: true, + vexpand: false + }); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.name = name; + this.layout = layout.MENU_TYPE; + + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.column_spacing = 0; + + this._image = new Gtk.Image({ + hexpand: false, + halign: Gtk.Align.START, + gicon: Gio.icon_new_for_string(file), + pixel_size: 46 + }); + + let titleLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", layout.TITLE).format(layout.TITLE) + "", + use_markup: true, + hexpand: true, + halign: Gtk.Align.CENTER, + vexpand: true, + valign: Gtk.Align.CENTER, + wrap: true, + }) + + let goNextImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + hexpand: false, + vexpand: false, + }) + + this.box._grid.attach(this._image, 0, 0, 1, 2); + this.box._grid.attach(titleLabel, 1, 0, 1, 1); + this.box._grid.attach(goNextImage, 2, 0, 1, 2); + + this._listBox.append(this.box); + } +}); diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js new file mode 100644 index 0000000..eb51dff --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js @@ -0,0 +1,111 @@ +const { Gtk, Gio, GLib } = imports.gi; +const ExtensionUtils = imports.misc.extensionUtils; +const Main = imports.ui.main; + +const LogEnabled = false; + +var isCanceled = false; +var currentQueries = []; + +var RecentFilesManager = class Arc_Menu_RecentFilesManager { + constructor() { + this._settings = ExtensionUtils.getSettings(); + this._recentManager = new Gtk.RecentManager(); + } + + filterRecentFiles(callback){ + isCanceled = false; + this._recentManager.get_items().sort((a, b) => b.get_modified() - a.get_modified()) + .forEach(item => { + this.queryFileExists(item) + .then(validFile => { + this.debugLog("Valid file - " + validFile.get_display_name()); + if(!isCanceled) + callback(validFile); + }) + .catch(err =>{ + this.debugLog(err); + }); + }); + } + + queryFileExists(item) { + return new Promise((resolve, reject) => { + let file = Gio.File.new_for_uri(item.get_uri()); + let cancellable = new Gio.Cancellable(); + + if(file === null) + reject("Recent file is null. Rejected."); + + //Create and store queryInfo to cancel any active queries when needed + let queryInfo = { + timeOutID: null, + cancellable, + reject, + item + }; + + currentQueries.push(queryInfo); + + file.query_info_async('standard::type,standard::is-hidden', 0, 0, cancellable, (source, res) => { + try { + let fileInfo = source.query_info_finish(res); + this.removeQueryInfoFromList(queryInfo); + if (fileInfo) { + let isHidden = fileInfo.get_attribute_boolean("standard::is-hidden"); + let showHidden = this._settings.get_boolean('show-hidden-recent-files'); + if(isHidden && !showHidden) + reject(item.get_display_name() + " is hidden. Rejected.") + resolve(item); + } + } + catch (err) { + if (err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + this.debugLog("Cancel Called: " + item.get_display_name()); + + this.removeQueryInfoFromList(queryInfo); + reject(err); + } + }); + }); + } + + removeQueryInfoFromList(queryInfo){ + let queryIndex = currentQueries.indexOf(queryInfo); + if(queryIndex !== -1) + currentQueries.splice(queryIndex, 1); + } + + cancelCurrentQueries(){ + if(currentQueries.length === 0) + return; + isCanceled = true; + this.debugLog("Canceling " + currentQueries.length + " queries...") + for(let queryInfo of currentQueries){ + this.debugLog("Cancel query - " + queryInfo.item.get_display_name()); + queryInfo.cancellable.cancel(); + queryInfo.cancellable = null; + queryInfo.reject("Query Canceled"); + } + currentQueries = null; + currentQueries = []; + this.debugLog("Cancel Finished"); + } + + debugLog(message){ + if (!LogEnabled) + return; + else log(message); + } + + getRecentManager(){ + return this._recentManager; + } + + destroy(){ + this.cancelCurrentQueries(); + this._settings = null; + this._recentManager = null; + } +} + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled new file mode 100644 index 0000000..473fe73 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml new file mode 100644 index 0000000..9638cb6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 50 + Menu position alignment + Menu position alignment 0 = Left, 50 = Center, 100 = Right + + + 'Default' + menu layout + Menu Layout + + + 'Off' + Force the menu to a specific location + Force the menu to a specific location + + + false + disable hotkey on key release + disable hotkey on key release. + + + false + show ArcMenu on primary monitor when using hotkey + show ArcMenu on primary monitor when using hotkey. + + + false + show standalone Runner menu on primary monitor when using hotkey + show standalone Runner menu monitor when using hotkey. + + + 875 + ArcMenu Settings Width + ArcMenu Settings Width. + + + 725 + ArcMenu Settings Height + ArcMenu Settings Height. + + + [true, false, false] + Keeps track of available placement for ArcMenu. [Main Panel, Dash to Panel, Dash to Dock] + false = not avaliable, true = avaliable + + + "Panel" + Embed ArcMenu button into Dash instead of panel + Embed ArcMenu button into Dash instead of panel + + + 'Left' + Raven layout position. 'Left' or 'Right' side of screen + Raven layout position. 'Left' or 'Right' side of screen. + + + true + Enable Weather Widget raven layout + Enable Weather Widget raven layout. + + + true + Enable Clocks Widget raven layout + Enable Clocks Widget raven layout. + + + false + Enable Weather Widget Unity layout + Enable Weather Widget Unity layout. + + + false + Enable Clocks Widget Unity layout + Enable Clocks Widget Unity layout. + + + false + Enable Category Sub Menus + Enable Category Sub Menus. + + + 'Full_Color' + Category icon type. Full_Color or Symbolic + Category icon type. Full_Color or Symbolic + + + 'Symbolic' + Shortcut icon type. Full_Color or Symbolic + Shortcut icon type. Full_Color or Symbolic + + + false + disable the fade effect on scrollviews + ddisable the fade effect on scrollviews (may help improve performace) + + + false + Show a larger icon and extra app details + Show a larger icon and extra app details. + + + 5 + The amount of search results to display. + The amount of search results to display. + + + false + Highlight search results terms + Highlight search results terms. + + + false + Show search result description label + Show search result description label. + + + false + Show custom search provider - open windows + Show custom search provider - open windows. + + + false + Show custom search provider - recent files + Show custom search provider - recent files. + + + false + Show hidden recent files + Show hidden recent files. + + + false + Activate Categories on Hover + Activate Categories on Hover. + + + false + disable recently installed apps + disable recently installed apps. + + + false + disable tooltips + disable tooltips. + + + true + Separate All Programs by a Character Listing + Separate All Programs by a Character Listing. + + + true + Multi-lined labels for large icon application grid layouts + Multi-lined labels for large icon application grid layouts. + + + 'Pinned_Apps' + Set ArcMenu Layout Default View + Set ArcMenu Layout Default View. + + + 'Categories_List' + Set Tognee Layout Default View + Set Tognee Layout Default View. + + + true + Set Unity layout to display "Home Screen" as default + Set Unity layout to display "Home Screen" as default. False = Show all Apps + + + false + Remove the themes menu arrow and displacement + Remove the themes menu arrow and displacement + + + false + Remove border around the searchbox + Remove border around the searchbox + + + false + Disable the user avatar icon from the menu + Disable the user avatar icon from the menu + + + false + Enable an Activitities Overview Shortcut + Enable an Activitities Overview Shortcut + + + 'Bottom' + Searchbar location for layouts with default searchbar on bottom + Searchbar location for layouts with default searchbar on bottom + + + 'Top' + Searchbar location for layouts with default searchbar on top + Searchbar location for layouts with default searchbar on top + + + false + Flip menu horizontally + Flip menu horizontally + + + false + Windows layout - disable frequent apps + Windows layout - disable frequent apps + + + false + Windows layout - disable pinned apps + Windows layout - disable pinned apps + + + false + GNOME Dash Layout - Show Applications + GNOME Dash Layout - Show Applications + + + "rgb(61, 174, 235)" + Plasma Selected Item Color + Plasma Selected Item Color. + + + "rgba(245, 245, 245, .05)" + Plasma Selected Item Background Color + Plasma Selected Item Background Color. + + + true + Plasma Menu Hover to activate item + Plasma Menu Hover to activate item. + + + false + Runner layout - show frequent apps + Runner layout - show frequent apps + + + false + Runner layout - use current shell theme gap + Runner layout - use current shell theme gap + + + 400 + Runner layout - menu height + Runner layout - menu height + + + 500 + Runner layout - menu width + Runner layout - menu width + + + 0 + Runner layout - font size + Runner layout - font size + + + false + Eleven Layout - disable frequent apps + Eleven Layout - disable frequent apps + + + false + Used to reload theme + Used to reload theme. + + + false + Enable a vertical separator + Enable a vertical separator. + + + "rgb(32,32,32)" + Separator Color + Separator Color. + + + "rgba(53,53,53,0.987)" + Menu Background Color + Menu Background Color. + + + "rgb(223,223,223)" + Menu Foreground Color + Menu Foreground Color. + + + "rgb(32,32,32)" + Border Color + Border Color. + + + "rgb(21,83,158)" + Highlight/Active Menu Item Background Color + Highlight/Active Menu Item Background Color. + + + "rgba(255,255,255,1)" + Highlight/Active Menu Item Foreground Color + Highlight/Active Menu Item Foreground Color. + + + 9 + Menu font size + Menu font size. + + + 1 + Menu border size + Menu border size. + + + 5 + Menu corner radius + Menu corner radius. + + + 24 + Menu margin + Menu margin. + + + 12 + Menu arrow size + Menu arrow size. + + + 550 + Menu Height + Menu Height. + + + 290 + Menu width + Menu width. + + + 0 + Menu Width Adjustement. + Menu Width Adjustement. 0 Default. A negative value decreses the default width, positive increases width. + + + 205 + Right Panel width + Right Panel width. + + + 0 + Gap Adjustment + Gap Adjustment + + + "rgb(41, 165, 249)" + Recently Installed Application Inidcator Color + Recently Installed Application Inidcator Color.. + + + "rgba(196, 196, 196, 0.3)" + Recently Installed Application Inidcator Text Background Color + Recently Installed Application Inidcator Text Background Color.. + + + false + Enable Custom ArcMenu Theme + Enable Custom ArcMenu Theme. + + + false + Enable Custom ArcMenu Layout + Enable Custom ArcMenu Layout. + + + false + Show External Devices + Show External Devices. + + + false + Show Bookmarks + Show Bookmarks. + + + [(0, true), (1, true), (2, true), (3, true), (4, false), (5, false), (6, false)] + Power Options + See Constants.js PowerOptions + + + false + Display on all monitors + Display the menu on all monitors when using Dash to Panel. + + + 'Default' + Activities hotcorner action + Activities hotcorner action. + + + false + Override action of activities hot corner + Override action of activities hot corner. + + + false + Show/Hide Activities Button in panel + Show/Hide Activities Button in panel. + + + "sh -c 'notify-send \"$(date)\"'" + Custom hot corner terminal command + Custom hot corner terminal command. + + + 'Undefined' + Set a hotkey to open ArcMenu + Set a hotkey to open ArcMenu. + + + ["<Super>x"] + Custom keybind to open ArcMenu + Custom keybind to open ArcMenu. + + + false + Enable a standalone Runner menu. + Enable a standalone Runner menu. + + + 'Custom' + Set a hotkey to open the standalone Runner menu. + Set a hotkey to open the standalone Runner menu. + + + ["<Alt>1"] + Keybinding to open the standalone runner menu + Keybinding to open the standalone runner menu. + + + 'Left' + The menu position in the panel + The menu position in the panel. + + + 'Top' + Runner Menu Position + Runner Menu Position. + + + 'Icon' + Appearance of the menu button. + Appearance of the menu button. + + + 'Circular' + Appearance of the avatar icon. + Appearance of the avatar icon. + + + false + Enables the default menu button arrow. + Enables the default menu button arrow. + + + 'Default' + Size of the menu items icon. + Size of the menu items icon. Includes all application items, category items, search results. + + + 'Default' + Size of the menu grid icons. + Size of the menu grid icon. + + + 'Default' + Size of the button items in ArcMenu. + Size of the button items in ArcMenu. Includes all buttons inside the menu + + + 'Default' + Size of misc items in ArcMenu. + Size of misc items in ArcMenu. Includes searchbox icons, back menu item, all applications menu item, usermenu item. + + + 'Default' + Size of quicklink items in ArcMenu. + Size of quicklink items in ArcMenu. Includes places, shortcuts, external devices, bookmarks. + + + 'Applications' + Text of the menu button. + Text of the menu button. + + + 'Arc_Menu_Icon' + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + '' + File path of the custom icon for the menu button. + File path of the custom icon for the menu button. + + + 20 + Size of the icon in percentage. + Size of the icon in percentage. + + + -1 + Menu Button Padding. + Menu Button Padding. + + + 0 + Menu button position offset for main panel + Menu button position offset for main panel + + + false + Override border radius styling of the menu button + Override border radius of the menu button. + + + 0 + The border radius size of the menu button + The border radius size of the menu button. + + + 'rgb(240,240,240)' + Color for the menu button icon + Color for the menu button icon. + + + false + Allows changing the menu button icon color + Allows changing the menu button icon color. + + + 'rgb(240,240,240)' + Active color for the menu button icon + Active color for the menu button icon. + + + false + Allows changing the menu button icon active color + Allows changing the menu button icon active color. + + + 'rgb(214,214,214)' + Hover color for the menu button icon + Hover color for the menu button icon. + + + false + Allows changing the menu button icon hover color + Allows changing the menu button icon hover color. + + + 'rgba(238,238,236,0.1)' + Hover background color for the menu button icon + Hover background color for the menu button icon. + + + false + Allows changing the menu button hover background color + Allows changing the menu button hover background color. + + + 'rgba(238,238,236,0.18)' + Active background color for the menu button icon + Active background color for the menu button icon. + + + false + Allows changing the menu button active background color + Allows changing the menu button active background color. + + + [(0, true), (1, true), (2, false), (3, false), (4, false)] + Array of extra categories. See Constants.js - Categories + Array of extra categories. See Constants.js - Categories + + + [(0, false), (1, false), (2, false), (3, false), (4, false)] + Array of extra categories links for ArcMenu layout. See Constants.js - Categories + Array of extra categories for ArcMenu layout. See Constants.js - Categories + + + 'Bottom' + Display extra categories quick links on ArcMenu Layout home page + Display extra categories quick links on ArcMenu Layout home page + + + [] + List of recently installed apps + List of recently installed apps + + + [ "ArcMenu_WebBrowser","WebBrowser", "WebBrowser", + "Files", "", "org.gnome.Nautilus.desktop", + "Terminal", "", "org.gnome.Terminal.desktop", + "ArcMenu Settings", "ArcMenu_ArcMenuIcon", "gnome-extensions prefs arcmenu@arcmenu.com" + ] + + List of Apps Pinned to Menu + List of Apps Pinned to Menu + + + false + Toggle for enabling custom shortcuts. + Toggle for enabling custom shortcuts. + + + [["Home","ArcMenu_Home", "ArcMenu_Home"], ["Documents","ArcMenu_Documents", "ArcMenu_Documents"],["Downloads","ArcMenu_Downloads", "ArcMenu_Downloads"], + ["Music","ArcMenu_Music", "ArcMenu_Music"],["Pictures","ArcMenu_Pictures", "ArcMenu_Pictures"],["Videos","ArcMenu_Videos", "ArcMenu_Videos"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [["Software","system-software-install-symbolic", "ArcMenu_Software"], ["Settings","preferences-system-symbolic", "gnome-control-center.desktop"], + ["Tweaks","org.gnome.tweaks-symbolic", "org.gnome.tweaks.desktop"],["Terminal","utilities-terminal-symbolic", "org.gnome.Terminal.desktop"], + ["Activities Overview", "view-fullscreen-symbolic", "ArcMenu_ActivitiesOverview"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [] + List of Unity Layout Pinned Apps + List of Uniity Layout Pinned Apps + + + 5 + Index of Unity Layout Pinned App Separator + Index of Unity Layout Pinned App Separator, 0 = none + + + ["Software","system-software-install-symbolic", "ArcMenu_Software", "Settings","preferences-system-symbolic", "gnome-control-center.desktop"] + List of Brisk Layout Shortcuts + List of Brisk Layout Shortcuts + + + [] + List of Mint Layout Pinned Apps + List of Mint Layout Pinned Apps + + + 5 + Index of Mint Layout Pinned App Separator + Index of Mint Layout Pinned App Separator, 0 = none + + + [['ArcMenu Style', 'rgba(53,53,53,0.987)', 'rgb(223,223,223)', 'rgb(32,32,32)', 'rgb(21,83,158)', 'rgba(255,255,255,1)', 'rgb(32,32,32)', '9', '1', '5', '12', '24', 'false'], + ['Simply Dark', 'rgba(28, 28, 28, 0.98)', 'rgba(211, 218, 227, 1)', 'rgb(63,62,64)', 'rgba(238, 238, 236, 0.1)', 'rgba(255,255,255,1)', 'rgb(63,62,64)', '9', '0', '0', '0', '0', 'false'], + ['Dark Blue Theme', 'rgb(25,31,34)', 'rgb(189,230,251)', 'rgb(41,50,55)', 'rgb(41,50,55)', 'rgba(255,255,255,1)', 'rgb(41,50,55)', '9', '1', '5', '12', '24', 'true'], + ['Light Blue Theme', 'rgb(255,255,255)', 'rgb(51,51,51)', 'rgb(235,235,235)', 'rgba(189,230,251,0.9)', 'rgba(89,89,89,1)', 'rgba(189,230,251,0.9)', '9', '1', '5', '12', '24', 'true']] + List of color-themes + List of color themes. + + + + 0 + Handles which page to open in ArcMenu Settings + See Constants.js PrefsVisiblePage + + + diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/search.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/search.js new file mode 100644 index 0000000..9085c77 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/search.js @@ -0,0 +1,872 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from GNOME Shell search.js file + * (https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/search.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Clutter, Gio, GLib, GObject, Shell, St } = imports.gi; +const AppDisplay = imports.ui.appDisplay; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const RemoteSearch = imports.ui.remoteSearch; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const { OpenWindowSearchProvider } = Me.imports.searchProviders.openWindows; +const { RecentFilesSearchProvider } = Me.imports.searchProviders.recentFiles; + +const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers'; + +var ListSearchResult = GObject.registerClass(class Arc_Menu_ListSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']); + + super._init(menulayout, app, Constants.DisplayType.LIST, metaInfo) + + this.app = app; + let layoutProperties = this._menuLayout.layoutProperties; + this.searchType = layoutProperties.SearchDisplayType; + this.metaInfo = metaInfo; + this.provider = provider; + this._settings = this._menuLayout._settings; + this.resultsView = resultsView; + this.layout = this._settings.get_enum('menu-layout'); + + if(this.provider.id === 'org.gnome.Nautilus.desktop' || this.provider.id === 'arcmenu.recent-files') + this._path = this.metaInfo['description']; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.metaInfo['description'] && this.provider.appInfo.get_id() === 'org.gnome.Calculator.desktop' && !showSearchResultDescriptions) + this.label.text = this.metaInfo['name'] + " " + this.metaInfo['description']; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var AppSearchResult = GObject.registerClass(class Arc_Menu_AppSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']) || appSys.lookup_app(provider.id); + let displayType = menulayout.layoutProperties.SearchDisplayType; + super._init(menulayout, app, displayType, metaInfo); + this.app = app; + this.provider = provider; + this.metaInfo = metaInfo; + this.resultsView = resultsView; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.descriptionLabel.text.split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var SearchResultsBase = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResultsBase extends St.BoxLayout { + _init(provider, resultsView) { + super._init({ vertical: true }); + this.provider = provider; + this.resultsView = resultsView; + this._menuLayout = resultsView._menuLayout; + this._terms = []; + + this._resultDisplayBin = new St.Bin({ + x_expand: true, + y_expand: true + }); + + this.add_child(this._resultDisplayBin); + + this._resultDisplays = {}; + this._clipboard = St.Clipboard.get_default(); + + this._cancellable = new Gio.Cancellable(); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + this._terms = []; + } + + _createResultDisplay(meta) { + if (this.provider.createResultObject) + return this.provider.createResultObject(meta, this.resultsView); + + return null; + } + + clear() { + this._cancellable.cancel(); + for (let resultId in this._resultDisplays) + this._resultDisplays[resultId].destroy(); + this._resultDisplays = {}; + this._clearResultDisplay(); + this.hide(); + } + + _setMoreCount(count) { + } + + _ensureResultActors(results, callback) { + let metasNeeded = results.filter( + resultId => this._resultDisplays[resultId] === undefined + ); + + if (metasNeeded.length === 0) { + callback(true); + } else { + this._cancellable.cancel(); + this._cancellable.reset(); + + this.provider.getResultMetas(metasNeeded, metas => { + if (this._cancellable.is_cancelled()) { + if (metas.length > 0) + log(`Search provider ${this.provider.id} returned results after the request was canceled`); + callback(false); + return; + } + if (metas.length != metasNeeded.length) { + log('Wrong number of result metas returned by search provider ' + this.provider.id + + ': expected ' + metasNeeded.length + ' but got ' + metas.length); + callback(false); + return; + } + if (metas.some(meta => !meta.name || !meta.id)) { + log('Invalid result meta returned from search provider ' + this.provider.id); + callback(false); + return; + } + + metasNeeded.forEach((resultId, i) => { + let meta = metas[i]; + let display = this._createResultDisplay(meta); + this._resultDisplays[resultId] = display; + }); + callback(true); + }, this._cancellable); + } + } + + updateSearch(providerResults, terms, callback) { + this._terms = terms; + if (providerResults.length == 0) { + this._clearResultDisplay(); + this.hide(); + callback(); + } else { + let maxResults = this._getMaxDisplayedResults(); + let results = this.provider.filterResults(providerResults, maxResults); + let moreCount = Math.max(providerResults.length - results.length, 0); + + this._ensureResultActors(results, successful => { + if (!successful) { + this._clearResultDisplay(); + callback(); + return; + } + + // To avoid CSS transitions causing flickering when + // the first search result stays the same, we hide the + // content while filling in the results. + this.hide(); + this._clearResultDisplay(); + results.forEach(resultId => { + this._addItem(this._resultDisplays[resultId]); + }); + + this._setMoreCount(this.provider.canLaunchSearch ? moreCount : 0); + this.show(); + callback(); + }); + } + } +}); + +var ListSearchResults = GObject.registerClass( +class ArcMenu_ListSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._menuLayout = resultsView._menuLayout; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._container = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + x_expand: true, + y_expand: true, + }); + + if(this.searchType === Constants.DisplayType.GRID){ + this.add_style_class_name('margin-box'); + } + + this.providerInfo = new ArcSearchProviderInfo(provider, this._menuLayout); + this.providerInfo.connect('activate', () => { + if (provider.canLaunchSearch) { + provider.launchSearch(this._terms); + this._menuLayout.arcMenu.toggle(); + } + }); + + this._container.add_child(this.providerInfo); + + this._content = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + + this._container.add_child(this._content); + this._resultDisplayBin.set_child(this._container); + } + + _setMoreCount(count) { + this.providerInfo.setMoreCount(count); + } + + _getMaxDisplayedResults() { + return this._settings.get_int('max-search-results'); + } + + _clearResultDisplay() { + this._content.remove_all_children(); + } + + _createResultDisplay(meta) { + return super._createResultDisplay(meta, this.resultsView) || + new ListSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + if(display.get_parent()) + display.get_parent().remove_child(display); + this._content.add_child(display); + } + + getFirstResult() { + if (this._content.get_n_children() > 0) + return this._content.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var AppSearchResults = GObject.registerClass( +class ArcMenu_AppSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._parentContainer = resultsView; + this._menuLayout = resultsView._menuLayout; + this._settings = this._menuLayout._settings; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this.layout = this._menuLayout._settings.get_enum('menu-layout'); + + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + + this.rtl = this._menuLayout.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.ColumnSpacing : 0, + row_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.RowSpacing : 0, + }); + this._grid = new St.Widget({ + x_expand: true, + x_align: this.searchType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this._grid); + + if(this.searchType === Constants.DisplayType.GRID){ + let spacing = this.layoutProperties.ColumnSpacing; + + this._grid.style = "padding: 0px 0px 10px 0px; spacing: " + spacing + "px;"; + this._resultDisplayBin.x_align = Clutter.ActorAlign.CENTER; + } + + this._resultDisplayBin.set_child(this._grid); + } + + _getMaxDisplayedResults() { + let maxDisplayedResults; + if(this.searchType === Constants.DisplayType.GRID) + maxDisplayedResults = this._menuLayout.getColumnsFromGridIconSizeSetting(); + else + maxDisplayedResults = this._settings.get_int('max-search-results'); + return maxDisplayedResults; + } + + _clearResultDisplay() { + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + this._grid.remove_all_children(); + } + + _createResultDisplay(meta) { + return new AppSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + const GridColumns = this.searchType === Constants.DisplayType.LIST ? 1 : this._menuLayout.getColumnsFromGridIconSizeSetting(); + if(!this.rtl && (this.itemCount % GridColumns === 0)){ + this.gridTop++; + this.gridLeft = 0; + } + else if(this.rtl && (this.gridLeft === 0)){ + this.gridTop++; + this.gridLeft = GridColumns; + } + this._grid.layout_manager.attach(display, this.gridLeft, this.gridTop, 1, 1); + display.gridLocation = [this.gridLeft, this.gridTop]; + + if(!this.rtl) + this.gridLeft++; + else if(this.rtl) + this.gridLeft--; + this.itemCount++; + } + + getFirstResult() { + if (this._grid.get_n_children() > 0) + return this._grid.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var SearchResults = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'have-results': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResults extends St.BoxLayout { + _init(menuLayout) { + super._init({ + vertical: true, + y_expand: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + this._menuLayout = menuLayout; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._content = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL + }); + + this.add_child(this._content); + + this._statusText = new St.Label(); + this._statusBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true, + y_expand: true + }); + + if(menuLayout._settings.get_boolean('enable-custom-arc-menu')) + this._statusText.style_class = 'arc-menu-status-text'; + else + this._statusText.style_class = ''; + + this.add_child(this._statusBin); + this._statusBin.set_child(this._statusText); + + this._highlightDefault = true; + this._defaultResult = null; + this._startingSearch = false; + + this._terms = []; + this._results = {}; + + this._providers = []; + + this._highlightRegex = null; + + this.recentFilesManager = new RecentFilesManager(); + + this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA }); + this.disabledID = this._searchSettings.connect('changed::disabled', this._reloadRemoteProviders.bind(this)); + this.enabledID = this._searchSettings.connect('changed::enabled', this._reloadRemoteProviders.bind(this)); + this.disablExternalID = this._searchSettings.connect('changed::disable-external', this._reloadRemoteProviders.bind(this)); + this.sortOrderID = this._searchSettings.connect('changed::sort-order', this._reloadRemoteProviders.bind(this)); + + this._searchTimeoutId = null; + this._cancellable = new Gio.Cancellable(); + + this._registerProvider(new AppDisplay.AppSearchProvider()); + + this.installChangedID = appSys.connect('installed-changed', this._reloadRemoteProviders.bind(this)); + + this._reloadRemoteProviders(); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + get terms() { + return this._terms; + } + + setStyle(style){ + if(this._statusText){ + this._statusText.style_class = style; + } + } + + _onDestroy(){ + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + if(this.disabledID){ + this._searchSettings.disconnect(this.disabledID); + this.disabledID = null; + } + if(this.enabledID){ + this._searchSettings.disconnect(this.enabledID); + this.enabledID = null; + } + if(this.disablExternalID){ + this._searchSettings.disconnect(this.disablExternalID); + this.disablExternalID = null; + } + if(this.sortOrderID){ + this._searchSettings.disconnect(this.sortOrderID); + this.sortOrderID = null; + } + if(this.installChangedID){ + appSys.disconnect(this.installChangedID); + this.installChangedID = null; + } + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + + this._content.destroy_all_children(); + } + + _reloadRemoteProviders() { + let currentTerms = this._terms; + //cancel any active search + if (this._terms.length !== 0) + this._reset(); + + this._oldProviders = null; + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + if(this._settings.get_boolean('search-provider-open-windows')) + this._registerProvider(new OpenWindowSearchProvider()); + if(this._settings.get_boolean('search-provider-recent-files')) + this._registerProvider(new RecentFilesSearchProvider(this.recentFilesManager)); + + RemoteSearch.loadRemoteSearchProviders(this._searchSettings, providers => { + providers.forEach(this._registerProvider.bind(this)); + }); + + //restart any active search + if(currentTerms.length > 0) + this.setTerms(currentTerms); + } + + _registerProvider(provider) { + provider.searchInProgress = false; + this._providers.push(provider); + this._ensureProviderDisplay(provider); + } + + _unregisterProvider(provider) { + let index = this._providers.indexOf(provider); + this._providers.splice(index, 1); + + if (provider.display){ + provider.display.destroy(); + } + } + + _gotResults(results, provider) { + this._results[provider.id] = results; + this._updateResults(provider, results); + } + + _clearSearchTimeout() { + if (this._searchTimeoutId) { + GLib.source_remove(this._searchTimeoutId); + this._searchTimeoutId = null; + } + } + + _reset() { + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + + this._updateSearchProgress(); + } + + _doSearch() { + this._startingSearch = false; + + let previousResults = this._results; + this._results = {}; + + this._providers.forEach(provider => { + provider.searchInProgress = true; + + let previousProviderResults = previousResults[provider.id]; + if (this._isSubSearch && previousProviderResults) + provider.getSubsearchResultSet(previousProviderResults, + this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + else + provider.getInitialResultSet(this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + }); + + this._updateSearchProgress(); + + this._clearSearchTimeout(); + } + + _onSearchTimeout() { + this._searchTimeoutId = null; + this._doSearch(); + return GLib.SOURCE_REMOVE; + } + + setTerms(terms) { + // Check for the case of making a duplicate previous search before + // setting state of the current search or cancelling the search. + // This will prevent incorrect state being as a result of a duplicate + // search while the previous search is still active. + let searchString = terms.join(' '); + let previousSearchString = this._terms.join(' '); + if (searchString == previousSearchString) + return; + + this._startingSearch = true; + + this.recentFilesManager.cancelCurrentQueries(); + + this._cancellable.cancel(); + this._cancellable.reset(); + + if (terms.length == 0) { + this._reset(); + return; + } + + let isSubSearch = false; + if (this._terms.length > 0) + isSubSearch = searchString.indexOf(previousSearchString) == 0; + + this._terms = terms; + this._isSubSearch = isSubSearch; + this._updateSearchProgress(); + + if (this._searchTimeoutId === null) + this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, this._onSearchTimeout.bind(this)); + + + + const escapedTerms = terms + .map(term => Shell.util_regex_escape(term)) + .filter(term => term.length > 0); + + if (escapedTerms.length === 0) + return; + + this._highlightRegex = new RegExp('(%s)'.format( + escapedTerms.join('|')), 'gi'); + + this.emit('terms-changed'); + } + + _ensureProviderDisplay(provider) { + if (provider.display) + return; + + let providerDisplay; + if (provider.appInfo) + providerDisplay = new ListSearchResults(provider, this); + else + providerDisplay = new AppSearchResults(provider, this); + providerDisplay.hide(); + this._content.add_child(providerDisplay); + provider.display = providerDisplay; + } + + _clearDisplay() { + this._providers.forEach(provider => { + provider.display.clear(); + }); + } + + _maybeSetInitialSelection() { + let newDefaultResult = null; + + let providers = this._providers; + for (let i = 0; i < providers.length; i++) { + let provider = providers[i]; + let display = provider.display; + + if (!display.visible) + continue; + + let firstResult = display.getFirstResult(); + if (firstResult) { + newDefaultResult = firstResult; + break; // select this one! + } + } + + if (newDefaultResult !== this._defaultResult) { + this._setSelected(this._defaultResult, false); + this._setSelected(newDefaultResult, this._highlightDefault); + + this._defaultResult = newDefaultResult; + } + } + + get searchInProgress() { + if (this._startingSearch) + return true; + + return this._providers.some(p => p.searchInProgress); + } + + _updateSearchProgress() { + let haveResults = this._providers.some(provider => { + let display = provider.display; + return (display.getFirstResult() != null); + }); + + this._statusBin.visible = !haveResults; + if (haveResults) + this.emit("have-results") + else if (!haveResults) { + if (this.searchInProgress) + this._statusText.set_text(_("Searching...")); + else + this._statusText.set_text(_("No results.")); + + this.emit("no-results") + } + } + + _updateResults(provider, results) { + let terms = this._terms; + let display = provider.display; + display.updateSearch(results, terms, () => { + provider.searchInProgress = false; + + this._maybeSetInitialSelection(); + this._updateSearchProgress(); + }); + } + + highlightDefault(highlight) { + this._highlightDefault = highlight; + this._setSelected(this._defaultResult, highlight); + } + + getTopResult(){ + return this._defaultResult; + } + + getProviders(){ + return this._providers; + } + + setProvider(providerID){ + if(!this._oldProviders) + this._oldProviders = this._providers; + this._clearDisplay(); + this._providers = this._oldProviders; + if(providerID === Constants.CategoryType.ALL_PROGRAMS){ + this._providers = this._providers.filter(p => (p.appInfo ? false : true)); + } + else if(providerID !== Constants.CategoryType.SEARCH_RESULTS){ + this._providers = this._providers.filter(p => (p.appInfo ? p.appInfo.get_id() : p) === providerID); + } + } + + _setSelected(result, selected) { + if(!result) + return; + + if(selected) + result.add_style_pseudo_class('active'); + else + result.remove_style_pseudo_class('active'); + } + + hasActiveResult(){ + return (this._defaultResult ? true : false) && this._highlightDefault; + } + + highlightTerms(text) { + if (!this._highlightRegex) + return GLib.markup_escape_text(text, -1); + + let escaped = []; + let lastMatchEnd = 0; + let match; + while ((match = this._highlightRegex.exec(text))) { + if (match.index > lastMatchEnd) { + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd, match.index), -1); + escaped.push(unmatched); + } + let matched = GLib.markup_escape_text(match[0], -1); + escaped.push('%s'.format(matched)); + lastMatchEnd = match.index + match[0].length; + } + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd), -1); + escaped.push(unmatched); + + return escaped.join(''); + } +}); + +var ArcSearchProviderInfo = GObject.registerClass(class Arc_Menu_ArcSearchProviderInfo extends MW.ArcMenuPopupBaseMenuItem{ + _init(provider, menuLayout) { + super._init(menuLayout); + this.provider = provider; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this.description = this.provider.appInfo.get_description(); + if(this.description) + this.description = this.description.split('\n')[0]; + + this.label = new St.Label({ + text: provider.appInfo.get_name(), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + style: 'text-align: left;' + }); + + this.label.style = 'font-weight: bold;'; + this.style = "padding: 10px 0px;"; + this.add_child(this.label); + + this._moreText = ""; + } + + setMoreCount(count) { + this._moreText = ngettext("%d more", "%d more", count).format(count); + + if(count > 0) + this.label.text = this.provider.appInfo.get_name() + " (" + this._moreText + ")"; + else + this.label.text = this.provider.appInfo.get_name(); + } +}); diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js new file mode 100644 index 0000000..933a1e6 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js @@ -0,0 +1,93 @@ +const { Meta, Gio, St, Shell } = imports.gi; + +const Main = imports.ui.main; +const { getWindows } = imports.ui.altTab; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(app, size) { + return app + ? app.create_icon_texture(size) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var OpenWindowSearchProvider = class { + constructor() { + this.id = 'arcmenu.open-windows'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + + this._appWindows = []; + this._windowTracker = Shell.WindowTracker.get_default(); + + this.appInfo = { + get_description: () => _('List of open windows across all workspaces'), + get_name: () => _('Open Windows'), + get_id: () => 'arcmenu.open-windows', + get_icon: () => Gio.icon_new_for_string('focus-windows-symbolic'), + } + } + + getResultMetas(winIds, callback) { + const metas = winIds.map(winId => { + const aw = this._getAppWindow(winId); + return aw ? { + id: winId, + name: aw.window.title ?? aw.app.get_name(), + description: aw.window.get_workspace() ? _("'%s' on Workspace %d").format(aw.app.get_name(), aw.window.get_workspace().index() + 1) : aw.app.get_name(), + createIcon: (size) => createIcon(aw.app, size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this._appWindows = getWindows(null).map(window => { + return { + window, + app: this._windowTracker.get_window_app(window), + } + }); + + callback(this._getFilteredWindowIds(terms, this._appWindows)); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const appWindows = previousResults.map(winId => this._getAppWindow(winId)).filter(aw => aw !== undefined); + callback(this._getFilteredWindowIds(terms, appWindows)); + } + + activateResult(winId, _terms) { + const window = this._getAppWindow(winId)?.window; + if (window) + Main.activateWindow(window); + } + + launchSearch() { + + } + + _getFilteredWindowIds(terms, appWindows) { + terms = terms.map(term => term.toLowerCase()); + appWindows = appWindows.filter(aw => { + const title = aw.window.title?.toLowerCase(); + const appName = aw.app.get_name()?.toLowerCase(); + const appDescription = aw.app.get_description()?.toLowerCase(); + return terms.some(term => title?.includes(term) || appName?.includes(term) || appDescription?.includes(term)); + }); + + return appWindows.map(aw => aw.window.get_id().toString()); + } + + _getAppWindow(winId) { + winId = typeof winId === "string" ? parseInt(winId) : winId; + return this._appWindows.find(aw => aw.window.get_id() === winId); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js new file mode 100644 index 0000000..fb595e4 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js @@ -0,0 +1,100 @@ +const { Meta, Gtk, Gio, GLib, St, Shell } = imports.gi; + +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(mimeType, size) { + let symbolicIcon = mimeType ? Gio.content_type_get_symbolic_icon(mimeType)?.to_string() : null; + return symbolicIcon + ? new St.Icon({ gicon: Gio.icon_new_for_string(symbolicIcon), icon_size: size }) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var RecentFilesSearchProvider = class { + constructor(recentFilesManager) { + this.id = 'arcmenu.recent-files'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + this.recentFilesManager = recentFilesManager; + this._recentFiles = []; + + this.appInfo = { + get_description: () => _('Recent Files'), + get_name: () => _('Recent Files'), + get_id: () => 'arcmenu.recent-files', + get_icon: () => Gio.icon_new_for_string('document-open-recent-symbolic'), + } + } + + getResultMetas(fileUris, callback) { + const metas = fileUris.map(fileUri => { + const rf = this._getRecentFile(fileUri); + const file = Gio.File.new_for_uri(rf.get_uri()); + return rf ? { + id: fileUri, + name: rf.get_display_name(), + description: file.get_parent()?.get_path(), // can be null + createIcon: (size) => createIcon(rf.get_mime_type(), size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this.recentFilesManager.cancelCurrentQueries(); + this._recentFiles = []; + this.recentFilesManager.filterRecentFiles(recentFile => { + this._recentFiles.push(recentFile); + callback(this._getFilteredFileUris(terms, this._recentFiles)); + }); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const recentFiles = previousResults.map(fileUri => this._getRecentFile(fileUri)).filter(rf => rf !== undefined); + callback(this._getFilteredFileUris(terms, recentFiles)); + } + + activateResult(fileUri, _terms) { + const recentFile = this._getRecentFile(fileUri); + if (recentFile){ + let context = global.create_app_launch_context(0, -1); + + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(recentFile.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(recentFile.get_display_name()), e.message); + reject(e); + } + }); + }); + } + } + + launchSearch() { + } + + _getFilteredFileUris(terms, recentFiles) { + terms = terms.map(term => term.toLowerCase()); + recentFiles = recentFiles.filter(rf => { + const fileName = rf.get_display_name()?.toLowerCase(); + return terms.some(term => fileName?.includes(term)); + }); + + return recentFiles.map(rf => rf.get_uri()); + } + + _getRecentFile(fileUri) { + return this._recentFiles.find(rf => rf.get_uri() === fileUri); + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js new file mode 100644 index 0000000..6c0613d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var StandaloneRunner = class Arc_Menu_StandaloneRunner{ + constructor(settings) { + this._settings = settings; + + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this.dummyWidget, 0.5, St.Side.TOP, this); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(Main.panel); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + let rect = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryMonitor.index); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + this.rise; + this.dummyWidget.set_position(positionX, positionY); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.subMenuManager._changeMenu = (menu) => {}; + } + + initiate(){ + this.initiateRecentlyInstalledApps(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._forcedMenuLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._forcedMenuLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(this.MenuLayout) + this.MenuLayout.updateStyle(); + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + if(!this.arcMenu.isOpen){ + this.MenuLayout.updateLocation(); + this.arcMenu.toggle(); + if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else + return null; + } + + destroy(){ + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.dummyWidget){ + Main.uiGroup.remove_child(this.dummyWidget); + this.dummyWidget.destroy(); + } + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + } + } +}; + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide, standaloneRunner) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this.standaloneRunner = standaloneRunner; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this.standaloneRunner.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this.standaloneRunner.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this.standaloneRunner.contextMenuManager.activeMenu) + this.standaloneRunner.contextMenuManager.activeMenu.toggle(); + if(this.standaloneRunner.subMenuManager.activeMenu) + this.standaloneRunner.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/utils.js b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/utils.js new file mode 100644 index 0000000..92207b5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/arcmenu@arcmenu.com/utils.js @@ -0,0 +1,687 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Constants = Me.imports.constants; +const {Gio, GLib} = imports.gi; + +const PowerManagerInterface = ` + + + + + + + + + + + + + + +`; +const PowerManager = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface); + +function canHibernate(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHibernate = needsAuth || result[0] === 'yes'; + asyncCallback(canHibernate, needsAuth); + } + }); +} + +function activateHibernate(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hibernate Error!"), _("System unable to hibernate.")); + else{ + proxy.HibernateRemote(true); + } + }); +} + +function canHybridSleep(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHybridSleep = needsAuth || result[0] === 'yes'; + asyncCallback(canHybridSleep, needsAuth); + } + }); +} + +function activateHybridSleep(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hybrid Sleep Error!"), _("System unable to hybrid sleep.")); + else{ + proxy.HybridSleepRemote(true); + } + }); +} + +function getMenuLayout(menuButton, layout, isStandaloneRunner){ + let MenuLayout = Me.imports.menulayouts; + switch(layout){ + case Constants.MenuLayout.ARCMENU: + return new MenuLayout.arcmenu.createMenu(menuButton); + case Constants.MenuLayout.BRISK: + return new MenuLayout.brisk.createMenu(menuButton); + case Constants.MenuLayout.WHISKER: + return new MenuLayout.whisker.createMenu(menuButton); + case Constants.MenuLayout.GNOME_MENU: + return new MenuLayout.gnomemenu.createMenu(menuButton); + case Constants.MenuLayout.MINT: + return new MenuLayout.mint.createMenu(menuButton); + case Constants.MenuLayout.GNOME_OVERVIEW: + return null; + case Constants.MenuLayout.ELEMENTARY: + return new MenuLayout.elementary.createMenu(menuButton); + case Constants.MenuLayout.REDMOND: + return new MenuLayout.redmond.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE: + return new MenuLayout.simple.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE_2: + return new MenuLayout.simple2.createMenu(menuButton); + case Constants.MenuLayout.UNITY: + return new MenuLayout.unity.createMenu(menuButton); + case Constants.MenuLayout.BUDGIE: + return new MenuLayout.budgie.createMenu(menuButton); + case Constants.MenuLayout.INSIDER: + return new MenuLayout.insider.createMenu(menuButton); + case Constants.MenuLayout.RUNNER: + return new MenuLayout.runner.createMenu(menuButton, isStandaloneRunner); + case Constants.MenuLayout.CHROMEBOOK: + return new MenuLayout.chromebook.createMenu(menuButton); + case Constants.MenuLayout.RAVEN: + return new MenuLayout.raven.createMenu(menuButton); + case Constants.MenuLayout.TOGNEE: + return new MenuLayout.tognee.createMenu(menuButton); + case Constants.MenuLayout.PLASMA: + return new MenuLayout.plasma.createMenu(menuButton); + case Constants.MenuLayout.WINDOWS: + return new MenuLayout.windows.createMenu(menuButton); + case Constants.MenuLayout.LAUNCHER: + return new MenuLayout.launcher.createMenu(menuButton); + case Constants.MenuLayout.ELEVEN: + return new MenuLayout.eleven.createMenu(menuButton); + case Constants.MenuLayout.AZ: + return new MenuLayout.az.createMenu(menuButton); + default: + return new MenuLayout.arcmenu.createMenu(menuButton); + } +} + +function getSettings(schema, extensionUUID) { + let extension = imports.ui.main.extensionManager.lookup(extensionUUID); + + if (!extension) + throw new Error('ArcMenu - getSettings() unable to find extension'); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Expect USER extensions to have a schemas/ subfolder, otherwise assume a + // SYSTEM extension that has been installed in the same prefix as the shell + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error(`Schema ${schema} could not be found for extension ${extension.metadata.uuid}. Please check your installation`); + + return new Gio.Settings({ settings_schema: schemaObj }); +} + +function convertToGridLayout(item){ + const Clutter = imports.gi.Clutter; + const settings = item._settings; + const layoutProperties = item._menuLayout.layoutProperties; + + let icon = item._icon ? item._icon : item._iconBin; + + item.vertical = true; + if(item._ornamentLabel) + item.remove_child(item._ornamentLabel); + + item.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + item.label.x_align = item.label.y_align = Clutter.ActorAlign.CENTER; + item.label.y_expand = true; + + icon.y_align = Clutter.ActorAlign.CENTER; + icon.y_expand = true; + if(settings.get_boolean('multi-lined-labels')){ + icon.y_align = Clutter.ActorAlign.TOP; + icon.y_expand = false; + + let clutterText = item.label.get_clutter_text(); + clutterText.set({ + line_wrap: true, + line_wrap_mode: imports.gi.Pango.WrapMode.WORD_CHAR, + }); + } + + if(item._indicator){ + item.remove_child(item._indicator); + item.insert_child_at_index(item._indicator, 0); + item._indicator.x_align = Clutter.ActorAlign.CENTER; + item._indicator.y_align = Clutter.ActorAlign.START; + item._indicator.y_expand = false; + } + + const iconSizeEnum = settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = layoutProperties.DefaultIconGridStyle; + + iconSize = getGridIconStyle(iconSizeEnum, defaultIconStyle); + item.name = iconSize; +} + +function getIconSize(iconSizeEnum, defaultIconSize){ + const IconSizeEnum = iconSizeEnum; + let iconSize = defaultIconSize; + if(IconSizeEnum === Constants.IconSize.DEFAULT) + iconSize = defaultIconSize; + else if(IconSizeEnum === Constants.IconSize.EXTRA_SMALL) + iconSize = Constants.EXTRA_SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.SMALL) + iconSize = Constants.SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.MEDIUM) + iconSize = Constants.MEDIUM_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.LARGE) + iconSize = Constants.LARGE_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.EXTRA_LARGE) + iconSize = Constants.EXTRA_LARGE_ICON_SIZE; + + return iconSize; +} + +function getGridIconSize(iconSizeEnum, defaultIconStyle){ + let iconSize; + if(iconSizeEnum === Constants.GridIconSize.DEFAULT){ + Constants.GridIconInfo.forEach((info) => { + if(info.NAME === defaultIconStyle){ + iconSize = info.ICON_SIZE; + } + }); + } + else + iconSize = Constants.GridIconInfo[iconSizeEnum - 1].ICON_SIZE; + + return iconSize; +} + +function getGridIconStyle(iconSizeEnum, defaultIconStyle){ + const IconSizeEnum = iconSizeEnum; + let iconStyle = defaultIconStyle; + if(IconSizeEnum === Constants.GridIconSize.DEFAULT) + iconStyle = defaultIconStyle; + else if(IconSizeEnum === Constants.GridIconSize.SMALL) + iconStyle = 'SmallIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM) + iconStyle = 'MediumIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE) + iconStyle = 'LargeIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.SMALL_RECT) + iconStyle = 'SmallRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM_RECT) + iconStyle = 'MediumRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE_RECT) + iconStyle = 'LargeRectIconGrid'; + + return iconStyle; +} + +function getCategoryDetails(currentCategory, categoryIconType){ + let name, gicon, iconName, fallbackIconName; + for(let entry of Constants.Categories){ + if(entry.CATEGORY === currentCategory){ + name = entry.NAME; + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + iconName = entry.FULL_COLOR_ICON; + else + iconName = entry.ICON; + return [name, gicon, iconName, fallbackIconName]; + } + } + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + name = _("Home Screen"); + gicon = Gio.icon_new_for_string(Me.path + '/media/icons/menu_icons/homescreen-symbolic.svg'); + return [name, gicon, iconName, fallbackIconName]; + } + else{ + name = currentCategory.get_name(); + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + gicon = currentCategory.get_icon() ? currentCategory.get_icon() : null; + else + iconName = currentCategory.get_icon().to_string() + "-symbolic"; + fallbackIconName = currentCategory.get_icon() ? currentCategory.get_icon().to_string() : null; + return [name, gicon, iconName, fallbackIconName]; + } +} + +function activateCategory(currentCategory, menuLayout, menuItem, extraParams = false){ + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + menuLayout.activeCategory = _("Pinned Apps"); + menuLayout.displayPinnedApps(); + } + else if(currentCategory === Constants.CategoryType.PINNED_APPS) + menuLayout.displayPinnedApps(); + else if(currentCategory === Constants.CategoryType.FREQUENT_APPS){ + menuLayout.setFrequentAppsList(menuItem); + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + } + else if(currentCategory === Constants.CategoryType.ALL_PROGRAMS) + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + else if(currentCategory === Constants.CategoryType.RECENT_FILES) + menuLayout.displayRecentFiles(); + else + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + + menuLayout.activeCategoryType = currentCategory; +} + +function getMenuButtonIcon(settings, path){ + let iconType = settings.get_enum('menu-button-icon'); + + if(iconType === Constants.MenuIcon.CUSTOM){ + if(path && GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else if(iconType === Constants.MenuIcon.DISTRO_ICON){ + let iconEnum = settings.get_int('distro-icon'); + path = Me.path + Constants.DistroIcons[iconEnum].PATH; + if(Constants.DistroIcons[iconEnum].PATH === 'start-here-symbolic') + return 'start-here-symbolic'; + else if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else{ + let iconEnum = settings.get_int('arc-menu-icon'); + path = Me.path + Constants.MenuIcons[iconEnum].PATH; + if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + + global.log("ArcMenu Error - Failed to set menu button icon. Set to System Default."); + return 'start-here-symbolic'; +} + +function findSoftwareManager(){ + let softwareManager = null; + let appSys = imports.gi.Shell.AppSystem.get_default(); + + for(let softwareManagerID of Constants.SoftwareManagerIDs){ + if(appSys.lookup_app(softwareManagerID)){ + softwareManager = softwareManagerID; + break; + } + } + + return softwareManager; +} + +function createXpmImage(color1, color2, color3, color4){ + let width = 42; + let height = 14; + let colors = 5; + let xpm = [width + " " + height + " " + colors + " " + 1, "1 c " + rgbStringToHex(color1), "2 c " + rgbStringToHex(color2), + "3 c " + rgbStringToHex(color3), "4 c " + rgbStringToHex(color4), "x c #AAAAAA"]; + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + for(let i = 0; i < height - 2; i++) + xpm.push("x1111111111222222222233333333334444444444x"); + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + return xpm; +} + +function areaOfTriangle(p1, p2, p3){ + return Math.abs((p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1])) / 2.0); +} + +function ensureActorVisibleInScrollView(actor) { + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2; + + let parent = actor.get_parent(); + while (!(parent instanceof imports.gi.St.ScrollView)) { + if (!parent) + return; + + box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + parent = parent.get_parent(); + } + + let adjustment = parent.vscroll.adjustment; + let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values(); + + let offset = 0; + let vfade = parent.get_effect("fade"); + if (vfade) + offset = vfade.fade_margins.top; + + if (y1 < value + offset) + value = Math.max(0, y1 - offset); + else if (y2 > value + pageSize - offset) + value = Math.min(upper, y2 + offset - pageSize); + else + return; + adjustment.set_value(value); +} + +function getArraysEqual(a, b) { + if(a instanceof Array && b instanceof Array){ + if (a.length !== b.length) + return false; + for(let i = 0; i < a.length; i++) + if (!getArraysEqual(a[i], b[i])) + return false; + return true; + } + else + return a === b; +} + +function createTooltip(button, widget, titleLabel, description, displayType){ + let lbl = titleLabel.clutter_text; + lbl.get_allocation_box(); + let isEllipsized = lbl.get_layout().is_ellipsized(); + if(displayType !== Constants.DisplayType.BUTTON && (isEllipsized || description)){ + let titleText, descriptionText; + if(isEllipsized && description){ + titleText = titleLabel.text.replace(/\n/g, " "); + descriptionText = description; + } + else if(isEllipsized && !description) + titleText = titleLabel.text.replace(/\n/g, " "); + else if(!isEllipsized && description) + descriptionText = description; + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, descriptionText); + widget.tooltip._onHover(); + } + else if(displayType === Constants.DisplayType.BUTTON){ + let titleText = titleLabel.text.replace(/\n/g, " "); + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, null); + widget.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + widget.tooltip._onHover(); + } +} + +function getDashToPanelPosition(settings, index){ + var positions = null; + var side; + + try{ + positions = JSON.parse(settings.get_string('panel-positions')) + } catch(e){ + log('Error parsing Dash to Panel positions: ' + e.message); + } + + if(!positions) + side = settings.get_string('panel-position'); + else{ + side = positions[index]; + } + + if (side === 'TOP') + return imports.gi.St.Side.TOP; + else if (side === 'RIGHT') + return imports.gi.St.Side.RIGHT; + else if (side === 'BOTTOM') + return imports.gi.St.Side.BOTTOM; + else if (side === 'LEFT') + return imports.gi.St.Side.LEFT; + else + return imports.gi.St.Side.BOTTOM; +} + +function getStylesheet(){ + let stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + + if(!stylesheet.query_exists(null)){ + GLib.spawn_command_line_sync("mkdir " + GLib.get_home_dir() + "/.local/share/arcmenu"); + GLib.spawn_command_line_sync("touch " + GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + } + + return stylesheet; +} + +function rgbStringToHex(colorString) { + let [r, g, b, a_] = parseRgbString(colorString) + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); +} + +function clutterColorToRGBA(color) { + return `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`; +} + +function parseRgbString(colorString){ + if(colorString.includes('rgba')) + colorString = colorString.replace('rgba(',''); + if(colorString.includes('rgb')) + colorString = colorString.replace('rgb(',''); + colorString = colorString.replace(')',''); + let rgbaColor = colorString.split(","); + + let r = parseFloat(rgbaColor[0]); + let g = parseFloat(rgbaColor[1]); + let b = parseFloat(rgbaColor[2]); + let a; + if(rgbaColor[3] != undefined) + a = parseFloat(rgbaColor[3]); + else + a = 1; + return [r, g, b, a]; +} + +function modifyColorLuminance(colorString, luminanceFactor, overrideAlpha){ + let Clutter = imports.gi.Clutter; + let color = Clutter.color_from_string(colorString)[1]; + let [hue, lum, sat] = color.to_hls(); + let modifiedLum = lum; + + if(lum >= .85) //if lum is too light, force darken + modifiedLum = Math.min((1 - Math.abs(luminanceFactor)) * modifiedLum, 1); + else if(lum <= .15) //if lum is too dark, force lighten + modifiedLum = Math.max((1 - Math.abs(luminanceFactor)) * modifiedLum, 0); + else if(luminanceFactor >= 0) //otherwise, darken or lighten based on luminanceFactor + modifiedLum = Math.min((1 + luminanceFactor) * modifiedLum, 1); + else + modifiedLum = Math.max((1 + luminanceFactor) * modifiedLum, 0); + + let alpha = (color.alpha / 255).toPrecision(3); + if(overrideAlpha) + alpha = overrideAlpha; + + let modifiedColor = Clutter.color_from_hls(hue, modifiedLum, sat); + + return `rgba(${modifiedColor.red}, ${modifiedColor.green}, ${modifiedColor.blue}, ${alpha})` +} + +function createStylesheet(settings){ + let customarcMenu = settings.get_boolean('enable-custom-arc-menu'); + let separatorColor = settings.get_string('separator-color'); + let menuColor = settings.get_string('menu-color'); + let menuForegroundColor = settings.get_string('menu-foreground-color'); + let borderColor = settings.get_string('border-color'); + let highlightColor = settings.get_string('highlight-color'); + let highlightForegroundColor = settings.get_string('highlight-foreground-color'); + let fontSize = settings.get_int('menu-font-size'); + let borderSize = settings.get_int('menu-border-size'); + let cornerRadius = settings.get_int('menu-corner-radius'); + let menuMargin = settings.get_int('menu-margin'); + let menuArrowSize = settings.get_int('menu-arrow-size'); + let leftPanelWidth = settings.get_int('menu-width'); + let leftPanelWidthSmall = settings.get_int('menu-width') - 65; + let rightPanelWidth = settings.get_int('right-panel-width'); + let rightPanelWidthPlus45 = settings.get_int('right-panel-width') + 45; + let rightPanelWidthPlus70 = settings.get_int('right-panel-width') + 70; + let avatarStyle = settings.get_enum('avatar-style'); + let avatarRadius = avatarStyle == 0 ? 999 : 0; + let menuButtonColor = settings.get_string('menu-button-color'); + let menuButtonHoverColor = settings.get_string('menu-button-hover-color'); + let menuButtonActiveColor = settings.get_string('menu-button-active-color'); + let menuButtonHoverBackgroundcolor = settings.get_string('menu-button-hover-backgroundcolor'); + let menuButtonActiveBackgroundcolor = settings.get_string('menu-button-active-backgroundcolor'); + let gapAdjustment = settings.get_int('gap-adjustment'); + let indicatorColor = settings.get_string('indicator-color'); + let indicatorTextBackgroundColor = settings.get_string('indicator-text-color'); + let plasmaSelectedItemColor = settings.get_string('plasma-selected-color'); + let plasmaSelectedItemBackgroundColor = settings.get_string('plasma-selected-background-color'); + let plasmaSearchBarTop = settings.get_enum('searchbar-default-top-location'); + let menuButtonBorderRadius = settings.get_int('menu-button-border-radius'); + let tooltipStyle, separatorColorStyle = "\n", smallButtonHoverStyle = "\n"; + let plasmaButtonStyle = plasmaSearchBarTop === Constants.SearchbarLocation.TOP ? 'border-top-width: 2px;' : 'border-bottom-width: 2px;'; + if(customarcMenu){ + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\nbox-shadow: 0 0 1px 0px " + separatorColor + ";\nfont-size:" + fontSize + "pt;\npadding: 3px 8px;\nmin-height: 0px;" + + "\ncolor:" + menuForegroundColor+ ";\nbackground-color:" + modifyColorLuminance(menuColor, 0.05, 1) + ";\nmax-width:550px;\n}\n\n"; + separatorColorStyle = ".separator-color-style{\nbackground-color: " + separatorColor + ";\n}\n\n"; + smallButtonHoverStyle = ".arc-menu .popup-menu-item .arcmenu-small-button.selected{\nbackground-color: " + modifyColorLuminance(highlightColor, -0.25) + "\n}\n\n"; + } + else + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\npadding: 3px 8px;\nmax-width:550px;\nmin-height: 0px;\n}\n\n"; + + let menuButtonStyle = ''; + if(settings.get_boolean('override-menu-button-color')) + menuButtonStyle += ".arc-menu-icon, .arc-menu-text, .arc-menu-arrow{\ncolor: " + menuButtonColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover{\nbackground-color: " + menuButtonHoverBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover .arc-menu-icon, .arc-menu-panel-menu:hover .arc-menu-text" + +", .arc-menu-panel-menu:hover .arc-menu-arrow{\ncolor: " + menuButtonHoverColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-color')) + menuButtonStyle += ".arc-menu-icon:active, .arc-menu-text:active, .arc-menu-arrow:active{\ncolor: " + menuButtonActiveColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:active{\nbackground-color: " + menuButtonActiveBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('menu-button-override-border-radius')){ + let border = menuButtonBorderRadius === 0 ? 1 : 3; + menuButtonStyle += ".arc-menu-panel-menu{\nborder-radius: " + menuButtonBorderRadius + "px;\nborder: " + border + "px solid transparent;\n}\n\n"; + } + + let iconGridStyle = "\ntext-align: center;\n border-radius: 8px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n"; + + let stylesheetCSS = "#arc-search{\nwidth: " + leftPanelWidth + "px;\n}\n\n" + +".arc-menu-status-text{\ncolor:" + menuForegroundColor + ";\nfont-size:" + fontSize + "pt;\n}\n\n" + +".search-statustext{\nfont-size:11pt;\n}\n\n" + + +"#ExtraLargeIconGrid{\nwidth: 150px;\n height: 150px;" + iconGridStyle + "}\n\n" + + +"#LargeIconGrid{\nwidth: 95px;\n height: 95px;" + iconGridStyle + "}\n\n" + + +"#MediumIconGrid{\nwidth: 87px;\n height: 87px;" + iconGridStyle + "}\n\n" + + +"#SmallIconGrid{\nwidth: 80px;\n height: 80px;" + iconGridStyle + "}\n\n" + + +"#LargeRectIconGrid{\nwidth: 95px;\n height: 85px;" + iconGridStyle + "}\n\n" + + +"#MediumRectIconGrid{\nwidth: 92px;\n height: 78px;" + iconGridStyle + "}\n\n" + + +"#SmallRectIconGrid{\nwidth: 85px;\n height: 70px;" + iconGridStyle + "}\n\n" + + +".left-panel{\nwidth:" + leftPanelWidth + "px;\n}\n\n" + +".left-panel-small{\nwidth:" + leftPanelWidthSmall + "px;\n}\n\n" + +".right-panel{\nwidth:" + rightPanelWidth + "px;\n}\n\n" + +".right-panel-plus45{\nwidth:" + rightPanelWidthPlus45 + "px;\n}\n\n" + +".right-panel-plus70{\nwidth:" + rightPanelWidthPlus70 + "px;\n}\n\n" + +".default-search-entry{\nmax-width: 17.667em;\n}\n\n" + +".arc-search-entry{\nmax-width: 17.667em;\nfont-size:" + fontSize + "pt;\nborder-color:" + separatorColor + ";\nborder-width: 1px;\n" + +"color:" + menuForegroundColor + ";\nbackground-color:" + modifyColorLuminance(menuColor, -0.1, 1) + ";\n}\n\n" + +".arc-search-entry:focus{\nborder-color:" + highlightColor + ";\nborder-width: 1px;\nbox-shadow: inset 0 0 0 1px " + modifyColorLuminance(highlightColor, 0.05) + ";\n}\n\n" + +".arc-search-entry StLabel.hint-text{\ncolor: " + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +"#ArcSearchEntry{\nmin-height: 0px;\nborder-radius: 8px;\nborder-width: 1px;\npadding: 7px 9px;\n}\n\n" + +"#ArcSearchEntryRound{\nmin-height: 0px;\nborder-radius: 18px;\nborder-width: 1px;\npadding: 7px 12px;\n}\n\n" + + menuButtonStyle + +".symbolic-icons{\n-st-icon-style: symbolic;\n}\n\n" + +".regular-icons{\n-st-icon-style: regular;\n}\n\n" + +".arcmenu-menu-item{\nborder-radius: 8px;\n}\n\n" + +".margin-box{\nmargin: 0px 4px;\n}\n\n" + +"#arc-menu-launcher-button{\nmax-width: 90px;\nborder-radius: 0px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\nborder-color: transparent;\nborder-bottom-width: 3px;\n}\n\n" + +"#arc-menu-launcher-button.active-item, #arc-menu-launcher-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + +"\nborder-color: " + plasmaSelectedItemColor + ";\nborder-bottom-width: 3px;\n}\n\n" + + +"#arc-menu-plasma-button{\nwidth: 90px;\n height: 65px;\nborder-radius: 8px;\n text-align: center;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n\n" + plasmaButtonStyle + ";\nborder-color: transparent;\n}\n\n" + +"#arc-menu-plasma-button:active-item, .arc-menu-plasma-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + + plasmaButtonStyle + "\nborder-color: " + plasmaSelectedItemColor + ";\n}\n\n" + + +"StScrollView .small-vfade{\n-st-vfade-offset: 44px;\n}\n\n" + + +".arc-menu-button{\n-st-icon-style: symbolic;\nborder-width: 1px;\nborder-radius: 8px;\npadding: 8px;\n}\n\n" + +".arcmenu-small-button{\n-st-icon-style: symbolic;\nborder-radius: 8px;\npadding: 3px 8px;\n}\n\n" + +smallButtonHoverStyle + + +".arc-menu-menu-item-indicator{\ncolor: " + indicatorColor + ";\n}\n\n" + +".arc-menu-menu-item-text-indicator{\nbackground-color: " + indicatorTextBackgroundColor + ";\n}\n\n" + + +tooltipStyle + + +".arc-menu{\n-boxpointer-gap: " + gapAdjustment + "px;\nmin-width: 15em;\ncolor: #D3DAE3;\nborder-image: none;\n" + +"box-shadow: none;\nfont-size:" + fontSize + "pt;\n}\n\n" + +".arc-menu .popup-sub-menu{\npadding-bottom: 1px;\nbackground-color: " + modifyColorLuminance(menuColor, 0.04) + ";\n}\n\n" + +".arc-menu .popup-menu-item{\nspacing: 6px; \nborder: none;\ncolor:" + menuForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:active{\nbackground-color:" + modifyColorLuminance(highlightColor, -0.15) + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item.selected{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:checked{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:insensitive{\ncolor:" + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +".arc-menu-boxpointer{ \n-arrow-border-radius:" + cornerRadius + "px;\n" + +"-arrow-background-color:" + menuColor + ";\n" + +"-arrow-border-color:" + borderColor + ";\n" + +"-arrow-border-width:" + borderSize + "px;\n" + +"-arrow-base:" + menuMargin + "px;\n" + +"-arrow-rise:" + menuArrowSize + "px;\n}\n\n" + +".arc-menu .popup-menu-content{\npadding: 16px 0px;\nmargin: 0;\nbackground-color: transparent;\nborder-radius: 0px;\nbox-shadow: 0;\n}\n\n" + + +".arcmenu-separator{\npadding: 0px;\nheight: 1px;\nmargin: 0px 20px;\n}\n\n" + + separatorColorStyle + +".menu-user-avatar{\nbackground-size: contain;\nborder-radius: " + avatarRadius + "px;\n}\n\n"; + + let stylesheet = getStylesheet(); + if(stylesheet){ + try{ + stylesheet.replace_contents(stylesheetCSS, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + } + catch(e){ + global.log("ArcMenu Error - Failed to update stylesheet. " + e.message); + } + } + else + global.log("ArcMenu Error - Failed to find stylesheet."); +} diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/appfolders.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/appfolders.js new file mode 100644 index 0000000..9548559 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/appfolders.js @@ -0,0 +1,225 @@ +'use strict'; + +const { Shell, GLib, Clutter } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const transparent = Clutter.Color.from_pixel(0x00000000); +const FOLDER_DIALOG_ANIMATION_TIME = 200; +const FRAME_UPDATE_PERIOD = 16; + +let original_zoomAndFadeIn = null; +let original_zoomAndFadeOut = null; +let sigma = 30; +let brightness = 0.6; + +let _zoomAndFadeIn = function () { + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.child.set({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + }); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + effect.sigma = 0; + Utils.ease_property(effect, 'sigma', 0, sigma, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + effect.brightness = 1.0; + Utils.ease_property(effect, 'brightness', 1.0, brightness, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + + this._needsZoomAndFade = false; + + if (this._sourceMappedId === 0) { + this._sourceMappedId = this._source.connect( + 'notify::mapped', this._zoomAndFadeOut.bind(this)); + } +} + +let _zoomAndFadeOut = function () { + if (!this._isOpen) + return; + + if (!this._source.mapped) { + this.hide(); + return; + } + + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + Utils.ease_property(effect, 'sigma', effect.sigma, 0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + Utils.ease_property(effect, 'brightness', effect.brightness, 1.0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this.child.set({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + }); + this.hide(); + + this._popdownCallbacks.forEach(func => func()); + this._popdownCallbacks = []; + }, + }); + + this._needsZoomAndFade = false; +} + + +var AppFoldersBlur = class AppFoldersBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + } + + enable() { + this._log("blurring appfolders"); + + if (Main.overview._overview.controls._appDisplay._folderIcons.length > 0) { + this.blur_appfolders(); + } + this.connections.connect(Main.overview._overview.controls._appDisplay, 'view-loaded', () => { + this.blur_appfolders(); + }) + } + + blur_appfolders() { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + icon._ensureFolderDialog(); + + if (original_zoomAndFadeIn == null) { + original_zoomAndFadeIn = icon._dialog._zoomAndFadeIn; + } + if (original_zoomAndFadeOut == null) { + original_zoomAndFadeOut = icon._dialog._zoomAndFadeOut; + } + + let effect = new Shell.BlurEffect({ + name: "appfolder-blur", + sigma: sigma, + brightness: brightness, + mode: 1 + }); + icon._dialog.remove_effect_by_name("appfolder-blur"); + icon._dialog.add_effect(effect); + + // HACK + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("appfolders hack level 1"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("appfolders hack level 2"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + icon._dialog._viewBox.set_style_class_name('app-folder-dialog transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + + icon._dialog._zoomAndFadeIn = _zoomAndFadeIn; + icon._dialog._zoomAndFadeOut = _zoomAndFadeOut; + }); + } + + set_sigma(s) { + sigma = s; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + set_brightness(b) { + brightness = b; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + disable() { + this._log("removing blur from appfolders"); + + if (original_zoomAndFadeIn != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeIn = original_zoomAndFadeIn; + }); + } + if (original_zoomAndFadeOut != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeOut = original_zoomAndFadeOut; + }); + } + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) { + icon._dialog.remove_effect_by_name("appfolder-blur") + icon._dialog._viewBox.remove_style_class_name('transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + } + }); + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/applications.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/applications.js new file mode 100644 index 0000000..e044464 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/applications.js @@ -0,0 +1,274 @@ +'use strict'; + +const { Shell, Clutter, Meta, GLib } = imports.gi; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; +const BlurMode = Shell.BlurMode; + +var ApplicationsBlur = class ApplicationsBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + + this.windowMap = new Map(); + this.blurActorMap = new Map(); + } + + enable() { + this._log("blurring applications..."); + + // iterate through existing windows and add blur as needed + for (let workspace = 0; workspace < global.workspace_manager.get_n_workspaces(); ++workspace) { + let metaWorkspace = global.workspace_manager.get_workspace_by_index(workspace); + let windows = metaWorkspace.list_windows(); + windows.forEach((meta_window) => { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + }) + } + + // blur every new window + this.connections.connect(global.display, 'window-created', (meta_display, meta_window) => { + this._log("window created"); + if (meta_window) { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + } + }); + + // workaround for blur being in front of target windows + this.connections.connect(global.display, 'notify::focus-window', () => { + if (this.blurActorMap.size > 0) { + let callbackId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + this.blurActorMap.forEach((blurActor, pid) => { + let actor = this.windowMap.get(pid).get_compositor_private(); + if (actor !== null && actor.get_parent() === blurActor.get_parent()) { + global.window_group.set_child_below_sibling(blurActor, actor); + } + }) + }) + } + }) + } + + // Blurs and add the needed signals to every new tracked window + track_new(window_actor, meta_window) { + // TODO change the pid to a more unique one, to prevent collisions? + let pid = Date.now(); + + window_actor['blur_provider_pid'] = pid; + meta_window['blur_provider_pid'] = pid; + + // remove the blur when the window is destroyed + this.connections.connect(window_actor, 'destroy', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (this.blurActorMap.has(pid)) { + this.remove_blur(pid) + } + }); + + // update the blur when the mutter-hint is changed + this.connections.connect(meta_window, 'notify::mutter-hints', (meta_window) => { + this._log("mutter-hint changed"); + let pid = meta_window.blur_provider_pid; + let window_actor = meta_window.get_compositor_private(); + this.update_blur(window_actor, meta_window, pid) + }); + + this.update_blur(window_actor, meta_window, pid); + } + + // This method is basically a catch-all for blurring windows. It handles the decisions + // to call different methods that handle removing, setting, and updating blur + update_blur(window_actor, meta_window, pid) { + let mutter_hint = meta_window.get_mutter_hints(); + + // check if the window wants blur and update it accordingly + if (mutter_hint != null && mutter_hint.includes("blur-provider")) { + // get blur effect parameters + let sigma = this.parse_sigma_value(mutter_hint); + let brightness = this.prefs.BRIGHTNESS.get(); + + // if the provided sigma value is incorrect + if (sigma == null || sigma < 0 || sigma > 111) { + this._log("sigma value is null or outside of range (0-111), defaulting to extension setting") + sigma = this.prefs.SIGMA.get(); + } + + // check wether the actor is already blurred and act consequently + if (this.blurActorMap.has(pid)) { + if (sigma == 0) { + // actor already blurred, should not be anymore + this.remove_blur(pid); + } else { + // actor already blurred, update it + this.update_blur_effect( + this.blurActorMap.get(pid), + sigma, + brightness + ); + } + } else if (sigma != 0) { + // actor not blurred, blur it + this.set_blur( + pid, + window_actor, + meta_window, + this.create_blur_effect(sigma, brightness) + ) + } + } else if (this.blurActorMap.has(pid)) { + // remove blur if the mutter_hint no longer contains our blur-provider value + this.remove_blur(pid); + } + } + + // Returns a new blur effect + create_blur_effect(sigma, brightness) { + return new Shell.BlurEffect({ + sigma: sigma, + brightness: brightness, + mode: BlurMode.BACKGROUND + }); + } + + // Add the blur effect to the actor + set_blur(pid, window_actor, meta_window, blurEffect) { + let blurActor = this.create_blur_actor(meta_window, window_actor, blurEffect); + + // if hacks are selected, force the repaint the window to prevent artifacts + if (this.prefs.HACKS_LEVEL.get() >= 1) { + this._log("applications hack level 1 or 2"); + this.paint_signals.disconnect_all(); + this.paint_signals.connect(blurActor, blurEffect); + } else { + this.paint_signals.disconnect_all(); + } + + global.window_group.insert_child_below(blurActor, window_actor); + + // registed the blur actor/effect + blurActor['blur_provider_pid'] = pid; + this.blurActorMap.set(pid, blurActor); + this.windowMap.set(pid, meta_window); + + // hide if window become invisible + this.connections.connect(window_actor, 'notify::visible', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (window_actor.visible) { + this.blurActorMap.get(pid).show(); + } else { + this.blurActorMap.get(pid).hide(); + } + }); + } + + // Returns a new already blurred widget, configured to follow the size and + // position of its target window + create_blur_actor(meta_window, window_actor, blurEffect) { + // create the constraints in size and position to its target window + let frame = meta_window.get_frame_rect(); + let buffer = meta_window.get_buffer_rect(); + + const offsetX = frame.x - buffer.x; + const offsetY = frame.y - buffer.y; + const offsetWidth = buffer.width - frame.width; + const offsetHeight = buffer.height - frame.height; + + let constraintPosX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.X, + offset: offsetX + }); + let constraintPosY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.Y, + offset: offsetY + }); + + let constraintSizeX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.WIDTH, + offset: -offsetWidth + }); + let constraintSizeY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.HEIGHT, + offset: -offsetHeight + }); + + // create the actor and add the constraints + let blurActor = new Clutter.Actor(); + blurActor.add_constraint(constraintPosX); + blurActor.add_constraint(constraintPosY); + blurActor.add_constraint(constraintSizeX); + blurActor.add_constraint(constraintSizeY); + + // add the effect + blurActor.add_effect_with_name('blur-effect', blurEffect); + + return blurActor; + } + + // Updates the blur effect by overwriting its sigma and brightness values + update_blur_effect(blur_actor, sigma, brightness) { + let effect = blur_actor.get_effect('blur-effect'); + effect.sigma = sigma; + effect.brightness = brightness; + } + + // Removes the blur actor from the shell and unregister it + remove_blur(pid) { + // global.window_group is null when restarting the shell, causing an innocent crash crash + if (global.window_group == null) + return + + global.window_group.remove_actor(this.blurActorMap.get(pid)); + this.blurActorMap.delete(pid); + this.windowMap.delete(pid); + } + + // When given the xprop property, returns either a valid sigma value between 0 and 111 + // or null if the parsing is incorrect + parse_sigma_value(property) { + let result = property.match("(blur-provider=)(\\d{1,3})") + if (result == null) { + return null; + } else { + return result[2]; + } + } + + disable() { + this._log("removing blur from applications..."); + + this.blurActorMap.forEach(((value, key) => { + this.remove_blur(key) + })); + this.connections.disconnect_all(); + this.paint_signals.disconnect_all(); + } + + // Updates each blur effect to use new sigma value + set_sigma(s) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_sigma(s) + }) + } + + // Updates each blur effect to use new brightness value + set_brightness(b) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_brightness(b) + }) + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/connections.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/connections.js new file mode 100644 index 0000000..3517a27 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/connections.js @@ -0,0 +1,81 @@ +'use strict'; + +const GObject = imports.gi.GObject; + + +var Connections = class Connections { + constructor() { + this.buffer = []; + } + + process_connection(actor, id) { + let infos = { + actor: actor, + id: id + }; + + if (actor.connect && (!(actor instanceof GObject.Object) || GObject.signal_lookup('destroy', actor))) { + let destroy_id = actor.connect('destroy', () => { + actor.disconnect(id); + actor.disconnect(destroy_id); + + let index = this.buffer.indexOf(infos); + if (index >= 0) { + this.buffer.splice(index, 1) + } + }) + } + + this.buffer.push(infos) + } + + connect(actor, signal, handler) { + let id = actor.connect(signal, handler); + this.process_connection(actor, id); + } + + connect_after(actor, signal, handler) { + let id = actor.connect_after(signal, handler); + + this.process_connection(actor, id); + } + + disconnect_all_for(actor) { + let actor_connections = [] + + this.buffer.forEach((infos) => { + if (infos.actor == actor) { + actor_connections.push(infos) + } + }); + + actor_connections.forEach((connection) => { + // disconnect + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + + // remove from buffer + let index = this.buffer.indexOf(connection); + this.buffer.splice(index, 1); + }) + } + + disconnect_all() { + this.buffer.forEach((connection) => { + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + }) + this.buffer = []; + } + + // no need to check if DEBUG here, the log function is only used on error + _log(str) { + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash.js new file mode 100644 index 0000000..650bf69 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash.js @@ -0,0 +1,51 @@ +'use strict'; + +const { St, Shell, Meta } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; + + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring dash"); + this.update(); + } + + update() { + if (Main.overview.dash.constructor.name == "Dash") { + Main.overview.dash.get_child_at_index(0).style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + // set search entry the same opacity as the dash + Main.overview._overview._controls._searchEntry.style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + disable() { + this._log("removing blur from dash"); + + if (Main.overview.dash.constructor.name == "Dash") { + if (Main.screenShield && !Main.screenShield.locked) { + try { + Main.overview.dash.get_child_at_index(0).style = null; + } catch (e) { + this._log(e); + } + } + } + Main.overview._overview._controls._searchEntry.style = null; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js new file mode 100644 index 0000000..166f147 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js @@ -0,0 +1,235 @@ +'use strict'; + +const { St, Shell, GLib } = imports.gi; +const Main = imports.ui.main; +const Signals = imports.signals; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +// This type of object is created for every dash found, and talks to the main DashBlur thanks +// to signals. This allows to dynamically track the created dashes for each screen. +class DashInfos { + constructor(dash_blur, dash, dash_box, background_parent, effect, prefs) { + // the parent DashBlur object, to communicate + this.dash_blur = dash_blur; + // the blurred dash + this.dash = dash; + // the actually blurred box + this.dash_box = dash_box; + this.background_parent = background_parent; + this.effect = effect; + this.prefs = prefs; + + dash_blur.connections.connect(dash_blur, 'remove-dashes', () => { + this._log("removing blur from dash"); + this.dash.get_parent().remove_child(this.background_parent); + this.dash.remove_style_class_name('blurred-dash'); + }); + + dash_blur.connections.connect(dash_blur, 'update-sigma', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'update-brightness', () => { + this.effect.brightness = this.dash_blur.brightness; + }); + + dash_blur.connections.connect(dash_blur, 'show', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'hide', () => { + this.effect.sigma = 0; + }); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.dashes = []; + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.sigma = prefs.SIGMA.get(); + this.brightness = prefs.BRIGHTNESS.get(); + } + + enable() { + this.connections.connect(Main.uiGroup, 'actor-added', (_, actor) => { + if ((actor.get_name() == "dashtodockContainer") && (actor.constructor.name == 'DashToDock')) + this.try_blur(actor); + }); + + this.blur_existing_dashes(); + } + + // Finds all existing dashes on every monitor, and call `try_blur` on them + // We cannot only blur `Main.overview.dash`, as there could be multiple screens + blur_existing_dashes() { + this._log("searching for dash"); + // blur every dash found + Main.uiGroup.get_children().filter((child) => { + // filter by name + return (child.get_name() == "dashtodockContainer") && (child.constructor.name == 'DashToDock') + }).forEach(this.try_blur.bind(this)); + } + + // Tries to blur the dash contained in the given actor + try_blur(dash_container) { + let dash_box = dash_container._slider.get_child(); + // verify that we did not already blur that dash + if (!dash_box.get_children().some((c) => { + return c.get_name() == "dash-blurred-background-parent" + })) { + // finally blur the dash + this._log("dash to dock found, blurring it"); + let dash = dash_box.get_children().find(c => { return c.get_name() == 'dash' }) + this.dashes.push(this.blur_dash_from(dash, dash_container)); + } + } + + // Blurs the dash and returns a `DashInfos` containing its informations + blur_dash_from(dash, dash_container) { + // the effect to be applied + let effect = new Shell.BlurEffect({ + brightness: this.brightness, + sigma: this.sigma, + mode: 1 + }); + + // dash background parent, not visible + let background_parent = new St.Widget({ + name: 'dash-blurred-background-parent', + style_class: 'dash-blurred-background-parent', + width: 0, + height: 0 + }); + + // dash background widget + let background = new St.Widget({ + name: 'dash-blurred-background', + style_class: 'dash-blurred-background', + x: 0, + y: dash_container._slider.y, + width: dash.width, + height: dash.height, + }); + + // updates size and position on change + this.connections.connect(dash_container._slider, 'notify::y', _ => { + background.y = dash_container._slider.y; + }); + this.connections.connect(dash, 'notify::width', _ => { + background.width = dash.width; + }); + this.connections.connect(dash, 'notify::height', _ => { + background.height = dash.height; + }); + + + // HACK + { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the dash buttons to cause artefacts on the dash itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("dash hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { + effect.queue_repaint() + }; + + dash._box.get_children().forEach((icon) => { + try { + let zone = icon.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._box, 'actor-added', (_, actor) => { + try { + let zone = actor.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._showAppsIcon, 'enter-event', rp); + this.connections.connect(dash._showAppsIcon, 'leave-event', rp); + this.connections.connect(dash._showAppsIcon, 'button-press-event', rp); + + this.connections.connect(dash, 'leave-event', rp); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("dash hack level 2"); + + this.paint_signals.connect(background, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + + // add the widget to the dash + background.add_effect(effect); + background_parent.add_child(background); + dash.get_parent().insert_child_at_index(background_parent, 0); + + // remove background color + dash.set_style_class_name('blurred-dash'); + + // returns infos + return new DashInfos(this, dash, dash._background, background_parent, effect, this.prefs); + } + + set_sigma(sigma) { + this.sigma = sigma; + this.emit('update-sigma', true); + } + + set_brightness(brightness) { + this.brightness = brightness; + this.emit('update-brightness', true); + } + + disable() { + this._log("removing blur from dashes"); + + this.emit('remove-dashes', true); + + this.dashes = []; + this.connections.disconnect_all(); + } + + show() { + this.emit('show', true); + } + hide() { + this.emit('hide', true); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +Signals.addSignalMethods(DashBlur.prototype); \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/extension.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/extension.js new file mode 100644 index 0000000..4d5c4c9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/extension.js @@ -0,0 +1,224 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const Settings = Me.imports.settings; +const Connections = Me.imports.connections; + +const Panel = Me.imports.panel; +const Dash = Me.imports.dash; +const Overview = Me.imports.overview; +const DashToDock = Me.imports.dash_to_dock; +const Lockscreen = Me.imports.lockscreen; +const AppFolders = Me.imports.appfolders; +const WindowList = Me.imports.window_list; +const Applications = Me.imports.applications; + + +class Extension { + constructor() { } + + enable() { + this._prefs = new Settings.Prefs; + + this._log("enabling extension..."); + this._connections = []; + + this._panel_blur = new Panel.PanelBlur(new Connections.Connections, this._prefs); + this._dash_blur = new Dash.DashBlur(new Connections.Connections, this._prefs); + this._dash_to_dock_blur = new DashToDock.DashBlur(new Connections.Connections, this._prefs); + this._overview_blur = new Overview.OverviewBlur(new Connections.Connections, this._prefs); + this._lockscreen_blur = new Lockscreen.LockscreenBlur(new Connections.Connections, this._prefs); + this._appfolders_blur = new AppFolders.AppFoldersBlur(new Connections.Connections, this._prefs); + this._window_list_blur = new WindowList.WindowListBlur(new Connections.Connections, this._prefs); + this._applications_blur = new Applications.ApplicationsBlur(new Connections.Connections, this._prefs); + + + this._connections.push(this._panel_blur.connections, this._dash_blur.connections, + this._dash_to_dock_blur.connections, this._overview_blur.connections, + this._lockscreen_blur.connections, this._appfolders_blur.connections, + this._window_list_blur.connections, this._applications_blur.connections); + + this._connect_to_settings(); + + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } + + this._update_sigma(); + this._update_brightness(); + + this._log("extension enabled."); + } + + disable() { + this._log("disabling extension..."); + + this._panel_blur.disable(); + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + this._overview_blur.disable(); + this._lockscreen_blur.disable(); + this._appfolders_blur.disable(); + this._window_list_blur.disable(); + this._applications_blur.disable(); + + this._panel_blur = null; + this._dash_blur = null; + this._dash_to_dock_blur = null; + this._overview_blur = null; + this._lockscreen_blur = null; + this._appfolders_blur = null; + this._window_list_blur = null; + this._applications_blur = null; + + this._disconnect_settings(); + + // in theory, this shouldn't be needed if we switch to making modules responsible for disconnecting their own + // signals. For now, I will leave this small bit of code in. Calling disable on all modules has already + // done the same thing + this._connections.forEach((connections) => { + connections.disconnect_all(); + }) + this._connections = []; + + this._log("extension disabled."); + + this._prefs = null; + } + + _connect_to_settings() { + this._prefs.SIGMA.changed(() => { + this._update_sigma(); + }); + this._prefs.BRIGHTNESS.changed(() => { + this._update_brightness(); + }); + + this._prefs.BLUR_DASH.changed(() => { + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } else { + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + } + }); + this._prefs.BLUR_PANEL.changed(() => { + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } else { + this._panel_blur.disable(); + } + }); + this._prefs.BLUR_OVERVIEW.changed(() => { + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } else { + this._overview_blur.disable(); + } + }); + this._prefs.BLUR_LOCKSCREEN.changed(() => { + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } else { + this._lockscreen_blur.disable(); + } + }); + this._prefs.BLUR_APPFOLDERS.changed(() => { + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } else { + this._appfolders_blur.disable(); + } + }); + this._prefs.BLUR_WINDOW_LIST.changed(() => { + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } else { + this._window_list_blur.disable(); + } + }); + this._prefs.BLUR_APPLICATIONS.changed(() => { + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } else { + this._applications_blur.disable(); + } + }) + this._prefs.DASH_OPACITY.changed(() => { + this._dash_blur.update(); + }); + this._prefs.APPFOLDER_DIALOG_OPACITY.changed(() => { + this._appfolders_blur.blur_appfolders(); + }); + this._prefs.STATIC_BLUR.changed(() => { + this._panel_blur.change_blur_type(); + }); + this._prefs.HIDETOPBAR.changed(() => { + this._panel_blur.connect_to_overview(); + }); + } + + _disconnect_settings() { + this._prefs.SIGMA.disconnect(); + this._prefs.BRIGHTNESS.disconnect(); + } + + _update_sigma() { + let sigma = this._prefs.SIGMA.get(); + + this._panel_blur.set_sigma(sigma); + this._dash_to_dock_blur.set_sigma(sigma); + this._overview_blur.set_sigma(sigma); + this._lockscreen_blur.set_sigma(sigma); + this._appfolders_blur.set_sigma(sigma); + this._window_list_blur.set_sigma(sigma); + this._applications_blur.set_sigma(sigma); + } + + _update_brightness() { + let brightness = this._prefs.BRIGHTNESS.get(); + + this._panel_blur.set_brightness(brightness); + this._dash_to_dock_blur.set_brightness(brightness); + this._overview_blur.set_brightness(brightness); + this._lockscreen_blur.set_brightness(brightness); + this._appfolders_blur.set_brightness(brightness); + this._window_list_blur.set_brightness(brightness); + this._applications_blur.set_brightness(brightness); + } + + _log(str) { + if (this._prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + + +// Called on gnome-shell loading, even if extension is deactivated +function init() { + return new Extension(); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/lockscreen.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/lockscreen.js new file mode 100644 index 0000000..e6d39b5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/lockscreen.js @@ -0,0 +1,64 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; +const Background = imports.ui.background; + +let sigma = 30; +let brightness = 0.6; + +const original_createBackground = imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects; + + +var LockscreenBlur = class LockscreenBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring lockscreen"); + + this.update_lockscreen(); + } + + update_lockscreen() { + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = this._createBackground; + } + + _createBackground() { + for (const widget of this._backgroundGroup) { + const effect = widget.get_effect('blur'); + + if (effect) { + effect.set({ + brightness: brightness, + sigma: sigma, + }); + } + } + } + + set_sigma(s) { + sigma = s; + this.update_lockscreen(); + } + + set_brightness(b) { + brightness = b; + this.update_lockscreen(); + } + + disable() { + this._log("removing blur from lockscreen"); + + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = original_createBackground; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/metadata.json b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/metadata.json new file mode 100644 index 0000000..820fa02 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/metadata.json @@ -0,0 +1,12 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.", + "name": "Blur my Shell", + "shell-version": [ + "40", + "41" + ], + "url": "https://github.com/aunetx/gnome-shell-extension-blur-my-shell", + "uuid": "blur-my-shell@aunetx", + "version": 29 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/overview.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/overview.js new file mode 100644 index 0000000..ffd86f9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/overview.js @@ -0,0 +1,161 @@ +'use strict'; + +const { Shell, Gio, Meta } = imports.gi; +const Main = imports.ui.main; +const WorkspaceAnimationController = imports.ui.workspaceAnimation.WorkspaceAnimationController; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; + + +var OverviewBlur = class OverviewBlur { + constructor(connections, prefs) { + this.connections = connections; + this.effects = []; + this.prefs = prefs; + this._workspace_switch_bg_actors = []; + } + + enable() { + this._log("blurring overview"); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this._log("updated background"); + this.update_backgrounds(); + }); + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this._log("changed monitors"); + this.update_backgrounds(); + } + }); + + // add css class names, to change folders and workspace-switch background + Main.uiGroup.add_style_class_name("blurred-overview"); + + // update background on extension activation + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + this.update_backgrounds(); + } catch (error) { this._log(`could not blur overview: ${error}`); } + + // store original methods for restoring them on disable() + this._origPrepareSwitch = WorkspaceAnimationController.prototype._prepareWorkspaceSwitch; + this._origFinishSwitch = WorkspaceAnimationController.prototype._finishWorkspaceSwitch; + + const outerThis = this; + + // create blurred background actors for each monitor during a workspace switch + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = function (...params) { + outerThis._log("prepare workspace switch"); + outerThis._origPrepareSwitch.apply(this, params); + + Main.layoutManager.monitors.forEach(monitor => { + if (!(Meta.prefs_get_workspaces_only_on_primary() && (monitor != Main.layoutManager.primaryMonitor))) { + const bg_actor = outerThis.create_background_actor(monitor); + Main.uiGroup.insert_child_above(bg_actor, global.window_group); + + // store the actors so that we can delete them later + outerThis._workspace_switch_bg_actors.push(bg_actor); + } + }); + }; + + // remove the workspace-switch actors when the switch is done + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = function (...params) { + outerThis._log("finish workspace switch"); + outerThis._origFinishSwitch.apply(this, params); + + outerThis._workspace_switch_bg_actors.forEach(actor => { + actor.destroy(); + }); + outerThis._workspace_switch_bg_actors = []; + }; + } + + update_backgrounds() { + // remove every old background + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + actor.destroy(); + } + }); + this.effects = []; + + // add new backgrounds + Main.layoutManager.monitors.forEach(monitor => { + const bg_actor = this.create_background_actor(monitor); + Main.layoutManager.overviewGroup.insert_child_at_index(bg_actor, monitor.index); + }); + } + + create_background_actor(monitor) { + let bg_actor = new Meta.BackgroundActor; + + let background = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - monitor.index - 1); + + if (!background) { + this._log("could not get background for overview"); + return bg_actor; + } + + bg_actor.set_content(background.get_content()); + + let effect = new Shell.BlurEffect({ + brightness: this.prefs.BRIGHTNESS.get(), + sigma: this.prefs.SIGMA.get(), + mode: 0 + }); + bg_actor.add_effect(effect); + this.effects.push(effect); + + bg_actor.set_x(monitor.x); + bg_actor.set_y(monitor.y); + + return bg_actor; + } + + set_sigma(s) { + this.effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.effects.forEach(effect => { + effect.brightness = b; + }); + } + + disable() { + this._log("removing blur from overview"); + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + } + }); + Main.uiGroup.remove_style_class_name("blurred-overview"); + + this.effects = []; + this.connections.disconnect_all(); + + // restore original behavior + if (this._origPrepareSwitch) { + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = this._origPrepareSwitch; + } + + if (this._origFinishSwitch) { + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = this._origFinishSwitch; + } + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/paint_signals.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/paint_signals.js new file mode 100644 index 0000000..0c3dc4f --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/paint_signals.js @@ -0,0 +1,59 @@ +'use strict' + +const { GObject, Clutter } = imports.gi; + + +var PaintSignals = class PaintSignals { + constructor(connections) { + this.buffer = []; + this.connections = connections + } + + connect(actor, blur_effect) { + let paint_effect = new EmitPaintSignal(); + let infos = { + actor: actor, + paint_effect: paint_effect + }; + let counter = 0; + + actor.add_effect(paint_effect); + this.connections.connect(paint_effect, 'update-blur', () => { + try { + // checking if blur_effect.queue_repaint() has been recently called + if (counter === 0) { + counter = 2; + blur_effect.queue_repaint(); + } + else counter--; + } catch (e) { } + }); + + this.buffer.push(infos) + } + + disconnect_all() { + this.buffer.forEach((infos) => { + this.connections.disconnect_all_for(infos.paint_effect); + infos.actor.remove_effect(infos.paint_effect); + }); + + this.buffer = [] + } +} + +var EmitPaintSignal = GObject.registerClass({ + GTypeName: 'EmitPaintSignal', + Signals: { + 'update-blur': { + param_types: [] + }, + } +}, + class EmitPaintSignal extends Clutter.Effect { + vfunc_paint(node, paint_context, paint_flags) { + this.emit("update-blur"); + super.vfunc_paint(node, paint_context, paint_flags); + } + } +); \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/panel.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/panel.js new file mode 100644 index 0000000..930ca4d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/panel.js @@ -0,0 +1,245 @@ +'use strict'; + +const { St, Shell, Meta, Gio, GLib } = imports.gi; +const Main = imports.ui.main; +const Config = imports.misc.config; +const backgroundSettings = new Gio.Settings({ schema: 'org.gnome.desktop.background' }) + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.'); + + +var PanelBlur = class PanelBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + this.effect = new Shell.BlurEffect({ + brightness: prefs.BRIGHTNESS.get(), + sigma: prefs.SIGMA.get(), + mode: prefs.STATIC_BLUR.get() ? 0 : 1 + }); + this.background_parent = new St.Widget({ + name: 'topbar-blurred-background-parent', + style_class: 'topbar-blurred-background-parent', + x: this.monitor.x, + y: this.monitor.y, + width: this.monitor.width, + height: 0, + }); + this.background = prefs.STATIC_BLUR.get() ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.background_parent.add_child(this.background); + } + + enable() { + this._log("blurring top panel"); + + if (GS_MAJOR < 42) { + // hide corners, can't style them + Main.panel._leftCorner.hide(); + Main.panel._rightCorner.hide(); + this.connections.connect(Main.panel._leftCorner, 'show', () => { Main.panel._leftCorner.hide(); }); + this.connections.connect(Main.panel._rightCorner, 'show', () => { Main.panel._rightCorner.hide(); }); + } + + // insert background parent + let children = Main.layoutManager.panelBox.get_children(); + for (let i = 0; i < children.length; ++i) + if (children[i].name == 'topbar-blurred-background-parent') + Main.layoutManager.panelBox.remove_child(children[i]); + Main.layoutManager.panelBox.insert_child_at_index(this.background_parent, 0); + + // remove background + Main.panel.add_style_class_name('transparent-panel'); + + // perform updates + this.change_blur_type(); + Utils.setTimeout(() => { this.change_blur_type() }, 500); + + // connect to panel size change + this.connections.connect(Main.panel, 'notify::height', () => { + this.update_size(this.prefs.STATIC_BLUR.get()); + }); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + }) + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + this.update_size(this.prefs.STATIC_BLUR.get()); + } + }); + + this.connect_to_overview(); + } + + change_blur_type() { + let is_static = this.prefs.STATIC_BLUR.get(); + + // reset widgets to right state + this.background_parent.remove_child(this.background); + this.background.remove_effect(this.effect); + this.background = is_static ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.effect.set_mode(is_static ? 0 : 1); + this.background.add_effect(this.effect); + this.background_parent.add_child(this.background); + + // perform updates + this.update_wallpaper(is_static); + this.update_size(is_static); + + // HACK + if (!is_static) { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("panel hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { this.effect.queue_repaint() }; + + this.connections.connect(Main.panel, 'enter-event', rp); + this.connections.connect(Main.panel, 'leave-event', rp); + this.connections.connect(Main.panel, 'button-press-event', rp); + + Main.panel.get_children().forEach(child => { + this.connections.connect(child, 'enter-event', rp); + this.connections.connect(child, 'leave-event', rp); + this.connections.connect(child, 'button-press-event', rp); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("panel hack level 2"); + this.paint_signals.disconnect_all(); + + this.paint_signals.connect(this.background, this.effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + } + + update_wallpaper(is_static) { + // if static blur, get right wallpaper and update blur with it + if (is_static) { + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + let bg = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - this.monitor.index - 1); + this.background.set_content(bg.get_content()); + } catch (error) { this._log(`could not blur panel: ${error}`) } + } + } + + update_size(is_static) { + this.background_parent.width = Main.panel.width; + this.background.width = Main.panel.width; + let panel_box = Main.layoutManager.panelBox; + this.background.height = panel_box.height; + let clip_box = panel_box.get_parent(); + if (is_static) { + this.background.set_clip( + clip_box.x, + clip_box.y, + panel_box.width, + panel_box.height + ); + this.background.x = -clip_box.x; + this.background.y = -clip_box.y; + } + } + + // returns either the primary monitor, or a dummy one if none is connected + get monitor() { + if (Main.layoutManager.primaryMonitor != null) { + return Main.layoutManager.primaryMonitor + } else { + return { x: 0, y: 0, width: 0, index: 0 } + } + } + + // connect when overview if opened/closed to hide/show the blur in consequence + // if HIDETOPBAR set, we need just to hide the blur when showing appgrid (so no shadow is cropped) + connect_to_overview() { + this.connections.disconnect_all_for(Main.overview._overview._controls._appDisplay); + this.connections.disconnect_all_for(Main.overview); + + if (!this.prefs.HIDETOPBAR.get()) { + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } else { + this.connections.connect(Main.overview._overview._controls._appDisplay, 'show', () => { + this.hide(); + }); + this.connections.connect(Main.overview._overview._controls._appDisplay, 'hide', () => { + this.show(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + } + + set_sigma(s) { + this.effect.sigma = s; + } + + set_brightness(b) { + this.effect.brightness = b; + } + + disable() { + this._log("removing blur from top panel"); + Main.panel.remove_style_class_name('transparent-panel'); + + if (GS_MAJOR < 42) { + Main.panel._leftCorner.show(); + Main.panel._rightCorner.show(); + } + + try { + Main.layoutManager.panelBox.remove_child(this.background_parent); + } catch (e) { } + + this.connections.disconnect_all(); + } + + show() { + this.background_parent.show(); + } + hide() { + this.background_parent.hide(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.js new file mode 100644 index 0000000..b8c1c41 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.js @@ -0,0 +1,187 @@ +'use strict'; + +const { GObject, Gtk } = imports.gi; + +const ExtensionUtils = imports.misc.extensionUtils; +const Extension = ExtensionUtils.getCurrentExtension(); +let Settings = Extension.imports.settings; +let config = new Settings.Prefs(); + + +const BlurMyShellPrefsWidget = GObject.registerClass({ + GTypeName: 'BlurMyShellPrefsWidget', + Template: Extension.dir.get_child('prefs.ui').get_uri(), + InternalChildren: [ + 'sigma_scale', + 'brightness_scale', + 'blur_dash', + 'blur_panel', + 'blur_overview', + 'blur_applications', + 'blur_lockscreen', + 'blur_appfolders', + 'blur_window_list', + 'hacks_level0', + 'hacks_level1', + 'hacks_level2', + 'dash_opacity_scale', + 'appfolder_dialog_opacity_scale', + 'static_blur', + 'hidetopbar', + 'debug_mode' + ], +}, class BlurMyShellPrefsWidget extends Gtk.Box { + _init(params = {}) { + super._init(params); + + // ! sigma + this._sigma_scale.set_value(config.SIGMA.get()); + + // ! brightness + this._brightness_scale.set_value(config.BRIGHTNESS.get()); + + // ! blur dash + this._blur_dash.set_active(config.BLUR_DASH.get()); + + // ! blur panel + this._blur_panel.set_active(config.BLUR_PANEL.get()); + + // ! blur overview + this._blur_overview.set_active(config.BLUR_OVERVIEW.get()); + + // ! blur applications + this._blur_applications.set_active(config.BLUR_APPLICATIONS.get()); + + // ! blur lockscreen + this._blur_lockscreen.set_active(config.BLUR_LOCKSCREEN.get()); + + // ! blur appfolders + this._blur_appfolders.set_active(config.BLUR_APPFOLDERS.get()); + + // ! blur window list + this._blur_window_list.set_active(config.BLUR_WINDOW_LIST.get()); + + // ! dash hacks + if (config.HACKS_LEVEL.get() == 0) { + this._hacks_level0.set_active(true); + } else if (config.HACKS_LEVEL.get() == 1) { + this._hacks_level1.set_active(true); + } else if (config.HACKS_LEVEL.get() == 2) { + this._hacks_level2.set_active(true); + } else { + this._log(`hack level out-of-bound: ${hack_level}, defaulting to 1.`); + this._hacks_level0.set_active(true); + } + + // ! dash opacity + this._dash_opacity_scale.set_value(config.DASH_OPACITY.get()); + + // ! appfolder dialog opacity + this._appfolder_dialog_opacity_scale.set_value(config.APPFOLDER_DIALOG_OPACITY.get()); + + // ! static panel blur + this._static_blur.set_active(config.STATIC_BLUR.get()); + + // ! hidetopbar compatibility + this._hidetopbar.set_active(config.HIDETOPBAR.get()); + + // ! debug mode + this._debug_mode.set_active(config.DEBUG.get()); + } + + sigma_changed(w) { + let value = w.get_value(); + config.SIGMA.set(value); + } + + brightness_changed(w) { + let value = w.get_value(); + config.BRIGHTNESS.set(value); + } + + blur_dash_toggled(w) { + let value = w.get_active(); + config.BLUR_DASH.set(value); + } + + blur_panel_toggled(w) { + let value = w.get_active(); + config.BLUR_PANEL.set(value); + } + + blur_overview_toggled(w) { + let value = w.get_active(); + config.BLUR_OVERVIEW.set(value); + } + + blur_applications_toggled(w) { + let value = w.get_active(); + config.BLUR_APPLICATIONS.set(value); + } + + blur_lockscreen_toggled(w) { + let value = w.get_active(); + config.BLUR_LOCKSCREEN.set(value); + } + + blur_appfolders_toggled(w) { + let value = w.get_active(); + config.BLUR_APPFOLDERS.set(value); + } + + blur_window_list_toggled(w) { + let value = w.get_active(); + config.BLUR_WINDOW_LIST.set(value); + } + + hacks_level0_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(0) } + } + + hacks_level1_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(1) } + } + + hacks_level2_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(2) } + } + + dash_opacity_changed(w) { + let value = w.get_value(); + config.DASH_OPACITY.set(value); + } + + appfolder_dialog_opacity_changed(w) { + let value = w.get_value(); + config.APPFOLDER_DIALOG_OPACITY.set(value); + } + + static_blur_toggled(w) { + let value = w.get_active(); + config.STATIC_BLUR.set(value); + } + + hidetopbar_toggled(w) { + let value = w.get_active(); + config.HIDETOPBAR.set(value); + } + + debug_mode_toggled(w) { + let value = w.get_active(); + config.DEBUG.set(value); + } + + _log(str) { + if (config.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +}); + +function init() { } + +function buildPrefsWidget() { + return new BlurMyShellPrefsWidget(); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.ui b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.ui new file mode 100644 index 0000000..a5d30c7 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/prefs.ui @@ -0,0 +1,410 @@ + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled new file mode 100644 index 0000000..ca00e0c Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml new file mode 100644 index 0000000..4417dce --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml @@ -0,0 +1,95 @@ + + + + + + 30 + Global sigma (gaussian blur radius) to use + + + + + 0.6 + Global brightness to use + + + + + true + Boolean, whether to blur the dash or not + + + + + true + Boolean, whether to blur the panel or not + + + + + true + Boolean, whether to blur the overview or not + + + + + true + Boolean, whether to blur lockscreen or not + + + + + true + Boolean, whether to blur appfolders or not + + + + + true + Boolean, whether to blur window list extension or not + + + + + false + Boolean, whether to blur applications that request it or not + + + + + 1 + Level of hacks to use (from 0 to 2) + + + + + 0.12 + Opacity of dash to use + + + + + 0.12 + Opacity of appfolder dialog to use + + + + + true + Boolean, whether to have a static blur on panel or a dynamic one + + + + + false + Boolean, whether to try compatibility with hidetopbar@mathieu.bidon.ca or not + + + + + false + Boolean, set to true to activate debug mode (more verbose journalctl logs) + + + + \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/settings.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/settings.js new file mode 100644 index 0000000..69a0093 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/settings.js @@ -0,0 +1,274 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Extension = imports.misc.extensionUtils.getCurrentExtension(); + +const SCHEMA_PATH = 'org.gnome.shell.extensions.blur-my-shell'; + +function get_local_gsettings(schema_path) { + const GioSSS = Gio.SettingsSchemaSource; + let schemaDir = Extension.dir.get_child('schemas'); + let schemaSource = GioSSS.get_default(); + + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory( + schemaDir.get_path(), + schemaSource, + false); + } + + let schemaObj = schemaSource.lookup(schema_path, true); + if (!schemaObj) { + throw new Error( + `Schema ${schema_path} could not be found for extension ${Extension.metadata.uuid}` + ); + } + return new Gio.Settings({ + settings_schema: schemaObj + }); +}; + +var Prefs = class Prefs { + constructor() { + var settings = this.settings = get_local_gsettings(SCHEMA_PATH); + this.SIGMA = { + key: 'sigma', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BRIGHTNESS = { + key: 'brightness', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BLUR_DASH = { + key: 'blur-dash', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_PANEL = { + key: 'blur-panel', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_OVERVIEW = { + key: 'blur-overview', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_LOCKSCREEN = { + key: 'blur-lockscreen', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPLICATIONS = { + key: 'blur-applications', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPFOLDERS = { + key: 'blur-appfolders', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_WINDOW_LIST = { + key: 'blur-window-list', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HACKS_LEVEL = { + key: 'hacks-level', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.DASH_OPACITY = { + key: 'dash-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.APPFOLDER_DIALOG_OPACITY = { + key: 'appfolder-dialog-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.STATIC_BLUR = { + key: 'static-blur', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HIDETOPBAR = { + key: 'hidetopbar', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.DEBUG = { + key: 'debug', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + } +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/stylesheet.css b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/stylesheet.css new file mode 100644 index 0000000..a094537 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/stylesheet.css @@ -0,0 +1,436 @@ +#panel.transparent-panel { + background: transparent; + transition-duration: 500ms; +} + +.blurred-overview .app-folder { + background-color: rgba(0, 0, 0, 0.12); +} + + +.blurred-overview .workspace-animation { + background-color: transparent !important; +} + +.transparent-app-folder-dialogs .edit-folder-button { + background: transparent; + border-radius: 19px; +} + +.blurred-dash .dash-background { + background: transparent; +} + +/* +! TRANSPARENT APPFOLDER DIALOGS + +python generator: + +```py +for e in range(0,101):print(".transparent-app-folder-dialogs-"+str(e)+"\n{background-color: rgba(0, 0, 0, "+str(round(e/100,2))+");}") +``` +*/ + +.transparent-app-folder-dialogs-0 { + background-color: rgba(0, 0, 0, 0.0); +} + +.transparent-app-folder-dialogs-1 { + background-color: rgba(0, 0, 0, 0.01); +} + +.transparent-app-folder-dialogs-2 { + background-color: rgba(0, 0, 0, 0.02); +} + +.transparent-app-folder-dialogs-3 { + background-color: rgba(0, 0, 0, 0.03); +} + +.transparent-app-folder-dialogs-4 { + background-color: rgba(0, 0, 0, 0.04); +} + +.transparent-app-folder-dialogs-5 { + background-color: rgba(0, 0, 0, 0.05); +} + +.transparent-app-folder-dialogs-6 { + background-color: rgba(0, 0, 0, 0.06); +} + +.transparent-app-folder-dialogs-7 { + background-color: rgba(0, 0, 0, 0.07); +} + +.transparent-app-folder-dialogs-8 { + background-color: rgba(0, 0, 0, 0.08); +} + +.transparent-app-folder-dialogs-9 { + background-color: rgba(0, 0, 0, 0.09); +} + +.transparent-app-folder-dialogs-10 { + background-color: rgba(0, 0, 0, 0.1); +} + +.transparent-app-folder-dialogs-11 { + background-color: rgba(0, 0, 0, 0.11); +} + +.transparent-app-folder-dialogs-12 { + background-color: rgba(0, 0, 0, 0.12); +} + +.transparent-app-folder-dialogs-13 { + background-color: rgba(0, 0, 0, 0.13); +} + +.transparent-app-folder-dialogs-14 { + background-color: rgba(0, 0, 0, 0.14); +} + +.transparent-app-folder-dialogs-15 { + background-color: rgba(0, 0, 0, 0.15); +} + +.transparent-app-folder-dialogs-16 { + background-color: rgba(0, 0, 0, 0.16); +} + +.transparent-app-folder-dialogs-17 { + background-color: rgba(0, 0, 0, 0.17); +} + +.transparent-app-folder-dialogs-18 { + background-color: rgba(0, 0, 0, 0.18); +} + +.transparent-app-folder-dialogs-19 { + background-color: rgba(0, 0, 0, 0.19); +} + +.transparent-app-folder-dialogs-20 { + background-color: rgba(0, 0, 0, 0.2); +} + +.transparent-app-folder-dialogs-21 { + background-color: rgba(0, 0, 0, 0.21); +} + +.transparent-app-folder-dialogs-22 { + background-color: rgba(0, 0, 0, 0.22); +} + +.transparent-app-folder-dialogs-23 { + background-color: rgba(0, 0, 0, 0.23); +} + +.transparent-app-folder-dialogs-24 { + background-color: rgba(0, 0, 0, 0.24); +} + +.transparent-app-folder-dialogs-25 { + background-color: rgba(0, 0, 0, 0.25); +} + +.transparent-app-folder-dialogs-26 { + background-color: rgba(0, 0, 0, 0.26); +} + +.transparent-app-folder-dialogs-27 { + background-color: rgba(0, 0, 0, 0.27); +} + +.transparent-app-folder-dialogs-28 { + background-color: rgba(0, 0, 0, 0.28); +} + +.transparent-app-folder-dialogs-29 { + background-color: rgba(0, 0, 0, 0.29); +} + +.transparent-app-folder-dialogs-30 { + background-color: rgba(0, 0, 0, 0.3); +} + +.transparent-app-folder-dialogs-31 { + background-color: rgba(0, 0, 0, 0.31); +} + +.transparent-app-folder-dialogs-32 { + background-color: rgba(0, 0, 0, 0.32); +} + +.transparent-app-folder-dialogs-33 { + background-color: rgba(0, 0, 0, 0.33); +} + +.transparent-app-folder-dialogs-34 { + background-color: rgba(0, 0, 0, 0.34); +} + +.transparent-app-folder-dialogs-35 { + background-color: rgba(0, 0, 0, 0.35); +} + +.transparent-app-folder-dialogs-36 { + background-color: rgba(0, 0, 0, 0.36); +} + +.transparent-app-folder-dialogs-37 { + background-color: rgba(0, 0, 0, 0.37); +} + +.transparent-app-folder-dialogs-38 { + background-color: rgba(0, 0, 0, 0.38); +} + +.transparent-app-folder-dialogs-39 { + background-color: rgba(0, 0, 0, 0.39); +} + +.transparent-app-folder-dialogs-40 { + background-color: rgba(0, 0, 0, 0.4); +} + +.transparent-app-folder-dialogs-41 { + background-color: rgba(0, 0, 0, 0.41); +} + +.transparent-app-folder-dialogs-42 { + background-color: rgba(0, 0, 0, 0.42); +} + +.transparent-app-folder-dialogs-43 { + background-color: rgba(0, 0, 0, 0.43); +} + +.transparent-app-folder-dialogs-44 { + background-color: rgba(0, 0, 0, 0.44); +} + +.transparent-app-folder-dialogs-45 { + background-color: rgba(0, 0, 0, 0.45); +} + +.transparent-app-folder-dialogs-46 { + background-color: rgba(0, 0, 0, 0.46); +} + +.transparent-app-folder-dialogs-47 { + background-color: rgba(0, 0, 0, 0.47); +} + +.transparent-app-folder-dialogs-48 { + background-color: rgba(0, 0, 0, 0.48); +} + +.transparent-app-folder-dialogs-49 { + background-color: rgba(0, 0, 0, 0.49); +} + +.transparent-app-folder-dialogs-50 { + background-color: rgba(0, 0, 0, 0.5); +} + +.transparent-app-folder-dialogs-51 { + background-color: rgba(0, 0, 0, 0.51); +} + +.transparent-app-folder-dialogs-52 { + background-color: rgba(0, 0, 0, 0.52); +} + +.transparent-app-folder-dialogs-53 { + background-color: rgba(0, 0, 0, 0.53); +} + +.transparent-app-folder-dialogs-54 { + background-color: rgba(0, 0, 0, 0.54); +} + +.transparent-app-folder-dialogs-55 { + background-color: rgba(0, 0, 0, 0.55); +} + +.transparent-app-folder-dialogs-56 { + background-color: rgba(0, 0, 0, 0.56); +} + +.transparent-app-folder-dialogs-57 { + background-color: rgba(0, 0, 0, 0.57); +} + +.transparent-app-folder-dialogs-58 { + background-color: rgba(0, 0, 0, 0.58); +} + +.transparent-app-folder-dialogs-59 { + background-color: rgba(0, 0, 0, 0.59); +} + +.transparent-app-folder-dialogs-60 { + background-color: rgba(0, 0, 0, 0.6); +} + +.transparent-app-folder-dialogs-61 { + background-color: rgba(0, 0, 0, 0.61); +} + +.transparent-app-folder-dialogs-62 { + background-color: rgba(0, 0, 0, 0.62); +} + +.transparent-app-folder-dialogs-63 { + background-color: rgba(0, 0, 0, 0.63); +} + +.transparent-app-folder-dialogs-64 { + background-color: rgba(0, 0, 0, 0.64); +} + +.transparent-app-folder-dialogs-65 { + background-color: rgba(0, 0, 0, 0.65); +} + +.transparent-app-folder-dialogs-66 { + background-color: rgba(0, 0, 0, 0.66); +} + +.transparent-app-folder-dialogs-67 { + background-color: rgba(0, 0, 0, 0.67); +} + +.transparent-app-folder-dialogs-68 { + background-color: rgba(0, 0, 0, 0.68); +} + +.transparent-app-folder-dialogs-69 { + background-color: rgba(0, 0, 0, 0.69); +} + +.transparent-app-folder-dialogs-70 { + background-color: rgba(0, 0, 0, 0.7); +} + +.transparent-app-folder-dialogs-71 { + background-color: rgba(0, 0, 0, 0.71); +} + +.transparent-app-folder-dialogs-72 { + background-color: rgba(0, 0, 0, 0.72); +} + +.transparent-app-folder-dialogs-73 { + background-color: rgba(0, 0, 0, 0.73); +} + +.transparent-app-folder-dialogs-74 { + background-color: rgba(0, 0, 0, 0.74); +} + +.transparent-app-folder-dialogs-75 { + background-color: rgba(0, 0, 0, 0.75); +} + +.transparent-app-folder-dialogs-76 { + background-color: rgba(0, 0, 0, 0.76); +} + +.transparent-app-folder-dialogs-77 { + background-color: rgba(0, 0, 0, 0.77); +} + +.transparent-app-folder-dialogs-78 { + background-color: rgba(0, 0, 0, 0.78); +} + +.transparent-app-folder-dialogs-79 { + background-color: rgba(0, 0, 0, 0.79); +} + +.transparent-app-folder-dialogs-80 { + background-color: rgba(0, 0, 0, 0.8); +} + +.transparent-app-folder-dialogs-81 { + background-color: rgba(0, 0, 0, 0.81); +} + +.transparent-app-folder-dialogs-82 { + background-color: rgba(0, 0, 0, 0.82); +} + +.transparent-app-folder-dialogs-83 { + background-color: rgba(0, 0, 0, 0.83); +} + +.transparent-app-folder-dialogs-84 { + background-color: rgba(0, 0, 0, 0.84); +} + +.transparent-app-folder-dialogs-85 { + background-color: rgba(0, 0, 0, 0.85); +} + +.transparent-app-folder-dialogs-86 { + background-color: rgba(0, 0, 0, 0.86); +} + +.transparent-app-folder-dialogs-87 { + background-color: rgba(0, 0, 0, 0.87); +} + +.transparent-app-folder-dialogs-88 { + background-color: rgba(0, 0, 0, 0.88); +} + +.transparent-app-folder-dialogs-89 { + background-color: rgba(0, 0, 0, 0.89); +} + +.transparent-app-folder-dialogs-90 { + background-color: rgba(0, 0, 0, 0.9); +} + +.transparent-app-folder-dialogs-91 { + background-color: rgba(0, 0, 0, 0.91); +} + +.transparent-app-folder-dialogs-92 { + background-color: rgba(0, 0, 0, 0.92); +} + +.transparent-app-folder-dialogs-93 { + background-color: rgba(0, 0, 0, 0.93); +} + +.transparent-app-folder-dialogs-94 { + background-color: rgba(0, 0, 0, 0.94); +} + +.transparent-app-folder-dialogs-95 { + background-color: rgba(0, 0, 0, 0.95); +} + +.transparent-app-folder-dialogs-96 { + background-color: rgba(0, 0, 0, 0.96); +} + +.transparent-app-folder-dialogs-97 { + background-color: rgba(0, 0, 0, 0.97); +} + +.transparent-app-folder-dialogs-98 { + background-color: rgba(0, 0, 0, 0.98); +} + +.transparent-app-folder-dialogs-99 { + background-color: rgba(0, 0, 0, 0.99); +} + +.transparent-app-folder-dialogs-100 { + background-color: rgba(0, 0, 0, 1.0); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/utilities.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/utilities.js new file mode 100644 index 0000000..5dbc319 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/utilities.js @@ -0,0 +1,39 @@ +'use strict' + +const GLib = imports.gi.GLib; + +let clearTimeout, clearInterval; +clearInterval = clearTimeout = GLib.Source.remove; + +var setTimeout = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_REMOVE; + }); +}; + +var setInterval = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_CONTINUE; + }); +}; + +var easeOutQuad = function(t, begin, end, duration) { + t /= duration + return begin + (t * (2 - t) * (end - begin)) +}; + +var ease_property = function(object, property, begin, end, duration, update) { + let start = Date.now(); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, update, () => { + let time = Date.now() - start; + if (time < duration) { + object[property] = easeOutQuad(time, begin, end, duration); + return GLib.SOURCE_CONTINUE; + } else { + object[property] = end; + return GLib.SOURCE_REMOVE; + } + }); +}; \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/window_list.js b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/window_list.js new file mode 100644 index 0000000..ca8708d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/blur-my-shell@aunetx/window_list.js @@ -0,0 +1,128 @@ +'use strict'; + +const { St, Shell, Meta, Gio } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + + +var WindowListBlur = class WindowListBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.blur_effects = []; + } + + enable() { + this._log("blurring window list"); + + // add the blur if window-list found + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_blur(child)); + + // listen to new actors in `Main.layoutManager.uiGroup` and blur if window-list + this.connections.connect(Main.layoutManager.uiGroup, 'actor-added', (_, child) => this.try_blur(child)); + + // connect to overview + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + + try_blur(child) { + if (child.constructor.name == "WindowList" && child.style != "background:transparent;") { + this._log("found window list to blur"); + + child.style = "background:transparent;"; + let effect = new Shell.BlurEffect({ + name: 'window-list-blur', + sigma: this.prefs.SIGMA.get(), + brightness: this.prefs.BRIGHTNESS.get(), + mode: 1 + }); + child.add_effect(effect); + this.blur_effects.push(effect); + + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("window list hack level 1"); + + child._windowList.get_children().forEach(child => { + this.connections.connect(child, 'button-press-event', () => { effect.queue_repaint(); }); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("window list hack level 2"); + + this.paint_signals.connect(child, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + child._windowList.get_children().forEach(window => this.blur_window_button(window)); + this.connections.connect(child._windowList, 'actor-added', (_, window) => { + this.blur_window_button(window); + }) + } + } + + blur_window_button(window) { + window.get_child_at_index(0).style = "box-shadow:none;background-color:rgba(0,0,0,0.2);border-radius:5px;"; + } + + try_remove_blur(child) { + if (child.constructor.name == "WindowList" && child.style == "background:transparent;") { + child.style = null; + child.remove_effect_by_name('window-list-blur'); + + child._windowList.get_children().forEach(child => { + child.get_child_at_index(0).style = null; + }); + } + } + + set_sigma(s) { + this.blur_effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.blur_effects.forEach(effect => { + effect.brightness = b; + }); + } + + hide() { + this.set_sigma(0); + } + + show() { + this.set_sigma(this.prefs.SIGMA.get()); + } + + disable() { + this._log("removing blur from window list"); + + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_remove_blur(child)) + + this.blur_effects = []; + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING new file mode 100644 index 0000000..8d61b15 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/README.md b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/README.md new file mode 100644 index 0000000..5000de1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/README.md @@ -0,0 +1,189 @@ +

+ +

+

+ + + + +

+ +![](media/design/png/dtp-main-p2.png) + +### Introduction + +Dash to Panel is an icon taskbar for Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications. + +Beyond that, just about every aspect of the panel is fully customizable. From positioning and scaling panel elements to running indicators to multi-monitor display, to window previews and even intellihide, Dash to Panel has everything you need to make your workspace feel like home. + +### Features + +|Customizable appearance| +|:-----:| +|![screenshot](media/design/gif/customizable.gif)| +|Hide & show panel elements and set their positions, sizes & colors| + +## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Customizable running indicators
MetroCiliora/Dashes
CilioraSquares/Segmented
DashesDots/Solid
Set position, style, weight & color of running indicators to easily and quickly identify focused and unfocused applications
+ +## + +|Live Previews on Hover| +|:-----:| +|![screenshot](media/design/gif/previews.gif)| +|Hover over the launcher icon for an open application to get a live window preview| + +## +|Launch by Number| +|:-----:| +|![](media/design/png/indicators-num.png.png)| +|Optionally launch your favorite applications via keyboard| + +## + +|Panel Intellihide| +|:-----:| +|![Intellihide](media/design/gif/Intellihide.gif)| +|Hide and reveal the panel according to your set preferences| + +## +|Additional Features|Feature Implemented| +|:-----|:-----:| +|Add "Show Desktop" button to panel|![](media/design/png/done.png)| +|Isolate running apps by workspaces and/or monitors|![](media/design/png/done.png)| +|Custom click behaviors (launch new window, cycle open windows, minimize, etc)|![](media/design/png/done.png)| +|Integrate native Gnome appMenu into right-click secondary menu|![](media/design/png/done.png)| +|Multi-monitor support|![](media/design/png/done.png)| +|Dynamic transparency|![](media/design/png/done.png)| +|Ungroup application windows|![](media/design/png/done.png)| +|Export and import settings|![](media/design/png/done.png)| +## + +### Installation + +**To install the most recent official release: +[Visit Dash-to-Panel at GNOME Extensions](https://extensions.gnome.org/extension/1160/dash-to-panel/)** + +To install a development version from source, please see the [Installation wiki page](https://github.com/jderose9/dash-to-panel/wiki/Installation). + +## +### FAQ + +How do I customize the panel? [See the Wiki](https://github.com/home-sweet-gnome/dash-to-panel/wiki/Enable-and-Customize#customize-it) + +How do I embed my bottom left notification drawer into the panel like a system tray? [Top Icons Plus](https://extensions.gnome.org/extension/2311/topicons-plus) or [(K)StatusNotifierItem/AppIndicator Support](https://extensions.gnome.org/extension/615/appindicator-support) + +How do I add a traditional start menu? [Arc Menu](https://extensions.gnome.org/extension/3628/arcmenu/) + +How do I disable the hot corner? [No Topleft Hot Corner](https://extensions.gnome.org/extension/118/no-topleft-hot-corner) + +How do I move the notifications to somewhere other than the top center? [Panel OSD](https://extensions.gnome.org/extension/708/panel-osd) + +How do I display Minimize & Maximize buttons? In the Tweak Tool application, turn on `Windows > Titlebar Buttons > Minimize & Maximize`. + +How do I reset the extension to its default settings? `dconf reset -f /org/gnome/shell/extensions/dash-to-panel/`. + +## +### Themes +While this extension works well with most popular Gnome Shell themes, the following themes are known to have explicitly added custom styles for this extension: +- [Ciliora Tertia](https://github.com/zagortenay333/ciliora-tertia-shell) / [Ciliora Secunda](https://github.com/zagortenay333/ciliora-secunda-shell) +- [Plano](https://github.com/lassekongo83/plano-theme) + + +## +### Compatibility + +This extension has been tested with Gnome 3.18+. + +This extension manipulates the Gnome Main Panel, aka Top Bar. So, most other extensions which operate on the top bar should be compatible. + +## +### Volunteers needed! + +This extension could be even better with your help! Any items in the issue tracker labelled `help wanted` or `good first issue` are up for grabs. For more info, see the [Contributing wiki page](https://github.com/jderose9/dash-to-panel/wiki/Contributing). + +## +### Credits + +This extension is developed and maintained by [@jderose9](https://github.com/jderose9) and [@charlesg99](https://github.com/charlesg99). + +Significant portions of code in this extension were derived from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html). + +Additional credits: This extension leverages the work for [ZorinOS Taskbar](https://github.com/ZorinOS/zorin-taskbar) (used in [ZorinOS](https://zorinos.com/)) to show window previews and allow the dash from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html) to be embedded in the Gnome main panel. +Code to set anchor position taken from [Thoma5/gnome-shell-extension-bottompanel](https://github.com/Thoma5/gnome-shell-extension-bottompanel). +Pattern for moving panel contents based on [Frippery Move Clock](http://frippery.org/extensions/) by R M Yorston. +Ideas for recursing child actors and assigning inline styles are based on code from the extension [StatusAreaHorizontalSpacing](https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension). +## + +#### Thanks to the following people for contributing via pull requests: + +- @franglais125 for launching apps by number (w/ overlay), bug fixes, and issue support +- @LinxGem33 and @sbarrett322 for artwork, logos, screenshots and design effort +- @dziku1337 for peek mode in window previews +- @robrobinbin for configuring appMenu on/off in the panel +- @MartinPL for toggling favorites on/off in panel +- @jackwickham for thumbnail middle and right click actions +- @abakkk for centering the taskbar icons in the panel, and animated taskbar hovering +- @quasoft for changing of font weight of ungrouped application titles +- @jordanribera for using icon's dominant color as running indicator color +- @tper0700 for dynamically building context menu based on system capabilities +- @levacic for configurable minimized application title font color +- @l3nn4rt for toggling workspace switch popup +- @hlechner for adjustable show desktop line color and window preview icon size +- @ArtyomZorin for animated urgent icons +- @jvpessoa10 for additional click window cycle options +- @marksvc for assigning percent of display for panel length +- @philippun1 for GNOME 40 support :rocket: + +#### Bug Fixes: +@imrvelj, @Teslator, @bil-elmoussaoui, @brandon-schumann, @sw9, @rockon999 , @lexruee, @3v1n0, @freeroot, @moqmar, @ArtyomZorin, @lkc0987, @saibotk, @vanillajonathan, @Zkdc, @leebickmtu, @l3nn4rt, @Melix19, @Aikatsui, @melix99, @kyrillzorin, @oneshadab, , @CorvetteCole + +#### Documentation Improvements: +@BoQsc, @zakkak, @dandv + +#### Translations: +@frnogueira / @victorwpbastos (pt_BR), @zeten30 (cs), @franglais125 / @calotam / @oeramirez (es), @LaurentTreguier / @SolarLiner (fr), @elsieholmes (uk), @hosiet (zh\_CN), @jonnius / @linuxr01 (de), @urbalazs / @pappfer (hu), @crayxt (kk), @pkomur / @MartinPL / @alex4401 (pl), @AlexGluck / @GoodNike / @rjapolov / @vantu5z (ru), @sicklylife-jp / @ryonakano (ja), @oltulu / @TeknoMobil / @daenney (tr), @sbadux / @kowalski7cc / @l3nn4rt (it), @OriginCode / @pan93412 (zh\_TW), @ojn (sv), @frandieguez (gl) + + +## +### License & Terms ![](media/design/png/copyleft-16.png) + +Dash to Panel is available under the terms of the GPL-v2 or later license See [`COPYING`](https://github.com/jderose9/dash-to-panel/blob/master/COPYING) for details. + +![](https://img.shields.io/badge/Language-JavaScript-yellow.svg) ![](https://img.shields.io/badge/Licence-GPL--2.0-blue.svg) diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui new file mode 100644 index 0000000..ed7ef90 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui @@ -0,0 +1,7508 @@ + + + + + + True + False + vertical + 1 + 1 + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animation type + 0 + + + + + True + False + center + + Simple + Ripple + Plank + + + + + + + + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 24 + 32 + + + True + False + 12 + Duration + True + 0 + end + + 0 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_duration_adjustment + 0 + 0 + right + True + + 0 + 1 + + + + + + True + False + Rotation + 0 + end + + 1 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_rotation_adjustment + 0 + 0 + right + True + + 1 + 1 + + + + + + True + False + Travel + 0 + end + + 2 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_travel_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + Zoom + 0 + end + + 3 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_zoom_adjustment + 0 + 0 + right + True + + 3 + 1 + + + + + + True + False + Convexity + 0 + end + + 4 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_convexity_adjustment + 1 + 1 + right + True + + 4 + 1 + + + + + + True + False + Extent + 0 + end + + 5 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_extent_adjustment + 0 + 0 + right + True + + 5 + 1 + + + + + + + + + + 100 + 1 + 10 + + + 0 + 300 + 1 + 5 + + + -30 + 30 + 1 + 5 + + + 0 + 100 + 1 + 5 + + + 100 + 250 + 1 + 5 + + + 0 + 3 + 0.1 + 1 + + + 1 + 10 + 0.1 + 1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + True + Nothing yet! + True + + + + + + + + + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + When set to minimize, double clicking minimizes all the windows of the application. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Toggle single / Cycle multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Shift+Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + + + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Integrate <i>AppMenu</i> items + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + <i>Show Details</i> menu item + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 1 + 5 + + + 5 + 1 + 5 + + + 50 + 9999 + 25 + 100 + + + 5 + 100 + 5 + 5 + + + True + False + 12 + 12 + vertical + 1 + 1 + + + True + False + 12 + 12 + 12 + 12 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Highlight focused application + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 8 + + + True + False + True + Icon dominant color + 0 + + 0 + 0 + + + + + + True + True + end + center + + + + + True + False + True + Custom color + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + Highlight opacity + 0 + + 2 + 0 + + + + + + True + True + end + 5 + focus_highlight_opacity_adjustment + 5 + + 2 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator size (px) + 0 + + 0 + 0 + + + + + + True + True + end + 0 + dot_size_adjustment + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator color - Icon Dominant + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + vertical + + + True + False + + + True + False + True + Indicator color - Override Theme + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + True + False + vertical + + + True + False + 12 + + + True + False + True + Use different for unfocused + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + + + + + + + + + + + 6 + 24 + 1 + 100 + + + 1000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + group_apps_label_font_size_adjustment + True + + 0 + 1 + + + + + + True + False + True + Font size (px) of the application titles (default is 14) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font weight of application titles + 0 + + 0 + 0 + + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the minimized application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Maximum width (px) of the application titles (default is 160) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + group_apps_label_max_width_adjustment + True + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use a fixed width for the application titles + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display running indicators on unfocused applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use the favorite icons as application launchers + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 2000 + 10 + 100 + + + 10 + 4000 + 10 + 100 + + + 10000 + 10 + 100 + + + 1 + 9990 + 10 + 100 + + + 1 + 5000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + True + + + True + False + True + Only hide the panel when it is obstructed by windows + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + The panel hides from + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Require pressure at the edge of the screen to reveal the panel + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + Required pressure threshold (px) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_threshold_adjustment + True + + 0 + 1 + + + + + + True + False + True + Required pressure timeout (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_time_adjustment + True + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Allow the panel to be revealed while in fullscreen mode + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Only hide secondary panels (requires multi-monitors option) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>i + + 0 + 1 + 2 + + + + + + True + False + True + Keyboard shortcut to reveal and hold the panel + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Hide and reveal animation duration (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_animation_time_adjustment + True + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before hiding the panel (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_close_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before enabling intellihide on start (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_enable_hide_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + + + + + 9999 + 25 + 100 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 255 + 10 + 25 + + + 1000 + 10 + 50 + + + 50 + 500 + 10 + 50 + + + 100 + 5 + 10 + + + 50 + 1 + 5 + + + 100 + 800 + 10 + 50 + + + 9999 + 25 + 100 + + + 6 + 24 + 1 + 100 + + + 8 + 48 + 1 + 100 + + + True + True + 460 + 480 + + + True + False + True + True + natural + natural + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + preview_timeout_adjustment + True + + 0 + 1 + + + + + + True + False + True + Time (ms) before showing (400 is default) + True + 0 + + 0 + 0 + + + + + + True + False + True + Animation time (ms) + 0 + + 2 + 0 + + + + + + True + True + end + 4 + 0 + preview_animation_time_adjustment + True + + 2 + 1 + + + + + + True + False + vertical + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + + + True + True + False + 12 + 4 + + + 4 + True + False + start + 4 + Immediate on application icon click + True + + + + + + 1 + 0 + + + + + + True + True + end + center + 4 + 25 + leave_timeout_adjustment + True + 25 + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Middle click on the preview to close the window + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + 0 + 0 + 2 + + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + 2 + 0 + + + + + + True + False + True + Window previews padding (px) + True + 0 + + 3 + 0 + + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + 3 + 1 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 1 + 1 + + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + 1 + 0 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 2 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use custom opacity for the previews background + True + 0 + + 0 + 0 + + + + + + True + False + True + If disabled, the previews background have the same opacity as the panel + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + center + 5 + preview_opacity_adjustment + 5 + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + + + True + False + end + 32 + + + Bottom + True + True + False + center + center + True + + + + + + Top + True + True + False + center + center + preview_title_position_bottom_button + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 32 + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + 4 + 6 + preview_custom_icon_size_adjustment + True + 6 + + + + 0 + 1 + + + + + + True + False + True + Icon size (px) of the window preview + True + 0 + + 1 + 0 + + + + + + True + False + True + If disabled, the previews icon size will be based on headerbar size + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + True + end + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + 0 + 1 + + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + 0 + 0 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + 0 + 0 + + + + + + True + False + end + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + 3 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + 4 + 0 + 2 + + + + + + + + + + True + True + 6 + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + peek_mode_opacity_adjustment + True + + 0 + 1 + + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 3 + 0 + 2 + + + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_icon_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_panel_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show popup when changing workspace + True + 0 + + 0 + 0 + + + + + + True + False + True + This affects workspace popup when scrolling on the panel only. + True + 0 + + + 1 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + + + + + + + 10000 + 250 + 1000 + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Super + Super + Alt + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys prefix + 0 + + 0 + 0 + + + + + + True + False + Hotkeys will either be Super+Number or Super+Alt+Num + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Never + Show temporarily + Always visible + + + 0 + 1 + 2 + + + + + + True + False + True + Number overlay + 0 + + 0 + 0 + + + + + + True + False + Temporarily show the application numbers over the icons when using the hotkeys. + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + shortcut_time_adjustment + + 0 + 1 + + + + + + True + False + True + Hide timeout (ms) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>q + + 0 + 1 + 2 + + + + + + True + False + True + Shortcut to show the overlay for 2 seconds + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show window previews on hotkey + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show previews when the application have multiple instances + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + end + center + + Number row + Numeric keypad + Both + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys are activated with + 0 + + 0 + 0 + + + + + + True + False + Select which keyboard number keys are used to activate the hotkeys + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + 100 + 1 + 10 + + + True + False + vertical + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Current Show Applications icon + True + 0 + + 0 + 0 + + + + + + 32 + 32 + True + False + end + gtk-missing-image + 32 + + 0 + 1 + + + + + + 140 + True + + 1 + 1 + + + + + + True + False + True + Custom Show Applications image icon + True + 0 + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + 0 + show_applications_side_padding_adjustment + + 0 + 1 + + + + + + True + False + True + Show Applications icon side padding (px) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Override escape key and return to desktop + True + 0 + + 0 + 0 + + + + + + + + + + 5000 + 10 + 100 + + + 5000 + 10 + 100 + + + 1 + 40 + 1 + 10 + + + True + False + vertical + + + True + False + none + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_width_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Override Show Desktop line color + 0 + + 1 + 0 + + + + + + True + False + 12 + end + + + True + True + True + end + True + + + + + True + True + end + center + + + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Reveal the desktop when hovering the Show Desktop button + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 4 + + + True + False + True + Delay before revealing the desktop (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_delay_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Fade duration (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_time_adjustment + True + 1 + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 2000 + 1 + 10 + + + 200 + 1 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + + + True + False + True + The panel background opacity is affected by + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_distance_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Change opacity when a window gets closer than (px) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + + + True + False + 12 + Change opacity to (%) + True + 0 + + + + + True + True + end + 0 + trans_opacity_min_adjustment + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_anim_time_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Opacity change animation duration (ms) + True + 0 + + 0 + 0 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + True + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + 32 + + + True + False + True + Display the main panel on + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Display panels on all monitors + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Panel Intellihide + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + True + False + True + Hide and reveal the panel according to preferences + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + + + True + False + True + Order and positions on monitor + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + Apply changes to all monitors + True + True + False + 12 + 4 + 4 + + 1 + 0 + 2 + + + + + + True + False + 6 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 6 + 6 + 12 + 32 + + + True + True + baseline + True + panel_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + Panel thickness (default is 48) + 0 + + 1 + 0 + + + + + + True + False + Panel length (%) (default is 100) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + panel_length_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + center + + Start + Middle + End + + + 3 + 1 + + + + + + True + False + Anchor + 0 + + 3 + 0 + + + + + + True + False + True + Panel screen position + 0 + + 0 + 0 + + + + + + True + False + 32 + + + Bottom + True + True + False + center + center + + True + + + + + + Top + True + True + False + center + center + + position_bottom_button + + + + + + Left + True + True + False + center + center + + position_bottom_button + + + + + + Right + True + True + False + center + center + + position_bottom_button + + + + 0 + 1 + + + + + + + 1 + 0 + + + + + + + + + + 2 + 0 + 2 + + + + + + + + True + False + 6 + none + + + + + + + + + + + + + + + + True + False + Position + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + App Icon Margin (default is 8) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_margin_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 32 + + + True + False + App Icon Padding (default is 4) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator position + 0 + + + + + True + False + 32 + + + Bottom + True + True + False + center + True + + + + + + Top + True + True + False + center + dots_bottom_button + + + + + + Left + True + True + False + center + dots_bottom_button + + + + + + Right + True + True + False + center + dots_bottom_button + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Focused app) + 0 + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Unfocused apps) + 0 + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background color + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + end + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background opacity + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Panel background opacity (%) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + 0 + trans_opacity_adjustment + + 0 + 1 + + + + + + True + False + True + vertical + + + True + False + True + Dynamic background opacity + True + 0 + + + + + True + False + True + Change opacity when a window gets close to the panel + True + 40 + 0 + + + + + 1 + 0 + + + + + + True + False + end + center + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme gradient + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Gradient top color and opacity (%) + 0 + + 0 + 0 + + + + + + True + False + True + Gradient bottom color and opacity (%) + 0 + + 1 + 0 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity1_adjustment + + + + 0 + 1 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity2_adjustment + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animate hovering app icons + 0 + + 2 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 2 + 1 + + + + + + + + + + + + + + + + + + True + False + Style + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Show favorite applications + 0 + + 0 + 0 + + + + + + True + False + True + Show running applications + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show favorite applications on secondary panels + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show <i>AppMenu</i> button + True + 0 + + 0 + 0 + + + + + + True + False + True + Top Bar > Show App Menu must be enabled in Tweak Tool + True + True + 0 + + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + True + False + True + Show window previews on hover + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show tooltip on hover + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Isolate Workspaces + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Isolate monitors + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Click empty space to close overview + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Disable show overview on startup + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Ungroup applications + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + + + + + + + + + + + + True + False + Behavior + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behaviour when clicking on the icon of a running application. + True + 0 + + + 1 + 0 + + + + + + True + False + True + Click action + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + center + + Cycle windows + minimize + Cycle through windows + Toggle single / Preview multiple + Toggle windows + Raise windows + Launch new instance + + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + False + 0 + + + True + False + 12 + 12 + 12 + 12 + 16 + 6 + + + True + False + vertical + + + True + False + True + Scroll panel action + 0 + + + + + True + False + True + Behavior when mouse scrolling over the panel. + True + 0 + + + + + 0 + 0 + + + + + + True + False + vertical + + + True + False + True + Scroll icon action + 0 + + + + + True + False + True + Behavior when mouse scrolling over an application icon. + True + 0 + + + + + 1 + 0 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + True + False + center + True + + Do nothing + Switch workspace + Cycle windows + Change volume + + + 0 + 2 + + + + + + True + False + center + True + + Do nothing + Cycle windows + Same as panel + + + 1 + 2 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 1 + 1 + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl. + True + True + 0 + + + 1 + 0 + + + + + + True + False + True + Use hotkeys to activate apps + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + True + False + Action + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + True + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + Tray Font Size (0 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_size_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + LeftBox Font Size (0 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + leftbox_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + Tray Item Padding (-1 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + Status Icon Padding (-1 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + statusicon_padding_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + LeftBox Padding (-1 = theme default) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + leftbox_padding_adjustment + 0 + 0 + right + True + + + 2 + 1 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Animate switching applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Animate launching new windows + 0 + + 1 + 0 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Keep original gnome-shell dash (overview) + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Force Activities hot corner on primary monitor + 0 + + 3 + 0 + + + + + + True + True + end + center + + 3 + 1 + + + + + + True + False + True + Activate panel menu buttons (e.g. date menu) on click only + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + False + True + Keep original gnome-shell top panel + 0 + + 1 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 20 + 32 + + + True + False + True + App icon secondary (right-click) menu + 0 + + 0 + 0 + + + + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + + + + + + + + + + + + Advanced Options + False + True + True + start + + + + + + + + + True + False + center + Fine-Tune + + + + + + + False + 24 + 24 + 24 + 24 + True + True + vertical + 5 + + + True + False + vertical + + + True + False + <b>Dash-to-Panel</b> + True + + + + + True + False + center + + + True + False + end + version: + + + + + True + False + start + ... + + + + + + + GitHub + True + True + True + center + https://github.com/jderose9/dash-to-panel + + + + + + + False + 20 + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + 12 + True + Use the buttons below to create a settings file from your current preferences that can be imported on a different machine. + True + 0 + + + 1 + 0 + 2 + + + + + + True + False + start + Export and import settings + + 0 + 0 + 2 + + + + + + Export to file + True + True + True + + 2 + 0 + + + + + + Import from file + True + True + True + + 2 + 1 + + + + + + + + + + + + + + + + + True + True + end + <span size="small">This program comes with ABSOLUTELY NO WARRANTY. See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span> + True + center + True + + + + + + + + + True + False + About + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js new file mode 100644 index 0000000..e79eae8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js @@ -0,0 +1,1964 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const Config = imports.misc.config; +const AppDisplay = imports.ui.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Taskbar = Me.imports.taskbar; +const Progress = Me.imports.progress; +const _ = imports.gettext.domain(Utils.TRANSLATION_DOMAIN).gettext; + +//timeout names +const T1 = 'setStyleTimeout'; +const T2 = 'mouseScrollTimeout'; +const T3 = 'showDotsTimeout'; +const T4 = 'overviewWindowDragEndTimeout'; +const T5 = 'switchWorkspaceTimeout'; +const T6 = 'displayProperIndicatorTimeout'; + +//right padding defined for .overview-label in stylesheet.css +const TITLE_RIGHT_PADDING = 8; + +let LABEL_GAP = 5; +let MAX_INDICATORS = 4; +var DEFAULT_PADDING_SIZE = 4; + +let DOT_STYLE = { + DOTS: "DOTS", + SQUARES: "SQUARES", + DASHES: "DASHES", + SEGMENTED: "SEGMENTED", + CILIORA: "CILIORA", + METRO: "METRO", + SOLID: "SOLID" +} + +let DOT_POSITION = { + TOP: "TOP", + BOTTOM: "BOTTOM", + LEFT: 'LEFT', + RIGHT: 'RIGHT' +} + +let recentlyClickedAppLoopId = 0; +let recentlyClickedApp = null; +let recentlyClickedAppWindows = null; +let recentlyClickedAppIndex = 0; +let recentlyClickedAppMonitorIndex; + +let tracker = Shell.WindowTracker.get_default(); +let menuRedisplayFunc = !!(AppDisplay.AppMenu || AppDisplay.AppIconMenu).prototype._rebuildMenu ? '_rebuildMenu' : '_redisplay'; + +/** + * Extend AppIcon + * + * - Apply a css class based on the number of windows of each application (#N); + * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); + * a class of the form "running#N" is applied to the AppWellIcon actor. + * like the original .running one. + * - add a .focused style to the focused app + * - Customize click actions. + * - Update minimization animation target + * + */ + +var taskbarAppIcon = Utils.defineClass({ + Name: 'DashToPanel.TaskbarAppIcon', + Extends: AppDisplay.AppIcon, + ParentConstrParams: [[0, 'app'], [2]], + + _init: function(appInfo, panel, iconParams, previewMenu, iconAnimator) { + this.dtpPanel = panel; + this._nWindows = 0; + this.window = appInfo.window; + this.isLauncher = appInfo.isLauncher; + this._previewMenu = previewMenu; + this.iconAnimator = iconAnimator; + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + // Fix touchscreen issues before the listener is added by the parent constructor. + this._onTouchEvent = function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) { + // Open the popup menu on long press. + this._setPopupTimeout(); + } else if (this._menuTimeoutId != 0 && (event.type() == Clutter.EventType.TOUCH_END || event.type() == Clutter.EventType.TOUCH_CANCEL)) { + // Activate/launch the application. + this.activate(1); + this._removeMenuTimeout(); + } + // Disable dragging via touch screen as it's buggy as hell. Not perfect for tablet users, but the alternative is way worse. + // Also, EVENT_PROPAGATE launches applications twice with this solution, so this.activate(1) above must only be called if there's already a window. + return Clutter.EVENT_STOP; + }; + // Hack for missing TOUCH_END event. + this._onLeaveEvent = function(actor, event) { + this.actor.fake_release(); + if (this._menuTimeoutId != 0) this.activate(1); // Activate/launch the application if TOUCH_END didn't fire. + this._removeMenuTimeout(); + }; + + this.callParent('_init', appInfo.app, iconParams); + + Utils.wrapActor(this.icon); + Utils.wrapActor(this); + + this._dot.set_width(0); + this._isGroupApps = Me.settings.get_boolean('group-apps'); + + this._container = new St.Widget({ style_class: 'dtp-container', layout_manager: new Clutter.BinLayout() }); + this._dotsContainer = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._dtpIconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(), style: getIconContainerStyle(panel.checkIfVertical()) }); + + this.actor.remove_actor(this._iconContainer); + + this._dtpIconContainer.add_child(this._iconContainer); + + if (appInfo.window) { + let box = new St.BoxLayout(); + + this._windowTitle = new St.Label({ + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.START, + style_class: 'overview-label' + }); + + this._updateWindowTitle(); + this._updateWindowTitleStyle(); + + this._scaleFactorChangedId = Utils.getStageTheme().connect('changed', () => this._updateWindowTitleStyle()); + + box.add_child(this._dtpIconContainer); + box.add_child(this._windowTitle); + + this._dotsContainer.add_child(box); + } else { + this._dotsContainer.add_child(this._dtpIconContainer); + } + + this._container.add_child(this._dotsContainer); + this.actor.set_child(this._container); + + if (panel.checkIfVertical()) { + this.actor.set_width(panel.geom.w); + } + + // Monitor windows-changes instead of app state. + // Keep using the same Id and function callback (that is extended) + if(this._stateChangedId > 0) { + this.app.disconnect(this._stateChangedId); + this._stateChangedId = 0; + } + + this._onAnimateAppiconHoverChanged(); + this._setAppIconPadding(); + this._showDots(); + + this._focusWindowChangedId = global.display.connect('notify::focus-window', + Lang.bind(this, this._onFocusAppChanged)); + + this._windowEnteredMonitorId = this._windowLeftMonitorId = 0; + this._stateChangedId = this.app.connect('windows-changed', Lang.bind(this, this.onWindowsChanged)); + + if (!this.window) { + if (Me.settings.get_boolean('isolate-monitors')) { + this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this)); + this._windowLeftMonitorId = Utils.DisplayWrapper.getScreen().connect('window-left-monitor', this.onWindowEnteredOrLeft.bind(this)); + } + + this._titleWindowChangeId = 0; + this._minimizedWindowChangeId = 0; + } else { + this._titleWindowChangeId = this.window.connect('notify::title', + Lang.bind(this, this._updateWindowTitle)); + + this._minimizedWindowChangeId = this.window.connect('notify::minimized', + Lang.bind(this, this._updateWindowTitleStyle)); + } + + this._scrollEventId = this.actor.connect('scroll-event', this._onMouseScroll.bind(this)); + + this._overviewWindowDragEndId = Main.overview.connect('window-drag-end', + Lang.bind(this, this._onOverviewWindowDragEnd)); + + this._switchWorkspaceId = global.window_manager.connect('switch-workspace', + Lang.bind(this, this._onSwitchWorkspace)); + + this._hoverChangeId = this.actor.connect('notify::hover', () => this._onAppIconHoverChanged()); + + this._dtpSettingsSignalIds = [ + Me.settings.connect('changed::animate-appicon-hover', Lang.bind(this, this._onAnimateAppiconHoverChanged)), + Me.settings.connect('changed::dot-position', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-size', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-focused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-unfocused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-override', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-different', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-color', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-opacity', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::group-apps-label-font-size', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-weight', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color-minimized', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-max-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-use-fixed-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-underline-unfocused', Lang.bind(this, this._settingsChangeRefresh)) + ] + + this.forcedOverview = false; + + this._progressIndicator = new Progress.ProgressIndicator(this, panel.progressManager); + + this._numberOverlay(); + }, + + getDragActor: function() { + return this.app.create_icon_texture(this.dtpPanel.taskbar.iconSize); + }, + + // Used by TaskbarItemContainer to animate appIcons on hover + getCloneButton: function() { + // The source of the clone is this._container, + // using this.actor directly would break DnD style. + let clone = new Clutter.Clone({ + source: this.actor.child, + x: this.actor.child.x, y: this.actor.child.y, + width: this.actor.child.width, height: this.actor.child.height, + pivot_point: new Utils.getPoint({ x: 0.5, y: 0.5 }), + opacity: 255, + reactive: false, + x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER, + }); + + // "clone" of this.actor + return new St.Button({ + child: clone, + x: this.actor.x, y: this.actor.y, + width: this.actor.width, height: this.actor.height, + reactive: false, + }); + }, + + shouldShowTooltip: function() { + if (!Me.settings.get_boolean('show-tooltip') || + (!this.isLauncher && Me.settings.get_boolean("show-window-previews") && + this.getAppIconInterestingWindows().length > 0)) { + return false; + } else { + return this.actor.hover && !this.window && + (!this._menu || !this._menu.isOpen) && + (this._previewMenu.getCurrentAppIcon() !== this); + } + }, + + _onAppIconHoverChanged: function() { + if (!Me.settings.get_boolean('show-window-previews') || + (!this.window && !this._nWindows)) { + return; + } + + if (this.actor.hover) { + this._previewMenu.requestOpen(this); + } else { + this._previewMenu.requestClose(); + } + }, + + _onDestroy: function() { + this.callParent('_onDestroy'); + this._destroyed = true; + + this._timeoutsHandler.destroy(); + + this._previewMenu.close(true); + + // Disconect global signals + // stateChangedId is already handled by parent) + + if(this._overviewWindowDragEndId) + Main.overview.disconnect(this._overviewWindowDragEndId); + + if(this._focusWindowChangedId) + global.display.disconnect(this._focusWindowChangedId); + + if(this._titleWindowChangeId) + this.window.disconnect(this._titleWindowChangeId); + + if(this._minimizedWindowChangeId) + this.window.disconnect(this._minimizedWindowChangeId); + + if (this._windowEnteredMonitorId) { + Utils.DisplayWrapper.getScreen().disconnect(this._windowEnteredMonitorId); + Utils.DisplayWrapper.getScreen().disconnect(this._windowLeftMonitorId); + } + + if(this._switchWorkspaceId) + global.window_manager.disconnect(this._switchWorkspaceId); + + if(this._scaleFactorChangedId) + Utils.getStageTheme().disconnect(this._scaleFactorChangedId); + + if (this._hoverChangeId) { + this.actor.disconnect(this._hoverChangeId); + } + + if (this._scrollEventId) { + this.actor.disconnect(this._scrollEventId); + } + + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + }, + + onWindowsChanged: function() { + this._updateWindows(); + this.updateIcon(); + }, + + onWindowEnteredOrLeft: function() { + if (this._checkIfFocusedApp()) { + this._updateWindows(); + this._displayProperIndicator(); + } + }, + + updateTitleStyle: function() { + this._updateWindowTitleStyle(); + }, + + // Update indicator and target for minimization animation + updateIcon: function() { + + // If (for unknown reason) the actor is not on the stage the reported size + // and position are random values, which might exceeds the integer range + // resulting in an error when assigned to the a rect. This is a more like + // a workaround to prevent flooding the system with errors. + if (this.actor.get_stage() == null) + return; + + let rect = new Meta.Rectangle(); + + [rect.x, rect.y] = this.actor.get_transformed_position(); + [rect.width, rect.height] = this.actor.get_transformed_size(); + + let windows = this.window ? [this.window] : this.getAppIconInterestingWindows(true); + windows.forEach(function(w) { + w.set_icon_geometry(rect); + }); + }, + + _onAnimateAppiconHoverChanged: function() { + if (Me.settings.get_boolean('animate-appicon-hover')) { + this._container.add_style_class_name('animate-appicon-hover'); + + // Workaround to prevent scaled icon from being ugly when it is animated on hover. + // It increases the "resolution" of the icon without changing the icon size. + this.icon.createIcon = (iconSize) => this.app.create_icon_texture(2 * iconSize); + this._iconIconBinActorAddedId = this.icon._iconBin.connect('actor-added', () => { + if (this.icon._iconBin.child.mapped) { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + } else { + let iconMappedId = this.icon._iconBin.child.connect('notify::mapped', () => { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + this.icon._iconBin.child.disconnect(iconMappedId); + }); + } + }); + if (this.icon._iconBin.child) + this.icon._createIconTexture(this.icon.iconSize); + } else { + this._container.remove_style_class_name('animate-appicon-hover'); + + if (this._iconIconBinActorAddedId) { + this.icon._iconBin.disconnect(this._iconIconBinActorAddedId); + this._iconIconBinActorAddedId = 0; + this.icon.createIcon = Lang.bind(this, this._createIcon); + } + } + }, + + _onMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-icon-action'); + + if (scrollAction === 'PASS_THROUGH') { + return this.dtpPanel._onPanelMouseScroll(actor, event); + } else if (scrollAction === 'NOTHING' || (!this.window && !this._nWindows)) { + return; + } + + let direction = Utils.getMouseScrollDirection(event); + + if (direction && !this._timeoutsHandler.getId(T2)) { + this._timeoutsHandler.add([T2, Me.settings.get_int('scroll-icon-delay'), () => {}]); + + let windows = this.getAppIconInterestingWindows(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + Utils.activateSiblingWindow(windows, direction, this.window); + } + }, + + _showDots: function() { + // Just update style if dots already exist + if (this._focusedDots && this._unfocusedDots) { + this._updateWindows(); + return; + } + + if (!this._isGroupApps) { + this._focusedDots = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + visible: false + }); + + let mappedId = this.actor.connect('notify::mapped', () => { + this._displayProperIndicator(); + this.actor.disconnect(mappedId); + }); + } else { + this._focusedDots = new St.DrawingArea(), + this._unfocusedDots = new St.DrawingArea(); + this._focusedDots._tweeningToSize = null, + this._unfocusedDots._tweeningToSize = null; + + this._focusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._focusedDots, Me.settings.get_string('dot-style-focused'), true); + this._displayProperIndicator(); + })); + + this._unfocusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._unfocusedDots, Me.settings.get_string('dot-style-unfocused'), false); + this._displayProperIndicator(); + })); + + this._dotsContainer.add_child(this._unfocusedDots); + + this._updateWindows(); + + this._timeoutsHandler.add([T3, 0, () => { + this._resetDots(); + this._displayProperIndicator(); + }]); + } + + this._dotsContainer.add_child(this._focusedDots); + }, + + _resetDots: function() { + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + [this._focusedDots, this._unfocusedDots].forEach(d => { + d._tweeningToSize = null; + d.set_size(-1, -1); + d.x_expand = d.y_expand = false; + + d[isHorizontalDots ? 'width' : 'height'] = 1; + d[(isHorizontalDots ? 'y' : 'x') + '_expand'] = true; + }); + }, + + _settingsChangeRefresh: function() { + if (this._isGroupApps) { + this._updateWindows(); + this._resetDots(); + this._focusedDots.queue_repaint(); + this._unfocusedDots.queue_repaint(); + } + + this._displayProperIndicator(true); + }, + + _updateWindowTitleStyle: function() { + if (this._windowTitle) { + let useFixedWidth = Me.settings.get_boolean('group-apps-use-fixed-width'); + let variableWidth = !useFixedWidth || this.dtpPanel.checkIfVertical() || this.dtpPanel.taskbar.fullScrollView; + let fontWeight = Me.settings.get_string('group-apps-label-font-weight'); + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let fontColor = this.window.minimized ? + Me.settings.get_string('group-apps-label-font-color-minimized') : + Me.settings.get_string('group-apps-label-font-color'); + let scaleFactor = Utils.getScaleFactor(); + let maxLabelWidth = Me.settings.get_int('group-apps-label-max-width') * scaleFactor; + + this._windowTitle[(maxLabelWidth > 0 ? 'show' : 'hide')](); + + this._windowTitle.clutter_text.natural_width = useFixedWidth ? maxLabelWidth : 0; + this._windowTitle.clutter_text.natural_width_set = useFixedWidth; + this._windowTitle.set_width(variableWidth ? -1 : maxLabelWidth + TITLE_RIGHT_PADDING * scaleFactor); + + this._windowTitle.set_style('font-size: ' + Me.settings.get_int('group-apps-label-font-size') * fontScale + 'px;' + + 'font-weight: ' + fontWeight + ';' + + (useFixedWidth ? '' : 'max-width: ' + maxLabelWidth + 'px;') + + 'color: ' + fontColor); + } + }, + + _updateWindowTitle: function() { + if (this._windowTitle.text != this.window.title) { + this._windowTitle.text = (this.window.title ? this.window.title : this.app.get_name()).replace(/\r?\n|\r/g, '').trim(); + + if (this._focusedDots) { + this._displayProperIndicator(); + } + } + }, + + _setIconStyle: function(isFocused) { + let inlineStyle = 'margin: 0;'; + + if(Me.settings.get_boolean('focus-highlight') && + this._checkIfFocusedApp() && !this.isLauncher && + (!this.window || isFocused) && !this._isThemeProvidingIndicator() && this._checkIfMonitorHasFocus()) { + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let isWide = this._isWideDotStyle(focusedDotStyle); + let pos = Me.settings.get_string('dot-position'); + let highlightMargin = isWide ? Me.settings.get_int('dot-size') : 0; + + if(!this.window) { + let containerWidth = this._dtpIconContainer.get_width() / Utils.getScaleFactor();; + let backgroundSize = containerWidth + "px " + + (containerWidth - (pos == DOT_POSITION.BOTTOM ? highlightMargin : 0)) + "px;"; + + if (focusedDotStyle == DOT_STYLE.CILIORA || focusedDotStyle == DOT_STYLE.SEGMENTED) + highlightMargin += 1; + + if (this._nWindows > 1 && focusedDotStyle == DOT_STYLE.METRO) { + let bgSvg = '/img/highlight_stacked_bg'; + + if (pos == DOT_POSITION.LEFT || pos == DOT_POSITION.RIGHT) { + bgSvg += (this.dtpPanel.checkIfVertical() ? '_2' : '_3'); + } + + inlineStyle += "background-image: url('" + Me.path + bgSvg + ".svg');" + + "background-position: 0 " + (pos == DOT_POSITION.TOP ? highlightMargin : 0) + "px;" + + "background-size: " + backgroundSize; + } + } + + let highlightColor = this._getFocusHighlightColor(); + inlineStyle += "background-color: " + cssHexTocssRgba(highlightColor, Me.settings.get_int('focus-highlight-opacity') * 0.01); + } + + if(this._dotsContainer.get_style() != inlineStyle && this._dotsContainer.mapped) { + if (!this._isGroupApps) { + //when the apps are ungrouped, set the style synchronously so the icons don't jump around on taskbar redraw + this._dotsContainer.set_style(inlineStyle); + } else if (!this._timeoutsHandler.getId(T1)) { + //graphical glitches if i dont set this on a timeout + this._timeoutsHandler.add([T1, 0, () => this._dotsContainer.set_style(inlineStyle)]); + } + } + }, + + _checkIfFocusedApp: function() { + return tracker.focus_app == this.app; + }, + + _checkIfMonitorHasFocus: function() { + return global.display.focus_window && + (!Me.settings.get_boolean('multi-monitors') || // only check same monitor index if multi window is enabled. + !Me.settings.get_boolean('isolate-monitors') || + global.display.focus_window.get_monitor() === this.dtpPanel.monitor.index); + }, + + _setAppIconPadding: function() { + let padding = getIconPadding(this.dtpPanel.monitor.index); + let margin = Me.settings.get_int('appicon-margin'); + + this.actor.set_style('padding:' + (this.dtpPanel.checkIfVertical() ? margin + 'px 0' : '0 ' + margin + 'px;')); + this._iconContainer.set_style('padding: ' + padding + 'px;'); + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + + if (this._draggable) { + this._draggable.fakeRelease(); + } + + if (this.isDragged) { + return; + } + + if (!this._menu) { + this._menu = new taskbarSecondaryMenu(this, this.dtpPanel); + this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { + this.activateWindow(window, Me.settings); + })); + this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + + this._menuManager.addMenu(this._menu); + } + + this.emit('menu-state-changed', true); + + this._previewMenu.close(true); + + this.actor.set_hover(true); + this._menu.actor.add_style_class_name('dashtopanelSecondaryMenu'); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + _onFocusAppChanged: function(windowTracker) { + this._displayProperIndicator(true); + }, + + _onOverviewWindowDragEnd: function(windowTracker) { + this._timeoutsHandler.add([T4, 0, () => this._displayProperIndicator()]); + }, + + _onSwitchWorkspace: function(windowTracker) { + if (this._isGroupApps) { + this._timeoutsHandler.add([T5, 0, () => this._displayProperIndicator(true)]); + } else { + this._displayProperIndicator(); + } + }, + + _displayProperIndicator: function (force) { + let isFocused = this._isFocusedWindow(); + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + this._setIconStyle(isFocused); + + if(!this._isGroupApps) { + if (this.window && (Me.settings.get_boolean('group-apps-underline-unfocused') || isFocused)) { + let align = Clutter.ActorAlign[position == DOT_POSITION.TOP || position == DOT_POSITION.LEFT ? 'START' : 'END']; + + this._focusedDots.set_size(0, 0); + this._focusedDots[isHorizontalDots ? 'height' : 'width'] = this._getRunningIndicatorSize(); + + this._focusedDots.y_align = this._focusedDots.x_align = Clutter.ActorAlign.FILL; + this._focusedDots[(isHorizontalDots ? 'y' : 'x') + '_align'] = align; + this._focusedDots.background_color = this._getRunningIndicatorColor(isFocused); + this._focusedDots.show(); + } else if (this._focusedDots.visible) { + this._focusedDots.hide(); + } + } else { + let sizeProp = isHorizontalDots ? 'width' : 'height'; + let containerSize = this._container[sizeProp]; + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let unfocusedDotStyle = Me.settings.get_string('dot-style-unfocused'); + let focusedIsWide = this._isWideDotStyle(focusedDotStyle); + let unfocusedIsWide = this._isWideDotStyle(unfocusedDotStyle); + + let newFocusedDotsSize = 0; + let newFocusedDotsOpacity = 0; + let newUnfocusedDotsSize = 0; + let newUnfocusedDotsOpacity = 0; + + isFocused = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + this._timeoutsHandler.add([T6, 0, () => { + if (!this._destroyed) { + if(isFocused) + this.actor.add_style_class_name('focused'); + else + this.actor.remove_style_class_name('focused'); + } + }]); + + if(focusedIsWide) { + newFocusedDotsSize = (isFocused && this._nWindows > 0) ? containerSize : 0; + newFocusedDotsOpacity = 255; + } else { + newFocusedDotsSize = containerSize; + newFocusedDotsOpacity = (isFocused && this._nWindows > 0) ? 255 : 0; + } + + if(unfocusedIsWide) { + newUnfocusedDotsSize = (!isFocused && this._nWindows > 0) ? containerSize : 0; + newUnfocusedDotsOpacity = 255; + } else { + newUnfocusedDotsSize = containerSize; + newUnfocusedDotsOpacity = (!isFocused && this._nWindows > 0) ? 255 : 0; + } + + // Only animate if... + // animation is enabled in settings + // AND (going from a wide style to a narrow style indicator or vice-versa + // OR going from an open app to a closed app or vice versa) + if(Me.settings.get_boolean('animate-app-switch') && + ((focusedIsWide != unfocusedIsWide) || + (this._focusedDots[sizeProp] != newUnfocusedDotsSize || this._unfocusedDots[sizeProp] != newFocusedDotsSize))) { + this._animateDotDisplay(this._focusedDots, newFocusedDotsSize, this._unfocusedDots, newUnfocusedDotsOpacity, force, sizeProp); + this._animateDotDisplay(this._unfocusedDots, newUnfocusedDotsSize, this._focusedDots, newFocusedDotsOpacity, force, sizeProp); + } else { + this._focusedDots.opacity = newFocusedDotsOpacity; + this._unfocusedDots.opacity = newUnfocusedDotsOpacity; + this._focusedDots[sizeProp] = newFocusedDotsSize; + this._unfocusedDots[sizeProp] = newUnfocusedDotsSize; + } + } + }, + + _animateDotDisplay: function (dots, newSize, otherDots, newOtherOpacity, force, sizeProp) { + if((dots[sizeProp] != newSize && dots._tweeningToSize !== newSize) || force) { + let tweenOpts = { + time: Taskbar.DASH_ANIMATION_TIME, + transition: 'easeInOutCubic', + onComplete: Lang.bind(this, function() { + if(newOtherOpacity > 0) + otherDots.opacity = newOtherOpacity; + dots._tweeningToSize = null; + }) + }; + + if(newOtherOpacity == 0) + otherDots.opacity = newOtherOpacity; + + tweenOpts[sizeProp] = newSize; + dots._tweeningToSize = newSize; + + Utils.animate(dots, tweenOpts); + } + }, + + _isFocusedWindow: function() { + let focusedWindow = global.display.focus_window; + + while (focusedWindow) { + if (focusedWindow == this.window) { + return true; + } + + focusedWindow = focusedWindow.get_transient_for(); + } + + return false; + }, + + _isWideDotStyle: function(dotStyle) { + return dotStyle == DOT_STYLE.SEGMENTED || + dotStyle == DOT_STYLE.CILIORA || + dotStyle == DOT_STYLE.METRO || + dotStyle == DOT_STYLE.SOLID; + }, + + _isThemeProvidingIndicator: function () { + // This is an attempt to determine if the theme is providing their own + // running indicator by way of a border image on the icon, for example in + // the theme Ciliora + return (this.icon.actor.get_stage() && + this.icon.actor.get_theme_node().get_border_image()); + }, + + activate: function(button, handleAsGrouped) { + let event = Clutter.get_current_event(); + let modifiers = event ? event.get_state() : 0; + + // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.) + modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK); + + // We don't change the CTRL-click behaviour: in such case we just chain + // up the parent method and return. + if (modifiers & Clutter.ModifierType.CONTROL_MASK) { + // Keep default behaviour: launch new window + // By calling the parent method I make it compatible + // with other extensions tweaking ctrl + click + this.callParent('activate', button); + return; + } + + // We check what type of click we have and if the modifier SHIFT is + // being used. We then define what buttonAction should be for this + // event. + let buttonAction = 0; + if (button && button == 2 ) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-middle-click-action'); + else + buttonAction = Me.settings.get_string('middle-click-action'); + } + else if (button && button == 1) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-click-action'); + else + buttonAction = Me.settings.get_string('click-action'); + } + + let appCount = this.getAppIconInterestingWindows().length; + let previewedAppIcon = this._previewMenu.getCurrentAppIcon(); + this._previewMenu.close(Me.settings.get_boolean('window-preview-hide-immediate-click')); + + // We check if the app is running, and that the # of windows is > 0 in + // case we use workspace isolation, + let appIsRunning = this.app.state == Shell.AppState.RUNNING && appCount > 0; + + // We customize the action only when the application is already running + if (appIsRunning && !this.isLauncher) { + if (this.window && !handleAsGrouped) { + //ungrouped applications behaviors + switch (buttonAction) { + case 'RAISE': case 'CYCLE': case 'CYCLE-MIN': case 'MINIMIZE': case 'TOGGLE-SHOWPREVIEW': case 'TOGGLE-CYCLE': + if (!Main.overview._shown && + (buttonAction == 'MINIMIZE' || buttonAction == 'TOGGLE-SHOWPREVIEW' || buttonAction == 'TOGGLE-CYCLE' || buttonAction == 'CYCLE-MIN') && + (this._isFocusedWindow() || (buttonAction == 'MINIMIZE' && (button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK)))) { + this.window.minimize(); + } else { + Main.activateWindow(this.window); + } + + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "QUIT": + this.window.delete(global.get_current_time()); + break; + } + } else { + //grouped application behaviors + let monitor = this.dtpPanel.monitor; + let appHasFocus = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + switch (buttonAction) { + case "RAISE": + activateAllWindows(this.app, monitor); + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "MINIMIZE": + // In overview just activate the app, unless the acion is explicitely + // requested with a keyboard modifier + if (!Main.overview._shown || modifiers){ + // If we have button=2 or a modifier, allow minimization even if + // the app is not focused + if (appHasFocus || button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) { + // minimize all windows on double click and always in the case of primary click without + // additional modifiers + let all_windows = (button == 1 && ! modifiers) || event.get_click_count() > 1; + minimizeWindow(this.app, all_windows, monitor); + } + else + activateAllWindows(this.app, monitor); + } + else + this.app.activate(); + break; + + case "CYCLE": + if (!Main.overview._shown){ + if (appHasFocus) + cycleThroughWindows(this.app, false, false, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "CYCLE-MIN": + if (!Main.overview._shown){ + if (appHasFocus || (recentlyClickedApp == this.app && recentlyClickedAppWindows[recentlyClickedAppIndex % recentlyClickedAppWindows.length] == "MINIMIZE")) + cycleThroughWindows(this.app, false, true, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "TOGGLE-SHOWPREVIEW": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + if (event.get_click_count() > 1) { + // minimize all windows if double clicked + minimizeWindow(this.app, true, monitor); + } else if (previewedAppIcon != this) { + this._previewMenu.open(this); + } + + this.emit('sync-tooltip'); + } + } + else + this.app.activate(); + break; + case "TOGGLE-CYCLE": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + cycleThroughWindows(this.app, false, false, monitor); + } + } + else + this.app.activate(); + break; + case "QUIT": + closeAllWindows(this.app, monitor); + break; + } + } + } + else { + this._launchNewInstance(); + } + + Main.overview.hide(); + }, + + _launchNewInstance: function() { + if (this.app.can_open_new_window()) { + let appActions = this.app.get_app_info().list_actions(); + let newWindowIndex = appActions.indexOf('new-window'); + + if(Me.settings.get_boolean('animate-window-launch')) { + this.animateLaunch(); + } + + if (newWindowIndex < 0) { + this.app.open_new_window(-1); + } else { + this.app.launch_action(appActions[newWindowIndex], global.get_current_time(), -1); + } + } else { + let windows = this.window ? [this.window] : this.app.get_windows(); + + if (windows.length) { + Main.activateWindow(windows[0]); + } else { + this.app.activate(); + } + } + }, + + _updateWindows: function() { + let windows = [this.window]; + + if (!this.window) { + windows = this.getAppIconInterestingWindows(); + + this._nWindows = windows.length; + + for (let i = 1; i <= MAX_INDICATORS; i++){ + let className = 'running'+i; + if(i != this._nWindows) + this.actor.remove_style_class_name(className); + else + this.actor.add_style_class_name(className); + } + } + + this._previewMenu.update(this, windows); + }, + + _getRunningIndicatorCount: function() { + return Math.min(this._nWindows, MAX_INDICATORS); + }, + + _getRunningIndicatorSize: function() { + return Me.settings.get_int('dot-size') * Utils.getScaleFactor(); + }, + + _getRunningIndicatorColor: function(isFocused) { + let color; + const fallbackColor = new Clutter.Color({ red: 82, green: 148, blue: 226, alpha: 255 }); + + if (Me.settings.get_boolean('dot-color-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) { + color = Clutter.color_from_string(palette.original)[1]; + } else { // unable to determine color, fall back to theme + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + } else if(Me.settings.get_boolean('dot-color-override')) { + let dotColorSettingPrefix = 'dot-color-'; + + if(!isFocused && Me.settings.get_boolean('dot-color-unfocused-different')) + dotColorSettingPrefix = 'dot-color-unfocused-'; + + color = Clutter.color_from_string(Me.settings.get_string(dotColorSettingPrefix + (this._getRunningIndicatorCount() || 1) ))[1]; + } else { + // Re-use the style - background color, and border width and color - + // of the default dot + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + + return color; + }, + + _getFocusHighlightColor: function() { + if (Me.settings.get_boolean('focus-highlight-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) return palette.original; + } + return Me.settings.get_string('focus-highlight-color'); + }, + + _drawRunningIndicator: function(area, type, isFocused) { + let n = this._getRunningIndicatorCount(); + + if (!n) { + return; + } + + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + let bodyColor = this._getRunningIndicatorColor(isFocused); + let [areaWidth, areaHeight] = area.get_surface_size(); + let cr = area.get_context(); + let size = this._getRunningIndicatorSize(); + + let areaSize = areaWidth; + let startX = 0; + let startY = 0; + + if (isHorizontalDots) { + if (position == DOT_POSITION.BOTTOM) { + startY = areaHeight - size; + } + } else { + areaSize = areaHeight; + + if (position == DOT_POSITION.RIGHT) { + startX = areaWidth - size; + } + } + + if (type == DOT_STYLE.SOLID || type == DOT_STYLE.METRO) { + if (type == DOT_STYLE.SOLID || n <= 1) { + cr.translate(startX, startY); + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [areaSize, size] : [size, areaSize])); + cr.fill(); + } else { + let blackenedLength = (1 / 48) * areaSize; // need to scale with the SVG for the stacked highlight + let darkenedLength = isFocused ? (2 / 48) * areaSize : (10 / 48) * areaSize; + let blackenedColor = bodyColor.shade(.3); + let darkenedColor = bodyColor.shade(.7); + let solidDarkLength = areaSize - darkenedLength; + let solidLength = solidDarkLength - blackenedLength; + + cr.translate(startX, startY); + + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [solidLength, size] : [size, solidLength])); + cr.fill(); + Clutter.cairo_set_source_color(cr, blackenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidLength, 0, 1, size] : [0, solidLength, size, 1]); + cr.fill(); + Clutter.cairo_set_source_color(cr, darkenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidDarkLength, 0, darkenedLength, size] : [0, solidDarkLength, size, darkenedLength]); + cr.fill(); + } + } else { + let spacing = Math.ceil(areaSize / 18); // separation between the indicators + let length; + let dist; + let indicatorSize; + let translate; + let preDraw = () => {}; + let draw; + let drawDash = (i, dashLength) => { + dist = i * dashLength + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0, dashLength, size] : [0, dist, size, dashLength])); + }; + + switch (type) { + case DOT_STYLE.CILIORA: + spacing = size; + length = areaSize - (size * (n - 1)) - (spacing * (n - 1)); + translate = () => cr.translate(startX, startY); + preDraw = () => { + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [length, size] : [size, length])); + }; + draw = i => { + dist = length + (i * spacing) + ((i - 1) * size); + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DOTS: + let radius = size / 2; + + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = (2 * i + 1) * radius + i * spacing; + cr.arc.apply(cr, (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI])); + }; + break; + case DOT_STYLE.SQUARES: + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = i * size + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DASHES: + length = Math.floor(areaSize / 4) - spacing; + translate = () => { + indicatorSize = Math.floor((areaSize - n * length - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => drawDash(i, length); + break; + case DOT_STYLE.SEGMENTED: + length = Math.ceil((areaSize - ((n - 1) * spacing)) / n); + translate = () => cr.translate(startX, startY); + draw = i => drawDash(i, length); + break; + } + + translate(); + + Clutter.cairo_set_source_color(cr, bodyColor); + preDraw(); + for (let i = 0; i < n; i++) { + cr.newSubPath(); + draw(i); + } + cr.fill(); + } + + cr.$dispose(); + }, + + _numberOverlay: function() { + // Add label for a Hot-Key visual aid + this._numberOverlayLabel = new St.Label({ style_class: 'badge' }); + this._numberOverlayBin = new St.Bin({ + child: this._numberOverlayLabel, y: 2 + }); + this._numberOverlayLabel.add_style_class_name('number-overlay'); + this._numberOverlayOrder = -1; + this._numberOverlayBin.hide(); + + this._dtpIconContainer.add_child(this._numberOverlayBin); + }, + + updateHotkeyNumberOverlay: function() { + this.updateNumberOverlay(this._numberOverlayBin, true); + }, + + updateNumberOverlay: function(bin, fixedSize) { + // We apply an overall scale factor that might come from a HiDPI monitor. + // Clutter dimensions are in physical pixels, but CSS measures are in logical + // pixels, so make sure to consider the scale. + // Set the font size to something smaller than the whole icon so it is + // still visible. The border radius is large to make the shape circular + let [minWidth, natWidth] = this._dtpIconContainer.get_preferred_width(-1); + let font_size = Math.round(Math.max(12, 0.3 * natWidth) / Utils.getScaleFactor()); + let size = Math.round(font_size * 1.3); + let label = bin.child; + let style = 'font-size: ' + font_size + 'px;' + + 'border-radius: ' + this.icon.iconSize + 'px;' + + 'height: ' + size +'px;'; + + if (fixedSize || label.get_text().length == 1) { + style += 'width: ' + size + 'px;'; + } else { + style += 'padding: 0 2px;'; + } + + bin.x = fixedSize ? natWidth - size - 2 : 2; + label.set_style(style); + }, + + setNumberOverlay: function(number) { + this._numberOverlayOrder = number; + this._numberOverlayLabel.set_text(number.toString()); + }, + + toggleNumberOverlay: function(activate) { + if (activate && this._numberOverlayOrder > -1) + this._numberOverlayBin.show(); + else + this._numberOverlayBin.hide(); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + this._previewMenu.close(true); + } + + return DND.DragMotionResult.CONTINUE; + }, + + // Disable all DnD methods on gnome-shell 3.34 + _onDragBegin: function() {}, + _onDragEnd: function() {}, + acceptDrop: function() { return false; }, + + getAppIconInterestingWindows: function(isolateMonitors) { + return getInterestingWindows(this.app, this.dtpPanel.monitor, isolateMonitors); + } +}); +taskbarAppIcon.prototype.scaleAndFade = taskbarAppIcon.prototype.undoScaleAndFade = () => {}; + +function minimizeWindow(app, param, monitor){ + // Param true make all app windows minimize + let windows = getInterestingWindows(app, monitor); + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + for (let i = 0; i < windows.length; i++) { + let w = windows[i]; + if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()){ + w.minimize(); + // Just minimize one window. By specification it should be the + // focused window on the current workspace. + if(!param) + break; + } + } +} + +/* + * By default only non minimized windows are activated. + * This activates all windows in the current workspace. + */ +function activateAllWindows(app, monitor){ + + // First activate first window so workspace is switched if needed, + // then activate all other app windows in the current workspace. + let windows = getInterestingWindows(app, monitor); + let w = windows[0]; + Main.activateWindow(w); + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + + if (windows.length <= 0) + return; + + for (let i = windows.length - 1; i >= 0; i--){ + if (windows[i].get_workspace().index() == activeWorkspace){ + Main.activateWindow(windows[i]); + } + } +} + +function activateFirstWindow(app, monitor){ + + let windows = getInterestingWindows(app, monitor); + Main.activateWindow(windows[0]); +} + +function cycleThroughWindows(app, reversed, shouldMinimize, monitor) { + // Store for a little amount of time last clicked app and its windows + // since the order changes upon window interaction + let MEMORY_TIME=3000; + + let app_windows = getInterestingWindows(app, monitor); + + if(shouldMinimize) + app_windows.push("MINIMIZE"); + + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); + + // If there isn't already a list of windows for the current app, + // or the stored list is outdated, use the current windows list. + if (!recentlyClickedApp || + recentlyClickedApp.get_id() != app.get_id() || + recentlyClickedAppWindows.length != app_windows.length || + recentlyClickedAppMonitorIndex != monitor.index) { + recentlyClickedApp = app; + recentlyClickedAppWindows = app_windows; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = monitor.index; + } + + if (reversed) { + recentlyClickedAppIndex--; + if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1; + } else { + recentlyClickedAppIndex++; + } + let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; + + if(recentlyClickedAppWindows[index] === "MINIMIZE") + minimizeWindow(app, true, monitor); + else + Main.activateWindow(recentlyClickedAppWindows[index]); +} + +function resetRecentlyClickedApp() { + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId=0; + recentlyClickedApp =null; + recentlyClickedAppWindows = null; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = null; + + return false; +} + +function closeAllWindows(app, monitor) { + let windows = getInterestingWindows(app, monitor); + for (let i = 0; i < windows.length; i++) + windows[i].delete(global.get_current_time()); +} + +// Filter out unnecessary windows, for instance +// nautilus desktop window. +function getInterestingWindows(app, monitor, isolateMonitors) { + let windows = app.get_windows().filter(function(w) { + return !w.skip_taskbar; + }); + + // When using workspace or monitor isolation, we filter out windows + // that are not in the current workspace or on the same monitor as the appicon + if (Me.settings.get_boolean('isolate-workspaces')) + windows = windows.filter(function(w) { + return w.get_workspace().index() == Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + }); + + if (monitor && Me.settings.get_boolean('multi-monitors') && (isolateMonitors || Me.settings.get_boolean('isolate-monitors'))) { + windows = windows.filter(function(w) { + return w.get_monitor() == monitor.index; + }); + } + + return windows; +} + +function cssHexTocssRgba(cssHex, opacity) { + var bigint = parseInt(cssHex.slice(1), 16); + var r = (bigint >> 16) & 255; + var g = (bigint >> 8) & 255; + var b = bigint & 255; + + return 'rgba(' + [r, g, b].join(',') + ',' + opacity + ')'; +} + +function getIconPadding(monitorIndex) { + let panelSize = PanelSettings.getPanelSize(Me.settings, monitorIndex); + let padding = Me.settings.get_int('appicon-padding'); + let availSize = panelSize - Taskbar.MIN_ICON_SIZE - panelSize % 2; + + if (padding * 2 > availSize) { + padding = availSize * .5; + } + + return padding; +} + +/** + * Extend AppMenu (AppIconMenu for pre gnome 41) + * + * - set popup arrow side based on taskbar orientation + * - Add close windows option based on quitfromdash extension + * (https://github.com/deuill/shell-extension-quitfromdash) + */ + +var taskbarSecondaryMenu = Utils.defineClass({ + Name: 'DashToPanel.SecondaryMenu', + Extends: (AppDisplay.AppMenu || AppDisplay.AppIconMenu), + ParentConstrParams: [[0]], + + _init: function(source, panel) { + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later + this.callParent('_init', source); + + let side = panel.getPosition(); + // Change the initialized side where required. + this._arrowSide = side; + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + }, + + // helper function for the quit windows abilities + _closeWindowInstance: function(metaWindow) { + metaWindow.delete(global.get_current_time()); + }, + + _dtpRedisplay: function(parentFunc) { + this.callParent(parentFunc); + + // Remove "Show Details" menu item + if(!Me.settings.get_boolean('secondarymenu-contains-showdetails')) { + let existingMenuItems = this._getMenuItems(); + for(let idx in existingMenuItems) { + if(existingMenuItems[idx].actor.label_actor.text == _("Show Details")) { + this.box.remove_child(existingMenuItems[idx].actor); + if(existingMenuItems[idx-1] instanceof PopupMenu.PopupSeparatorMenuItem) + this.box.remove_child(existingMenuItems[idx-1].actor); + break; + } + } + } + + // prepend items from the appMenu (for native gnome apps) + if(Me.settings.get_boolean('secondarymenu-contains-appmenu')) { + let appMenu = this._source.app.menu; + if(appMenu) { + let remoteMenu = new imports.ui.remoteMenu.RemoteMenu(this._source.actor, this._source.app.menu, this._source.app.action_group); + let appMenuItems = remoteMenu._getMenuItems(); + for(var i = 0, l = appMenuItems.length || 0; i < l; ++i) { + let menuItem = appMenuItems[i]; + let labelText = menuItem.actor.label_actor.text; + if(labelText == _("New Window") || labelText == _("Quit")) + continue; + + if(menuItem instanceof PopupMenu.PopupSeparatorMenuItem) + continue; + + // this ends up getting called multiple times, and bombing due to the signal id's being invalid + // on a 2nd pass. disconnect the base handler and attach our own that wraps the id's in if statements + menuItem.disconnect(menuItem._popupMenuDestroyId) + menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) { + if(menuItem._popupMenuDestroyId) { + menuItem.disconnect(menuItem._popupMenuDestroyId); + menuItem._popupMenuDestroyId = 0; + } + if(menuItem._activateId) { + menuItem.disconnect(menuItem._activateId); + menuItem._activateId = 0; + } + if(menuItem._activeChangeId) { + menuItem.disconnect(menuItem._activeChangeId); + menuItem._activeChangeId = 0; + } + if(menuItem._sensitiveChangeId) { + menuItem.disconnect(menuItem._sensitiveChangeId); + menuItem._sensitiveChangeId = 0; + } + this.disconnect(menuItem._parentSensitiveChangeId); + if (menuItem == this._activeMenuItem) + this._activeMenuItem = null; + })); + + menuItem.actor.get_parent().remove_child(menuItem.actor); + if(menuItem instanceof PopupMenu.PopupSubMenuMenuItem) { + let newSubMenuMenuItem = new PopupMenu.PopupSubMenuMenuItem(labelText); + let appSubMenuItems = menuItem.menu._getMenuItems(); + for(let appSubMenuIdx in appSubMenuItems){ + let subMenuItem = appSubMenuItems[appSubMenuIdx]; + subMenuItem.actor.get_parent().remove_child(subMenuItem.actor); + newSubMenuMenuItem.menu.addMenuItem(subMenuItem); + } + this.addMenuItem(newSubMenuMenuItem, i); + } else + this.addMenuItem(menuItem, i); + } + + if(i > 0) { + let separator = new PopupMenu.PopupSeparatorMenuItem(); + this.addMenuItem(separator, i); + } + } + } + + // quit menu + let app = this._source.app; + let window = this._source.window; + let count = window ? 1 : getInterestingWindows(app).length; + if ( count > 0) { + this._appendSeparator(); + let quitFromTaskbarMenuText = ""; + if (count == 1) + quitFromTaskbarMenuText = _("Quit"); + else + quitFromTaskbarMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + + this._quitfromTaskbarMenuItem = this._appendMenuItem(quitFromTaskbarMenuText); + this._quitfromTaskbarMenuItem.connect('activate', Lang.bind(this, function() { + let app = this._source.app; + let windows = window ? [window] : app.get_windows(); + for (i = 0; i < windows.length; i++) { + this._closeWindowInstance(windows[i]) + } + })); + } + } +}); +Signals.addSignalMethods(taskbarSecondaryMenu.prototype); +adjustMenuRedisplay(taskbarSecondaryMenu.prototype); + +/** + * This function is used for extendDashItemContainer + */ +function ItemShowLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.allocation.x2 - this.allocation.x1; + let itemHeight = this.allocation.y2 - this.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let position = this._dtpPanel.getPosition(); + let labelOffset = node.get_length('-x-offset'); + + // From TaskbarItemContainer + if (this._getIconAnimationOffset) + labelOffset += this._getIconAnimationOffset(); + + let xOffset = Math.floor((itemWidth - labelWidth) / 2); + let x = stageX + xOffset + let y = stageY + (itemHeight - labelHeight) * .5; + + switch(position) { + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + break; + case St.Side.BOTTOM: + y = stageY - labelHeight - labelOffset; + break; + case St.Side.LEFT: + x = stageX + labelOffset + itemWidth; + break; + case St.Side.RIGHT: + x = stageX - labelWidth - labelOffset; + break; + } + + // keep the label inside the screen border + // Only needed for the x coordinate. + + // Leave a few pixel gap + let gap = LABEL_GAP; + let monitor = Main.layoutManager.findMonitorForActor(this); + if ( x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if ( x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth -( monitor.x + monitor.width) + gap; + + this.label.set_position(Math.round(x), Math.round(y)); + + let duration = Dash.DASH_ITEM_LABEL_SHOW_TIME; + + if (duration > 1) { + duration /= 1000; + } + + Utils.animate(this.label, { + opacity: 255, + time: duration, + transition: 'easeOutQuad', + }); +}; + +/** + * A wrapper class around the ShowAppsIcon class. + * + * - Pass settings to the constructor + * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class) + * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class) + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon + * use of this class in place of the original showAppsButton. + * + */ +var ShowAppsIconWrapper = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconWrapper', + + _init: function(dtpPanel) { + this.realShowAppsIcon = new Dash.ShowAppsIcon(); + + Utils.wrapActor(this.realShowAppsIcon); + Utils.wrapActor(this.realShowAppsIcon.toggleButton); + + /* the variable equivalent to toggleButton has a different name in the appIcon class + (actor): duplicate reference to easily reuse appIcon methods */ + this.actor = this.realShowAppsIcon.toggleButton; + this.realShowAppsIcon.show(false); + + // Re-use appIcon methods + this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; + this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; + this._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; + + // No action on clicked (showing of the appsview is controlled elsewhere) + this._onClicked = Lang.bind(this, function(actor, button) { + this._removeMenuTimeout(); + }); + + this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); + this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent)); + this.actor.connect('clicked', Lang.bind(this, this._onClicked)); + this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu)); + + this._menu = null; + this._menuManager = new PopupMenu.PopupMenuManager(this.actor); + this._menuTimeoutId = 0; + + this.realShowAppsIcon._dtpPanel = dtpPanel; + Taskbar.extendDashItemContainer(this.realShowAppsIcon); + + let customIconPath = Me.settings.get_string('show-apps-icon-file'); + + this.realShowAppsIcon.icon.createIcon = function(size) { + this._iconActor = new St.Icon({ icon_name: 'view' + (Config.PACKAGE_VERSION < '3.20' ? '' : '-app') + '-grid-symbolic', + icon_size: size, + style_class: 'show-apps-icon', + track_hover: true }); + + if (customIconPath) { + this._iconActor.gicon = new Gio.FileIcon({ file: Gio.File.new_for_path(customIconPath) }); + } + + return this._iconActor; + }; + + this._changedShowAppsIconId = Me.settings.connect('changed::show-apps-icon-file', () => { + customIconPath = Me.settings.get_string('show-apps-icon-file'); + this.realShowAppsIcon.icon._createIconTexture(this.realShowAppsIcon.icon.iconSize); + }); + + this._changedAppIconPaddingId = Me.settings.connect('changed::appicon-padding', () => this.setShowAppsPadding()); + this._changedAppIconSidePaddingId = Me.settings.connect('changed::show-apps-icon-side-padding', () => this.setShowAppsPadding()); + + this.setShowAppsPadding(); + }, + + _onButtonPress: function(_actor, event) { + let button = event.get_button(); + if (button == 1) { + this._setPopupTimeout(); + } else if (button == 3) { + this.popupMenu(); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + }, + + _onLeaveEvent: function(_actor, _event) { + this.actor.fake_release(); + this._removeMenuTimeout(); + }, + + _onTouchEvent: function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) + this._setPopupTimeout(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMenuPoppedDown: function() { + this._menu.sourceActor = this.actor; + this.actor.sync_hover(); + this.emit('menu-state-changed', false); + }, + + setShowAppsPadding: function() { + let padding = getIconPadding(this.realShowAppsIcon._dtpPanel.monitor.index); + let sidePadding = Me.settings.get_int('show-apps-icon-side-padding'); + let isVertical = this.realShowAppsIcon._dtpPanel.checkIfVertical(); + + this.actor.set_style('padding:' + (padding + (isVertical ? sidePadding : 0)) + 'px ' + (padding + (isVertical ? 0 : sidePadding)) + 'px;'); + }, + + createMenu: function() { + if (!this._menu) { + this._menu = new MyShowAppsIconMenu(this.actor, this.realShowAppsIcon._dtpPanel); + this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function() { + this._menu.close(); + })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + this._menuManager.addMenu(this._menu); + } + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + this.createMenu(this.actor); + + //this.emit('menu-state-changed', true); + + this.actor.set_hover(true); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + shouldShowTooltip: function() { + return Me.settings.get_boolean('show-tooltip') && + (this.actor.hover && (!this._menu || !this._menu.isOpen)); + }, + + destroy: function() { + Me.settings.disconnect(this._changedShowAppsIconId); + Me.settings.disconnect(this._changedAppIconSidePaddingId); + Me.settings.disconnect(this._changedAppIconPaddingId); + + this.realShowAppsIcon.destroy(); + } +}); +Signals.addSignalMethods(ShowAppsIconWrapper.prototype); + +/** + * A menu for the showAppsIcon + */ +var MyShowAppsIconMenu = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconMenu', + Extends: taskbarSecondaryMenu, + ParentConstrParams: [[0], [1]], + + _dtpRedisplay: function() { + this.removeAll(); + + // Only add menu entries for commands that exist in path + function _appendItem(obj, info) { + if (Utils.checkIfCommandExists(info.cmd[0])) { + let item = obj._appendMenuItem(_(info.title)); + + item.connect('activate', function() { + Util.spawn(info.cmd); + }); + return item; + } + + return null; + } + + function _appendList(obj, commandList, titleList) { + if (commandList.length != titleList.length) { + return; + } + + for (var entry = 0; entry < commandList.length; entry++) { + _appendItem(obj, { + title: titleList[entry], + cmd: commandList[entry].split(' ') + }); + } + } + + if (this.sourceActor != Main.layoutManager.dummyCursor) { + _appendItem(this, { + title: 'Power options', + cmd: ['gnome-control-center', 'power'] + }); + + _appendItem(this, { + title: 'Event logs', + cmd: ['gnome-logs'] + }); + + _appendItem(this, { + title: 'System', + cmd: ['gnome-control-center', 'info-overview'] + }); + + _appendItem(this, { + title: 'Device Management', + cmd: ['gnome-control-center', 'display'] + }); + + _appendItem(this, { + title: 'Disk Management', + cmd: ['gnome-disks'] + }); + + _appendList( + this, + Me.settings.get_strv('show-apps-button-context-menu-commands'), + Me.settings.get_strv('show-apps-button-context-menu-titles') + ) + + this._appendSeparator(); + } + + _appendItem(this, { + title: 'Terminal', + cmd: ['gnome-terminal'] + }); + + _appendItem(this, { + title: 'System monitor', + cmd: ['gnome-system-monitor'] + }); + + _appendItem(this, { + title: 'Files', + cmd: ['nautilus'] + }); + + _appendItem(this, { + title: 'Extensions', + cmd: ['gnome-shell-extension-prefs'] + }); + + _appendItem(this, { + title: 'Settings', + cmd: ['gnome-control-center', 'wifi'] + }); + + _appendList( + this, + Me.settings.get_strv('panel-context-menu-commands'), + Me.settings.get_strv('panel-context-menu-titles') + ) + + this._appendSeparator(); + + let lockTaskbarMenuItem = this._appendMenuItem(Me.settings.get_boolean('taskbar-locked') ? _('Unlock taskbar') : _('Lock taskbar')); + lockTaskbarMenuItem.connect('activate', () => { + Me.settings.set_boolean('taskbar-locked', !Me.settings.get_boolean('taskbar-locked')); + }); + + let settingsMenuItem = this._appendMenuItem(_('Dash to Panel Settings')); + settingsMenuItem.connect('activate', function () { + let command = ["gnome-shell-extension-prefs"]; + + if (Config.PACKAGE_VERSION > '3.36') { + command = ["gnome-extensions", "prefs"]; + } + + Util.spawn(command.concat([Me.metadata.uuid])); + }); + + if(this._source._dtpPanel) { + this._appendSeparator(); + let item = this._appendMenuItem(this._source._dtpPanel._restoreWindowList ? _('Restore Windows') : _('Show Desktop')); + item.connect('activate', Lang.bind(this._source._dtpPanel, this._source._dtpPanel._onShowDesktopButtonPress)); + } + } +}); +adjustMenuRedisplay(MyShowAppsIconMenu.prototype); + +function adjustMenuRedisplay(menuProto) { + menuProto[menuRedisplayFunc] = function() { this._dtpRedisplay(menuRedisplayFunc) }; +} + +var getIconContainerStyle = function(isVertical) { + let style = 'padding: '; + + if (Me.settings.get_boolean('group-apps')) { + style += (isVertical ? '0;' : '0 ' + DEFAULT_PADDING_SIZE + 'px;'); + } else { + style += (isVertical ? '' : '0 ') + DEFAULT_PADDING_SIZE + 'px;'; + } + + return style; +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js new file mode 100644 index 0000000..57d2f13 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js @@ -0,0 +1,89 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // Check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) + Gettext.bindtextdomain(domain, localeDir.get_path()); + else + Gettext.bindtextdomain(domain, Config.LOCALEDIR); +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + else + schemaSource = GioSSS.get_default(); + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error('Schema ' + schema + ' could not be found for extension ' + + extension.metadata.uuid + '. Please check your installation.'); + + return new Gio.Settings({ + settings_schema: schemaObj + }); +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js new file mode 100644 index 0000000..7ab80f2 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js @@ -0,0 +1,149 @@ +/* + * Dash-To-Panel extension for Gnome 3 + * Copyright 2016 Jason DeRose (jderose9) and Charles Gagnon (charlesg99) + * + * 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 2 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 . + * + */ + + +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Lang = imports.lang; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const ExtensionUtils = imports.misc.extensionUtils; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + +const Me = ExtensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const PanelManager = Me.imports.panelManager; +const Utils = Me.imports.utils; + +const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +let panelManager; +let extensionChangedHandler; +let disabledUbuntuDock; +let extensionSystem = (Main.extensionManager || imports.ui.extensionSystem); + +function init() { + this._realHasOverview = Main.sessionMode.hasOverview; + + Convenience.initTranslations(Utils.TRANSLATION_DOMAIN); + + //create an object that persists until gnome-shell is restarted, even if the extension is disabled + Me.persistentStorage = {}; +} + +function enable() { + // The Ubuntu Dock extension might get enabled after this extension + extensionChangedHandler = extensionSystem.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === UBUNTU_DOCK_UUID && extension.state === 1) { + _enable(); + } + }); + + //create a global object that can emit signals and conveniently expose functionalities to other extensions + global.dashToPanel = {}; + Signals.addSignalMethods(global.dashToPanel); + + _enable(); +} + +function _enable() { + let ubuntuDock = Main.extensionManager ? + Main.extensionManager.lookup(UBUNTU_DOCK_UUID) : //gnome-shell >= 3.33.4 + ExtensionUtils.extensions[UBUNTU_DOCK_UUID]; + + if (ubuntuDock && ubuntuDock.stateObj && ubuntuDock.stateObj.dockManager) { + // Disable Ubuntu Dock + let extensionOrder = (extensionSystem.extensionOrder || extensionSystem._extensionOrder); + + Utils.getStageTheme().get_theme().unload_stylesheet(ubuntuDock.stylesheet); + ubuntuDock.stateObj.disable(); + disabledUbuntuDock = true; + ubuntuDock.state = 2; //ExtensionState.DISABLED + extensionOrder.splice(extensionOrder.indexOf(UBUNTU_DOCK_UUID), 1); + + //reset to prevent conflicts with the ubuntu-dock + if (panelManager) { + disable(true); + } + } + + if (panelManager) return; //already initialized + + Me.settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + Me.desktopSettings = Convenience.getSettings('org.gnome.desktop.interface'); + + Main.layoutManager.startInOverview = !Me.settings.get_boolean('hide-overview-on-startup'); + + if (Me.settings.get_boolean('hide-overview-on-startup') && Main.layoutManager._startingUp) { + Main.sessionMode.hasOverview = false; + Main.layoutManager.connect('startup-complete', () => { + Main.sessionMode.hasOverview = this._realHasOverview + }); + } + + panelManager = new PanelManager.dtpPanelManager(); + + panelManager.enable(); + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(this, function() { + if(Me.settings.get_boolean('show-appmenu')) + Main.wm._toggleAppMenu(); + else + panelManager.primaryPanel.taskbar.popupFocusedAppSecondaryMenu(); + }), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); +} + +function disable(reset) { + panelManager.disable(); + Me.settings.run_dispose(); + Me.desktopSettings.run_dispose(); + + delete Me.settings; + panelManager = null; + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(Main.wm, Main.wm._toggleAppMenu), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); + + if (!reset) { + extensionSystem.disconnect(extensionChangedHandler); + delete global.dashToPanel; + + // Re-enable Ubuntu Dock if it was disabled by dash to panel + if (disabledUbuntuDock && Main.sessionMode.allowExtensions) { + (extensionSystem._callExtensionEnable || extensionSystem.enableExtension).call(extensionSystem, UBUNTU_DOCK_UUID); + } + } + + Main.sessionMode.hasOverview = this._realHasOverview; +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg new file mode 100644 index 0000000..977146b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg new file mode 100644 index 0000000..47aa802 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg new file mode 100644 index 0000000..80420fd --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js new file mode 100644 index 0000000..8fb1e97 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js @@ -0,0 +1,401 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +var GrabHelper = imports.ui.grabHelper; +const Layout = imports.ui.layout; +const Main = imports.ui.main; +const OverviewControls = imports.ui.overviewControls; +const PointerWatcher = imports.ui.pointerWatcher; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +//timeout intervals +const CHECK_POINTER_MS = 200; +const CHECK_GRAB_MS = 400; +const POST_ANIMATE_MS = 50; +const MIN_UPDATE_MS = 250; + +//timeout names +const T1 = 'checkGrabTimeout'; +const T2 = 'limitUpdateTimeout'; +const T3 = 'postAnimateTimeout'; +const T4 = 'panelBoxClipTimeout'; + +var SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1); + +var Hold = { + NONE: 0, + TEMPORARY: 1, + PERMANENT: 2 +}; + +var Intellihide = Utils.defineClass({ + Name: 'DashToPanel.Intellihide', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._panelBox = dtpPanel.panelBox; + this._panelManager = dtpPanel.panelManager; + this._proximityManager = this._panelManager.proximityManager; + this._holdStatus = Hold.NONE; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._intellihideChangedId = Me.settings.connect('changed::intellihide', () => this._changeEnabledStatus()); + this._intellihideOnlySecondaryChangedId = Me.settings.connect('changed::intellihide-only-secondary', () => this._changeEnabledStatus()); + + this.enabled = false; + this._changeEnabledStatus(); + }, + + enable: function() { + this.enabled = true; + this._monitor = this._dtpPanel.monitor; + this._animationDestination = -1; + this._pendingUpdate = false; + this._hoveredOut = false; + this._windowOverlap = false; + this._translationProp = 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y'); + + this._panelBox.translation_y = 0; + this._panelBox.translation_x = 0; + + this._setTrackPanel(true); + this._bindGeneralSignals(); + + if (Me.settings.get_boolean('intellihide-hide-from-windows')) { + this._proximityWatchId = this._proximityManager.createWatch( + this._panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('intellihide-behaviour')], + 0, 0, + overlap => { + this._windowOverlap = overlap; + this._queueUpdatePanelPosition(); + } + ); + } + + this._setRevealMechanism(); + this._queueUpdatePanelPosition(); + }, + + disable: function(reset) { + if (this._proximityWatchId) { + this._proximityManager.removeWatch(this._proximityWatchId); + } + + this._setTrackPanel(false); + + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + + this._removeRevealMechanism(); + + this._revealPanel(!reset); + + this.enabled = false; + }, + + destroy: function() { + Me.settings.disconnect(this._intellihideChangedId); + Me.settings.disconnect(this._intellihideOnlySecondaryChangedId); + + if (this.enabled) { + this.disable(); + } + }, + + toggle: function() { + this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](Hold.PERMANENT); + }, + + revealAndHold: function(holdStatus) { + if (this.enabled && !this._holdStatus) { + this._revealPanel(); + } + + this._holdStatus |= holdStatus; + }, + + release: function(holdStatus) { + this._holdStatus -= holdStatus; + + if (this.enabled && !this._holdStatus) { + this._queueUpdatePanelPosition(); + } + }, + + reset: function() { + this.disable(true); + this.enable(); + }, + + _changeEnabledStatus: function() { + let intellihide = Me.settings.get_boolean('intellihide'); + let onlySecondary = Me.settings.get_boolean('intellihide-only-secondary'); + let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary); + + if (this.enabled !== enabled) { + this[enabled ? 'enable' : 'disable'](); + } + }, + + _bindGeneralSignals: function() { + this._signalsHandler.add( + [ + this._dtpPanel.taskbar, + 'menu-closed', + () => this._panelBox.sync_hover() + ], + [ + Me.settings, + [ + 'changed::intellihide-use-pressure', + 'changed::intellihide-hide-from-windows', + 'changed::intellihide-behaviour', + 'changed::intellihide-pressure-threshold', + 'changed::intellihide-pressure-time' + ], + () => this.reset() + ], + [ + this._panelBox, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._dtpPanel.taskbar.previewMenu, + 'open-state-changed', + () => this._queueUpdatePanelPosition() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._queueUpdatePanelPosition() + ] + ); + }, + + _onHoverChanged: function() { + this._hoveredOut = !this._panelBox.hover; + this._queueUpdatePanelPosition(); + }, + + _setTrackPanel: function(enable) { + let trackedIndex = Main.layoutManager._findActor(this._panelBox); + let actorData = Main.layoutManager._trackedActors[trackedIndex] + + actorData.affectsStruts = !enable; + actorData.trackFullscreen = !enable; + + this._panelBox.track_hover = enable; + this._panelBox.reactive = enable; + this._panelBox.visible = enable ? enable : this._panelBox.visible; + + Main.layoutManager._queueUpdateRegions(); + }, + + _setRevealMechanism: function() { + if (global.display.supports_extended_barriers() && Me.settings.get_boolean('intellihide-use-pressure')) { + this._edgeBarrier = this._createBarrier(); + this._pressureBarrier = new Layout.PressureBarrier( + Me.settings.get_int('intellihide-pressure-threshold'), + Me.settings.get_int('intellihide-pressure-time'), + Shell.ActionMode.NORMAL + ); + this._pressureBarrier.addBarrier(this._edgeBarrier); + this._signalsHandler.add([this._pressureBarrier, 'trigger', () => this._queueUpdatePanelPosition(true)]); + } else { + this._pointerWatch = PointerWatcher.getPointerWatcher() + .addWatch(CHECK_POINTER_MS, (x, y) => this._checkMousePointer(x, y)); + } + }, + + _removeRevealMechanism: function() { + if (this._pointerWatch) { + PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch); + } + + if (this._pressureBarrier) { + this._pressureBarrier.destroy(); + this._edgeBarrier.destroy(); + } + }, + + _createBarrier: function() { + let position = this._dtpPanel.geom.position; + let opts = { display: global.display }; + + if (this._dtpPanel.checkIfVertical()) { + opts.y1 = this._monitor.y; + opts.y2 = this._monitor.y + this._monitor.height; + opts.x1 = opts.x2 = this._monitor.x; + } else { + opts.x1 = this._monitor.x; + opts.x2 = this._monitor.x + this._monitor.width; + opts.y1 = opts.y2 = this._monitor.y; + } + + if (position == St.Side.TOP) { + opts.directions = Meta.BarrierDirection.POSITIVE_Y; + } else if (position == St.Side.BOTTOM) { + opts.y1 = opts.y2 = opts.y1 + this._monitor.height; + opts.directions = Meta.BarrierDirection.NEGATIVE_Y; + } else if (position == St.Side.LEFT) { + opts.directions = Meta.BarrierDirection.POSITIVE_X; + } else { + opts.x1 = opts.x2 = opts.x1 + this._monitor.width; + opts.directions = Meta.BarrierDirection.NEGATIVE_X; + } + + return new Meta.Barrier(opts); + }, + + _checkMousePointer: function(x, y) { + let position = this._dtpPanel.geom.position; + + if (!this._panelBox.hover && !Main.overview.visible && + ((position == St.Side.TOP && y <= this._monitor.y + 1) || + (position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - 1) || + (position == St.Side.LEFT && x <= this._monitor.x + 1) || + (position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - 1)) && + ((x >= this._monitor.x && x < this._monitor.x + this._monitor.width) && + (y >= this._monitor.y && y < this._monitor.y + this._monitor.height))) { + this._queueUpdatePanelPosition(true); + } + }, + + _queueUpdatePanelPosition: function(fromRevealMechanism) { + if (!fromRevealMechanism && this._timeoutsHandler.getId(T2) && !Main.overview.visible) { + //unless this is a mouse interaction or entering/leaving the overview, limit the number + //of updates, but remember to update again when the limit timeout is reached + this._pendingUpdate = true; + } else if (!this._holdStatus) { + this._checkIfShouldBeVisible(fromRevealMechanism) ? this._revealPanel() : this._hidePanel(); + this._timeoutsHandler.add([T2, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + } + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdatePanelPosition(); + } + }, + + _checkIfShouldBeVisible: function(fromRevealMechanism) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || + this._panelBox.get_hover() || this._checkIfGrab()) { + return true; + } + + if (fromRevealMechanism) { + let mouseBtnIsPressed = global.get_pointer()[2] & Clutter.ModifierType.BUTTON1_MASK; + + //the user is trying to reveal the panel + if (this._monitor.inFullscreen && !mouseBtnIsPressed) { + return Me.settings.get_boolean('intellihide-show-in-fullscreen'); + } + + return !mouseBtnIsPressed; + } + + if (!Me.settings.get_boolean('intellihide-hide-from-windows')) { + return this._panelBox.hover; + } + + return !this._windowOverlap; + }, + + _checkIfGrab: function() { + if (GrabHelper._grabHelperStack.some(gh => gh._owner == this._dtpPanel.panel.actor)) { + //there currently is a grab on a child of the panel, check again soon to catch its release + this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]); + + return true; + } + }, + + _revealPanel: function(immediate) { + if (!this._panelBox.visible) { + this._panelBox.visible = true; + this._dtpPanel.taskbar._shownInitially = false; + } + + this._animatePanel(0, immediate); + }, + + _hidePanel: function(immediate) { + let position = this._dtpPanel.geom.position; + let size = this._panelBox[position == St.Side.LEFT || position == St.Side.RIGHT ? 'width' : 'height']; + let coefficient = position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1; + + this._animatePanel(size * coefficient, immediate); + }, + + _animatePanel: function(destination, immediate) { + let animating = Utils.isAnimating(this._panelBox, this._translationProp); + + if (!((animating && destination === this._animationDestination) || + (!animating && destination === this._panelBox[this._translationProp]))) { + //the panel isn't already at, or animating to the asked destination + if (animating) { + Utils.stopAnimations(this._panelBox); + } + + this._animationDestination = destination; + + if (immediate) { + this._panelBox[this._translationProp] = destination; + this._panelBox.visible = !destination; + } else { + let tweenOpts = { + //when entering/leaving the overview, use its animation time instead of the one from the settings + time: Main.overview.visible ? + SIDE_CONTROLS_ANIMATION_TIME : + Me.settings.get_int('intellihide-animation-time') * 0.001, + //only delay the animation when hiding the panel after the user hovered out + delay: destination != 0 && this._hoveredOut ? Me.settings.get_int('intellihide-close-delay') * 0.001 : 0, + transition: 'easeOutQuad', + onComplete: () => { + this._panelBox.visible = !destination; + Main.layoutManager._queueUpdateRegions(); + this._timeoutsHandler.add([T3, POST_ANIMATE_MS, () => this._queueUpdatePanelPosition()]); + } + }; + + tweenOpts[this._translationProp] = destination; + Utils.animate(this._panelBox, tweenOpts); + } + } + + this._hoveredOut = false; + }, +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8425f68 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..86da090 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..7a5af2f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..70da5fa Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..f52e89a Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2fd26da Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..c467e93 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bd1a46 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..84eac31 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..99b526b Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8ae66e3 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..0d64932 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..e7cacbb Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bc58a5 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2993304 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..26ed613 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..ed1cc6d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json new file mode 100644 index 0000000..4b11eea --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json @@ -0,0 +1,13 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "An icon taskbar for the Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications.\n\nFor a more traditional experience, you may also want to use Tweak Tool to enable Windows > Titlebar Buttons > Minimize & Maximize.\n\nFor the best support, please report any issues on Github. Dash-to-panel is developed and maintained by @jderose9 and @charlesg99.", + "extension-id": "dash-to-panel", + "gettext-domain": "dash-to-panel", + "name": "Dash to Panel", + "shell-version": [ + "40" + ], + "url": "https://github.com/home-sweet-gnome/dash-to-panel", + "uuid": "dash-to-panel@jderose9.github.com", + "version": 44 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js new file mode 100644 index 0000000..57600a5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js @@ -0,0 +1,708 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Intellihide = Me.imports.intellihide; +const Utils = Me.imports.utils; + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Lang = imports.lang; +const Main = imports.ui.main; +const Shell = imports.gi.Shell; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; +const Mainloop = imports.mainloop; +const IconGrid = imports.ui.iconGrid; +const OverviewControls = imports.ui.overviewControls; +const Workspace = imports.ui.workspace; +const St = imports.gi.St; +const WorkspaceThumbnail = imports.ui.workspaceThumbnail; + +const Meta = imports.gi.Meta; + +const GS_HOTKEYS_KEY = 'switch-to-application-'; +const BACKGROUND_MARGIN = 12; +const SMALL_WORKSPACE_RATIO = 0.15; +const DASH_MAX_HEIGHT_RATIO = 0.15; + + +//timeout names +const T1 = 'swipeEndTimeout'; + +var dtpOverview = Utils.defineClass({ + Name: 'DashToPanel.Overview', + + _init: function() { + this._numHotkeys = 10; + this._timeoutsHandler = new Utils.TimeoutsHandler(); + }, + + enable : function(panel) { + this._panel = panel; + this.taskbar = panel.taskbar; + + this._injectionsHandler = new Utils.InjectionsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._optionalWorkspaceIsolation(); + this._optionalHotKeys(); + this._optionalNumberOverlay(); + this._optionalClickToExit(); + this._toggleDash(); + this._hookupAllocation(); + + this._signalsHandler.add([ + Me.settings, + 'changed::stockgs-keep-dash', + () => this._toggleDash() + ]); + + }, + + disable: function () { + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', Workspace.WorkspaceBackground.prototype.vfunc_allocate); + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', OverviewControls.ControlsManagerLayout.prototype.vfunc_allocate); + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = this._oldComputeWorkspacesBoxForState; + + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); + + this._toggleDash(true); + + // Remove key bindings + this._disableHotKeys(); + this._disableExtraShortcut(); + this._disableClickToExit(); + }, + + _toggleDash: function(visible) { + // To hide the dash, set its width to 1, so it's almost not taken into account by code + // calculaing the reserved space in the overview. The reason to keep it at 1 is + // to allow its visibility change to trigger an allocaion of the appGrid which + // in turn is triggergin the appsIcon spring animation, required when no other + // actors has this effect, i.e in horizontal mode and without the workspaceThumnails + // 1 static workspace only) + + if (visible === undefined) { + visible = Me.settings.get_boolean('stockgs-keep-dash'); + } + + let visibilityFunc = visible ? 'show' : 'hide'; + let width = visible ? -1 : 1; + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + + overviewControls.dash.actor[visibilityFunc](); + overviewControls.dash.actor.set_width(width); + + // This force the recalculation of the icon size + overviewControls.dash._maxHeight = -1; + }, + + /** + * Isolate overview to open new windows for inactive apps + */ + _optionalWorkspaceIsolation: function() { + let label = 'optionalWorkspaceIsolation'; + + this._signalsHandler.add([ + Me.settings, + 'changed::isolate-workspaces', + Lang.bind(this, function() { + this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons()); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + else + Lang.bind(this, disable)(); + }) + ]); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + + function enable() { + this._injectionsHandler.removeWithLabel(label); + + this._injectionsHandler.addWithLabel(label, [ + Shell.App.prototype, + 'activate', + IsolatedOverview + ]); + + this._signalsHandler.removeWithLabel(label); + + this._signalsHandler.addWithLabel(label, [ + global.window_manager, + 'switch-workspace', + () => this._panel.panelManager.allPanels.forEach(p => p.taskbar.handleIsolatedWorkspaceSwitch()) + ]); + } + + function disable() { + this._signalsHandler.removeWithLabel(label); + this._injectionsHandler.removeWithLabel(label); + } + + function IsolatedOverview() { + // These lines take care of Nautilus for icons on Desktop + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = this.get_windows().filter(w => w.get_workspace().index() == activeWorkspace.index()); + + if (windows.length > 0 && + (!(windows.length == 1 && windows[0].skip_taskbar) || + this.is_on_workspace(activeWorkspace))) + return Main.activateWindow(windows[0]); + + return this.open_new_window(-1); + } + }, + + // Hotkeys + _activateApp: function(appIndex) { + let seenApps = {}; + let apps = []; + + this.taskbar._getAppIcons().forEach(function(appIcon) { + if (!seenApps[appIcon.app]) { + apps.push(appIcon); + } + + seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1; + }); + + this._showOverlay(); + + if (appIndex < apps.length) { + let appIcon = apps[appIndex]; + let seenAppCount = seenApps[appIcon.app]; + let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows; + + if (Me.settings.get_boolean('shortcut-previews') && windowCount > 1 && + !(Clutter.get_current_event().get_state() & ~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.MOD4_MASK))) { //ignore the alt (MOD1_MASK) and super key (MOD4_MASK) + if (this._hotkeyPreviewCycleInfo && this._hotkeyPreviewCycleInfo.appIcon != appIcon) { + this._endHotkeyPreviewCycle(); + } + + if (!this._hotkeyPreviewCycleInfo) { + this._hotkeyPreviewCycleInfo = { + appIcon: appIcon, + currentWindow: appIcon.window, + keyFocusOutId: appIcon.actor.connect('key-focus-out', () => appIcon.actor.grab_key_focus()), + capturedEventId: global.stage.connect('captured-event', (actor, e) => { + if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)) { + this._endHotkeyPreviewCycle(true); + } + + return Clutter.EVENT_PROPAGATE; + }) + }; + + appIcon._hotkeysCycle = appIcon.window; + appIcon.window = null; + appIcon._previewMenu.open(appIcon); + appIcon.actor.grab_key_focus(); + } + + appIcon._previewMenu.focusNext(); + } else { + // Activate with button = 1, i.e. same as left click + let button = 1; + this._endHotkeyPreviewCycle(); + appIcon.activate(button, true); + } + } + }, + + _endHotkeyPreviewCycle: function(focusWindow) { + if (this._hotkeyPreviewCycleInfo) { + global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId); + this._hotkeyPreviewCycleInfo.appIcon.actor.disconnect(this._hotkeyPreviewCycleInfo.keyFocusOutId); + + if (focusWindow) { + this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused(); + } + + this._hotkeyPreviewCycleInfo.appIcon.window = this._hotkeyPreviewCycleInfo.currentWindow; + delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle; + this._hotkeyPreviewCycleInfo = 0; + } + }, + + _optionalHotKeys: function() { + this._hotKeysEnabled = false; + if (Me.settings.get_boolean('hot-keys')) + this._enableHotKeys(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys')) + Lang.bind(this, this._enableHotKeys)(); + else + Lang.bind(this, this._disableHotKeys)(); + }) + ]); + }, + + _resetHotkeys: function() { + this._disableHotKeys(); + this._enableHotKeys(); + }, + + _enableHotKeys: function() { + if (this._hotKeysEnabled) + return; + + //3.32 introduced app hotkeys, disable them to prevent conflicts + if (Main.wm._switchToApplication) { + for (let i = 1; i < 10; ++i) { + Utils.removeKeybinding(GS_HOTKEYS_KEY + i); + } + } + + // Setup keyboard bindings for taskbar elements + let shortcutNumKeys = Me.settings.get_string('shortcut-num-keys'); + let bothNumKeys = shortcutNumKeys == 'BOTH'; + let keys = []; + + if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') { + keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'); // Regular numbers + } + + if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') { + keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-'); // Key-pad numbers + } + + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + let appNum = i; + + Utils.addKeybinding(key + (i + 1), Me.settings, () => this._activateApp(appNum)); + } + }, this); + + this._hotKeysEnabled = true; + + if (Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + }, + + _disableHotKeys: function() { + if (!this._hotKeysEnabled) + return; + + let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-', // Regular numbers + 'app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-']; // Key-pad numbers + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + Utils.removeKeybinding(key + (i + 1)); + } + }, this); + + if (Main.wm._switchToApplication) { + let gsSettings = new Gio.Settings({ schema_id: imports.ui.windowManager.SHELL_KEYBINDINGS_SCHEMA }); + + for (let i = 1; i < 10; ++i) { + Utils.addKeybinding(GS_HOTKEYS_KEY + i, gsSettings, Main.wm._switchToApplication.bind(Main.wm)); + } + } + + this._hotKeysEnabled = false; + + this.taskbar.toggleNumberOverlay(false); + }, + + _optionalNumberOverlay: function() { + // Enable extra shortcut + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, this._checkHotkeysOptions) + ], [ + Me.settings, + 'changed::hotkeys-overlay-combo', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys') && Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + else + this.taskbar.toggleNumberOverlay(false); + }) + ], [ + Me.settings, + 'changed::shortcut-num-keys', + () => this._resetHotkeys() + ]); + }, + + _checkHotkeysOptions: function() { + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + else + this._disableExtraShortcut(); + }, + + _enableExtraShortcut: function() { + Utils.addKeybinding('shortcut', Me.settings, () => this._showOverlay(true)); + }, + + _disableExtraShortcut: function() { + Utils.removeKeybinding('shortcut'); + }, + + _showOverlay: function(overlayFromShortcut) { + //wait for intellihide timeout initialization + if (!this._panel.intellihide) { + return; + } + + // Restart the counting if the shortcut is pressed again + if (this._numberOverlayTimeoutId) { + Mainloop.source_remove(this._numberOverlayTimeoutId); + this._numberOverlayTimeoutId = 0; + } + + let hotkey_option = Me.settings.get_string('hotkeys-overlay-combo'); + + if (hotkey_option === 'NEVER') + return; + + if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut) + this.taskbar.toggleNumberOverlay(true); + + this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY); + + let timeout = Me.settings.get_int('overlay-timeout'); + + if (overlayFromShortcut) { + timeout = Me.settings.get_int('shortcut-timeout'); + } + + // Hide the overlay/dock after the timeout + this._numberOverlayTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, function() { + this._numberOverlayTimeoutId = 0; + + if (hotkey_option != 'ALWAYS') { + this.taskbar.toggleNumberOverlay(false); + } + + this._panel.intellihide.release(Intellihide.Hold.TEMPORARY); + })); + }, + + _optionalClickToExit: function() { + this._clickToExitEnabled = false; + if (Me.settings.get_boolean('overview-click-to-exit')) + this._enableClickToExit(); + + this._signalsHandler.add([ + Me.settings, + 'changed::overview-click-to-exit', + Lang.bind(this, function() { + if (Me.settings.get_boolean('overview-click-to-exit')) + Lang.bind(this, this._enableClickToExit)(); + else + Lang.bind(this, this._disableClickToExit)(); + }) + ]); + }, + + _enableClickToExit: function() { + if (this._clickToExitEnabled) + return; + + let view = imports.ui.appDisplay; + this._oldOverviewReactive = Main.overview._overview.reactive + + Main.overview._overview.reactive = true; + + this._clickAction = new Clutter.ClickAction(); + this._clickAction.connect('clicked', () => { + + if (this._swiping) + return Clutter.EVENT_PROPAGATE; + + let [x, y] = global.get_pointer(); + let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); + + Main.overview.toggle(); + }); + Main.overview._overview.add_action(this._clickAction); + + this._clickToExitEnabled = true; + }, + + _disableClickToExit: function () { + if (!this._clickToExitEnabled) + return; + + Main.overview._overview.remove_action(this._clickAction); + Main.overview._overview.reactive = this._oldOverviewReactive; + + this._signalsHandler.removeWithLabel('clickToExit'); + + this._clickToExitEnabled = false; + }, + + _onSwipeBegin: function() { + this._swiping = true; + return true; + }, + + _onSwipeEnd: function() { + this._timeoutsHandler.add([ + T1, + 0, + () => this._swiping = false + ]); + return true; + }, + + _hookupAllocation: function() { + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', function vfunc_allocate(container, box) { + const childBox = new Clutter.ActorBox(); + + const { spacing } = this; + + let startY = 0; + let startX = 0; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) { + startY = Main.layoutManager.panelBox.height; + box.y1 += startY; + } + + const panel = global.dashToPanel.panels[0]; + if(panel) { + switch (panel.getPosition()) { + case St.Side.TOP: + startY = panel.panelBox.height; + box.y1 += startY; + break; + case St.Side.LEFT: + startX = panel.panelBox.width; + box.x1 += startX; + break; + case St.Side.RIGHT: + box.x2 -= panel.panelBox.width; + break; + + } + } + + + const [width, height] = box.get_size(); + let availableHeight = height; + + // Search entry + let [searchHeight] = this._searchEntry.get_preferred_height(width); + childBox.set_origin(startX, startY); + childBox.set_size(width, searchHeight); + this._searchEntry.allocate(childBox); + + availableHeight -= searchHeight + spacing; + + // Dash + const maxDashHeight = Math.round(box.get_height() * DASH_MAX_HEIGHT_RATIO); + this._dash.setMaxSize(width, maxDashHeight); + + let [, dashHeight] = this._dash.get_preferred_height(width); + if (Me.settings.get_boolean('stockgs-keep-dash')) + dashHeight = Math.min(dashHeight, maxDashHeight); + else + dashHeight = spacing*5; // todo: determine proper spacing for window labels on maximized windows on workspace display + childBox.set_origin(startX, startY + height - dashHeight); + childBox.set_size(width, dashHeight); + this._dash.allocate(childBox); + + availableHeight -= dashHeight + spacing; + + // Workspace Thumbnails + let thumbnailsHeight = 0; + if (this._workspacesThumbnails.visible) { + const { expandFraction } = this._workspacesThumbnails; + [thumbnailsHeight] = + this._workspacesThumbnails.get_preferred_height(width); + thumbnailsHeight = Math.min( + thumbnailsHeight * expandFraction, + height * WorkspaceThumbnail.MAX_THUMBNAIL_SCALE); + childBox.set_origin(startX, startY + searchHeight + spacing); + childBox.set_size(width, thumbnailsHeight); + this._workspacesThumbnails.allocate(childBox); + } + + // Workspaces + let params = [box, startX, startY, searchHeight, dashHeight, thumbnailsHeight]; + const transitionParams = this._stateAdjustment.getStateTransitionParams(); + + // Update cached boxes + for (const state of Object.values(OverviewControls.ControlsState)) { + this._cachedWorkspaceBoxes.set( + state, this._computeWorkspacesBoxForState(state, ...params)); + } + + let workspacesBox; + if (!transitionParams.transitioning) { + workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); + } else { + const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); + const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); + workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._workspacesDisplay.allocate(workspacesBox); + + // AppDisplay + if (this._appDisplay.visible) { + const workspaceAppGridBox = + this._cachedWorkspaceBoxes.get(OverviewControls.ControlsState.APP_GRID); + + if (Config.PACKAGE_VERSION > '40.3') { + const monitor = Main.layoutManager.findMonitorForActor(this._container); + const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); + const workAreaBox = new Clutter.ActorBox(); + + workAreaBox.set_origin(startX, startY); + workAreaBox.set_size(workArea.width, workArea.height); + + params = [workAreaBox, searchHeight, dashHeight, workspaceAppGridBox] + } else { + params = [box, startX, searchHeight, dashHeight, workspaceAppGridBox]; + } + + let appDisplayBox; + if (!transitionParams.transitioning) { + appDisplayBox = + this._getAppDisplayBoxForState(transitionParams.currentState, ...params); + } else { + const initialBox = + this._getAppDisplayBoxForState(transitionParams.initialState, ...params); + const finalBox = + this._getAppDisplayBoxForState(transitionParams.finalState, ...params); + + appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._appDisplay.allocate(appDisplayBox); + } + + // Search + childBox.set_origin(0, startY + searchHeight + spacing); + childBox.set_size(width, availableHeight); + + this._searchController.allocate(childBox); + + this._runPostAllocation(); + }); + + this._oldComputeWorkspacesBoxForState = OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState; + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = function _computeWorkspacesBoxForState(state, box, startX, startY, searchHeight, dashHeight, thumbnailsHeight) { + const workspaceBox = box.copy(); + const [width, height] = workspaceBox.get_size(); + const { spacing } = this; + const { expandFraction } = this._workspacesThumbnails; + + switch (state) { + case OverviewControls.ControlsState.HIDDEN: + break; + case OverviewControls.ControlsState.WINDOW_PICKER: + workspaceBox.set_origin(startX, + startY + searchHeight + spacing + + thumbnailsHeight + spacing * expandFraction); + workspaceBox.set_size(width, + height - + dashHeight - spacing - + searchHeight - spacing - + thumbnailsHeight - spacing * expandFraction); + break; + case OverviewControls.ControlsState.APP_GRID: + workspaceBox.set_origin(startX, startY + searchHeight + spacing); + workspaceBox.set_size( + width, + Math.round(height * SMALL_WORKSPACE_RATIO)); + break; + } + + return workspaceBox; + } + + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', function vfunc_allocate(box) { + const [width, height] = box.get_size(); + const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const scaledHeight = height - (BACKGROUND_MARGIN * 2 * scaleFactor); + const scaledWidth = (scaledHeight / height) * width; + + const scaledBox = box.copy(); + scaledBox.set_origin( + box.x1 + (width - scaledWidth) / 2, + box.y1 + (height - scaledHeight) / 2); + scaledBox.set_size(scaledWidth, scaledHeight); + + const progress = this._stateAdjustment.value; + + if (progress === 1) + box = scaledBox; + else if (progress !== 0) + box = box.interpolate(scaledBox, progress); + + this.set_allocation(box); + + const themeNode = this.get_theme_node(); + const contentBox = themeNode.get_content_box(box); + + this._bin.allocate(contentBox); + + + const [contentWidth, contentHeight] = contentBox.get_size(); + const monitor = Main.layoutManager.monitors[this._monitorIndex]; + let xOff = (contentWidth / this._workarea.width) * + (this._workarea.x - monitor.x); + let yOff = (contentHeight / this._workarea.height) * + (this._workarea.y - monitor.y); + + let startX = -xOff; + let startY = -yOff; + const panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == this._monitorIndex); + switch (panel.getPosition()) { + case St.Side.TOP: + yOff += panel.panelBox.height; + startY -= panel.panelBox.height; + break; + case St.Side.BOTTOM: + yOff += panel.panelBox.height; + break; + case St.Side.RIGHT: + xOff += panel.panelBox.width; + break; + } + contentBox.set_origin(startX, startY); + contentBox.set_size(xOff + contentWidth, yOff + contentHeight); + this._backgroundGroup.allocate(contentBox); + }); + + } +}); diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js new file mode 100644 index 0000000..5e0b5f9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js @@ -0,0 +1,1512 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gtk = imports.gi.Gtk; +const Gi = imports._gi; +const AppIcons = Me.imports.appIcons; +const Utils = Me.imports.utils; +const Taskbar = Me.imports.taskbar; +const Pos = Me.imports.panelPositions; +const PanelSettings = Me.imports.panelSettings; +const PanelStyle = Me.imports.panelStyle; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Dash = imports.ui.dash; +const CtrlAltTab = imports.ui.ctrlAltTab; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const St = imports.gi.St; +const GLib = imports.gi.GLib; +const Meta = imports.gi.Meta; +const Pango = imports.gi.Pango; +const DND = imports.ui.dnd; +const Shell = imports.gi.Shell; +const PopupMenu = imports.ui.popupMenu; +const IconGrid = imports.ui.iconGrid; +const DateMenu = imports.ui.dateMenu; +const Volume = imports.ui.status.volume; +const Progress = Me.imports.progress; + +const Intellihide = Me.imports.intellihide; +const Transparency = Me.imports.transparency; +const _ = imports.gettext.domain(Me.imports.utils.TRANSLATION_DOMAIN).gettext; + +let tracker = Shell.WindowTracker.get_default(); +var panelBoxes = ['_leftBox', '_centerBox', '_rightBox']; + +//timeout names +const T1 = 'startDynamicTransparencyTimeout'; +const T2 = 'startIntellihideTimeout'; +const T3 = 'allocationThrottleTimeout'; +const T4 = 'showDesktopTimeout'; +const T5 = 'trackerFocusAppTimeout'; +const T6 = 'scrollPanelDelayTimeout'; +const T7 = 'waitPanelBoxAllocation'; + +var dtpPanel = Utils.defineClass({ + Name: 'DashToPanel-Panel', + Extends: St.Widget, + + _init: function(panelManager, monitor, panelBox, isStandalone) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this.panelManager = panelManager; + this.panelStyle = new PanelStyle.dtpPanelStyle(); + + this.monitor = monitor; + this.panelBox = panelBox; + + // when the original gnome-shell top panel is kept, all panels are "standalone", + // so in this case use isPrimary to get the panel on the primary dtp monitor, which + // might be different from the system's primary monitor. + this.isStandalone = isStandalone; + this.isPrimary = !isStandalone || (Me.settings.get_boolean('stockgs-keep-top-panel') && + monitor == panelManager.dtpPrimaryMonitor); + + this._sessionStyle = null; + this._unmappedButtons = []; + this._elementGroups = []; + this.cornerSize = 0; + + let position = this.getPosition(); + + if (isStandalone) { + this.panel = new dtpSecondaryPanel({ name: 'panel', reactive: true }); + this.statusArea = this.panel.statusArea = {}; + + Utils.wrapActor(this.panel); + + //next 3 functions are needed by other extensions to add elements to the secondary panel + this.panel.addToStatusArea = function(role, indicator, position, box) { + return Main.panel.addToStatusArea.call(this, role, indicator, position, box); + }; + + this.panel._addToPanelBox = function(role, indicator, position, box) { + Main.panel._addToPanelBox.call(this, role, indicator, position, box); + }; + + this.panel._onMenuSet = function(indicator) { + Main.panel._onMenuSet.call(this, indicator); + }; + + this._leftBox = this.panel._leftBox = new St.BoxLayout({ name: 'panelLeft' }); + this._centerBox = this.panel._centerBox = new St.BoxLayout({ name: 'panelCenter' }); + this._rightBox = this.panel._rightBox = new St.BoxLayout({ name: 'panelRight' }); + + this.menuManager = this.panel.menuManager = new PopupMenu.PopupMenuManager(this.panel); + + this._setPanelMenu('aggregateMenu', dtpSecondaryAggregateMenu, this.panel.actor); + this._setPanelMenu('dateMenu', DateMenu.DateMenuButton, this.panel.actor); + this._setPanelMenu('activities', Panel.ActivitiesButton, this.panel.actor); + + this.panel.add_child(this._leftBox); + this.panel.add_child(this._centerBox); + this.panel.add_child(this._rightBox); + } else { + this.panel = Main.panel; + this.statusArea = Main.panel.statusArea; + this.menuManager = Main.panel.menuManager; + + panelBoxes.forEach(p => this[p] = Main.panel[p]); + + ['activities', 'aggregateMenu', 'dateMenu'].forEach(b => { + let container = this.statusArea[b].container; + let parent = container.get_parent(); + + container._dtpOriginalParent = parent; + parent ? parent.remove_child(container) : null; + this.panel.actor.add_child(container); + }); + } + + // Create a wrapper around the real showAppsIcon in order to add a popupMenu. Most of + // its behavior is handled by the taskbar, but its positioning is done at the panel level + this.showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this); + this.panel.actor.add_child(this.showAppsIconWrapper.realShowAppsIcon); + + this.panel.actor._delegate = this; + + Utils.wrapActor(this.statusArea.activities); + + this.add_child(this.panel.actor); + + if (Main.panel._onButtonPress || Main.panel._tryDragWindow) { + this._signalsHandler.add([ + this.panel.actor, + [ + 'button-press-event', + 'touch-event' + ], + this._onButtonPress.bind(this) + ]); + } + + if (Main.panel._onKeyPress) { + this._signalsHandler.add([this.panel.actor, 'key-press-event', Main.panel._onKeyPress.bind(this)]); + } + + Main.ctrlAltTabManager.addGroup(this, _("Top Bar")+" "+ monitor.index, 'focus-top-bar-symbolic', + { sortGroup: CtrlAltTab.SortGroup.TOP }); + }, + + enable : function() { + let position = this.getPosition(); + + if (this.statusArea.aggregateMenu) { + Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll = 1; + } + + this.geom = this.getGeometry(); + + // The overview uses the panel height as a margin by way of a "ghost" transparent Clone + // This pushes everything down, which isn't desired when the panel is moved to the bottom + // I'm adding a 2nd ghost panel and will resize the top or bottom ghost depending on the panel position + this._myPanelGhost = new Clutter.Actor({ + x: this.geom.x, + y: this.geom.y , + reactive: false, + opacity: 0 + }); + + let isTop = this.geom.position == St.Side.TOP; + + if (isTop) { + this.panel._leftCorner = this.panel._leftCorner || new Panel.PanelCorner(St.Side.LEFT); + this.panel._rightCorner = this.panel._rightCorner || new Panel.PanelCorner(St.Side.RIGHT); + + Main.overview._overview.insert_child_at_index(this._myPanelGhost, 0); + } else { + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + Main.overview._overview.add_actor(this._myPanelGhost); + } + + if (this.panel._leftCorner) { + Utils.wrapActor(this.panel._leftCorner); + Utils.wrapActor(this.panel._rightCorner); + + if (isTop) { + if (this.isStandalone) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + } else if (Config.PACKAGE_VERSION >= '3.32') { + this.panel.actor.remove_child(this.panel._leftCorner.actor); + this.panel.actor.remove_child(this.panel._rightCorner.actor); + } + } + + this._setPanelPosition(); + + if (!this.isStandalone) { + if (this.panel.vfunc_allocate) { + this._panelConnectId = 0; + Utils.hookVfunc(this.panel.__proto__, 'allocate', (box, flags) => this._mainPanelAllocate(0, box, flags)); + } else { + this._panelConnectId = this.panel.actor.connect('allocate', (actor, box, flags) => this._mainPanelAllocate(actor, box, flags)); + } + + // remove the extra space before the clock when the message-indicator is displayed + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', () => [0,0]); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', () => [0,0]); + } + } + + if (!DateMenu.IndicatorPad && this.statusArea.dateMenu) { + //3.36 switched to a size constraint applied on an anonymous child + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints = indicatorPad.get_constraints(); + indicatorPad.clear_constraints(); + } + + // The main panel's connection to the "allocate" signal is competing with this extension + // trying to move the centerBox over to the right, creating a never-ending cycle. + // Since we don't have the ID to disconnect that handler, wrap the allocate() function + // it calls instead. If the call didn't originate from this file, ignore it. + panelBoxes.forEach(b => { + this[b].allocate = (box, flags, isFromDashToPanel) => { + if (isFromDashToPanel) { + Utils.allocate(this[b], box, flags, true); + } + } + }); + + this.menuManager._oldChangeMenu = this.menuManager._changeMenu; + this.menuManager._changeMenu = (menu) => { + if (!Me.settings.get_boolean('stockgs-panelbtn-click-only')) { + this.menuManager._oldChangeMenu(menu); + } + }; + + this.dynamicTransparency = new Transparency.DynamicTransparency(this); + + this.taskbar = new Taskbar.taskbar(this); + + this.panel.actor.add_child(this.taskbar.actor); + + this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')); + this._setShowDesktopButton(true); + + this._setAllocationMap(); + + this.panel.actor.add_style_class_name('dashtopanelMainPanel ' + this.getOrientation()); + + this._setPanelGhostSize(); + + this._timeoutsHandler.add([T2, Me.settings.get_int('intellihide-enable-start-delay'), () => this.intellihide = new Intellihide.Intellihide(this)]); + + this._signalsHandler.add( + // this is to catch changes to the theme or window scale factor + [ + Utils.getStageTheme(), + 'changed', + () => (this._resetGeometry(), this._setShowDesktopButtonStyle()), + ], + [ + // sync hover after a popupmenu is closed + this.taskbar, + 'menu-closed', + Lang.bind(this, function(){this.panel.actor.sync_hover();}) + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._adjustForOverview() + ], + [ + Main.overview, + 'hidden', + () => { + if (this.isPrimary) { + //reset the primary monitor when exiting the overview + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this.statusArea.activities.actor, + 'captured-event', + (actor, e) => { + // todo this is not being called right now, so the overview is not shown on the correct monitor + if (e.type() == Clutter.EventType.BUTTON_PRESS || e.type() == Clutter.EventType.TOUCH_BEGIN) { + //temporarily use as primary the monitor on which the activities btn was clicked + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this._centerBox, + 'actor-added', + () => this._onBoxActorAdded(this._centerBox) + ], + [ + this._rightBox, + 'actor-added', + () => this._onBoxActorAdded(this._rightBox) + ], + [ + this.panel.actor, + 'scroll-event', + this._onPanelMouseScroll.bind(this) + ], + [ + Main.layoutManager, + 'startup-complete', + () => this._resetGeometry() + ] + ); + + this._bindSettingsChanges(); + + this.panelStyle.enable(this); + + if (this.checkIfVertical()) { + this._signalsHandler.add([ + this.panelBox, + 'notify::visible', + () => { + if (this.panelBox.visible) { + this._refreshVerticalAlloc(); + } + } + ]); + + this._setSearchEntryOffset(this.geom.w); + + if (this.statusArea.dateMenu) { + this._formatVerticalClock(); + + this._signalsHandler.add([ + this.statusArea.dateMenu._clock, + 'notify::clock', + () => this._formatVerticalClock() + ]); + } + } + + // Since we are usually visible but not usually changing, make sure + // most repaint requests don't actually require us to repaint anything. + // This saves significant CPU when repainting the screen. + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._initProgressManager(); + }, + + disable: function () { + this.panelStyle.disable(); + + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + this._disablePanelCornerSignals(); + + this.panel.actor.remove_child(this.taskbar.actor); + this._setAppmenuVisible(false); + + if (this.intellihide) { + this.intellihide.destroy(); + } + + this.dynamicTransparency.destroy(); + + this.progressManager.destroy(); + + this.taskbar.destroy(); + this.showAppsIconWrapper.destroy(); + + this.menuManager._changeMenu = this.menuManager._oldChangeMenu; + + this._myPanelGhost.get_parent().remove_actor(this._myPanelGhost); + this._setSearchEntryOffset(0); + + panelBoxes.forEach(b => delete this[b].allocate); + this._unmappedButtons.forEach(a => this._disconnectVisibleId(a)); + + if (this._dateMenuIndicatorPadContraints && this.statusArea.dateMenu) { + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints.forEach(c => indicatorPad.add_constraint(c)); + } + + this._setVertical(this.panel.actor, false); + + if (!this.isStandalone) { + this.statusArea.dateMenu._clockDisplay.text = this.statusArea.dateMenu._clock.clock; + + ['vertical', 'horizontal', 'dashtopanelMainPanel'].forEach(c => this.panel.actor.remove_style_class_name(c)); + + if (!Main.sessionMode.isLocked) { + [['activities', 0], ['aggregateMenu', -1], ['dateMenu', 0]].forEach(b => { + let container = this.statusArea[b[0]].container; + let originalParent = container._dtpOriginalParent; + + this.panel.actor.remove_child(container); + originalParent ? originalParent.insert_child_at_index(container, b[1]) : null; + delete container._dtpOriginalParent; + }); + } + + if (!this.panel._leftCorner.actor.mapped) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + + this._setShowDesktopButton(false); + + delete Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll; + + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_width); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_height); + } + + if (this._panelConnectId) { + this.panel.actor.disconnect(this._panelConnectId); + } else { + Utils.hookVfunc(this.panel.__proto__, 'allocate', this.panel.__proto__.vfunc_allocate); + } + + this.panel.actor._delegate = this.panel; + } else { + this._removePanelMenu('dateMenu'); + this._removePanelMenu('aggregateMenu'); + this._removePanelMenu('activities'); + } + + Main.ctrlAltTabManager.removeGroup(this); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + + // open overview so they can choose a window for focusing + // and ultimately dropping dragged item onto + if(Main.overview.shouldToggleByCornerOrButton()) + Main.overview.show(); + } + + return DND.DragMotionResult.CONTINUE; + }, + + getPosition: function() { + let position = PanelSettings.getPanelPosition(Me.settings, this.monitor.index); + + if (position == Pos.TOP) { + return St.Side.TOP; + } else if (position == Pos.RIGHT) { + return St.Side.RIGHT; + } else if (position == Pos.BOTTOM) { + return St.Side.BOTTOM; + } + + return St.Side.LEFT; + }, + + checkIfVertical: function() { + let position = this.getPosition(); + + return (position == St.Side.LEFT || position == St.Side.RIGHT); + }, + + getOrientation: function() { + return (this.checkIfVertical() ? 'vertical' : 'horizontal'); + }, + + updateElementPositions: function() { + let panelPositions = this.panelManager.panelsElementPositions[this.monitor.index] || Pos.defaults; + + this._updateGroupedElements(panelPositions); + + this._disablePanelCornerSignals(); + + if (this.getPosition() == St.Side.TOP) { + let visibleElements = panelPositions.filter(pp => pp.visible); + let connectCorner = (corner, button) => { + corner._button = button; + corner._buttonStyleChangedSignalId = button.connect('style-changed', () => { + corner.set_style_pseudo_class(button.get_style_pseudo_class()); + }); + } + + if (visibleElements[0].element == Pos.ACTIVITIES_BTN) { + connectCorner(this.panel._leftCorner, this.statusArea.activities); + } + + if (visibleElements[visibleElements.length - 1].element == Pos.SYSTEM_MENU) { + connectCorner(this.panel._rightCorner, this.statusArea.aggregateMenu); + } + } + + this.panel.actor.hide(); + this.panel.actor.show(); + }, + + _updateGroupedElements: function(panelPositions) { + let previousPosition = 0; + let previousCenteredPosition = 0; + let currentGroup = -1; + + this._elementGroups = []; + + panelPositions.forEach(pos => { + let allocationMap = this.allocationMap[pos.element]; + + if (allocationMap.actor) { + allocationMap.actor.visible = pos.visible; + + if (!pos.visible) { + return; + } + + let currentPosition = pos.position; + let isCentered = Pos.checkIfCentered(currentPosition); + + if (currentPosition == Pos.STACKED_TL && previousPosition == Pos.STACKED_BR) { + currentPosition = Pos.STACKED_BR; + } + + if (!previousPosition || + (previousPosition == Pos.STACKED_TL && currentPosition != Pos.STACKED_TL) || + (previousPosition != Pos.STACKED_BR && currentPosition == Pos.STACKED_BR) || + (isCentered && previousPosition != currentPosition && previousPosition != Pos.STACKED_BR)) { + this._elementGroups[++currentGroup] = { elements: [], index: this._elementGroups.length, expandableIndex: -1 }; + previousCenteredPosition = 0; + } + + if (pos.element == Pos.TASKBAR) { + this._elementGroups[currentGroup].expandableIndex = this._elementGroups[currentGroup].elements.length; + } + + if (isCentered && !this._elementGroups[currentGroup].isCentered) { + this._elementGroups[currentGroup].isCentered = 1; + previousCenteredPosition = currentPosition; + } + + this._elementGroups[currentGroup].position = previousCenteredPosition || currentPosition; + this._elementGroups[currentGroup].elements.push(allocationMap); + + allocationMap.position = currentPosition; + previousPosition = currentPosition; + } + }); + }, + + _disablePanelCornerSignals: function() { + if (this.panel._rightCorner && this.panel._rightCorner._buttonStyleChangedSignalId) { + this.panel._rightCorner._button.disconnect(this.panel._rightCorner._buttonStyleChangedSignalId); + delete this.panel._rightCorner._buttonStyleChangedSignalId; + } + + if (this.panel._leftCorner && this.panel._leftCorner._buttonStyleChangedSignalId) { + this.panel._leftCorner._button.disconnect(this.panel._leftCorner._buttonStyleChangedSignalId); + delete this.panel._leftCorner._buttonStyleChangedSignalId; + } + }, + + _bindSettingsChanges: function() { + let isVertical = this.checkIfVertical(); + + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::group-apps' + ], + () => this._resetGeometry() + ], + [ + Me.settings, + [ + 'changed::appicon-margin', + 'changed::appicon-padding' + ], + () => this.taskbar.resetAppIcons() + ], + [ + Me.settings, + 'changed::show-appmenu', + () => this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')) + ], + [ + Me.settings, + [ + 'changed::showdesktop-button-width', + 'changed::trans-use-custom-bg', + 'changed::desktop-line-use-custom-color', + 'changed::desktop-line-custom-color', + 'changed::trans-bg-color' + ], + () => this._setShowDesktopButtonStyle() + ], + [ + Me.desktopSettings, + 'changed::clock-format', + () => { + this._clockFormat = null; + + if (isVertical) { + this._formatVerticalClock(); + } + } + ], + [ + Me.settings, + 'changed::progress-show-bar', + () => this._initProgressManager() + ], + [ + Me.settings, + 'changed::progress-show-count', + () => this._initProgressManager() + ] + ); + + if (isVertical) { + this._signalsHandler.add([Me.settings, 'changed::group-apps-label-max-width', () => this._resetGeometry()]); + } + }, + + _setPanelMenu: function(propName, constr, container) { + if (!this.statusArea[propName]) { + this.statusArea[propName] = this._getPanelMenu(propName, constr); + this.menuManager.addMenu(this.statusArea[propName].menu); + container.insert_child_at_index(this.statusArea[propName].container, 0); + } + }, + + _removePanelMenu: function(propName) { + if (this.statusArea[propName]) { + let parent = this.statusArea[propName].container.get_parent(); + + if (parent) { + parent.remove_actor(this.statusArea[propName].container); + } + + //calling this.statusArea[propName].destroy(); is buggy for now, gnome-shell never + //destroys those panel menus... + //since we can't destroy the menu (hence properly disconnect its signals), let's + //store it so the next time a panel needs one of its kind, we can reuse it instead + //of creating a new one + let panelMenu = this.statusArea[propName]; + + this.menuManager.removeMenu(panelMenu.menu); + Me.persistentStorage[propName].push(panelMenu); + this.statusArea[propName] = null; + } + }, + + _getPanelMenu: function(propName, constr) { + Me.persistentStorage[propName] = Me.persistentStorage[propName] || []; + + if (!Me.persistentStorage[propName].length) { + Me.persistentStorage[propName].push(new constr()); + } + + return Me.persistentStorage[propName].pop(); + }, + + _setPanelGhostSize: function() { + this._myPanelGhost.set_size(this.width, this.checkIfVertical() ? 1 : this.height); + }, + + _setSearchEntryOffset: function(offset) { + if (this.isPrimary) { + //In the overview, when the panel is vertical the search-entry is the only element + //that doesn't natively take into account the size of a side dock, as it is always + //centered relatively to the monitor. This looks misaligned, adjust it here so it + //is centered like the rest of the overview elements. + let paddingSide = this.getPosition() == St.Side.LEFT ? 'left' : 'right'; + let scaleFactor = Utils.getScaleFactor(); + let style = offset ? 'padding-' + paddingSide + ':' + (offset / scaleFactor) + 'px;' : null; + let searchEntry = Main.overview._overview._controls._searchEntry; + searchEntry.get_parent().set_style(style); + } + }, + + _adjustForOverview: function() { + let isFocusedMonitor = this.panelManager.checkIfFocusedMonitor(this.monitor); + let isOverview = !!Main.overview.visibleTarget; + let isOverviewFocusedMonitor = isOverview && isFocusedMonitor; + let isShown = !isOverview || isOverviewFocusedMonitor; + + this.panelBox[isShown ? 'show' : 'hide'](); + + if (isOverview) { + this._myPanelGhost[isOverviewFocusedMonitor ? 'show' : 'hide'](); + + if (isOverviewFocusedMonitor) { + Utils.getPanelGhost().set_size(1, this.geom.position == St.Side.TOP ? 0 : 32); + } + } + }, + + _resetGeometry: function() { + this.geom = this.getGeometry(); + this._setPanelGhostSize(); + this._setPanelPosition(); + this.taskbar.resetAppIcons(true); + this.dynamicTransparency.updateExternalStyle(); + + if (this.intellihide && this.intellihide.enabled) { + this.intellihide.reset(); + } + + if (this.checkIfVertical()) { + this.showAppsIconWrapper.realShowAppsIcon.toggleButton.set_width(this.geom.w); + this._refreshVerticalAlloc(); + this._setSearchEntryOffset(this.geom.w); + } + }, + + getGeometry: function() { + let scaleFactor = Utils.getScaleFactor(); + let panelBoxTheme = this.panelBox.get_theme_node(); + let lrPadding = panelBoxTheme.get_padding(St.Side.RIGHT) + panelBoxTheme.get_padding(St.Side.LEFT); + let topPadding = panelBoxTheme.get_padding(St.Side.TOP); + let tbPadding = topPadding + panelBoxTheme.get_padding(St.Side.BOTTOM); + let position = this.getPosition(); + let length = PanelSettings.getPanelLength(Me.settings, this.monitor.index) / 100; + let anchor = PanelSettings.getPanelAnchor(Me.settings, this.monitor.index); + let anchorPlaceOnMonitor = 0; + let gsTopPanelOffset = 0; + let x = 0, y = 0; + let w = 0, h = 0; + + const panelSize = PanelSettings.getPanelSize(Me.settings, this.monitor.index); + this.dtpSize = panelSize * scaleFactor; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.primaryMonitor == this.monitor) { + gsTopPanelOffset = Main.layoutManager.panelBox.height - topPadding; + } + + if (this.checkIfVertical()) { + if (!Me.settings.get_boolean('group-apps')) { + // add window title width and side padding of _dtpIconContainer when vertical + this.dtpSize += Me.settings.get_int('group-apps-label-max-width') + AppIcons.DEFAULT_PADDING_SIZE * 2 / scaleFactor; + } + + this.sizeFunc = 'get_preferred_height', + this.fixedCoord = { c1: 'x1', c2: 'x2' }, + this.varCoord = { c1: 'y1', c2: 'y2' }; + + w = this.dtpSize; + h = this.monitor.height * length - tbPadding - gsTopPanelOffset; + } else { + this.sizeFunc = 'get_preferred_width'; + this.fixedCoord = { c1: 'y1', c2: 'y2' }; + this.varCoord = { c1: 'x1', c2: 'x2' }; + + w = this.monitor.width * length - lrPadding; + h = this.dtpSize; + } + + if (position == St.Side.TOP || position == St.Side.LEFT) { + x = this.monitor.x; + y = this.monitor.y + gsTopPanelOffset; + } else if (position == St.Side.RIGHT) { + x = this.monitor.x + this.monitor.width - this.dtpSize - lrPadding; + y = this.monitor.y + gsTopPanelOffset; + } else { //BOTTOM + x = this.monitor.x; + y = this.monitor.y + this.monitor.height - this.dtpSize - tbPadding; + } + + if (this.checkIfVertical()) { + let viewHeight = this.monitor.height - gsTopPanelOffset; + + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (viewHeight - h) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = viewHeight - h; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + y = y + anchorPlaceOnMonitor; + } else { + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (this.monitor.width - w) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = this.monitor.width - w; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + x = x + anchorPlaceOnMonitor; + } + + return { + x: x, y: y, + w: w, h: h, + lrPadding: lrPadding, + tbPadding: tbPadding, + position: position + }; + }, + + _setAllocationMap: function() { + this.allocationMap = {}; + let setMap = (name, actor, isBox) => this.allocationMap[name] = { + actor: actor, + isBox: isBox || 0, + box: new Clutter.ActorBox() + }; + + setMap(Pos.SHOW_APPS_BTN, this.showAppsIconWrapper.realShowAppsIcon); + setMap(Pos.ACTIVITIES_BTN, this.statusArea.activities ? this.statusArea.activities.container : 0); + setMap(Pos.LEFT_BOX, this._leftBox, 1); + setMap(Pos.TASKBAR, this.taskbar.actor); + setMap(Pos.CENTER_BOX, this._centerBox, 1); + setMap(Pos.DATE_MENU, this.statusArea.dateMenu.container); + setMap(Pos.SYSTEM_MENU, this.statusArea.aggregateMenu.container); + setMap(Pos.RIGHT_BOX, this._rightBox, 1); + setMap(Pos.DESKTOP_BTN, this._showDesktopButton); + }, + + _mainPanelAllocate: function(actor, box, flags) { + Utils.setAllocation(this.panel.actor, box, flags); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + + let fixed = 0; + let centeredMonitorGroup; + let panelAlloc = new Clutter.ActorBox({ x1: 0, y1: 0, x2: this.geom.w, y2: this.geom.h }); + let assignGroupSize = (group, update) => { + group.size = 0; + group.tlOffset = 0; + group.brOffset = 0; + + group.elements.forEach(element => { + if (!update) { + element.box[this.fixedCoord.c1] = panelAlloc[this.fixedCoord.c1]; + element.box[this.fixedCoord.c2] = panelAlloc[this.fixedCoord.c2]; + element.natSize = element.actor[this.sizeFunc](-1)[1]; + } + + if (!group.isCentered || Pos.checkIfCentered(element.position)) { + group.size += element.natSize; + } else if (element.position == Pos.STACKED_TL) {  + group.tlOffset += element.natSize; + } else { // Pos.STACKED_BR + group.brOffset += element.natSize; + } + }); + + if (group.isCentered) { + group.size += Math.max(group.tlOffset, group.brOffset) * 2; + group.tlOffset = Math.max(group.tlOffset - group.brOffset, 0); + } + }; + let allocateGroup = (group, tlLimit, brLimit) => { + let startPosition = tlLimit; + let currentPosition = 0; + + if (group.expandableIndex >= 0) { + let availableSize = brLimit - tlLimit; + let expandable = group.elements[group.expandableIndex]; + let i = 0; + let l = this._elementGroups.length; + let tlSize = 0; + let brSize = 0; + + if (centeredMonitorGroup && (centeredMonitorGroup != group || expandable.position != Pos.CENTERED_MONITOR)) { + if (centeredMonitorGroup.index < group.index || (centeredMonitorGroup == group && expandable.position == Pos.STACKED_TL)) { + i = centeredMonitorGroup.index; + } else { + l = centeredMonitorGroup.index; + } + } + + for (; i < l; ++i) { + let refGroup = this._elementGroups[i]; + + if (i < group.index && (!refGroup.fixed || refGroup[this.varCoord.c2] > tlLimit)) { + tlSize += refGroup.size; + } else if (i > group.index && (!refGroup.fixed || refGroup[this.varCoord.c1] < brLimit)) { + brSize += refGroup.size; + } + } + + if (group.isCentered) { + availableSize -= Math.max(tlSize, brSize) * 2; + } else { + availableSize -= tlSize + brSize; + } + + if (availableSize < group.size) { + expandable.natSize -= (group.size - availableSize) * (group.isCentered && !Pos.checkIfCentered(expandable.position) ? .5 : 1); + assignGroupSize(group, true); + } + } + + if (group.isCentered) { + startPosition = tlLimit + (brLimit - tlLimit - group.size) * .5; + } else if (group.position == Pos.STACKED_BR) { + startPosition = brLimit - group.size; + } + + currentPosition = group.tlOffset + startPosition; + + group.elements.forEach(element => { + element.box[this.varCoord.c1] = Math.round(currentPosition); + element.box[this.varCoord.c2] = Math.round((currentPosition += element.natSize)); + + if (element.isBox) { + return element.actor.allocate(element.box, flags, true); + } + + Utils.allocate(element.actor, element.box, flags, false); + }); + + group[this.varCoord.c1] = startPosition; + group[this.varCoord.c2] = currentPosition; + group.fixed = 1; + ++fixed; + }; + + Utils.allocate(this.panel.actor, panelAlloc, flags); + + this._elementGroups.forEach(group => { + group.fixed = 0; + + assignGroupSize(group); + + if (group.position == Pos.CENTERED_MONITOR) { + centeredMonitorGroup = group; + } + }); + + if (centeredMonitorGroup) { + allocateGroup(centeredMonitorGroup, panelAlloc[this.varCoord.c1], panelAlloc[this.varCoord.c2]); + } + + let iterations = 0; //failsafe + while (fixed < this._elementGroups.length && ++iterations < 10) { + for (let i = 0, l = this._elementGroups.length; i < l; ++i) { + let group = this._elementGroups[i]; + + if (group.fixed) { + continue; + } + + let prevGroup = this._elementGroups[i - 1]; + let nextGroup = this._elementGroups[i + 1]; + let prevLimit = prevGroup && prevGroup.fixed ? prevGroup[this.varCoord.c2] : + centeredMonitorGroup && group.index > centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c2] : panelAlloc[this.varCoord.c1]; + let nextLimit = nextGroup && nextGroup.fixed ? nextGroup[this.varCoord.c1] : + centeredMonitorGroup && group.index < centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c1] : panelAlloc[this.varCoord.c2]; + + if (group.position == Pos.STACKED_TL) { + allocateGroup(group, panelAlloc[this.varCoord.c1], nextLimit); + } else if (group.position == Pos.STACKED_BR) { + allocateGroup(group, prevLimit, panelAlloc[this.varCoord.c2]); + } else if ((!prevGroup || prevGroup.fixed) && (!nextGroup || nextGroup.fixed)) { // CENTERED + allocateGroup(group, prevLimit, nextLimit); + } + } + } + + if (this.geom.position == St.Side.TOP) { + let childBoxLeftCorner = new Clutter.ActorBox(); + let childBoxRightCorner = new Clutter.ActorBox(); + let currentCornerSize = this.cornerSize; + let panelAllocFixedSize = box[this.fixedCoord.c2] - box[this.fixedCoord.c1]; + + [ , this.cornerSize] = this.panel._leftCorner.actor[this.sizeFunc](-1); + childBoxLeftCorner[this.varCoord.c1] = 0; + childBoxLeftCorner[this.varCoord.c2] = this.cornerSize; + childBoxLeftCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxLeftCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + childBoxRightCorner[this.varCoord.c1] = box[this.varCoord.c2] - this.cornerSize; + childBoxRightCorner[this.varCoord.c2] = box[this.varCoord.c2]; + childBoxRightCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxRightCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + Utils.allocate(this.panel._leftCorner.actor, childBoxLeftCorner, flags); + Utils.allocate(this.panel._rightCorner.actor, childBoxRightCorner, flags); + + if (this.cornerSize != currentCornerSize) { + this._setPanelClip(); + } + } + }, + + _setPanelPosition: function() { + let clipContainer = this.panelBox.get_parent(); + + this.set_size(this.geom.w, this.geom.h); + clipContainer.set_position(this.geom.x, this.geom.y); + + this._setVertical(this.panel.actor, this.checkIfVertical()); + + // styles for theming + Object.keys(St.Side).forEach(p => { + let cssName = 'dashtopanel' + p.charAt(0) + p.slice(1).toLowerCase(); + + this.panel.actor[(St.Side[p] == this.geom.position ? 'add' : 'remove') + '_style_class_name'](cssName); + }); + + this._setPanelClip(clipContainer); + + Main.layoutManager._updateHotCorners(); + Main.layoutManager._updatePanelBarrier(this); + }, + + _setPanelClip: function(clipContainer) { + clipContainer = clipContainer || this.panelBox.get_parent(); + this._timeoutsHandler.add([T7, 0, () => Utils.setClip(clipContainer, clipContainer.x, clipContainer.y, this.panelBox.width, this.panelBox.height + this.cornerSize)]); + }, + + _onButtonPress: function(actor, event) { + let type = event.type(); + let isPress = type == Clutter.EventType.BUTTON_PRESS; + let button = isPress ? event.get_button() : -1; + let [stageX, stageY] = event.get_coords(); + + if (button == 3 && global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, stageX, stageY) == this.panel.actor) { + //right click on an empty part of the panel, temporarily borrow and display the showapps context menu + Main.layoutManager.setDummyCursorGeometry(stageX, stageY, 0, 0); + + this.showAppsIconWrapper.createMenu(); + this.showAppsIconWrapper._menu.sourceActor = Main.layoutManager.dummyCursor; + this.showAppsIconWrapper.popupMenu(); + + return Clutter.EVENT_STOP; + } else if (Main.modalCount > 0 || event.get_source() != actor || + (!isPress && type != Clutter.EventType.TOUCH_BEGIN) || + (isPress && button != 1)) { + return Clutter.EVENT_PROPAGATE; + } + + let params = this.checkIfVertical() ? [stageY, 'y', 'height'] : [stageX, 'x', 'width']; + let dragWindow = this._getDraggableWindowForPosition.apply(this, params.concat(['maximized_' + this.getOrientation() + 'ly'])); + + if (!dragWindow) + return Clutter.EVENT_PROPAGATE; + + global.display.begin_grab_op(dragWindow, + Meta.GrabOp.MOVING, + false, /* pointer grab */ + true, /* frame action */ + button, + event.get_state(), + event.get_time(), + stageX, stageY); + + return Clutter.EVENT_STOP; + }, + + _getDraggableWindowForPosition: function(stageCoord, coord, dimension, maximizedProp) { + let workspace = Utils.getCurrentWorkspace(); + let allWindowsByStacking = global.display.sort_windows_by_stacking( + workspace.list_windows() + ).reverse(); + + return Utils.find(allWindowsByStacking, metaWindow => { + let rect = metaWindow.get_frame_rect(); + + return metaWindow.get_monitor() == this.monitor.index && + metaWindow.showing_on_its_workspace() && + metaWindow.get_window_type() != Meta.WindowType.DESKTOP && + metaWindow[maximizedProp] && + stageCoord > rect[coord] && stageCoord < rect[coord] + rect[dimension]; + }); + }, + + _onBoxActorAdded: function(box) { + if (this.checkIfVertical()) { + this._setVertical(box, true); + } + }, + + _refreshVerticalAlloc: function() { + this._setVertical(this._centerBox, true); + this._setVertical(this._rightBox, true); + this._formatVerticalClock(); + }, + + _setVertical: function(actor, isVertical) { + let _set = (actor, isVertical) => { + if (!actor || actor instanceof Dash.DashItemContainer || actor instanceof Taskbar.TaskbarItemContainer) { + return; + } + + if (actor instanceof St.BoxLayout) { + actor.vertical = isVertical; + } else if ((actor._delegate || actor) instanceof PanelMenu.ButtonBox && actor != this.statusArea.appMenu) { + let child = actor.get_first_child(); + + if (isVertical && !actor.visible && !actor._dtpVisibleId) { + this._unmappedButtons.push(actor); + actor._dtpVisibleId = actor.connect('notify::visible', () => { + this._disconnectVisibleId(actor); + this._refreshVerticalAlloc(); + }); + actor._dtpDestroyId = actor.connect('destroy', () => this._disconnectVisibleId(actor)); + } + + if (child) { + let [, natWidth] = actor.get_preferred_width(-1); + + child.x_align = Clutter.ActorAlign[isVertical ? 'CENTER' : 'START']; + actor.set_width(isVertical ? this.dtpSize : -1); + isVertical = isVertical && (natWidth > this.dtpSize); + actor[(isVertical ? 'add' : 'remove') + '_style_class_name']('vertical'); + } + } + + actor.get_children().forEach(c => _set(c, isVertical)); + }; + + _set(actor, false); + _set(actor, isVertical); + }, + + _disconnectVisibleId: function(actor) { + actor.disconnect(actor._dtpVisibleId); + actor.disconnect(actor._dtpDestroyId); + + delete actor._dtpVisibleId; + delete actor._dtpDestroyId; + + this._unmappedButtons.splice(this._unmappedButtons.indexOf(actor), 1); + }, + + _setAppmenuVisible: function(isVisible) { + let parent; + let appMenu = this.statusArea.appMenu; + + if(appMenu) + parent = appMenu.container.get_parent(); + + if (parent) { + parent.remove_child(appMenu.container); + } + + if (isVisible && appMenu) { + this._leftBox.insert_child_above(appMenu.container, null); + } + }, + + _formatVerticalClock: function() { + // https://github.com/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-wall-clock.c#L310 + if (this.statusArea.dateMenu) { + let datetime = this.statusArea.dateMenu._clock.clock; + let datetimeParts = datetime.split(' '); + let time = datetimeParts[1]; + let clockText = this.statusArea.dateMenu._clockDisplay.clutter_text; + let setClockText = text => { + let stacks = text instanceof Array; + let separator = '\n‧‧\n'; + + clockText.set_text((stacks ? text.join(separator) : text).trim()); + clockText.set_use_markup(stacks); + clockText.get_allocation_box(); + + return !clockText.get_layout().is_ellipsized(); + }; + + if (clockText.ellipsize == Pango.EllipsizeMode.NONE) { + //on gnome-shell 3.36.4, the clockdisplay isn't ellipsize anymore, so set it back + clockText.ellipsize = Pango.EllipsizeMode.END; + } + + if (!time) { + datetimeParts = datetime.split(' '); + time = datetimeParts.pop(); + datetimeParts = [datetimeParts.join(' '), time]; + } + + if (!setClockText(datetime) && + !setClockText(datetimeParts) && + !setClockText(time)) { + let timeParts = time.split('∶'); + + if (!this._clockFormat) { + this._clockFormat = Me.desktopSettings.get_string('clock-format'); + } + + if (this._clockFormat == '12h') { + timeParts.push.apply(timeParts, timeParts.pop().split(' ')); + } + + setClockText(timeParts); + } + } + }, + + _setShowDesktopButton: function (add) { + if (add) { + if(this._showDesktopButton) + return; + + this._showDesktopButton = new St.Bin({ style_class: 'showdesktop-button', + reactive: true, + can_focus: true, + // x_fill: true, + // y_fill: true, + track_hover: true }); + + this._setShowDesktopButtonStyle(); + + this._showDesktopButton.connect('button-press-event', () => this._onShowDesktopButtonPress()); + this._showDesktopButton.connect('enter-event', () => { + this._showDesktopButton.add_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + this._timeoutsHandler.add([T4, Me.settings.get_int('show-showdesktop-delay'), () => { + this._hiddenDesktopWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + this._toggleWorkspaceWindows(true, this._hiddenDesktopWorkspace); + }]); + } + }); + + this._showDesktopButton.connect('leave-event', () => { + this._showDesktopButton.remove_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + if (this._timeoutsHandler.getId(T4)) { + this._timeoutsHandler.remove(T4); + } else if (this._hiddenDesktopWorkspace) { + this._toggleWorkspaceWindows(false, this._hiddenDesktopWorkspace); + } +  } + }); + + this.panel.actor.add_child(this._showDesktopButton); + } else { + if(!this._showDesktopButton) + return; + + this.panel.actor.remove_child(this._showDesktopButton); + this._showDesktopButton.destroy(); + this._showDesktopButton = null; + } + }, + + _setShowDesktopButtonStyle: function() { + let rgb = this._getBackgroundBrightness() ? "rgba(55, 55, 55, .2)" : "rgba(200, 200, 200, .2)"; + + let isLineCustom = Me.settings.get_boolean('desktop-line-use-custom-color'); + rgb = isLineCustom ? Me.settings.get_string('desktop-line-custom-color') : rgb; + + if (this._showDesktopButton) { + let buttonSize = Me.settings.get_int('showdesktop-button-width') + 'px;'; + let isVertical = this.checkIfVertical(); + + let sytle = "border: 0 solid " + rgb + ";"; + sytle += isVertical ? 'border-top-width:1px;height:' + buttonSize : 'border-left-width:1px;width:' + buttonSize; + + this._showDesktopButton.set_style(sytle); + this._showDesktopButton[(isVertical ? 'x' : 'y') + '_expand'] = true; + } + }, + + // _getBackgroundBrightness: return true if panel has a bright background color + _getBackgroundBrightness: function() { + return Utils.checkIfColorIsBright(this.dynamicTransparency.backgroundColorRgb); + }, + + _toggleWorkspaceWindows: function(hide, workspace) { + let time = Me.settings.get_int('show-showdesktop-time') * .001; + + workspace.list_windows().forEach(w => { + if (!w.minimized) { + let tweenOpts = { + opacity: hide ? 0 : 255, + time: time, + transition: 'easeOutQuad' + }; + + Utils.animateWindowOpacity(w.get_compositor_private(), tweenOpts); + } + }); + }, + + _onShowDesktopButtonPress: function() { + let label = 'trackerFocusApp'; + + this._signalsHandler.removeWithLabel(label); + this._timeoutsHandler.remove(T5); + + if(this._restoreWindowList && this._restoreWindowList.length) { + this._timeoutsHandler.remove(T4); + + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows(); + this._restoreWindowList.forEach(function(w) { + if(windows.indexOf(w) > -1) + Main.activateWindow(w); + }); + this._restoreWindowList = null; + } else { + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows().filter(function (w) { + return w.showing_on_its_workspace() && !w.skip_taskbar; + }); + windows = global.display.sort_windows_by_stacking(windows); + + windows.forEach(function(w) { + w.minimize(); + }); + + this._restoreWindowList = windows; + + this._timeoutsHandler.add([T5, 20, () => this._signalsHandler.addWithLabel( + label, + [ + tracker, + 'notify::focus-app', + () => this._restoreWindowList = null + ] + )]); + } + + Main.overview.hide(); + }, + + _onPanelMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-panel-action'); + let direction = Utils.getMouseScrollDirection(event); + + if (!this._checkIfIgnoredScrollSource(event.get_source()) && !this._timeoutsHandler.getId(T6)) { + if (direction && scrollAction === 'SWITCH_WORKSPACE') { + let args = [global.display]; + + //adjust for horizontal workspaces + if (Utils.DisplayWrapper.getWorkspaceManager().layout_rows === 1) { + direction = direction == 'up' ? 'left' : 'right'; + } + + //gnome-shell < 3.30 needs an additional "screen" param + global.screen ? args.push(global.screen) : 0; + + let showWsPopup = Me.settings.get_boolean('scroll-panel-show-ws-popup'); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = { display: () => {} }; + Main.wm._showWorkspaceSwitcher.apply(Main.wm, args.concat([0, { get_name: () => 'switch---' + direction }])); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = null; + } else if (direction && scrollAction === 'CYCLE_WINDOWS') { + let windows = this.taskbar.getAppInfos().reduce((ws, appInfo) => ws.concat(appInfo.windows), []); + + Utils.activateSiblingWindow(windows, direction); + } else if (scrollAction === 'CHANGE_VOLUME' && !event.is_pointer_emulated()) { + var proto = Volume.Indicator.prototype; + var func = proto._handleScrollEvent || proto.vfunc_scroll_event || proto._onScrollEvent; + + func.call(Main.panel.statusArea.aggregateMenu._volume, 0, event); + } else { + return; + } + + var scrollDelay = Me.settings.get_int('scroll-panel-delay'); + + if (scrollDelay) { + this._timeoutsHandler.add([T6, scrollDelay, () => {}]); + } + } + }, + + _checkIfIgnoredScrollSource: function(source) { + let ignoredConstr = ['WorkspaceIndicator']; + + return source.get_parent()._dtpIgnoreScroll || ignoredConstr.indexOf(source.constructor.name) >= 0; + }, + + _initProgressManager: function() { + if(!this.progressManager && (Me.settings.get_boolean('progress-show-bar') || Me.settings.get_boolean('progress-show-count'))) + this.progressManager = new Progress.ProgressManager(); + }, +}); + +var dtpSecondaryPanel = Utils.defineClass({ + Name: 'DashToPanel-SecondaryPanel', + Extends: St.Widget, + + _init: function(params) { + this.callParent('_init', params); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + } +}); + +var dtpSecondaryAggregateMenu = Utils.defineClass({ + Name: 'DashToPanel-SecondaryAggregateMenu', + Extends: PanelMenu.Button, + + _init: function() { + this.callParent('_init', 0.0, C_("System menu in the top bar", "System"), false); + + Utils.wrapActor(this); + + this.menu.actor.add_style_class_name('aggregate-menu'); + + let menuLayout = new Panel.AggregateLayout(); + this.menu.box.set_layout_manager(menuLayout); + + this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' }); + this.actor.add_child(this._indicators); + + this._power = new imports.ui.status.power.Indicator(); + this._volume = new imports.ui.status.volume.Indicator(); + this._brightness = new imports.ui.status.brightness.Indicator(); + this._system = new imports.ui.status.system.Indicator(); + + if (Config.PACKAGE_VERSION >= '3.28') { + this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._thunderbolt)); + } + + if (Config.PACKAGE_VERSION < '3.37') { + this._screencast = new imports.ui.status.screencast.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._screencast)); + } + + if (Config.PACKAGE_VERSION >= '3.24') { + this._nightLight = new imports.ui.status.nightLight.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._nightLight)); + } + + if (Config.HAVE_NETWORKMANAGER && Config.PACKAGE_VERSION >= '3.24') { + this._network = new imports.ui.status.network.NMApplet(); + this._indicators.add_child(Utils.getIndicators(this._network)); + } + + if (Config.HAVE_BLUETOOTH) { + this._bluetooth = new imports.ui.status.bluetooth.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._bluetooth)); + } + + this._indicators.add_child(Utils.getIndicators(this._volume)); + this._indicators.add_child(Utils.getIndicators(this._power)); + + this.menu.addMenuItem(this._volume.menu); + this._volume._volumeMenu._readOutput(); + this._volume._volumeMenu._readInput(); + + this.menu.addMenuItem(this._brightness.menu); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + if (this._network) { + this.menu.addMenuItem(this._network.menu); + } + + if (this._bluetooth) { + this.menu.addMenuItem(this._bluetooth.menu); + } + + this.menu.addMenuItem(this._power.menu); + this._power._sync(); + + if (this._nightLight) { + this.menu.addMenuItem(this._nightLight.menu); + } + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(this._system.menu); + + menuLayout.addSizeChild(this._power.menu.actor); + menuLayout.addSizeChild(this._system.menu.actor); + }, +}); diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js new file mode 100644 index 0000000..d572d8b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js @@ -0,0 +1,789 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Overview = Me.imports.overview; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Proximity = Me.imports.proximity; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +const Config = imports.misc.config; +const Lang = imports.lang; +const Gi = imports._gi; +const GLib = imports.gi.GLib; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +const AppDisplay = imports.ui.appDisplay; +const BoxPointer = imports.ui.boxpointer; +const Dash = imports.ui.dash; +const IconGrid = imports.ui.iconGrid; +const LookingGlass = imports.ui.lookingGlass; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const Layout = imports.ui.layout; +const WM = imports.ui.windowManager; +const WorkspacesView = imports.ui.workspacesView; + +var dtpPanelManager = Utils.defineClass({ + Name: 'DashToPanel.PanelManager', + + _init: function() { + this.overview = new Overview.dtpOverview(); + this.panelsElementPositions = {}; + + this._saveMonitors(); + + Utils.getAppDisplayViews().forEach(v => { + Utils.wrapActor(v.view); + Utils.wrapActor(v.view._grid); + }); + }, + + enable: function(reset) { + let dtpPrimaryIndex = Me.settings.get_int('primary-monitor'); + + this.dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex] || Main.layoutManager.primaryMonitor; + this.proximityManager = new Proximity.ProximityManager(); + + this._oldGetShowAppsButton = imports.ui.main.overview.dash.showAppsButton; + + Utils.wrapActor(Main.panel); + Utils.wrapActor(Main.overview.dash || 0); + + this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel')); + this.allPanels = [ this.primaryPanel ]; + + this.overview.enable(this.primaryPanel); + + if (Me.settings.get_boolean('multi-monitors')) { + Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => { + this.allPanels.push(this._createPanel(m, true)); + }); + } + + global.dashToPanel.panels = this.allPanels; + global.dashToPanel.emit('panels-created'); + + this.allPanels.forEach(p => { + let panelPosition = p.getPosition(); + let leftOrRight = (panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT); + + p.panelBox.set_size( + leftOrRight ? -1 : p.geom.w + p.geom.lrPadding, + leftOrRight ? p.geom.h + p.geom.tbPadding : -1 + ); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => this._adjustPanelMenuButton(pmb, p.monitor, panelPosition)); + + p.taskbar.iconAnimator.start(); + }); + + //in 3.32, BoxPointer now inherits St.Widget + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + let panelManager = this; + + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', function(forWidth) { + let alloc = { min_size: 0, natural_size: 0 }; + + [alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth); + + return panelManager._getBoxPointerPreferredHeight(this, alloc); + }); + } + + this._updatePanelElementPositions(); + this.setFocusedMonitor(this.dtpPrimaryMonitor); + + if (this.primaryPanel.checkIfVertical()) { + Main.wm._getPositionForDirection = newGetPositionForDirection; + } + + if (reset) return; + + if (Config.PACKAGE_VERSION > '3.35.1') { + this._oldDoSpringAnimation = AppDisplay.BaseAppView.prototype._doSpringAnimation; + AppDisplay.BaseAppView.prototype._doSpringAnimation = newDoSpringAnimation; + } + + this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier; + Main.layoutManager._updatePanelBarrier = (panel) => { + let panelUpdates = panel ? [panel] : this.allPanels; + + panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p)); + }; + Main.layoutManager._updatePanelBarrier(); + + this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners; + Main.layoutManager._updateHotCorners = Lang.bind(Main.layoutManager, newUpdateHotCorners); + Main.layoutManager._updateHotCorners(); + + this._forceHotCornerId = Me.settings.connect('changed::stockgs-force-hotcorner', () => Main.layoutManager._updateHotCorners()); + + if (Main.layoutManager._interfaceSettings) { + this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners()); + } + + Main.overview.getShowAppsButton = this._newGetShowAppsButton.bind(this); + + this._needsDashItemContainerAllocate = !Dash.DashItemContainer.prototype.hasOwnProperty('vfunc_allocate'); + + if (this._needsDashItemContainerAllocate) { + Utils.hookVfunc(Dash.DashItemContainer.prototype, 'allocate', this._newDashItemContainerAllocate); + } + + LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize; + LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize; + + LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open; + LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + if (Config.PACKAGE_VERSION > '3.35.9') { + let currentAppsView; + + this._oldAnimateIconPosition = IconGrid.animateIconPosition; + IconGrid.animateIconPosition = newAnimateIconPosition.bind(this); + + this._signalsHandler.add( + [ + Utils.DisplayWrapper.getScreen(), + 'window-entered-monitor', + () => this._needsIconAllocate = 1 + ] + ); + + Utils.getAppDisplayViews().forEach(v => { + if (!v.control || v.control.has_style_pseudo_class('checked')) { + currentAppsView = v; + } + + if (v.control) { + this._signalsHandler.add( + [ + v.control, + 'clicked', + () => { + this._needsIconAllocate = currentAppsView != v; + currentAppsView = v; + } + ] + ); + } + + this._signalsHandler.add( + [ + v.view, + 'notify::visible', + () => this._needsIconAllocate = !(currentAppsView != v && !v.view.visible) + ], + [ + v.view._grid, + 'animation-done', + () => this._needsIconAllocate = 0 + ] + ); + }); + } + + //listen settings + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::primary-monitor', + 'changed::multi-monitors', + 'changed::isolate-monitors', + 'changed::panel-positions', + 'changed::panel-lengths', + 'changed::panel-anchors', + 'changed::stockgs-keep-top-panel' + ], + () => this._reset() + ], + [ + Me.settings, + 'changed::panel-element-positions', + () => this._updatePanelElementPositions() + ], + [ + Me.settings, + 'changed::intellihide-key-toggle-text', + () => this._setKeyBindings(true) + ], + [ + Utils.DisplayWrapper.getMonitorManager(), + 'monitors-changed', + () => { + if (Main.layoutManager.primaryMonitor) { + this._saveMonitors(); + this._reset(); + } + } + ] + ); + + Panel.panelBoxes.forEach(c => this._signalsHandler.add( + [Main.panel[c], 'actor-added', (parent, child) => this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, this.primaryPanel.getPosition())] + )); + + this._setKeyBindings(true); + + // keep GS overview.js from blowing away custom panel styles + if(!Me.settings.get_boolean('stockgs-keep-top-panel')) + Object.defineProperty(Main.panel, "style", {configurable: true, set: function(v) {}}); + }, + + disable: function(reset) { + this.overview.disable(); + this.proximityManager.destroy(); + + this.allPanels.forEach(p => { + p.taskbar.iconAnimator.pause(); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => { + if (pmb.menu._boxPointer._dtpGetPreferredHeightId) { + pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId); + } + + pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor; + delete pmb.menu._boxPointer._dtpSourceActor; + pmb.menu._boxPointer._userArrowSide = St.Side.TOP; + }) + + this._removePanelBarriers(p); + + p.disable(); + + let clipContainer = p.panelBox.get_parent(); + + Main.layoutManager._untrackActor(p.panelBox); + Main.layoutManager.removeChrome(clipContainer); + + if (p.isStandalone) { + p.panelBox.destroy(); + } else { + p.panelBox.remove_child(p); + p.remove_child(p.panel.actor); + p.panelBox.add(p.panel.actor); + + p.panelBox.set_position(clipContainer.x, clipContainer.y); + + clipContainer.remove_child(p.panelBox); + Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true }); + } + }); + + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height); + } + + delete Main.wm._getPositionForDirection; + + if (Main.layoutManager.primaryMonitor) { + Main.layoutManager.panelBox.set_position(Main.layoutManager.primaryMonitor.x, Main.layoutManager.primaryMonitor.y); + Main.layoutManager.panelBox.set_size(Main.layoutManager.primaryMonitor.width, -1); + } + + if (reset) return; + + this._setKeyBindings(false); + + this._signalsHandler.destroy(); + + Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners; + Main.layoutManager._updateHotCorners(); + + Me.settings.disconnect(this._forceHotCornerId); + + if (this._enableHotCornersId) { + Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId); + } + + Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier; + Main.layoutManager._updatePanelBarrier(); + + Utils.getPanelGhost().set_size(-1, -1); + + if (this._oldDoSpringAnimation) { + AppDisplay.BaseAppView.prototype._doSpringAnimation = this._oldDoSpringAnimation; + } + + if (this._oldAnimateIconPosition) { + IconGrid.animateIconPosition = this._oldAnimateIconPosition; + } + + LookingGlass.LookingGlass.prototype._resize = LookingGlass.LookingGlass.prototype._oldResize; + delete LookingGlass.LookingGlass.prototype._oldResize; + + LookingGlass.LookingGlass.prototype.open = LookingGlass.LookingGlass.prototype._oldOpen; + delete LookingGlass.LookingGlass.prototype._oldOpen + + delete Main.panel.style; + }, + + setFocusedMonitor: function(monitor, ignoreRelayout) { + // todo show overview on non primary monitor is not working right now on gnome40 + + // this._needsIconAllocate = 1; + + // if (!this.checkIfFocusedMonitor(monitor)) { + // Main.overview._overview._controls._workspacesDisplay._primaryIndex = monitor.index; + + // Main.overview._overview.clear_constraints(); + // Main.overview._overview.add_constraint(new Layout.MonitorConstraint({ index: monitor.index })); + // } + }, + + _saveMonitors: function() { + //Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same + //monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()). + //Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store + //the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell + let primaryIndex = Main.layoutManager.primaryIndex; + let monitors = [primaryIndex]; + + Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => monitors.push(m.index)); + Me.settings.set_value('available-monitors', new GLib.Variant('ai', monitors)); + }, + + checkIfFocusedMonitor: function(monitor) { + return Main.overview._overview._controls._workspacesDisplay._primaryIndex == monitor.index; + }, + + _createPanel: function(monitor, isStandalone) { + let panelBox; + let panel; + let clipContainer = new Clutter.Actor(); + + if (isStandalone) { + panelBox = new St.BoxLayout({ name: 'panelBox' }); + } else { + panelBox = Main.layoutManager.panelBox; + Main.layoutManager._untrackActor(panelBox); + panelBox.remove_child(Main.panel.actor); + Main.layoutManager.removeChrome(panelBox); + } + + Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false }); + clipContainer.add_child(panelBox); + Main.layoutManager.trackChrome(panelBox, { trackFullscreen: true, affectsStruts: true, affectsInputRegion: true }); + + panel = new Panel.dtpPanel(this, monitor, panelBox, isStandalone); + panelBox.add(panel); + panel.enable(); + + panelBox.visible = true; + if (monitor.inFullscreen) { + panelBox.hide(); + } + panelBox.set_position(0, 0); + + return panel; + }, + + _reset: function() { + this.disable(true); + this.allPanels = []; + this.enable(true); + }, + + _updatePanelElementPositions: function() { + this.panelsElementPositions = PanelSettings.getSettingsJson(Me.settings, 'panel-element-positions'); + this.allPanels.forEach(p => p.updateElementPositions()); + }, + + _adjustPanelMenuButton: function(button, monitor, arrowSide) { + if (button) { + Utils.wrapActor(button); + button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor; + button.menu._boxPointer.sourceActor = button.actor; + button.menu._boxPointer._userArrowSide = arrowSide; + button.menu._boxPointer._dtpInPanel = 1; + + if (!button.menu._boxPointer.vfunc_get_preferred_height) { + button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => { + this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor); + }); + } + } + }, + + _getBoxPointerPreferredHeight: function(boxPointer, alloc, monitor) { + if (boxPointer._dtpInPanel && boxPointer.sourceActor && Me.settings.get_boolean('intellihide')) { + monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor); + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor == monitor); + let excess = alloc.natural_size + panel.dtpSize + 10 - monitor.height; // 10 is arbitrary + + if (excess > 0) { + alloc.natural_size -= excess; + } + } + + return [alloc.min_size, alloc.natural_size]; + }, + + _findPanelMenuButtons: function(container) { + let panelMenuButtons = []; + let panelMenuButton; + + let find = parent => parent.get_children().forEach(c => { + if ((panelMenuButton = this._getPanelMenuButton(c))) { + panelMenuButtons.push(panelMenuButton); + } + + find(c); + }); + + find(container); + + return panelMenuButtons; + }, + + _removePanelBarriers: function(panel) { + if (panel.isStandalone && panel._rightPanelBarrier) { + panel._rightPanelBarrier.destroy(); + } + + if (panel._leftPanelBarrier) { + panel._leftPanelBarrier.destroy(); + delete panel._leftPanelBarrier; + } + }, + + _getPanelMenuButton: function(obj) { + return obj._delegate && obj._delegate instanceof PanelMenu.Button ? obj._delegate : 0; + }, + + _setKeyBindings: function(enable) { + let keys = { + 'intellihide-key-toggle': () => this.allPanels.forEach(p => p.intellihide.toggle()) + }; + + Object.keys(keys).forEach(k => { + Utils.removeKeybinding(k); + + if (enable) { + Utils.addKeybinding(k, Me.settings, keys[k], Shell.ActionMode.NORMAL); + } + }); + }, + + _newGetShowAppsButton: function() { + let focusedMonitorIndex = Utils.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor)); + + return this.allPanels[focusedMonitorIndex].taskbar.showAppsButton; + } +}); + +// This class drives long-running icon animations, to keep them running in sync +// with each other. +var IconAnimator = Utils.defineClass({ + Name: 'DashToPanel.IconAnimator', + + _init: function(actor) { + this._count = 0; + this._started = false; + this._animations = { + dance: [], + }; + this._timeline = new Clutter.Timeline({ + duration: 3000, + repeat_count: -1, + }); + + /* Just use the construction property when no need to support 3.36 */ + if (this._timeline.set_actor) + this._timeline.set_actor(actor); + + this._timeline.connect('new-frame', () => { + const progress = this._timeline.get_progress(); + const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0; + const dancers = this._animations.dance; + for (let i = 0, iMax = dancers.length; i < iMax; i++) { + dancers[i].target.rotation_angle_z = danceRotation; + } + }); + }, + + destroy: function() { + this._timeline.stop(); + this._timeline = null; + for (let name in this._animations) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + pair.target.disconnect(pair.targetDestroyId); + } + } + this._animations = null; + }, + + pause: function() { + if (this._started && this._count > 0) { + this._timeline.stop(); + } + this._started = false; + }, + + start: function() { + if (!this._started && this._count > 0) { + this._timeline.start(); + } + this._started = true; + }, + + addAnimation: function(target, name) { + const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name)); + this._animations[name].push({ target: target, targetDestroyId: targetDestroyId }); + if (this._started && this._count === 0) { + this._timeline.start(); + } + this._count++; + }, + + removeAnimation: function(target, name) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + if (pair.target === target) { + target.disconnect(pair.targetDestroyId); + pairs.splice(i, 1); + this._count--; + if (this._started && this._count === 0) { + this._timeline.stop(); + } + return; + } + } + } +}); + +function newGetPositionForDirection(direction, fromWs, toWs) { + let [xDest, yDest] = WM.WindowManager.prototype._getPositionForDirection(direction, fromWs, toWs); + + if (direction == Meta.MotionDirection.UP || + direction == Meta.MotionDirection.UP_LEFT || + direction == Meta.MotionDirection.UP_RIGHT) { + yDest -= Main.panel.height; + } else if (direction != Meta.MotionDirection.LEFT && + direction != Meta.MotionDirection.RIGHT) { + yDest += Main.panel.height; + } + + return [xDest, yDest]; +} + +function newDoSpringAnimation(animationDirection) { + this._grid.opacity = 255; + this._grid.animateSpring(animationDirection, Main.overview.getShowAppsButton()); +} + +function newAnimateIconPosition(icon, box, flags, nChangedIcons) { + if (this._needsIconAllocate) { + Utils.allocate(icon, box, flags); + return; + } + + return this._oldAnimateIconPosition(icon, box, flags, nChangedIcons);; +} + +function newUpdateHotCorners() { + // destroy old hot corners + this.hotCorners.forEach(function(corner) { + if (corner) + corner.destroy(); + }); + this.hotCorners = []; + + //global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner) + //this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34 + if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) || + (this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) { + this.emit('hot-corners-changed'); + return; + } + + // build new hot corners + for (let i = 0; i < this.monitors.length; i++) { + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == i); + let panelPosition = panel ? panel.getPosition() : St.Side.BOTTOM; + let panelTopLeft = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT; + let monitor = this.monitors[i]; + let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; + let cornerY = monitor.y; + + let haveTopLeftCorner = true; + + // If the panel is on the bottom, unless this is explicitly forced, don't add a topleft + // hot corner unless it is actually a top left panel. Otherwise, it stops the mouse + // as you are dragging across. In the future, maybe we will automatically move the + // hotcorner to the bottom when the panel is positioned at the bottom + if (i != this.primaryIndex || (!panelTopLeft && !Me.settings.get_boolean('stockgs-force-hotcorner'))) { + // Check if we have a top left (right for RTL) corner. + // I.e. if there is no monitor directly above or to the left(right) + let besideX = this._rtl ? monitor.x + 1 : cornerX - 1; + let besideY = cornerY; + let aboveX = cornerX; + let aboveY = cornerY - 1; + + for (let j = 0; j < this.monitors.length; j++) { + if (i == j) + continue; + let otherMonitor = this.monitors[j]; + if (besideX >= otherMonitor.x && + besideX < otherMonitor.x + otherMonitor.width && + besideY >= otherMonitor.y && + besideY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + if (aboveX >= otherMonitor.x && + aboveX < otherMonitor.x + otherMonitor.width && + aboveY >= otherMonitor.y && + aboveY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + } + } + + if (haveTopLeftCorner) { + let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY); + + corner.setBarrierSize = size => corner.__proto__.setBarrierSize.call(corner, Math.min(size, 32)); + corner.setBarrierSize(panel ? panel.dtpSize : 32); + this.hotCorners.push(corner); + } else { + this.hotCorners.push(null); + } + } + + this.emit('hot-corners-changed'); +} + +function newUpdatePanelBarrier(panel) { + let barriers = { + _rightPanelBarrier: [(panel.isStandalone ? panel : this)], + _leftPanelBarrier: [panel] + }; + + Object.keys(barriers).forEach(k => { + let obj = barriers[k][0]; + + if (obj[k]) { + obj[k].destroy(); + obj[k] = null; + } + }); + + if (!this.primaryMonitor || !panel.panelBox.height) { + return; + } + + let barrierSize = Math.min(10, panel.panelBox.height); + let fixed1 = panel.monitor.y; + let fixed2 = panel.monitor.y + barrierSize; + + if (panel.checkIfVertical()) { + barriers._rightPanelBarrier.push(panel.monitor.y + panel.monitor.height, Meta.BarrierDirection.POSITIVE_Y); + barriers._leftPanelBarrier.push(panel.monitor.y, Meta.BarrierDirection.NEGATIVE_Y); + } else { + barriers._rightPanelBarrier.push(panel.monitor.x + panel.monitor.width, Meta.BarrierDirection.NEGATIVE_X); + barriers._leftPanelBarrier.push(panel.monitor.x, Meta.BarrierDirection.POSITIVE_X); + } + + switch (panel.getPosition()) { + //values are initialized as St.Side.TOP + case St.Side.BOTTOM: + fixed1 = panel.monitor.y + panel.monitor.height - barrierSize; + fixed2 = panel.monitor.y + panel.monitor.height; + break; + case St.Side.LEFT: + fixed1 = panel.monitor.x; + fixed2 = panel.monitor.x + barrierSize; + break; + case St.Side.RIGHT: + fixed1 = panel.monitor.x + panel.monitor.width; + fixed2 = panel.monitor.x + panel.monitor.width - barrierSize; + break; + } + + //remove left barrier if it overlaps one of the hotcorners + for (let k in this.hotCorners) { + let hc = this.hotCorners[k]; + + if (hc && hc._monitor == panel.monitor && + ((fixed1 == hc._x || fixed2 == hc._x) || fixed1 == hc._y || fixed2 == hc._y)) { + delete barriers._leftPanelBarrier; + break; + } + } + + Object.keys(barriers).forEach(k => { + let barrierOptions = { + display: global.display, + directions: barriers[k][2] + }; + + barrierOptions[panel.varCoord.c1] = barrierOptions[panel.varCoord.c2] = barriers[k][1]; + barrierOptions[panel.fixedCoord.c1] = fixed1; + barrierOptions[panel.fixedCoord.c2] = fixed2; + + barriers[k][0][k] = new Meta.Barrier(barrierOptions); + }); +} + +function _newLookingGlassResize() { + let primaryMonitorPanel = Utils.find(global.dashToPanel.panels, p => p.monitor == Main.layoutManager.primaryMonitor); + let topOffset = primaryMonitorPanel.getPosition() == St.Side.TOP ? primaryMonitorPanel.dtpSize + 8 : 32; + + this._oldResize(); + Utils.wrapActor(this); + Utils.wrapActor(this._objInspector); + + this._hiddenY = Main.layoutManager.primaryMonitor.y + topOffset - this.actor.height; + this._targetY = this._hiddenY + this.actor.height; + this.actor.y = this._hiddenY; + + this._objInspector.actor.set_position(this.actor.x + Math.floor(this.actor.width * 0.1), this._targetY + Math.floor(this.actor.height * 0.1)); +} + +function _newLookingGlassOpen() { + if (this._open) + return; + + this._resize(); + this._oldOpen(); +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js new file mode 100644 index 0000000..52458bb --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js @@ -0,0 +1,61 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +var SHOW_APPS_BTN = 'showAppsButton'; +var ACTIVITIES_BTN = 'activitiesButton'; +var TASKBAR = 'taskbar'; +var DATE_MENU = 'dateMenu'; +var SYSTEM_MENU = 'systemMenu'; +var LEFT_BOX = 'leftBox'; +var CENTER_BOX = 'centerBox'; +var RIGHT_BOX = 'rightBox'; +var DESKTOP_BTN = 'desktopButton'; + +var STACKED_TL = 'stackedTL'; +var STACKED_BR = 'stackedBR'; +var CENTERED = 'centered'; +var CENTERED_MONITOR = 'centerMonitor'; + +var TOP = 'TOP'; +var BOTTOM = 'BOTTOM'; +var LEFT = 'LEFT'; +var RIGHT = 'RIGHT'; + +var START = 'START'; +var MIDDLE = 'MIDDLE'; +var END = 'END'; + +var defaults = [ + { element: SHOW_APPS_BTN, visible: true, position: STACKED_TL }, + { element: ACTIVITIES_BTN, visible: false, position: STACKED_TL }, + { element: LEFT_BOX, visible: true, position: STACKED_TL }, + { element: TASKBAR, visible: true, position: STACKED_TL }, + { element: CENTER_BOX, visible: true, position: STACKED_BR }, + { element: RIGHT_BOX, visible: true, position: STACKED_BR }, + { element: DATE_MENU, visible: true, position: STACKED_BR }, + { element: SYSTEM_MENU, visible: true, position: STACKED_BR }, + { element: DESKTOP_BTN, visible: true, position: STACKED_BR }, +]; + +var optionDialogFunctions = {}; + +optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions'; +optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'; + +function checkIfCentered(position) { + return position == CENTERED || position == CENTERED_MONITOR; +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js new file mode 100644 index 0000000..4feb3fd --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js @@ -0,0 +1,112 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Pos = Me.imports.panelPositions; + +/** Return object representing a settings value that is stored as JSON. */ +function getSettingsJson(settings, setting) { + try { + return JSON.parse(settings.get_string(setting)); + } catch(e) { + log('Error parsing positions: ' + e.message); + } +} +/** Write value object as JSON to setting in settings. */ +function setSettingsJson(settings, setting, value) { + try { + const json = JSON.stringify(value); + settings.set_string(setting, json); + } catch(e) { + log('Error serializing setting: ' + e.message); + } +} + +/** Returns size of panel on a specific monitor, in pixels. */ +function getPanelSize(settings, monitorIndex) { + const sizes = getSettingsJson(settings, 'panel-sizes'); + // Pull in deprecated setting if panel-sizes does not have setting for monitor. + const fallbackSize = settings.get_int('panel-size'); + const theDefault = 48; + return sizes[monitorIndex] || fallbackSize || theDefault; +} + +function setPanelSize(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 128 && value >= 16)) { + log('Not setting invalid panel size: ' + value); + return; + } + let sizes = getSettingsJson(settings, 'panel-sizes'); + sizes[monitorIndex] = value; + setSettingsJson(settings, 'panel-sizes', sizes); +} + +/** + * Returns length of panel on a specific monitor, as a whole number percent, + * from settings. e.g. 100 + */ +function getPanelLength(settings, monitorIndex) { + const lengths = getSettingsJson(settings, 'panel-lengths'); + const theDefault = 100; + return lengths[monitorIndex] || theDefault; +} + +function setPanelLength(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 100 && value >= 0)) { + log('Not setting invalid panel length: ' + value); + return; + } + let lengths = getSettingsJson(settings, 'panel-lengths'); + lengths[monitorIndex] = value; + setSettingsJson(settings, 'panel-lengths', lengths); +} + +/** Returns position of panel on a specific monitor. */ +function getPanelPosition(settings, monitorIndex) { + const positions = getSettingsJson(settings, 'panel-positions'); + const fallbackPosition = settings.get_string('panel-position'); + const theDefault = Pos.BOTTOM; + return positions[monitorIndex] || fallbackPosition || theDefault; +} + +function setPanelPosition(settings, monitorIndex, value) { + if (!(value === Pos.TOP || value === Pos.BOTTOM || value === Pos.LEFT + || value === Pos.RIGHT)) { + log('Not setting invalid panel position: ' + value); + return; + } + const positions = getSettingsJson(settings, 'panel-positions'); + positions[monitorIndex] = value; + setSettingsJson(settings, 'panel-positions', positions); +} + +/** Returns anchor location of panel on a specific monitor. */ +function getPanelAnchor(settings, monitorIndex) { + const anchors = getSettingsJson(settings, 'panel-anchors'); + const theDefault = Pos.MIDDLE; + return anchors[monitorIndex] || theDefault; +} + +function setPanelAnchor(settings, monitorIndex, value) { + if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) { + log('Not setting invalid panel anchor: ' + value); + return; + } + const anchors = getSettingsJson(settings, 'panel-anchors'); + anchors[monitorIndex] = value; + setSettingsJson(settings, 'panel-anchors', anchors); +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js new file mode 100644 index 0000000..2697ace --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js @@ -0,0 +1,326 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * Ideas for recursing child actors and assigning inline styles + * are based on code from the StatusAreaHorizontalSpacing extension + * https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension + * mathematical.coffee@gmail.com + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const ExtensionUtils = imports.misc.extensionUtils; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const St = imports.gi.St; +const Shell = imports.gi.Shell; + +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +var dtpPanelStyle = Utils.defineClass({ + Name: 'DashToPanel.PanelStyle', + + _init: function() { + + }, + + enable : function(panel) { + this.panel = panel; + + this._applyStyles(); + + this._bindSettingsChanges(); + }, + + disable: function () { + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + + this._removeStyles(); + }, + + _bindSettingsChanges: function() { + let configKeys = [ + "tray-size", + "leftbox-size", + "tray-padding", + "leftbox-padding", + "status-icon-padding", + ]; + + this._dtpSettingsSignalIds = []; + + for(let i in configKeys) { + this._dtpSettingsSignalIds.push(Me.settings.connect('changed::' + configKeys[i], Lang.bind(this, function () { + this._removeStyles(); + this._applyStyles(); + }))); + } + }, + + _applyStyles: function() { + this._rightBoxOperations = []; + + let trayPadding = Me.settings.get_int('tray-padding'); + let isVertical = this.panel.checkIfVertical(); + let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx'); + + if(trayPadding >= 0) { + let operation = {}; + let trayPaddingStyleLine; + + if (isVertical) { + trayPaddingStyleLine = paddingStyle.format(trayPadding); + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + } else { + trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding); + if (trayPadding < 6) { + trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(trayPadding); + } + + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('panel-button')); + }; + } + + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayPaddingStyleLine, operationIdx); + this._refreshPanelButton(actor); + }); + this._rightBoxOperations.push(operation); + } + + let statusIconPadding = Me.settings.get_int('status-icon-padding'); + if(statusIconPadding >= 0) { + let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('system-status-icon')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + } + + let trayContentSize = Me.settings.get_int('tray-size'); + if(trayContentSize > 0) { + let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0); + this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0); + } + + // center box has been moved next to the right box and will be treated the same + this._centerBoxOperations = this._rightBoxOperations; + + this._leftBoxOperations = []; + + let leftboxPadding = Me.settings.get_int('leftbox-padding'); + if(leftboxPadding >= 0) { + let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding); + let operation = {}; + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + } + + let leftboxContentSize = Me.settings.get_int('leftbox-size'); + if(leftboxContentSize > 0) { + let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(leftboxContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(leftboxContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0); + } + + this._applyStylesRecursively(); + + /* connect signal */ + this._rightBoxActorAddedID = this.panel._rightBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._rightBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._rightBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._centerBoxActorAddedID = this.panel._centerBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._centerBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._centerBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._leftBoxActorAddedID = this.panel._leftBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._leftBoxOperations.length) + this._recursiveApply(actor, this._leftBoxOperations); + }) + ); + }, + + _removeStyles: function() { + /* disconnect signal */ + if (this._rightBoxActorAddedID) + this.panel._rightBox.disconnect(this._rightBoxActorAddedID); + if (this._centerBoxActorAddedID) + this.panel._centerBox.disconnect(this._centerBoxActorAddedID); + if (this._leftBoxActorAddedID) + this.panel._leftBox.disconnect(this._leftBoxActorAddedID); + + this._restoreOriginalStyle(this.panel._rightBox); + this._restoreOriginalStyle(this.panel._centerBox); + this._restoreOriginalStyle(this.panel._leftBox); + + this._applyStylesRecursively(true); + }, + + _applyStylesRecursively: function(restore) { + /*recurse actors */ + if(this._rightBoxOperations.length) { + // add the system menu as we move it from the rightbox to the panel to position it independently + let children = this.panel._rightBox.get_children().concat([this.panel.statusArea.aggregateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._rightBoxOperations, restore); + } + + if(this._centerBoxOperations.length) { + // add the date menu as we move it from the centerbox to the panel to position it independently + let children = this.panel._centerBox.get_children().concat([this.panel.statusArea.dateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._centerBoxOperations, restore); + } + + if(this._leftBoxOperations.length) { + let children = this.panel._leftBox.get_children(); + for(let i in children) + this._recursiveApply(children[i], this._leftBoxOperations, restore); + } + }, + + _recursiveApply: function(actor, operations, restore) { + for(let i in operations) { + let o = operations[i]; + if(o.compareFn(actor)) + if(restore) + o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor); + else + o.applyFn(actor, i); + } + + if(actor.get_children) { + let children = actor.get_children(); + for(let i in children) { + this._recursiveApply(children[i], operations, restore); + } + } + }, + + _overrideStyle: function(actor, styleLine, operationIdx) { + if (actor._dtp_original_inline_style === undefined) { + actor._dtp_original_inline_style = actor.get_style(); + } + + if(actor._dtp_style_overrides === undefined) { + actor._dtp_style_overrides = {}; + } + + actor._dtp_style_overrides[operationIdx] = styleLine; + let newStyleLine = ''; + for(let i in actor._dtp_style_overrides) + newStyleLine += actor._dtp_style_overrides[i] + '; '; + actor.set_style(newStyleLine + (actor._dtp_original_inline_style || '')); + }, + + _restoreOriginalStyle: function(actor) { + if (actor._dtp_original_inline_style !== undefined) { + actor.set_style(actor._dtp_original_inline_style); + delete actor._dtp_original_inline_style; + delete actor._dtp_style_overrides; + } + + if (actor.has_style_class_name('panel-button')) { + this._refreshPanelButton(actor); + } + }, + + _refreshPanelButton: function(actor) { + if (actor.visible && imports.misc.config.PACKAGE_VERSION >= '3.34.0') { + //force gnome 3.34+ to refresh (having problem with the -natural-hpadding) + let parent = actor.get_parent(); + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(actor); + } + + this._ignoreAddedChild = [this.panel._centerBox, this.panel._rightBox].indexOf(parent) >= 0; + + parent.remove_child(actor); + parent.insert_child_at_index(actor, actorIndex); + } + } + +}); diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js new file mode 100644 index 0000000..3040787 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js @@ -0,0 +1,2468 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg. + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Lang = imports.lang; +const Mainloop = imports.mainloop; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; +const N_ = function(e) { return e }; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; + +const SCALE_UPDATE_TIMEOUT = 500; +const DEFAULT_PANEL_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; +const DEFAULT_FONT_SIZES = [ 96, 64, 48, 32, 24, 16, 0 ]; +const DEFAULT_MARGIN_SIZES = [ 32, 24, 16, 12, 8, 4, 0 ]; +const DEFAULT_PADDING_SIZES = [ 32, 24, 16, 12, 8, 4, 0, -1 ]; +// Minimum length could be 0, but a higher value may help prevent confusion about where the panel went. +const LENGTH_MARKS = [ 100, 90, 80, 70, 60, 50, 40, 30, 20, 10 ]; +const MAX_WINDOW_INDICATOR = 4; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/dash-to-panel/'; +const GSET = 'gnome-shell-extension-tool'; + +/** + * This function was copied from the activities-config extension + * https://github.com/nls1729/acme-code/tree/master/activities-config + * by Norman L. Smith. + */ +function cssHexString(css) { + let rrggbb = '#'; + let start; + for (let loop = 0; loop < 3; loop++) { + let end = 0; + let xx = ''; + for (let loop = 0; loop < 2; loop++) { + while (true) { + let x = css.slice(end, end + 1); + if ((x == '(') || (x == ',') || (x == ')')) + break; + end++; + } + if (loop == 0) { + end++; + start = end; + } + } + xx = parseInt(css.slice(start, end)).toString(16); + if (xx.length == 1) + xx = '0' + xx; + rrggbb += xx; + css = css.slice(end); + } + return rrggbb; +} + +function setShortcut(settings, shortcutName) { + let shortcut_text = settings.get_string(shortcutName + '-text'); + let [key, mods] = Gtk.accelerator_parse(shortcut_text); + + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + settings.set_strv(shortcutName, [shortcut]); + } + else { + settings.set_strv(shortcutName, []); + } +} + +function checkHotkeyPrefix(settings) { + settings.delay(); + + let hotkeyPrefix = settings.get_string('hotkey-prefix-text'); + if (hotkeyPrefix == 'Super') + hotkeyPrefix = ''; + else if (hotkeyPrefix == 'SuperAlt') + hotkeyPrefix = ''; + let [, mods] = Gtk.accelerator_parse(hotkeyPrefix); + let [, shift_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + let [, ctrl_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + + let numHotkeys = 10; + for (let i = 1; i <= numHotkeys; i++) { + let number = i; + if (number == 10) + number = 0; + let key = Gdk.keyval_from_name(number.toString()); + let key_kp = Gdk.keyval_from_name('KP_' + number.toString()); + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + let shortcut_kp = Gtk.accelerator_name(key_kp, mods); + + // Setup shortcut strings + settings.set_strv('app-hotkey-' + i, [shortcut]); + settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, shift_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods); + settings.set_strv('app-shift-hotkey-' + i, [shortcut]); + settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, ctrl_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods); + settings.set_strv('app-ctrl-hotkey-' + i, [shortcut]); + settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp]); + } + else { + // Reset default settings for the relevant keys if the + // accelerators are invalid + let keys = ['app-hotkey-' + i, 'app-shift-hotkey-' + i, 'app-ctrl-hotkey-' + i, // Regular numbers + 'app-hotkey-kp-' + i, 'app-shift-hotkey-kp-' + i, 'app-ctrl-hotkey-kp-' + i]; // Key-pad numbers + keys.forEach(function(val) { + settings.set_value(val, settings.get_default_value(val)); + }, this); + } + } + + settings.apply(); +} + +function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +const Preferences = new Lang.Class({ + Name: 'DashToPanel.Preferences', + + _init: function() { + this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); + this._builder = new Gtk.Builder(); + this._builder.set_scope(new BuilderScope(this)); + this._builder.set_translation_domain(Me.metadata['gettext-domain']); + this._builder.add_from_file(Me.path + '/Settings.ui'); + this.notebook = this._builder.get_object('settings_notebook'); + + // Timeout to delay the update of the settings + this._panel_size_timeout = 0; + this._dot_height_timeout = 0; + this._tray_size_timeout = 0; + this._leftbox_size_timeout = 0; + this._appicon_margin_timeout = 0; + this._appicon_padding_timeout = 0; + this._opacity_timeout = 0; + this._tray_padding_timeout = 0; + this._statusicon_padding_timeout = 0; + this._leftbox_padding_timeout = 0; + this._addFormatValueCallbacks(); + this._bindSettings(); + }, + + /** + * Connect signals + */ + _connector: function(builder, object, signal, handler) { + object.connect(signal, Lang.bind(this, this._SignalHandler[handler])); + }, + + _updateVerticalRelatedOptions: function() { + let position = this._getPanelPosition(this._currentMonitorIndex); + let isVertical = position == Pos.LEFT || position == Pos.RIGHT; + let showDesktopWidthLabel = this._builder.get_object('show_showdesktop_width_label'); + + showDesktopWidthLabel.set_text(isVertical ? _('Show Desktop button height (px)') : _('Show Desktop button width (px)')); + + this._displayPanelPositionsForMonitor(this._currentMonitorIndex); + }, + + _maybeDisableTopPosition: function() { + let keepTopPanel = this._settings.get_boolean('stockgs-keep-top-panel'); + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let topAvailable = !keepTopPanel || (!monitorSync && this._currentMonitorIndex != this.monitors[0]); + let topRadio = this._builder.get_object('position_top_button'); + + topRadio.set_sensitive(topAvailable); + topRadio.set_tooltip_text(!topAvailable ? _('Unavailable when gnome-shell top panel is present') : ''); + }, + + _getPanelPosition: function(monitorIndex) { + return PanelSettings.getPanelPosition(this._settings, monitorIndex); + }, + + _setPanelPosition: function(position) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelPosition(this._settings, monitorIndex, position); + }); + this._setAnchorLabels(this._currentMonitorIndex); + }, + + _setPositionRadios: function(position) { + this._ignorePositionRadios = true; + + switch (position) { + case Pos.BOTTOM: + this._builder.get_object('position_bottom_button').set_active(true); + break; + case Pos.TOP: + this._builder.get_object('position_top_button').set_active(true); + break; + case Pos.LEFT: + this._builder.get_object('position_left_button').set_active(true); + break; + case Pos.RIGHT: + this._builder.get_object('position_right_button').set_active(true); + break; + } + + this._ignorePositionRadios = false; + }, + + /** + * Set panel anchor combo labels according to whether the monitor's panel is vertical + * or horizontal, or if all monitors' panels are being configured and they are a mix + * of vertical and horizontal. + */ + _setAnchorLabels: function(currentMonitorIndex) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [currentMonitorIndex]; + const allVertical = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.LEFT || position === Pos.RIGHT + }); + const allHorizontal = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.TOP || position === Pos.BOTTOM; + }); + + const anchor_combo = this._builder.get_object('panel_anchor_combo'); + anchor_combo.remove_all(); + + if (allHorizontal) { + anchor_combo.append(Pos.START, _('Left')); + anchor_combo.append(Pos.MIDDLE, _('Center')); + anchor_combo.append(Pos.END, _('Right')); + } else if (allVertical) { + anchor_combo.append(Pos.START, _('Top')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('Bottom')); + } else { + // Setting for a mix of horizontal and vertical panels on different monitors. + anchor_combo.append(Pos.START, _('Start')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('End')); + } + + // Set combo box after re-populating its options. But only if it's for a single-panel + // configuration, or a multi-panel configuration where they all have the same anchor + // setting. So don't set the combo box if there is a multi-panel configuration with + // different anchor settings. + const someAnchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + if (monitorsToSetFor.every(i => + PanelSettings.getPanelAnchor(this._settings, i) === someAnchor)) { + const panel_anchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + this._builder.get_object('panel_anchor_combo').set_active_id(panel_anchor); + } + }, + + /** + * When a monitor is selected, update the widgets for panel position, size, anchoring, + * and contents so they accurately show the settings for the panel on that monitor. + */ + _updateWidgetSettingsForMonitor: function(monitorIndex) { + // Update display of panel screen position setting + this._maybeDisableTopPosition(); + const panelPosition = this._getPanelPosition(monitorIndex); + this._setPositionRadios(panelPosition); + + // Update display of thickness, length, and anchor settings + const panel_size_scale = this._builder.get_object('panel_size_scale'); + const size = PanelSettings.getPanelSize(this._settings, monitorIndex); + panel_size_scale.set_value(size); + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + const length = PanelSettings.getPanelLength(this._settings, monitorIndex); + panel_length_scale.set_value(length); + this._setAnchorWidgetSensitivity(length); + + this._setAnchorLabels(monitorIndex); + + // Update display of panel content settings + this._displayPanelPositionsForMonitor(monitorIndex); + }, + + /** + * Anchor is only relevant if panel length is less than 100%. Enable or disable + * anchor widget sensitivity accordingly. + */ + _setAnchorWidgetSensitivity: function(panelLength) { + const isPartialLength = panelLength < 100; + this._builder.get_object('panel_anchor_label').set_sensitive(isPartialLength); + this._builder.get_object('panel_anchor_combo').set_sensitive(isPartialLength); + }, + + _displayPanelPositionsForMonitor: function(monitorIndex) { + let taskbarListBox = this._builder.get_object('taskbar_display_listbox'); + + while(taskbarListBox.get_first_child()) + { + taskbarListBox.remove(taskbarListBox.get_first_child()); + } + + let labels = {}; + let panelPosition = this._getPanelPosition(monitorIndex); + let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT; + let panelElementPositionsSettings = PanelSettings.getSettingsJson(this._settings, 'panel-element-positions'); + let panelElementPositions = panelElementPositionsSettings[monitorIndex] || Pos.defaults; + let updateElementsSettings = () => { + let newPanelElementPositions = []; + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let monitors = monitorSync ? this.monitors : [monitorIndex]; + + let child = taskbarListBox.get_first_child(); + while (child != null) + { + newPanelElementPositions.push({ + element: child.id, + visible: child.visibleToggleBtn.get_active(), + position: child.positionCombo.get_active_id() + }); + child = child.get_next_sibling(); + } + + monitors.forEach(m => panelElementPositionsSettings[m] = newPanelElementPositions); + this._settings.set_string('panel-element-positions', JSON.stringify(panelElementPositionsSettings)); + }; + + + labels[Pos.SHOW_APPS_BTN] = _('Show Applications button'); + labels[Pos.ACTIVITIES_BTN] = _('Activities button'); + labels[Pos.TASKBAR] = _('Taskbar'); + labels[Pos.DATE_MENU] = _('Date menu'); + labels[Pos.SYSTEM_MENU] = _('System menu'); + labels[Pos.LEFT_BOX] = _('Left box'); + labels[Pos.CENTER_BOX] = _('Center box'); + labels[Pos.RIGHT_BOX] = _('Right box'); + labels[Pos.DESKTOP_BTN] = _('Desktop button'); + + panelElementPositions.forEach(el => { + let row = new Gtk.ListBoxRow(); + let grid = new Gtk.Grid({ margin_start: 12, margin_end: 12, column_spacing: 8 }); + let upDownGrid = new Gtk.Grid({ column_spacing: 2 }); + let upBtn = new Gtk.Button({ tooltip_text: _('Move up') }); + let upImg = new Gtk.Image({ icon_name: 'go-up-symbolic', pixel_size: 12 }); + let downBtn = new Gtk.Button({ tooltip_text: _('Move down') }); + let downImg = new Gtk.Image({ icon_name: 'go-down-symbolic', pixel_size: 12 }); + let visibleToggleBtn = new Gtk.ToggleButton({ label: _('Visible'), active: el.visible }); + let positionCombo = new Gtk.ComboBoxText({ tooltip_text: _('Select element position') }); + let upDownClickHandler = limit => { + let index = row.get_index(); + + if (index != limit) { + taskbarListBox.remove(row); + taskbarListBox.insert(row, index + (!limit ? -1 : 1)); + updateElementsSettings(); + } + }; + + positionCombo.append(Pos.STACKED_TL, isVertical ? _('Stacked to top') : _('Stacked to left')); + positionCombo.append(Pos.STACKED_BR, isVertical ? _('Stacked to bottom') :_('Stacked to right')); + positionCombo.append(Pos.CENTERED, _('Centered')); + positionCombo.append(Pos.CENTERED_MONITOR, _('Monitor Center')); + positionCombo.set_active_id(el.position); + + upBtn.connect('clicked', () => upDownClickHandler(0)); + downBtn.connect('clicked', () => upDownClickHandler(panelElementPositions.length - 1)); + visibleToggleBtn.connect('toggled', () => updateElementsSettings()); + positionCombo.connect('changed', () => updateElementsSettings()); + + upBtn.set_child(upImg); + downBtn.set_child(downImg); + + upDownGrid.attach(upBtn, 0, 0, 1, 1); + upDownGrid.attach(downBtn, 1, 0, 1, 1); + + grid.attach(upDownGrid, 0, 0, 1, 1); + grid.attach(new Gtk.Label({ label: labels[el.element], xalign: 0, hexpand: true }), 1, 0, 1, 1); + + if (Pos.optionDialogFunctions[el.element]) { + let cogImg = new Gtk.Image({ icon_name: 'emblem-system-symbolic' }); + let optionsBtn = new Gtk.Button({ tooltip_text: _('More options') }); + + optionsBtn.get_style_context().add_class('circular'); + optionsBtn.set_child(cogImg); + grid.attach(optionsBtn, 2, 0, 1, 1); + + optionsBtn.connect('clicked', () => this[Pos.optionDialogFunctions[el.element]]()); + } + + grid.attach(visibleToggleBtn, 3, 0, 1, 1); + grid.attach(positionCombo, 4, 0, 1, 1); + + row.id = el.element; + row.visibleToggleBtn = visibleToggleBtn; + row.positionCombo = positionCombo; + + row.set_child(grid); + taskbarListBox.insert(row, -1); + }); + }, + + _showShowAppsButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Applications options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('show_applications_options'); + dialog.get_content_area().append(box); + + let fileChooserButton = this._builder.get_object('show_applications_icon_file_filebutton'); + let fileChooser = new Gtk.FileChooserNative({ title: _('Open icon'), transient_for: dialog }); + let fileImage = this._builder.get_object('show_applications_current_icon_image'); + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + fileChooser.filter = fileFilter; + + let handleIconChange = function(newIconPath) { + if (newIconPath && GLib.file_test(newIconPath, GLib.FileTest.EXISTS)) { + let file = Gio.File.new_for_path(newIconPath); + let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(file.read(null), 32, 32, true, null); + + fileImage.set_from_pixbuf(pixbuf); + fileChooser.set_file(file); + fileChooserButton.set_label(newIconPath); + } else { + newIconPath = ''; + fileImage.set_from_icon_name('view-app-grid-symbolic'); + let picturesFolder = Gio.File.new_for_path(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)); + fileChooser.set_file(picturesFolder); + fileChooserButton.set_label("(None)"); + } + + this._settings.set_string('show-apps-icon-file', newIconPath || ''); + }; + + fileChooserButton.connect('clicked', Lang.bind(this, function() { + fileChooser.show(); + })); + + fileChooser.connect('response', widget => handleIconChange.call(this, widget.get_file().get_path())); + handleIconChange.call(this, this._settings.get_string('show-apps-icon-file')); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-apps-icon-side-padding', this._settings.get_default_value('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._settings.set_value('show-apps-override-escape', this._settings.get_default_value('show-apps-override-escape')); + handleIconChange.call(this, null); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + fileChooser.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _showDesktopButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Desktop options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_show_showdesktop_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('showdesktop-button-width', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-delay', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-time', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('showdesktop-button-width', this._settings.get_default_value('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + + this._settings.set_value('show-showdesktop-hover', this._settings.get_default_value('show-showdesktop-hover')); + + this._settings.set_value('show-showdesktop-delay', this._settings.get_default_value('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + + this._settings.set_value('show-showdesktop-time', this._settings.get_default_value('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _addFormatValueCallbacks: function() { + // position + this._builder.get_object('panel_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // style + this._builder.get_object('appicon_margin_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('appicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box1 + this._builder.get_object('tray_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box2 + this._builder.get_object('tray_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('statusicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // animate hovering app icons dialog + this._builder.get_object('animate_appicon_hover_options_duration_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d ms").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_rotation_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d °").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_travel_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_zoom_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_convexity_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%.1f").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_extent_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return Gettext.ngettext("%d icon", "%d icons", value).format(value); + })); + }, + + _bindSettings: function() { + // size options + let panel_size_scale = this._builder.get_object('panel_size_scale'); + panel_size_scale.set_range(DEFAULT_PANEL_SIZES[DEFAULT_PANEL_SIZES.length - 1], DEFAULT_PANEL_SIZES[0]); + DEFAULT_PANEL_SIZES.slice(1, -1).forEach(function(val) { + panel_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Correct for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + panel_size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + panel_size_scale.set_flippable(false); + panel_size_scale.set_inverted(true); + } + + // Dots Position option + let dotPosition = this._settings.get_string('dot-position'); + + switch (dotPosition) { + case 'BOTTOM': + this._builder.get_object('dots_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('dots_top_button').set_active(true); + break; + case 'LEFT': + this._builder.get_object('dots_left_button').set_active(true); + break; + case 'RIGHT': + this._builder.get_object('dots_right_button').set_active(true); + break; + } + + this._builder.get_object('dot_style_focused_combo').set_active_id(this._settings.get_string('dot-style-focused')); + this._builder.get_object('dot_style_focused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-focused', widget.get_active_id()); + })); + + this._builder.get_object('dot_style_unfocused_combo').set_active_id(this._settings.get_string('dot-style-unfocused')); + this._builder.get_object('dot_style_unfocused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-unfocused', widget.get_active_id()); + })); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let idx = i; + this._builder.get_object('dot_color_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-' + idx, hexString); + })); + + this._builder.get_object('dot_color_unfocused_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-unfocused-' + idx, hexString); + })); + } + + this._builder.get_object('dot_color_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_value('dot-color-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('dot_color_unfocused_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_value('dot-color-unfocused-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('focus_highlight_color_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('focus-highlight-color', hexString); + })); + + this._builder.get_object('dot_style_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Running Indicator Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dots_options'); + dialog.get_content_area().append(box); + + this._settings.bind('dot-color-dominant', + this._builder.get_object('dot_color_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // when either becomes active, turn the other off + this._builder.get_object('dot_color_dominant_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-override', false); + })); + this._builder.get_object('dot_color_override_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-dominant', false); + })); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('dot_color_unfocused_different_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('grid_dot_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_unfocused_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('grid_dot_color_unfocused'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.bind('focus-highlight', + this._builder.get_object('focus_highlight_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight', + this._builder.get_object('grid_focus_highlight_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_label'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('focus-highlight-opacity', widget.get_value()); + })); + + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + this._builder.get_object('dot_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('dot-size', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('dot-color-dominant', this._settings.get_default_value('dot-color-dominant')); + this._settings.set_value('dot-color-override', this._settings.get_default_value('dot-color-override')); + this._settings.set_value('dot-color-unfocused-different', this._settings.get_default_value('dot-color-unfocused-different')); + + this._settings.set_value('focus-highlight-color', this._settings.get_default_value('focus-highlight-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('focus-highlight-opacity', this._settings.get_default_value('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_default_value('dot-color-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_default_value('dot-color-unfocused-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.set_value('dot-size', this._settings.get_default_value('dot-size')); + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + + this._settings.set_value('focus-highlight', this._settings.get_default_value('focus-highlight')); + this._settings.set_value('focus-highlight-dominant', this._settings.get_default_value('focus-highlight-dominant')); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + //multi-monitor + this.monitors = this._settings.get_value('available-monitors').deep_unpack(); + + let dtpPrimaryMonitorIndex = this.monitors.indexOf(this._settings.get_int('primary-monitor')); + + if (dtpPrimaryMonitorIndex < 0) { + dtpPrimaryMonitorIndex = 0; + } + + this._currentMonitorIndex = this.monitors[dtpPrimaryMonitorIndex]; + + this._settings.connect('changed::panel-positions', () => this._updateVerticalRelatedOptions()); + this._updateVerticalRelatedOptions(); + + for (let i = 0; i < this.monitors.length; ++i) { + //the primary index is the first one in the "available-monitors" setting + let label = !i ? _('Primary monitor') : _('Monitor ') + (i + 1); + + this._builder.get_object('multimon_primary_combo').append_text(label); + this._builder.get_object('taskbar_position_monitor_combo').append_text(label); + } + + this._builder.get_object('multimon_primary_combo').set_active(dtpPrimaryMonitorIndex); + this._builder.get_object('taskbar_position_monitor_combo').set_active(dtpPrimaryMonitorIndex); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_sync_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_monitor_combo'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.connect('changed::panel-element-positions-monitors-sync', () => { + this._maybeDisableTopPosition(); + // The anchor combo box may has different labels for single- or all-monitor configuration. + this._setAnchorLabels(this._currentMonitorIndex); + }); + + this._builder.get_object('multimon_primary_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('primary-monitor', this.monitors[widget.get_active()]); + })); + + this._builder.get_object('taskbar_position_monitor_combo').connect('changed', Lang.bind (this, function(widget) { + this._currentMonitorIndex = this.monitors[widget.get_active()]; + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + })); + + this._settings.bind('multi-monitors', + this._builder.get_object('multimon_multi_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + if (this.monitors.length === 1) { + this._builder.get_object('multimon_multi_switch').set_sensitive(false); + } + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + panel_length_scale.connect('value-changed', Lang.bind (this, function(widget) { + const value = widget.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelLength(this._settings, monitorIndex, value); + }); + + this._setAnchorWidgetSensitivity(value); + })); + + this._builder.get_object('panel_anchor_combo').connect('changed', Lang.bind (this, function(widget) { + const value = widget.get_active_id(); + // Value can be null while anchor labels are being swapped out + if (value !== null) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelAnchor(this._settings, monitorIndex, value); + }); + } + })); + + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + + //dynamic opacity + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('trans-bg-color')); + this._builder.get_object('trans_bg_color_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_bg_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-bg-color', hexString); + })); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('trans_opacity_override_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('trans_dyn_switch').set_active(false); + }); + + this._builder.get_object('trans_opacity_spinbutton').set_value(this._settings.get_double('trans-panel-opacity') * 100); + this._builder.get_object('trans_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-panel-opacity', widget.get_value() * 0.01); + })); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-dynamic-behavior', + this._builder.get_object('trans_options_window_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('trans-gradient-top-color')); + this._builder.get_object('trans_gradient_color1_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color1_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-top-color', hexString); + })); + + this._builder.get_object('trans_gradient_color1_spinbutton').set_value(this._settings.get_double('trans-gradient-top-opacity') * 100); + this._builder.get_object('trans_gradient_color1_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-top-opacity', widget.get_value() * 0.01); + })); + + rgba.parse(this._settings.get_string('trans-gradient-bottom-color')); + this._builder.get_object('trans_gradient_color2_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color2_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-bottom-color', hexString); + })); + + this._builder.get_object('trans_gradient_color2_spinbutton').set_value(this._settings.get_double('trans-gradient-bottom-opacity') * 100); + this._builder.get_object('trans_gradient_color2_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-bottom-opacity', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-distance', widget.get_value()); + })); + + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + this._builder.get_object('trans_options_min_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-dynamic-anim-target', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-anim-time', widget.get_value()); + })); + + this._builder.get_object('trans_dyn_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Dynamic opacity options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dynamic_opacity_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('trans-dynamic-behavior', this._settings.get_default_value('trans-dynamic-behavior')); + + this._settings.set_value('trans-dynamic-distance', this._settings.get_default_value('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + + this._settings.set_value('trans-dynamic-anim-target', this._settings.get_default_value('trans-dynamic-anim-target')); + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + + this._settings.set_value('trans-dynamic-anim-time', this._settings.get_default_value('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('desktop-line-custom-color')); + this._builder.get_object('override_show_desktop_line_color_colorbutton').set_rgba(rgba); + this._builder.get_object('override_show_desktop_line_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + this._settings.set_string('desktop-line-custom-color', css); + })); + + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_window_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_behaviour_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-behaviour', + this._builder.get_object('intellihide_behaviour_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-show-in-fullscreen', + this._builder.get_object('intellihide_show_in_fullscreen_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-only-secondary', + this._builder.get_object('intellihide_only_secondary_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('multi-monitors', + this._builder.get_object('grid_intellihide_only_secondary'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('multimon_multi_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('intellihide_only_secondary_switch').set_active(false); + }); + + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-threshold', widget.get_value()); + })); + + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-time', widget.get_value()); + })); + + this._settings.bind('intellihide-key-toggle-text', + this._builder.get_object('intellihide_toggle_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::intellihide-key-toggle-text', () => setShortcut(this._settings, 'intellihide-key-toggle')); + + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-animation-time', widget.get_value()); + })); + + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-close-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-enable-start-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Intellihide options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_intellihide_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('intellihide-hide-from-windows', this._settings.get_default_value('intellihide-hide-from-windows')); + this._settings.set_value('intellihide-behaviour', this._settings.get_default_value('intellihide-behaviour')); + this._settings.set_value('intellihide-use-pressure', this._settings.get_default_value('intellihide-use-pressure')); + this._settings.set_value('intellihide-show-in-fullscreen', this._settings.get_default_value('intellihide-show-in-fullscreen')); + this._settings.set_value('intellihide-only-secondary', this._settings.get_default_value('intellihide-only-secondary')); + + this._settings.set_value('intellihide-pressure-threshold', this._settings.get_default_value('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + + this._settings.set_value('intellihide-pressure-time', this._settings.get_default_value('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + + this._settings.set_value('intellihide-key-toggle-text', this._settings.get_default_value('intellihide-key-toggle-text')); + + this._settings.set_value('intellihide-animation-time', this._settings.get_default_value('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + + this._settings.set_value('intellihide-close-delay', this._settings.get_default_value('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + + this._settings.set_value('intellihide-enable-start-delay', this._settings.get_default_value('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + // Behavior panel + + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-apps-icon-side-padding', widget.get_value()); + })); + + this._settings.bind('show-apps-override-escape', + this._builder.get_object('show_applications_esc_key_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('show_showdesktop_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('grid_show_showdesktop_hide_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-appmenu', + this._builder.get_object('show_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-tooltip', + this._builder.get_object('show_tooltip_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('show_favorite_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites-all-monitors', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-running-apps', + this._builder.get_object('show_runnning_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._setPreviewTitlePosition(); + + this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('window-preview-title-font-color', hexString); + })); + + this._builder.get_object('show_window_previews_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Window preview options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let scrolledWindow = this._builder.get_object('box_window_preview_options'); + + dialog.get_content_area().append(scrolledWindow); + + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-window-previews-timeout', widget.get_value()); + })); + + this._settings.bind('preview-middle-click-close', + this._builder.get_object('preview_middle_click_close_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-x', + this._builder.get_object('preview_aspect_ratio_x_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-y', + this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('preview-custom-opacity', widget.get_value()); + })); + + this._settings.bind('peek-mode', + this._builder.get_object('peek_mode_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_enter_peek_mode_timeout'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_peek_mode_opacity'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-show-title', + this._builder.get_object('preview_show_title_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_custom_icon_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_weight'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_font_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('enter-peek-mode-timeout', widget.get_value()); + })); + + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('leave-timeout', widget.get_value()); + })); + + this._settings.bind('window-preview-hide-immediate-click', + this._builder.get_object('preview_immediate_click_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-animation-time', widget.get_value()); + })); + + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('peek-mode-opacity', widget.get_value()); + })); + + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-size', widget.get_value()); + })); + + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + this._builder.get_object('preview_aspect_ratio_x_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-x', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + this._builder.get_object('preview_aspect_ratio_y_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-y', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-padding', widget.get_value()); + })); + + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-title-font-size', widget.get_value()); + })); + + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-custom-icon-size', widget.get_value()); + })); + + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('window-preview-title-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-window-previews-timeout', this._settings.get_default_value('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + + this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + + this._settings.set_value('window-preview-hide-immediate-click', this._settings.get_default_value('window-preview-hide-immediate-click')); + + this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + + this._settings.set_value('preview-use-custom-opacity', this._settings.get_default_value('preview-use-custom-opacity')); + + this._settings.set_value('window-preview-use-custom-icon-size', this._settings.get_default_value('window-preview-use-custom-icon-size')); + + this._settings.set_value('preview-custom-opacity', this._settings.get_default_value('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + + this._settings.set_value('window-preview-title-position', this._settings.get_default_value('window-preview-title-position')); + this._setPreviewTitlePosition(); + + this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); + this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); + this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + + this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + + this._settings.set_value('window-preview-fixed-x', this._settings.get_default_value('window-preview-fixed-x')); + this._settings.set_value('window-preview-fixed-y', this._settings.get_default_value('window-preview-fixed-y')); + + this._settings.set_value('window-preview-aspect-ratio-x', this._settings.get_default_value('window-preview-aspect-ratio-x')); + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + + this._settings.set_value('window-preview-aspect-ratio-y', this._settings.get_default_value('window-preview-aspect-ratio-y')); + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + + this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + + this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); + + this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + + this._settings.set_value('window-preview-custom-icon-size', this._settings.get_default_value('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + + this._settings.set_value('window-preview-title-font-weight', this._settings.get_default_value('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + + this._settings.set_value('window-preview-title-font-color', this._settings.get_default_value('window-preview-title-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(scrolledWindow); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('isolate-workspaces', + this._builder.get_object('isolate_workspaces_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('isolate-monitors', + this._builder.get_object('multimon_multi_isolate_monitor_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overview-click-to-exit', + this._builder.get_object('clicktoexit_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('hide-overview-on-startup', + this._builder.get_object('hide_overview_on_startup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps', + this._builder.get_object('group_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('group-apps', + this._builder.get_object('show_group_apps_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._builder.get_object('group_apps_label_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color', hexString); + })); + + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color-minimized', hexString); + })); + + this._settings.bind('group-apps-use-fixed-width', + this._builder.get_object('group_apps_use_fixed_width_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-underline-unfocused', + this._builder.get_object('group_apps_underline_unfocused_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-use-launchers', + this._builder.get_object('group_apps_use_launchers_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('show_group_apps_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Ungrouped application options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_group_apps_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-font-size', widget.get_value()); + })); + + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('group-apps-label-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-max-width', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('group-apps-label-font-size', this._settings.get_default_value('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + + this._settings.set_value('group-apps-label-font-weight', this._settings.get_default_value('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + + this._settings.set_value('group-apps-label-font-color', this._settings.get_default_value('group-apps-label-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('group-apps-label-font-color-minimized', this._settings.get_default_value('group-apps-label-font-color-minimized')); + let minimizedFontColor = new Gdk.RGBA(); + minimizedFontColor.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(minimizedFontColor); + + this._settings.set_value('group-apps-label-max-width', this._settings.get_default_value('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + + this._settings.set_value('group-apps-use-fixed-width', this._settings.get_default_value('group-apps-use-fixed-width')); + this._settings.set_value('group-apps-underline-unfocused', this._settings.get_default_value('group-apps-underline-unfocused')); + this._settings.set_value('group-apps-use-launchers', this._settings.get_default_value('group-apps-use-launchers')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + this._builder.get_object('click_action_combo').set_active_id(this._settings.get_string('click-action')); + this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('click-action', widget.get_active_id()); + })); + + this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-click-action', widget.get_active_id()); + })); + + this._builder.get_object('middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('middle-click-action', widget.get_active_id()); + })); + this._builder.get_object('shift_middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-middle-click-action', widget.get_active_id()); + })); + + // Create dialog for middle-click options + this._builder.get_object('middle_click_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Customize middle-click behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_middle_click_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + + this._settings.bind('shift-click-action', + this._builder.get_object('shift_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('middle-click-action', + this._builder.get_object('middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('shift-middle-click-action', + this._builder.get_object('shift_middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(700, 1); + + })); + + this._builder.get_object('scroll_panel_combo').set_active_id(this._settings.get_string('scroll-panel-action')); + this._builder.get_object('scroll_panel_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-panel-action', widget.get_active_id()); + })); + + this._builder.get_object('scroll_icon_combo').set_active_id(this._settings.get_string('scroll-icon-action')); + this._builder.get_object('scroll_icon_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-icon-action', widget.get_active_id()); + })); + + // Create dialog for panel scroll options + this._builder.get_object('scroll_panel_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize panel scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_panel_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-panel-delay', widget.get_value()); + })); + + this._settings.bind('scroll-panel-show-ws-popup', + this._builder.get_object('scroll_panel_options_show_ws_popup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-panel-delay', this._settings.get_default_value('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + + this._settings.set_value('scroll-panel-show-ws-popup', this._settings.get_default_value('scroll-panel-show-ws-popup')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + // Create dialog for icon scroll options + this._builder.get_object('scroll_icon_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize icon scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_icon_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-icon-delay', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-icon-delay', this._settings.get_default_value('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + this._settings.bind('hot-keys', + this._builder.get_object('hot_keys_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('hot-keys', + this._builder.get_object('overlay_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id()); + })); + + this._settings.bind('shortcut-previews', + this._builder.get_object('shortcut_preview_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('shortcut_num_keys_combo').set_active_id(this._settings.get_string('shortcut-num-keys')); + this._builder.get_object('shortcut_num_keys_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shortcut-num-keys', widget.get_active_id()); + })); + + this._settings.connect('changed::hotkey-prefix-text', Lang.bind(this, function() {checkHotkeyPrefix(this._settings);})); + + this._builder.get_object('hotkey_prefix_combo').set_active_id(this._settings.get_string('hotkey-prefix-text')); + + this._settings.bind('hotkey-prefix-text', + this._builder.get_object('hotkey_prefix_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').set_active_id(this._settings.get_string('hotkeys-overlay-combo')); + + this._settings.bind('hotkeys-overlay-combo', + this._builder.get_object('overlay_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overlay-timeout', + this._builder.get_object('timeout_spinbutton'), + 'value', + Gio.SettingsBindFlags.DEFAULT); + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') { + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + } + + this._settings.connect('changed::hotkeys-overlay-combo', Lang.bind(this, function() { + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + else + this._builder.get_object('timeout_spinbutton').set_sensitive(true); + })); + + this._settings.bind('shortcut-text', + this._builder.get_object('shortcut_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::shortcut-text', Lang.bind(this, function() {setShortcut(this._settings, 'shortcut');})); + + // Create dialog for number overlay options + this._builder.get_object('overlay_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced hotkeys options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_overlay_shortcut'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['hotkey-prefix-text', 'shortcut-text', 'hotkeys-overlay-combo', 'overlay-timeout', 'shortcut-previews']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + // setup dialog for secondary menu options + this._builder.get_object('secondarymenu_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Secondary Menu Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_secondarymenu_options'); + dialog.get_content_area().append(box); + + this._settings.bind('secondarymenu-contains-appmenu', + this._builder.get_object('secondarymenu_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('secondarymenu-contains-showdetails', + this._builder.get_object('secondarymenu_showdetails_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('secondarymenu-contains-appmenu', this._settings.get_default_value('secondarymenu-contains-appmenu')); + this._settings.set_value('secondarymenu-contains-showdetails', this._settings.get_default_value('secondarymenu-contains-showdetails')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // setup dialog for advanced options + this._builder.get_object('button_advanced_options').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_advanced_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // Fine-tune panel + + let sizeScales = [ + {objectName: 'tray_size_scale', valueName: 'tray-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'leftbox_size_scale', valueName: 'leftbox-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'appicon_margin_scale', valueName: 'appicon-margin', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'appicon_padding_scale', valueName: 'appicon-padding', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'tray_padding_scale', valueName: 'tray-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'leftbox_padding_scale', valueName: 'leftbox-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'statusicon_padding_scale', valueName: 'status-icon-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'panel_length_scale', valueName: '', range: LENGTH_MARKS } + ]; + + for(var idx in sizeScales) { + let size_scale = this._builder.get_object(sizeScales[idx].objectName); + let range = sizeScales[idx].range; + size_scale.set_range(range[range.length - 1], range[0]); + let value; + if (sizeScales[idx].objectName === 'panel_length_scale') { + value = PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex); + } else { + value = this._settings.get_int(sizeScales[idx].valueName); + } + size_scale.set_value(value); + // Add marks from range arrays, omitting the first and last values. + range.slice(1, -1).forEach(function(val) { + size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Corrent for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + size_scale.set_flippable(false); + size_scale.set_inverted(true); + } + } + + this._settings.bind('animate-app-switch', + this._builder.get_object('animate_app_switch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-window-launch', + this._builder.get_object('animate_window_launch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + { + this._settings.bind('animate-appicon-hover-animation-type', + this._builder.get_object('animate_appicon_hover_options_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + let scales = [ + ['animate_appicon_hover_options_duration_scale', 'animate-appicon-hover-animation-duration', 1], + ['animate_appicon_hover_options_rotation_scale', 'animate-appicon-hover-animation-rotation', 1], + ['animate_appicon_hover_options_travel_scale', 'animate-appicon-hover-animation-travel', 100], + ['animate_appicon_hover_options_zoom_scale', 'animate-appicon-hover-animation-zoom', 100], + ['animate_appicon_hover_options_convexity_scale', 'animate-appicon-hover-animation-convexity', 1], + ['animate_appicon_hover_options_extent_scale', 'animate-appicon-hover-animation-extent', 1], + ]; + + let updateScale = scale => { + let [id, key, factor] = scale; + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let value = this._settings.get_value(key).deep_unpack()[type]; + let defaultValue = this._settings.get_default_value(key).deep_unpack()[type]; + this._builder.get_object(id).sensitive = defaultValue !== undefined; + this._builder.get_object(id).set_value(value * factor || 0); + this._builder.get_object(id).clear_marks(); + this._builder.get_object(id).add_mark(defaultValue * factor, Gtk.PositionType.TOP, + defaultValue !== undefined ? (defaultValue * factor).toString() : ' '); + }; + + scales.forEach(scale => { + let [id, key, factor] = scale; + this._settings.connect('changed::' + key, () => updateScale(scale)); + this._builder.get_object(id).connect('value-changed', widget => { + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let variant = this._settings.get_value(key); + let unpacked = variant.deep_unpack(); + if (unpacked[type] != widget.get_value() / factor) { + unpacked[type] = widget.get_value() / factor; + this._settings.set_value(key, new GLib.Variant(variant.get_type_string(), unpacked)); + } + }); + }); + + this._settings.connect('changed::animate-appicon-hover-animation-type', () => scales.forEach(updateScale)); + scales.forEach(updateScale); + } + + this._builder.get_object('animate_appicon_hover_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('App icon animation options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('animate_appicon_hover_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('animate-appicon-hover-animation-type', this._settings.get_default_value('animate-appicon-hover-animation-type')); + this._settings.set_value('animate-appicon-hover-animation-duration', this._settings.get_default_value('animate-appicon-hover-animation-duration')); + this._settings.set_value('animate-appicon-hover-animation-rotation', this._settings.get_default_value('animate-appicon-hover-animation-rotation')); + this._settings.set_value('animate-appicon-hover-animation-travel', this._settings.get_default_value('animate-appicon-hover-animation-travel')); + this._settings.set_value('animate-appicon-hover-animation-zoom', this._settings.get_default_value('animate-appicon-hover-animation-zoom')); + this._settings.set_value('animate-appicon-hover-animation-convexity', this._settings.get_default_value('animate-appicon-hover-animation-convexity')); + this._settings.set_value('animate-appicon-hover-animation-extent', this._settings.get_default_value('animate-appicon-hover-animation-extent')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('stockgs-keep-dash', + this._builder.get_object('stockgs_dash_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-keep-top-panel', + this._builder.get_object('stockgs_top_panel_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + + + this._settings.connect('changed::stockgs-keep-top-panel', () => this._maybeDisableTopPosition()); + + this._maybeDisableTopPosition(); + + this._settings.bind('stockgs-panelbtn-click-only', + this._builder.get_object('stockgs_panelbtn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-force-hotcorner', + this._builder.get_object('stockgs_hotcorner_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // About Panel + + this._builder.get_object('extension_version').set_label(Me.metadata.version.toString() + (Me.metadata.commit ? ' (' + Me.metadata.commit + ')' : '')); + + this._builder.get_object('importexport_export_button').connect('clicked', widget => { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE }, + "Save", + filename => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + this._builder.get_object('importexport_import_button').connect('clicked', widget => { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "Open", + filename => { + if (filename && GLib.file_test(filename, GLib.FileTest.EXISTS)) { + let settingsFile = Gio.File.new_for_path(filename); + let [ , pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + let [ , , , retCode] = GLib.spawn_command_line_sync(GSET + ' -d ' + Me.uuid); + if (retCode == 0) { + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => GLib.spawn_command_line_sync(GSET + ' -e ' + Me.uuid)); + } + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + } + ); + }); + + }, + + _setPreviewTitlePosition: function() { + switch (this._settings.get_string('window-preview-title-position')) { + case 'BOTTOM': + this._builder.get_object('preview_title_position_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('preview_title_position_top_button').set_active(true); + break; + } + }, + + _showFileChooser: function(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog(mergeObjects({ title: title, transient_for: this.notebook.get_root() }, params)); + + dialog.add_button("Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.show(); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + acceptHandler.call(this, dialog.get_file().get_path()); + dialog.destroy(); + })); + } +}); + + +const BuilderScope = GObject.registerClass({ + Implements: [Gtk.BuilderScope], +}, class BuilderScope extends GObject.Object { + + _init(preferences) { + this._preferences = preferences; + super._init(); + } + + vfunc_create_closure(builder, handlerName, flags, connectObject) { + if (flags & Gtk.BuilderClosureFlags.SWAPPED) + throw new Error('Unsupported template signal flag "swapped"'); + + if (typeof this[handlerName] === 'undefined') + throw new Error(`${handlerName} is undefined`); + + return this[handlerName].bind(connectObject || this); + } + + on_btn_click(connectObject) { + connectObject.set_label("Clicked"); + } + + position_bottom_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.BOTTOM); + } + + position_top_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.TOP); + } + + position_left_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.LEFT); + } + + position_right_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.RIGHT); + } + + dots_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "BOTTOM"); + } + + dots_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "TOP"); + } + + dots_left_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "LEFT"); + } + + dots_right_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "RIGHT"); + } + + preview_title_position_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'BOTTOM'); + } + + preview_title_position_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'TOP'); + } + + panel_size_scale_value_changed_cb(scale) { + // Avoid settings the size continuously + if (this._preferences._panel_size_timeout > 0) + Mainloop.source_remove(this._preferences._panel_size_timeout); + + this._preferences._panel_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this._preferences, function() { + const value = scale.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelSize(this._settings, monitorIndex, value); + }); + + this._panel_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_size_timeout > 0) + Mainloop.source_remove(this._preferences._tray_size_timeout); + + this._preferences._tray_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-size', scale.get_value()); + this._preferences._tray_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_size_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_size_timeout); + + this._preferences._leftbox_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-size', scale.get_value()); + this._preferences._leftbox_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_margin_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_margin_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_margin_timeout); + + this._preferences._appicon_margin_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-margin', scale.get_value()); + this._preferences._appicon_margin_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_padding_timeout); + + this._preferences._appicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-padding', scale.get_value()); + this._preferences._appicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_padding_timeout > 0) + Mainloop.source_remove(this._preferences._tray_padding_timeout); + + this._preferences._tray_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-padding', scale.get_value()); + this._preferences._tray_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + statusicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._statusicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._statusicon_padding_timeout); + + this._preferences._statusicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('status-icon-padding', scale.get_value()); + this._preferences._statusicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_padding_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_padding_timeout); + + this._preferences._leftbox_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-padding', scale.get_value()); + this._preferences._leftbox_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } +}); + +function init() { + Convenience.initTranslations(); +} + +function buildPrefsWidget() { + Gtk.Window.list_toplevels()[0].set_default_size(680, 740); + + let preferences = new Preferences(); + + return preferences.notebook; +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js new file mode 100644 index 0000000..1e84e82 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js @@ -0,0 +1,598 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gio = imports.gi.Gio; +const Cairo = imports.cairo; +const Clutter = imports.gi.Clutter; +const Pango = imports.gi.Pango; +const St = imports.gi.St; +const Signals = imports.signals; +const Utils = Me.imports.utils; + + +var ProgressManager = Utils.defineClass({ + Name: 'DashToPanel.ProgressManager', + + _init: function() { + + this._entriesByDBusName = {}; + + this._launcher_entry_dbus_signal_id = + Gio.DBus.session.signal_subscribe(null, // sender + 'com.canonical.Unity.LauncherEntry', // iface + null, // member + null, // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onEntrySignalReceived.bind(this)); + + this._dbus_name_owner_changed_signal_id = + Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender + 'org.freedesktop.DBus', // interface + 'NameOwnerChanged', // member + '/org/freedesktop/DBus', // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onDBusNameOwnerChanged.bind(this)); + + this._acquireUnityDBus(); + }, + + destroy: function() { + if (this._launcher_entry_dbus_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id); + } + + if (this._dbus_name_owner_changed_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id); + } + + this._releaseUnityDBus(); + }, + + size: function() { + return Object.keys(this._entriesByDBusName).length; + }, + + lookupByDBusName: function(dbusName) { + return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null; + }, + + lookupById: function(appId) { + let ret = []; + for (let dbusName in this._entriesByDBusName) { + let entry = this._entriesByDBusName[dbusName]; + if (entry && entry.appId() == appId) { + ret.push(entry); + } + } + + return ret; + }, + + addEntry: function(entry) { + let existingEntry = this.lookupByDBusName(entry.dbusName()); + if (existingEntry) { + existingEntry.update(entry); + } else { + this._entriesByDBusName[entry.dbusName()] = entry; + this.emit('progress-entry-added', entry); + } + }, + + removeEntry: function(entry) { + delete this._entriesByDBusName[entry.dbusName()] + this.emit('progress-entry-removed', entry); + }, + + _acquireUnityDBus: function() { + if (!this._unity_bus_id) { + Gio.DBus.session.own_name('com.canonical.Unity', + Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); + } + }, + + _releaseUnityDBus: function() { + if (this._unity_bus_id) { + Gio.DBus.session.unown_name(this._unity_bus_id); + this._unity_bus_id = 0; + } + }, + + _onEntrySignalReceived: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !signal_name) + return; + + if (signal_name == 'Update') { + if (!sender_name) { + return; + } + + this._handleUpdateRequest(sender_name, parameters); + } + }, + + _onDBusNameOwnerChanged: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !this.size()) + return; + + let [name, before, after] = parameters.deep_unpack(); + + if (!after) { + if (this._entriesByDBusName.hasOwnProperty(before)) { + this.removeEntry(this._entriesByDBusName[before]); + } + } + }, + + _handleUpdateRequest: function(senderName, parameters) { + if (!senderName || !parameters) { + return; + } + + let [appUri, properties] = parameters.deep_unpack(); + let appId = appUri.replace(/(^\w+:|^)\/\//, ''); + let entry = this.lookupByDBusName(senderName); + + if (entry) { + entry.setDBusName(senderName); + entry.update(properties); + } else { + let entry = new AppProgress(senderName, appId, properties); + this.addEntry(entry); + } + } +}); +Signals.addSignalMethods(ProgressManager.prototype); + +var AppProgress = Utils.defineClass({ + Name: 'DashToPanel.AppProgress', + + _init: function(dbusName, appId, properties) { + this._dbusName = dbusName; + this._appId = appId; + this._count = 0; + this._countVisible = false; + this._progress = 0.0; + this._progressVisible = false; + this._urgent = false; + this.update(properties); + }, + + appId: function() { + return this._appId; + }, + + dbusName: function() { + return this._dbusName; + }, + + count: function() { + return this._count; + }, + + setCount: function(count) { + if (this._count != count) { + this._count = count; + this.emit('count-changed', this._count); + } + }, + + countVisible: function() { + return this._countVisible; + }, + + setCountVisible: function(countVisible) { + if (this._countVisible != countVisible) { + this._countVisible = countVisible; + this.emit('count-visible-changed', this._countVisible); + } + }, + + progress: function() { + return this._progress; + }, + + setProgress: function(progress) { + if (this._progress != progress) { + this._progress = progress; + this.emit('progress-changed', this._progress); + } + }, + + progressVisible: function() { + return this._progressVisible; + }, + + setProgressVisible: function(progressVisible) { + if (this._progressVisible != progressVisible) { + this._progressVisible = progressVisible; + this.emit('progress-visible-changed', this._progressVisible); + } + }, + + urgent: function() { + return this._urgent; + }, + + setUrgent: function(urgent) { + if (this._urgent != urgent) { + this._urgent = urgent; + this.emit('urgent-changed', this._urgent); + } + }, + + setDBusName: function(dbusName) { + if (this._dbusName != dbusName) { + let oldName = this._dbusName; + this._dbusName = dbusName; + this.emit('dbus-name-changed', oldName); + } + }, + + update: function(other) { + if (other instanceof AppProgress) { + this.setDBusName(other.dbusName()) + this.setCount(other.count()); + this.setCountVisible(other.countVisible()); + this.setProgress(other.progress()); + this.setProgressVisible(other.progressVisible()) + this.setUrgent(other.urgent()); + } else { + for (let property in other) { + if (other.hasOwnProperty(property)) { + if (property == 'count') { + this.setCount(other[property].get_int64()); + } else if (property == 'count-visible') { + this.setCountVisible(Me.settings.get_boolean('progress-show-count') && other[property].get_boolean()); + } else if (property == 'progress') { + this.setProgress(other[property].get_double()); + } else if (property == 'progress-visible') { + this.setProgressVisible(Me.settings.get_boolean('progress-show-bar') && other[property].get_boolean()); + } else if (property == 'urgent') { + this.setUrgent(other[property].get_boolean()); + } else { + // Not implemented yet + } + } + } + } + } +}); +Signals.addSignalMethods(AppProgress.prototype); + + +var ProgressIndicator = Utils.defineClass({ + Name: 'DashToPanel.ProgressIndicator', + + _init: function(source, progressManager) { + this._source = source; + this._progressManager = progressManager; + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._sourceDestroyId = this._source.actor.connect('destroy', () => { + this._signalsHandler.destroy(); + }); + + this._notificationBadgeLabel = new St.Label({ style_class: 'badge' }); + this._notificationBadgeBin = new St.Bin({ + child: this._notificationBadgeLabel, y: 2, x: 2 + }); + this._notificationBadgeLabel.add_style_class_name('notification-badge'); + this._notificationBadgeCount = 0; + this._notificationBadgeBin.hide(); + + this._source._dtpIconContainer.add_child(this._notificationBadgeBin); + this._source._dtpIconContainer.connect('notify::allocation', this.updateNotificationBadge.bind(this)); + + this._progressManagerEntries = []; + this._progressManager.lookupById(this._source.app.id).forEach( + (entry) => { + this.insertEntry(entry); + } + ); + + this._signalsHandler.add([ + this._progressManager, + 'progress-entry-added', + this._onEntryAdded.bind(this) + ], [ + this._progressManager, + 'progress-entry-removed', + this._onEntryRemoved.bind(this) + ]); + }, + + destroy: function() { + this._source.actor.disconnect(this._sourceDestroyId); + this._signalsHandler.destroy(); + }, + + _onEntryAdded: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.insertEntry(entry); + } + }, + + _onEntryRemoved: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.removeEntry(entry); + } + }, + + updateNotificationBadge: function() { + this._source.updateNumberOverlay(this._notificationBadgeBin); + this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; + }, + + _notificationBadgeCountToText: function(count) { + if (count <= 9999) { + return count.toString(); + } else if (count < 1e5) { + let thousands = count / 1e3; + return thousands.toFixed(1).toString() + "k"; + } else if (count < 1e6) { + let thousands = count / 1e3; + return thousands.toFixed(0).toString() + "k"; + } else if (count < 1e8) { + let millions = count / 1e6; + return millions.toFixed(1).toString() + "M"; + } else if (count < 1e9) { + let millions = count / 1e6; + return millions.toFixed(0).toString() + "M"; + } else { + let billions = count / 1e9; + return billions.toFixed(1).toString() + "B"; + } + }, + + setNotificationBadge: function(count) { + this._notificationBadgeCount = count; + let text = this._notificationBadgeCountToText(count); + this._notificationBadgeLabel.set_text(text); + }, + + toggleNotificationBadge: function(activate) { + if (activate && this._notificationBadgeCount > 0) { + this.updateNotificationBadge(); + this._notificationBadgeBin.show(); + } + else + this._notificationBadgeBin.hide(); + }, + + _showProgressOverlay: function() { + if (this._progressOverlayArea) { + this._updateProgressOverlay(); + return; + } + + this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); + this._progressOverlayArea.add_style_class_name('progress-bar'); + this._progressOverlayArea.connect('repaint', () => { + this._drawProgressOverlay(this._progressOverlayArea); + }); + + this._source._iconContainer.add_child(this._progressOverlayArea); + let node = this._progressOverlayArea.get_theme_node(); + + let [hasColor, color] = node.lookup_color('-progress-bar-background', false); + if (hasColor) + this._progressbar_background = color + else + this._progressbar_background = new Clutter.Color({red: 204, green: 204, blue: 204, alpha: 255}); + + [hasColor, color] = node.lookup_color('-progress-bar-border', false); + if (hasColor) + this._progressbar_border = color; + else + this._progressbar_border = new Clutter.Color({red: 230, green: 230, blue: 230, alpha: 255}); + + this._updateProgressOverlay(); + }, + + _hideProgressOverlay: function() { + if (this._progressOverlayArea) + this._progressOverlayArea.destroy(); + + this._progressOverlayArea = null; + this._progressbar_background = null; + this._progressbar_border = null; + }, + + _updateProgressOverlay: function() { + + if (this._progressOverlayArea) { + this._progressOverlayArea.queue_repaint(); + } + }, + + _drawProgressOverlay: function(area) { + let scaleFactor = Utils.getScaleFactor(); + let [surfaceWidth, surfaceHeight] = area.get_surface_size(); + let cr = area.get_context(); + + let iconSize = this._source.icon.iconSize * scaleFactor; + + let x = Math.floor((surfaceWidth - iconSize) / 2); + let y = Math.floor((surfaceHeight - iconSize) / 2); + + let lineWidth = Math.floor(1.0 * scaleFactor); + let padding = Math.floor(iconSize * 0.05); + let width = iconSize - 2.0*padding; + let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize)); + x += padding; + y += iconSize - height - padding; + + cr.setLineWidth(lineWidth); + + // Draw the outer stroke + let stroke = new Cairo.LinearGradient(0, y, 0, y + height); + let fill = null; + stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1); + stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the background + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9); + fill = new Cairo.LinearGradient(0, y, 0, y + height); + fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0); + fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the finished bar + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + let finishedWidth = Math.ceil(this._progress * width); + + let bg = this._progressbar_background; + let bd = this._progressbar_border; + + stroke = Cairo.SolidPattern.createRGBA(bd.red/255, bd.green/255, bd.blue/255, bd.alpha/255); + fill = Cairo.SolidPattern.createRGBA(bg.red/255, bg.green/255, bg.blue/255, bg.alpha/255); + + if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) + Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + else + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + + cr.$dispose(); + }, + + setProgress: function(progress) { + this._progress = Math.min(Math.max(progress, 0.0), 1.0); + this._updateProgressOverlay(); + }, + + toggleProgressOverlay: function(activate) { + if (activate) { + this._showProgressOverlay(); + } + else { + this._hideProgressOverlay(); + } + }, + + insertEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) !== -1) + return; + + this._progressManagerEntries.push(appProgress); + this._selectEntry(appProgress); + }, + + removeEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) == -1) + return; + + this._progressManagerEntries.splice(this._progressManagerEntries.indexOf(appProgress), 1); + + if (this._progressManagerEntries.length > 0) { + this._selectEntry(this._progressManagerEntries[this._progressManagerEntries.length-1]); + } else { + this.setNotificationBadge(0); + this.toggleNotificationBadge(false); + this.setProgress(0); + this.toggleProgressOverlay(false); + this.setUrgent(false); + } + }, + + _selectEntry: function(appProgress) { + if (!appProgress) + return; + + this._signalsHandler.removeWithLabel('progress-entry'); + + this._signalsHandler.addWithLabel('progress-entry', + [ + appProgress, + 'count-changed', + (appProgress, value) => { + this.setNotificationBadge(value); + } + ], [ + appProgress, + 'count-visible-changed', + (appProgress, value) => { + this.toggleNotificationBadge(value); + } + ], [ + appProgress, + 'progress-changed', + (appProgress, value) => { + this.setProgress(value); + } + ], [ + appProgress, + 'progress-visible-changed', + (appProgress, value) => { + this.toggleProgressOverlay(value); + } + ], [ + appProgress, + 'urgent-changed', + (appProgress, value) => { + this.setUrgent(value) + } + ]); + + this.setNotificationBadge(appProgress.count()); + this.toggleNotificationBadge(appProgress.countVisible()); + this.setProgress(appProgress.progress()); + this.toggleProgressOverlay(appProgress.progressVisible()); + + this._isUrgent = false; + }, + + setUrgent: function(urgent) { + const icon = this._source.icon._iconBin; + if (urgent) { + if (!this._isUrgent) { + icon.set_pivot_point(0.5, 0.5); + this._source.iconAnimator.addAnimation(icon, 'dance'); + this._isUrgent = true; + } + } else { + if (this._isUrgent) { + this._source.iconAnimator.removeAnimation(icon, 'dance'); + this._isUrgent = false; + } + icon.rotation_angle_z = 0; + } + } +}); diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js new file mode 100644 index 0000000..c298f84 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js @@ -0,0 +1,262 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Meta = imports.gi.Meta; + +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; + +//timeout intervals +const MIN_UPDATE_MS = 200; + +//timeout names +const T1 = 'limitUpdateTimeout'; + +var Mode = { + ALL_WINDOWS: 0, + FOCUSED_WINDOWS: 1, + MAXIMIZED_WINDOWS: 2 +}; + +var ProximityWatch = Utils.defineClass({ + Name: 'DashToPanel.ProximityWatch', + + _init: function(actor, mode, xThreshold, yThreshold, handler) { + this.actor = actor; + this.overlap = 0; + this.mode = mode; + this.threshold = [xThreshold, yThreshold]; + this.handler = handler; + + this._allocationChangedId = actor.connect('notify::allocation', () => this._update()); + + this._update(); + }, + + destroy: function() { + this.actor.disconnect(this._allocationChangedId); + }, + + _update: function() { + this.monitorIndex = Main.layoutManager.findIndexForActor(this.actor); + + this._updateWatchRect(); + }, + + _updateWatchRect: function() { + let [actorX, actorY] = this.actor.get_position(); + + this.rect = new Meta.Rectangle({ + x: actorX - this.threshold[0], + y: actorY - this.threshold[1], + width: this.actor.width + this.threshold[0] * 2, + height: this.actor.height + this.threshold[1] * 2 + }); + }, +}); + +var ProximityManager = Utils.defineClass({ + Name: 'DashToPanel.ProximityManager', + + _init: function() { + this._counter = 1; + this._watches = {}; + this._focusedWindowInfo = null; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._bindSignals(); + this._setFocusedWindow(); + }, + + createWatch: function(actor, mode, xThreshold, yThreshold, handler) { + let watch = new ProximityWatch(actor, mode, xThreshold, yThreshold, handler); + + this._watches[this._counter] = watch; + this.update(); + + return this._counter++; + }, + + removeWatch: function(id) { + if (this._watches[id]) { + this._watches[id].destroy(); + delete this._watches[id]; + } + }, + + update: function() { + this._queueUpdate(true); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + this._disconnectFocusedWindow(); + Object.keys(this._watches).forEach(id => this.removeWatch(id)); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + global.window_manager, + 'switch-workspace', + () => Object.keys(this._watches).forEach(id => this._watches[id].overlap = 0) + ], + [ + Main.overview, + 'hidden', + () => this._queueUpdate() + ], + [ + global.display, + 'notify::focus-window', + () => { + this._setFocusedWindow(); + this._queueUpdate(); + } + ], + [ + global.window_group, + [ + 'actor-added', + 'actor-removed' + ], + () => this._queueUpdate() + ] + ); + }, + + _setFocusedWindow: function() { + this._disconnectFocusedWindow(); + + let focusedWindow = global.display.focus_window; + + if (focusedWindow) { + let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow); + + if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) { + focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('notify::allocation', () => this._queueUpdate()); + focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true)); + + this._focusedWindowInfo = focusedWindowInfo; + } + } + }, + + _getFocusedWindowInfo: function(focusedWindow) { + let window = focusedWindow.get_compositor_private(); + let focusedWindowInfo; + + if (window) { + focusedWindowInfo = { window: window }; + focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window(); + + if (focusedWindow.is_attached_dialog()) { + let mainMetaWindow = focusedWindow.get_transient_for(); + + if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) { + focusedWindowInfo.window = mainMetaWindow.get_compositor_private(); + focusedWindowInfo.metaWindow = mainMetaWindow; + } + } + } + + return focusedWindowInfo; + }, + + _disconnectFocusedWindow: function(destroy) { + if (this._focusedWindowInfo && !destroy) { + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId); + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId); + } + + this._focusedWindowInfo = null; + }, + + _getHandledWindows: function() { + return global.get_window_actors() + .filter(w => w.visible) + .map(w => w.get_meta_window()) + .filter(mw => this._checkIfHandledWindow(mw)); + }, + + _checkIfHandledWindow: function(metaWindow) { + return metaWindow && !metaWindow.minimized && + this._checkIfHandledWindowType(metaWindow); + }, + + _checkIfHandledWindowType: function(metaWindow) { + let metaWindowType = metaWindow.get_window_type(); + + //https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html + return metaWindowType <= Meta.WindowType.SPLASHSCREEN && + metaWindowType != Meta.WindowType.DESKTOP; + }, + + _queueUpdate: function(noDelay) { + if (!noDelay && this._timeoutsHandler.getId(T1)) { + //limit the number of updates + this._pendingUpdate = true; + return; + } + + this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + + let metaWindows = this._getHandledWindows(); + + Object.keys(this._watches).forEach(id => { + let watch = this._watches[id]; + let overlap = this._update(watch, metaWindows); + + if (overlap !== watch.overlap) { + watch.handler(overlap); + watch.overlap = overlap; + } + }); + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdate(); + } + }, + + _update: function(watch, metaWindows) { + if (watch.mode === Mode.FOCUSED_WINDOWS) { + return (this._focusedWindowInfo && + this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) && + this._checkProximity(this._focusedWindowInfo.metaWindow, watch)); + } else if (watch.mode === Mode.MAXIMIZED_WINDOWS) { + return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally && + mw.get_monitor() == watch.monitorIndex); + } + + //Mode.ALL_WINDOWS + return metaWindows.some(mw => this._checkProximity(mw, watch)); + }, + + _checkProximity: function(metaWindow, watch) { + return metaWindow.get_frame_rect().overlap(watch.rect); + }, +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled new file mode 100644 index 0000000..ef5dc7d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml new file mode 100644 index 0000000..7e8ea3a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -0,0 +1,1278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'BOTTOM' + Panel position (Deprecated) + Panel is shown on the Bottom or Top of the screen. + + + true + Sync element positions + Sync panel element positions on all monitors. + + + '{}' + Panel positions + Panel positions (JSON). + + + '{}' + Panel element positions + Panel element positions (JSON). + + + '{}' + Percentages of screen edge for panel to span + Length of the panels, in percent (JSON). + + + '{}' + Positions along screen edge + Where to show the panels if it is not the full length of the screen edge (JSON). + + + '{}' + Panel sizes + Sizes of panels, in pixels. + + + 48 + Panel size (Deprecated) + Set the size of the panel. + + + false + Override Show Desktop line color + Replace current Show Desktop button line color + + + "rgba(200,200,200,0.2)" + Custom Show Desktop line color + Custom Show Desktop button line color + + + 'BOTTOM' + Dot position + Running indicators are shown on the Bottom or Top of the screen. + + + 'METRO' + Style of the running indicator (focused) + Style of the running indicator for the icon for the currently focused application + + + 'METRO' + Style of the running indicator (unfocused) + Style of the running indicator for the icon for applications which are not currently focused + + + false + Running indicator dominant color + Whether to use the app icon's dominant color for .app-well-running-dot + + + false + Running indicator color override + Whether to override the theme background color for .app-well-running-dot + + + "#5294e2" + Color of running indicator (1 window) + Customize the color of the running indicator when one window is running for that application + + + "#5294e2" + Color of running indicator (2 windows) + Customize the color of the running indicator when two windows are running for that application + + + "#5294e2" + Color of running indicator (3 windows) + Customize the color of the running indicator when three windows are running for that application + + + "#5294e2" + Color of running indicator (4+ windows) + Customize the color of the running indicator when four or more windows are running for that application + + + false + Unfocused color is different than focused + Whether to apply a 2nd color scheme to the indicator when the app is not focused + + + "#5294e2" + Color of unfocused running indicator (1 window) + Customize the color of the unfocused running indicator when one window is running for that application + + + "#5294e2" + Color of unfocused running indicator (2 windows) + Customize the color of the unfocused running indicator when two windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (3 windows) + Customize the color of the unfocused running indicator when three windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (4+ windows) + Customize the color of the unfocused running indicator when four or more windows are running for that application + + + 3 + Running indicator height + Height of the running indicator line/diameter of window indicator dots + + + true + Highlight icon of focused application + Whether to highlight the background of the currently focused application's icon + + + false + Highlight icon dominant color + Base the active window highlight color on that application's icon + + + "#EEEEEE" + Color of highlight of focused application + Customize the color of the highlight of the focused application + + + 25 + Opacity of highlight of focused application + Customize the opacity of the highlight of the focused application + + + false + Keep dash + Whether to keep the stock gnome-shell dash while in overview + + + false + Keep top panel + Whether to keep the stock gnome-shell top panel + + + false + Panel menu buttons require click + Whether to activate the panel menu buttons on hover or on click + + + false + Force hot corner + Wheter to force having an Activities hot corner on the primary monitor + + + false + Lock the taskbar + Specifies if the user can modify the taskbar + + + false + Override theme background color + Replace current theme background color for the panel + + + "#000" + Custom background color + Custom background color for the panel + + + false + Custom background color + Replace current theme background color for the panel + + + false + Dynamic opacity + Enable dynamic opacity + + + 0.4 + Panel opacity + Custom opacity for the panel + + + 'ALL_WINDOWS' + Dynamic opacity behavior + Dictates which window type affects the panel opacity + + + 20 + Distance to change opacity + The distance a window needs to be from the panel to change opacity + + + 0.8 + Modified panel opacity + Modified opacity for the panel when a window is near + + + 300 + Opacity change duration + The duration of the animation when the opacity changes + + + false + Custom gradient + Replace current theme gradient for the panel + + + "#000" + Custom gradient top color + Custom gradient top color for the panel + + + 0 + Custom gradient top opacity + Custom gradient top opacity for the panel + + + "#000" + Custom gradient bottom color + Custom gradient bottom color for the panel + + + 0.2 + Custom gradient bottom opacity + Custom gradient bottom opacity for the panel + + + false + Intellihide + Whether to intelligently hide the panel + + + false + Only hide from windows + Dictates if the dash should only hide when in conflict with windows + + + 'FOCUSED_WINDOWS' + Intellihide behaviour + Dictates how to intelligently hide the panel + + + false + Intellihide pressure + To reveal the panel, pressure needs to be applied to the edege of the screen + + + 100 + Intellihide pressure threshold + The pressure needed to reveal the panel + + + 1000 + Intellihide pressure time + The numer of milliseconds that the pressure needs to be applied to reveal the panel + + + false + Intellihide pressure + Allow the panel to be revealed while an application is in fullscreen mode + + + false + Intellihide only secondary + Whether to only hide secondary panels + + + 200 + Intellihide animation time + The animation time (ms) to hide and reveal the panel + + + 400 + Intellihide close delay + The delay (ms) before hiding the panel + + + "<Super>i" + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + i']]]> + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + 2000 + Intellihide enable start delay + The delay before enabling intellihide on start + + + "" + Custom Show Applications icon + Customize the Show Applications icon + + + 8 + Show Applications icon side padding + Customize the Show Applications icon side padding + + + true + Override escape key + Override the escape key to return to the desktop when entering the overview using the Show Applications button + + + [] + Show Apps button context menu commands + Commands to add to the Show Apps button right click menu + + + [] + Show Apps button context menu titles + Titles for commands added to Show Apps button right click menu + + + [] + Panel context menu commands + Commands to add to the panel right click menu + + + [] + Panel context menu titles + Titles for commands added to panel right click menu + + + false + Show activities button + Show activities button on the left hand side of the taskbar + + + 8 + Width of show Desktop button + Customize the width of the show Desktop button + + + false + Show desktop on hover + Show the desktop on mouse hover + + + 1000 + Delay show desktop + Delay before showing the desktop + + + 300 + Show desktop animation time + Window fade animation time when showing the destop + + + false + Show appMenu button + Show appMenu on the right hand side of the panel + + + true + Show window preview + Show preview of running window on hover of app icon + + + true + Show tooltip + Show tooltip on hover of app icon + + + true + Show running apps + Show or hide running application icons in the dash + + + true + Show favorites apps + Show or hide favorite application icons in the dash + + + 400 + Icon enter display time + Amount of time after entering icon to wait before displaying window preview if icon is not clicked or mouse has not left. + + + true + Enable peek mode + Peek a window upon hover for some time + + + true + Display title in preview + Display window title in preview + + + false + Window previews manual styling + This defines if the default window previews styling should be applied + + + 'TOP' + Title position + Position of the window title, close button and icon in preview. + + + "#dddddd" + Window previews title font color + This defines the window preview titles font color. + + + 14 + Window previews title font size + This defines the window preview titles font size. + + + false + Window previews use custom icon size + Window previews use custom application icon size. + + + 16 + Window previews custom icon size + Window previews custom application icon size. + + + 260 + Window previews animation time + This defines the window previews animation time. + + + 'inherit' + Font weight of window preview titles + This defines the font weight of window preview titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + 240 + Window previews size + Preferred window previews size + + + false + Fixed aspect ratio X + This defines if the window previews use a fixed aspect ratio X. + + + true + Fixed aspect ratio Y + This defines if the window previews use a fixed aspect ratio Y. + + + 8 + Window previews padding + The padding of the window previews + + + 16 + Aspect ratio X + The window previews respected aspect ratio X. + + + 9 + Aspect ratio Y + The window previews respected aspect ratio Y. + + + false + Immediate hide on icon click + The window previews immediately hide when an application icon is clicked. + + + false + Provide workspace isolation + Dash shows only windows from the current workspace + + + false + Close overview by clicking in empty space + Close overview or app grid by clicking in empty space + + + false + Hide overview on startup + Hide overview on startup, which would be shown by default at gnome startup. + + + true + Group applications + Dash groups the application instances under the same icon + + + 14 + Application title font size + When the applications are ungrouped, this defines the application titles font size. + + + 'inherit' + Font weight of application titles + When the applications are ungrouped, this defines font weight of application titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + "#dddddd" + Application title font color + When the applications are ungrouped, this defines the application titles font color. + + + "#dddddd" + Minimized application title font color + When the applications are ungrouped, this defines the titles font color for minimized applications. + + + 160 + Application title max width + When the applications are ungrouped, this defines the application titles maximum width. + + + true + Use a fixed width for the application titles + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + + + true + Display running indicators on unfocused applications + When the applications are ungrouped, this defines if running applications should display an indicator. + + + false + Use favorite icons as application launchers + When the applications are ungrouped, this defines if running applications stay separate from the favorite icons. + + + 0 + Primary monitor index + Specifies the index of the primary monitor. + + + true + Display panels on all monitors + Specifies if a panel is shown on every monitors + + + [] + Available monitors + Available gnome-shell (Mutter) monitors, internal use + + + false + Provide monitor isolation + Dash shows only windows from the current monitor + + + true + Display the favorites on all monitors + Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor. + + + true + Customize click behaviour + Customize action on various mouse events + + + true + Minimize on shift+click + + + true + Activate only one window + + + 'CYCLE-MIN' + Action when clicking on a running app + Set the action that is executed when clicking on the icon of a running application + + + 'MINIMIZE' + Action when shift+clicking on a running app + Set the action that is executed when shift+clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when middle-clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when shift+middle-clicking on the icon of a running application + + + 'SWITCH_WORKSPACE' + Action when scrolling over the panel + Set the action that is executed when scrolling over the panel + + + 0 + Delay between panel mouse scroll events + Set the minimum delay between panel mouse scroll events + + + true + Show the workspace switch head-up when workspace is changed by scrolling on the panel + + + 'CYCLE_WINDOWS' + Action when scrolling over a running app + Set the action that is executed when scrolling over a running application + + + 0 + Delay between icon mouse scroll events + Set the minimum delay between icon mouse scroll events + + + 100 + Icon leave preview timeout + Amount of time to leave preview windows open when the mouse has left the application's icon. + + + 500 + Enter window peeking mode timeout + Amount of time of inactivity to enter the window peeking mode when the mouse has entered a window preview. + + + 40 + Window peeking mode opacity + All windows except for the peeked one have their opacity set to the same value. + + + true + Middle click preview to close window + Middle click on the window preview to close that window + + + true + Window previews use custom opacity + Window previews background use a different opacity from the panel + + + 80 + Window previews background opacity + Window previews use this custom background opacity. + + + 0 + Tray font size + Set the size of the tray font. (0 for default) + + + 0 + Leftbox font size + Set the size of the leftBox font. (0 for default) + + + 8 + App icon margin + Set the margin for application icons in the embedded dash. + + + 4 + App icon padding + Set the padding for application icons in the embedded dash. + + + -1 + Tray item padding + Set the size of the tray padding. (-1 for default) + + + -1 + Leftbox item padding + Set the size of the leftBox padding. (-1 for default) + + + -1 + Status icon padding + Set the size of the aggregate (status) menu icon padding. (-1 for default) + + + true + Animate running indicator when open/closing/switching applications + + + true + Animate when new window launched + + + false + Animate app icon on hover + + + 'SIMPLE' + App icon hover animation type + + + {'RIPPLE':2,'PLANK':1} + App icon hover animation curve convexity (1 is linear, more is convex, less is concave) + + + {'SIMPLE':160,'RIPPLE':130,'PLANK':100} + App icon hover animation duration in milliseconds + + + {'RIPPLE':4,'PLANK':4} + App icon hover animation extent (maximum number of animated icons) + + + {'SIMPLE':0,'RIPPLE':10,'PLANK':0} + App icon hover animation rotation in degrees + + + {'SIMPLE':0.30,'RIPPLE':0.40,'PLANK':0} + App icon hover animation travel translation in relation to the app icon size + + + {'SIMPLE':1,'RIPPLE':1.25,'PLANK':2} + App icon hover animation zoom scale in relation to the app icon size + + + true + Integrate items from the gnome appmenu into the right click menu + + + false + Display Show Details to open Gnome Software from right click menu + + + "<Super>q" + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + q']]]> + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + 2000 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 750 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 'TEMPORARILY' + Transitivity of the number overlay + You can choose between NEVER, TEMPORARILY and ALWAYS. + + + false + Super Hot-Keys + Launch and switch between dash items using Super+(0-9) + + + 'Super' + Prefix to use for hotkeys + You can choose between Super or SuperAlt as the prefix for hotkeys. + + + false + Show window previews + When multiple instances of the application are available, show their window previews + + + 'BOTH' + Hotkeys number keys + Which number keys are used for the hotkeys + + + 1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + 2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + 3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + 4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + 5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + 6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + 7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + 8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + 9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + 0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + 1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + 2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + 3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + 4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + 5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + 6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + 7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + 8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + 9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + 0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + 1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + 2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + 3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + 4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + 5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + 6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + 7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + 8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + 9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + 0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + KP_1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + KP_2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + KP_3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + KP_4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + KP_5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + KP_6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + KP_7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + KP_8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + KP_9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + KP_0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + KP_1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + KP_4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + KP_5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + KP_6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + KP_7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + KP_8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + KP_9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + KP_0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + KP_1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + KP_4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + KP_5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + KP_6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + KP_7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + KP_8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + KP_9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + KP_0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + true + Show progress bar on app icon + Whether to show progress bar overlay on app icon, for supported applications. + + + true + Show badge count on app icon + Whether to show badge count overlay on app icon, for supported applications. + + + diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css new file mode 100644 index 0000000..6917e24 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css @@ -0,0 +1,151 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +#dashtopanelTaskbar .dash-item-container > StWidget { + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-icon, +.dashtopanelMainPanel .show-apps .overview-icon { + background: none; + border: none; + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-label { + /* must match TITLE_RIGHT_PADDING in apppicons.js */ + padding-right: 8px; +} + +#dashtopanelScrollview .app-well-app:hover .overview-icon, +#dashtopanelScrollview .app-well-app:focus .overview-icon { + background: none; +} + +.dashtopanelMainPanel .show-apps:hover .overview-icon, +#dashtopanelScrollview .app-well-app:hover .dtp-container, +#dashtopanelScrollview .app-well-app:focus .dtp-container { + background-color: rgba(238, 238, 236, 0.1); +} + +#dashtopanelScrollview .app-well-app:hover .dtp-container.animate-appicon-hover { + background: none; +} + +#dashtopanelScrollview .app-well-app:active .dtp-container { + background-color: rgba(238, 238, 236, 0.18); +} + +#dashtopanelScrollview .app-well-app .favorite { + background-color: rgba(80, 150, 255, 0.4); +} + +#dashtopanelScrollview .app-well-app-running-dot { + margin-bottom: 0; +} + +#dashtopanelTaskbar .scrollview-fade { + background-gradient-end: rgba(0, 0, 0, 0); +} + +.dashtopanelSecondaryMenu { + max-width: 400px; +} + +.dashtopanelMainPanel.vertical .panel-button { + text-align: center; +} + +.dashtopanelMainPanel.vertical .panel-button.vertical *, +.dashtopanelMainPanel.vertical .panel-button.clock-display * { + padding: 0; + margin: 0; +} + +.dashtopanelMainPanel.vertical .panel-button > *, +.dashtopanelMainPanel.vertical .panel-button.vertical > *, +.dashtopanelMainPanel.vertical .panel-button.clock-display > * { + padding: 8px 0; +} + +#dashtopanelThumbnailList { + spacing: 0em; + padding: 0 1em; +} + +#dashtopanelThumbnailList .popup-menu-item { + padding: 0; + border-radius: 5px; + spacing: 0; +} + +#dashtopanelThumbnailList .window-box { + padding: 0; + spacing: 0; +} + +#dashtopanelThumbnailList .preview-window-title { + padding-top: 1em; +} + +.popup-menu.panel-menu { + margin-bottom: 0; +} + +#panel #panelLeft, #panel #panelCenter { + spacing: 0px; +} + +.showdesktop-button-dark-hovered { + background-color: rgba(200, 200, 200, .4); +} + +.showdesktop-button-light-hovered { + background-color: rgba(55, 55, 55, .4); +} + +.panel-corner.hidden:active, .panel-corner.hidden:overview, .panel-corner.hidden:focus { + -panel-corner-border-color: rgba(0, 0, 0, .001); +} +#dashtopanelScrollview .badge { + color: rgba(255, 255, 255, 1); + font-weight: bold; + text-align: center; +} + +#dashtopanelScrollview .number-overlay { + background-color: rgba(0,0,0,0.8); +} + +#dashtopanelScrollview .notification-badge { + background-color: rgba(255,0,0,0.8); +} + +#dashtopanelScrollview .progress-bar { + /* Customization of the progress bar style, e.g.: + -progress-bar-background: rgba(0.8, 0.8, 0.8, 1); + -progress-bar-border: rgba(0.9, 0.9, 0.9, 1); + */ +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js new file mode 100644 index 0000000..4f74d1e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js @@ -0,0 +1,1557 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const SearchController = imports.ui.main.overview._overview._controls._searchController; +const AppDisplay = imports.ui.main.overview._overview._controls.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const AppIcons = Me.imports.appIcons; +const Panel = Me.imports.panel; +const PanelManager = Me.imports.panelManager; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; +const Utils = Me.imports.utils; +const WindowPreview = Me.imports.windowPreview; + +var DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME / (Dash.DASH_ANIMATION_TIME > 1 ? 1000 : 1); +var DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; +var MIN_ICON_SIZE = 4; + +/** + * Extend DashItemContainer + * + * - set label position based on taskbar orientation + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this ugly pattern. + */ + +function extendDashItemContainer(dashItemContainer) { + dashItemContainer.showLabel = AppIcons.ItemShowLabel; +}; + +const iconAnimationSettings = { + _getDictValue: function(key) { + let type = Me.settings.get_string('animate-appicon-hover-animation-type'); + return Me.settings.get_value(key).deep_unpack()[type] || 0; + }, + + get type() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return ""; + + return Me.settings.get_string('animate-appicon-hover-animation-type'); + }, + + get convexity() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-convexity')); + }, + + get duration() { + return this._getDictValue('animate-appicon-hover-animation-duration'); + }, + + get extent() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-extent')); + }, + + get rotation() { + return this._getDictValue('animate-appicon-hover-animation-rotation'); + }, + + get travel() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-travel')); + }, + + get zoom() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-zoom')); + }, +}; + +/* This class is a fork of the upstream DashActor class (ui.dash.js) + * + * Summary of changes: + * - modified chldBox calculations for when 'show-apps-at-top' option is checked + * - handle horizontal dash + */ +var taskbarActor = Utils.defineClass({ + Name: 'DashToPanel-TaskbarActor', + Extends: St.Widget, + + _init: function(delegate) { + this._delegate = delegate; + this._currentBackgroundColor = 0; + this.callParent('_init', { name: 'dashtopanelTaskbar', + layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation[delegate.dtpPanel.getOrientation().toUpperCase()] }), + clip_to_allocation: true }); + }, + + vfunc_allocate: function(box, flags)  { + Utils.setAllocation(this, box, flags); + + let panel = this._delegate.dtpPanel; + let availFixedSize = box[panel.fixedCoord.c2] - box[panel.fixedCoord.c1]; + let availVarSize = box[panel.varCoord.c2] - box[panel.varCoord.c1]; + let [dummy, scrollview, leftFade, rightFade] = this.get_children(); + let [, natSize] = this[panel.sizeFunc](availFixedSize); + let childBox = new Clutter.ActorBox(); + let orientation = panel.getOrientation(); + + Utils.allocate(dummy, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c1]; + childBox[panel.varCoord.c2] = Math.min(availVarSize, natSize); + childBox[panel.fixedCoord.c1] = box[panel.fixedCoord.c1]; + childBox[panel.fixedCoord.c2] = box[panel.fixedCoord.c2]; + + Utils.allocate(scrollview, childBox, flags); + + let [value, , upper, , , pageSize] = scrollview[orientation[0] + 'scroll'].adjustment.get_values(); + upper = Math.floor(upper); + scrollview._dtpFadeSize = upper > pageSize ? this._delegate.iconSize : 0; + + if (this._currentBackgroundColor !== panel.dynamicTransparency.currentBackgroundColor) { + this._currentBackgroundColor = panel.dynamicTransparency.currentBackgroundColor; + let gradientStyle = 'background-gradient-start: ' + this._currentBackgroundColor + + 'background-gradient-direction: ' + orientation; + + leftFade.set_style(gradientStyle); + rightFade.set_style(gradientStyle); + } + + childBox[panel.varCoord.c2] = childBox[panel.varCoord.c1] + (value > 0 ? scrollview._dtpFadeSize : 0); + Utils.allocate(leftFade, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c2] - (value + pageSize < upper ? scrollview._dtpFadeSize : 0); + childBox[panel.varCoord.c2] = box[panel.varCoord.c2]; + Utils.allocate(rightFade, childBox, flags); + }, + + // We want to request the natural size of all our children + // as our natural width, so we chain up to StWidget (which + // then calls BoxLayout) + vfunc_get_preferred_width: function(forHeight) { + let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); + + return [0, natWidth]; + }, + + vfunc_get_preferred_height: function(forWidth) { + let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); + + return [0, natHeight]; + }, +}); + +/* This class is a fork of the upstream dash class (ui.dash.js) + * + * Summary of changes: + * - disconnect global signals adding a destroy method; + * - play animations even when not in overview mode + * - set a maximum icon size + * - show running and/or favorite applications + * - emit a custom signal when an app icon is added + * - Add scrollview + * Ensure actor is visible on keyfocus inside the scrollview + * - add 128px icon size, might be useful for hidpi display + * - Sync minimization application target position. + */ + +var taskbar = Utils.defineClass({ + Name: 'DashToPanel.Taskbar', + + _init : function(panel) { + this.dtpPanel = panel; + + // start at smallest size due to running indicator drawing area expanding but not shrinking + this.iconSize = 16; + + this._shownInitially = false; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._showLabelTimeoutId = 0; + this._resetHoverTimeoutId = 0; + this._ensureAppIconVisibilityTimeoutId = 0; + this._labelShowing = false; + this.fullScrollView = 0; + + let isVertical = panel.checkIfVertical(); + + this._box = new St.BoxLayout({ vertical: isVertical, + clip_to_allocation: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START }); + + this._container = new taskbarActor(this); + this._scrollView = new St.ScrollView({ name: 'dashtopanelScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true }); + + this._scrollView.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this._scrollView.connect('motion-event', Lang.bind(this, this._onMotionEvent)); + this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); + this._scrollView.add_actor(this._box); + + this._showAppsIconWrapper = panel.showAppsIconWrapper; + this._showAppsIconWrapper.connect('menu-state-changed', Lang.bind(this, function(showAppsIconWrapper, opened) { + this._itemMenuStateChanged(showAppsIconWrapper, opened); + })); + // an instance of the showAppsIcon class is encapsulated in the wrapper + this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon; + this.showAppsButton = this._showAppsIcon.toggleButton; + + if (isVertical) { + this.showAppsButton.set_width(panel.geom.w); + } + + this.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); + + this.showAppsButton.checked = (SearchController._showAppsButton) ? SearchController._showAppsButton.checked : false; + + this._showAppsIcon.childScale = 1; + this._showAppsIcon.childOpacity = 255; + this._showAppsIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper); + + this._container.add_child(new St.Widget({ width: 0, reactive: false })); + this._container.add_actor(this._scrollView); + + let orientation = panel.getOrientation(); + let fadeStyle = 'background-gradient-direction:' + orientation; + let fade1 = new St.Widget({ style_class: 'scrollview-fade', reactive: false }); + let fade2 = new St.Widget({ style_class: 'scrollview-fade', + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: 180 }); + + fade1.set_style(fadeStyle); + fade2.set_style(fadeStyle); + + this._container.add_actor(fade1); + this._container.add_actor(fade2); + + this.previewMenu = new WindowPreview.PreviewMenu(panel); + this.previewMenu.enable(); + + let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + this.actor = new St.Bin({ child: this._container, + y_align: St.Align.START, x_align:rtl?St.Align.END:St.Align.START + }); + + let adjustment = this._scrollView[orientation[0] + 'scroll'].adjustment; + + this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); + + this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); + + this._appSystem = Shell.AppSystem.get_default(); + + this.iconAnimator = new PanelManager.IconAnimator(this.dtpPanel.panel.actor); + + this._signalsHandler.add( + [ + this.dtpPanel.panel.actor, + 'notify::height', + () => this._queueRedisplay() + ], + [ + this.dtpPanel.panel.actor, + 'notify::width', + () => this._queueRedisplay() + ], + [ + this._appSystem, + 'installed-changed', + Lang.bind(this, function() { + AppFavorites.getAppFavorites().reload(); + this._queueRedisplay(); + }) + ], + [ + this._appSystem, + 'app-state-changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + AppFavorites.getAppFavorites(), + 'changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + global.window_manager, + 'switch-workspace', + () => this._connectWorkspaceSignals() + ], + [ + Utils.DisplayWrapper.getScreen(), + [ + 'window-entered-monitor', + 'window-left-monitor' + ], + () => { + if (Me.settings.get_boolean('isolate-monitors')) { + this._queueRedisplay(); + } + } + ], + [ + Main.overview, + 'item-drag-begin', + Lang.bind(this, this._onDragBegin) + ], + [ + Main.overview, + 'item-drag-end', + Lang.bind(this, this._onDragEnd) + ], + [ + Main.overview, + 'item-drag-cancelled', + Lang.bind(this, this._onDragCancelled) + ], + [ + // Ensure the ShowAppsButton status is kept in sync + SearchController._showAppsButton, + 'notify::checked', + Lang.bind(this, this._syncShowAppsButtonToggled) + ], + [ + Me.settings, + [ + 'changed::dot-size', + 'changed::show-favorites', + 'changed::show-running-apps', + 'changed::show-favorites-all-monitors' + ], + Lang.bind(this, this._redisplay) + ], + [ + Me.settings, + 'changed::group-apps', + Lang.bind(this, function() { + this.isGroupApps = Me.settings.get_boolean('group-apps'); + this._connectWorkspaceSignals(); + }) + ], + [ + Me.settings, + [ + 'changed::group-apps-use-launchers', + 'changed::taskbar-locked' + ], + () => this.resetAppIcons() + ], + [ + adjustment, + [ + 'notify::upper', + 'notify::pageSize' + ], + () => this._onScrollSizeChange(adjustment) + ] + ); + + this.isGroupApps = Me.settings.get_boolean('group-apps'); + + this._onScrollSizeChange(adjustment); + this._connectWorkspaceSignals(); + }, + + destroy: function() { + this.iconAnimator.destroy(); + + this._signalsHandler.destroy(); + this._signalsHandler = 0; + + this._container.destroy(); + + this.previewMenu.disable(); + this.previewMenu.destroy(); + + this._disconnectWorkspaceSignals(); + }, + + _dropIconAnimations: function() { + this._getTaskbarIcons().forEach(item => { + item.raise(0); + item.stretch(0); + }); + }, + + _updateIconAnimations: function(pointerX, pointerY) { + this._iconAnimationTimestamp = Date.now(); + let type = iconAnimationSettings.type; + + if (!pointerX || !pointerY) + [pointerX, pointerY] = global.get_pointer(); + + this._getTaskbarIcons().forEach(item => { + let [x, y] = item.get_transformed_position(); + let [width, height] = item.get_transformed_size(); + let [centerX, centerY] = [x + width / 2, y + height / 2]; + let size = this._box.vertical ? height : width; + let difference = this._box.vertical ? pointerY - centerY : pointerX - centerX; + let distance = Math.abs(difference); + let maxDistance = (iconAnimationSettings.extent / 2) * size; + + if (type == 'PLANK') { + // Make the position stable for items that are far from the pointer. + let translation = distance <= maxDistance ? + distance / (2 + 8 * distance / maxDistance) : + // the previous expression with distance = maxDistance + maxDistance / 10; + + if (difference > 0) + translation *= -1; + + item.stretch(translation); + } + + if (distance <= maxDistance) { + let level = (maxDistance - distance) / maxDistance; + level = Math.pow(level, iconAnimationSettings.convexity); + item.raise(level); + } else { + item.raise(0); + } + }); + }, + + _onLeaveEvent: function(actor) { + let [stageX, stageY] = global.get_pointer(); + let [success, x, y] = actor.transform_stage_point(stageX, stageY); + if (success && !actor.allocation.contains(x, y) && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._dropIconAnimations(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMotionEvent: function(actor_, event) { + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + let timestamp = Date.now(); + if (!this._iconAnimationTimestamp || + (timestamp - this._iconAnimationTimestamp >= iconAnimationSettings.duration / 2)) { + let [pointerX, pointerY] = event.get_coords(); + this._updateIconAnimations(pointerX, pointerY); + } + } + + return Clutter.EVENT_PROPAGATE; + }, + + _onScrollEvent: function(actor, event) { + + let orientation = this.dtpPanel.getOrientation(); + + // reset timeout to avid conflicts with the mousehover event + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + // Skip to avoid double events mouse + if (event.is_pointer_emulated()) + return Clutter.EVENT_STOP; + + let adjustment, delta; + + adjustment = this._scrollView[orientation[0] + 'scroll'].get_adjustment(); + + let increment = adjustment.step_increment; + + switch ( event.get_scroll_direction() ) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + delta = -increment; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + delta = +increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy*increment; + delta += dx*increment; + break; + + } + + adjustment.set_value(adjustment.get_value() + delta); + + return Clutter.EVENT_STOP; + + }, + + _onScrollSizeChange: function(adjustment) { + // Update minimization animation target position on scrollview change. + this._updateAppIcons(); + + // When applications are ungrouped and there is some empty space on the horizontal taskbar, + // force a fixed label width to prevent the icons from "wiggling" when an animation runs + // (adding or removing an icon). When the taskbar is full, revert to a dynamic label width + // to allow them to resize and make room for new icons. + if (!this.dtpPanel.checkIfVertical() && !this.isGroupApps) { + let initial = this.fullScrollView; + + if (!this.fullScrollView && Math.floor(adjustment.upper) > adjustment.page_size) { + this.fullScrollView = adjustment.page_size; + } else if (adjustment.page_size < this.fullScrollView) { + this.fullScrollView = 0; + } + + if (initial != this.fullScrollView) { + this._getAppIcons().forEach(a => a.updateTitleStyle()); + } + } + }, + + _onDragBegin: function() { + this._dragCancelled = false; + this._dragMonitor = { + dragMotion: Lang.bind(this, this._onDragMotion) + }; + DND.addDragMonitor(this._dragMonitor); + + if (this._box.get_n_children() == 0) { + this._emptyDropTarget = new Dash.EmptyDropTargetItem(); + this._box.insert_child_at_index(this._emptyDropTarget, 0); + this._emptyDropTarget.show(true); + } + + this._toggleFavortieHighlight(true); + }, + + _onDragCancelled: function() { + this._dragCancelled = true; + + if (this._dragInfo) { + this._box.set_child_at_index(this._dragInfo[1]._dashItemContainer, this._dragInfo[0]); + } + + this._endDrag(); + }, + + _onDragEnd: function() { + if (this._dragCancelled) + return; + + this._endDrag(); + }, + + _endDrag: function() { + if (this._dragInfo && this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem) { + this._box.remove_child(this._dragInfo[1]._dashItemContainer); + this._dragInfo[1]._dashItemContainer.destroy(); + delete this._dragInfo[1]._dashItemContainer; + } + + this._dragInfo = null; + this._clearEmptyDropTarget(); + this._showAppsIcon.setDragApp(null); + DND.removeDragMonitor(this._dragMonitor); + + this._toggleFavortieHighlight(); + }, + + _onDragMotion: function(dragEvent) { + let app = Dash.getAppFromSource(dragEvent.source); + if (app == null) + return DND.DragMotionResult.CONTINUE; + + let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor); + + if (showAppsHovered) + this._showAppsIcon.setDragApp(app); + else + this._showAppsIcon.setDragApp(null); + + return DND.DragMotionResult.CONTINUE; + }, + + _toggleFavortieHighlight: function(show) { + let appFavorites = AppFavorites.getAppFavorites(); + let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name'; + + this._getAppIcons().filter(appIcon => appFavorites.isFavorite(appIcon.app.get_id())) + .forEach(fav => fav._container[cssFuncName]('favorite')); + }, + + handleIsolatedWorkspaceSwitch: function() { + this._shownInitially = this.isGroupApps; + this._queueRedisplay(); + }, + + _connectWorkspaceSignals: function() { + this._disconnectWorkspaceSignals(); + + this._lastWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + + this._workspaceWindowAddedId = this._lastWorkspace.connect('window-added', () => this._queueRedisplay()); + this._workspaceWindowRemovedId = this._lastWorkspace.connect('window-removed', () => this._queueRedisplay()); + }, + + _disconnectWorkspaceSignals: function() { + if (this._lastWorkspace) { + this._lastWorkspace.disconnect(this._workspaceWindowAddedId); + this._lastWorkspace.disconnect(this._workspaceWindowRemovedId); + + this._lastWorkspace = null; + } + }, + + _queueRedisplay: function () { + Main.queueDeferredWork(this._workId); + }, + + _hookUpLabel: function(item, syncHandler) { + item.child.connect('notify::hover', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + + syncHandler.connect('sync-tooltip', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + }, + + _createAppItem: function(app, window, isLauncher) { + let appIcon = new AppIcons.taskbarAppIcon( + { + app: app, + window: window, + isLauncher: isLauncher + }, + this.dtpPanel, + { + setSizeManually: true, + showLabel: false, + isDraggable: !Me.settings.get_boolean('taskbar-locked'), + }, + this.previewMenu, + this.iconAnimator + ); + + if (appIcon._draggable) { + appIcon._draggable.connect('drag-begin', + Lang.bind(this, function() { + appIcon.actor.opacity = 0; + appIcon.isDragged = 1; + this._dropIconAnimations(); + })); + appIcon._draggable.connect('drag-end', + Lang.bind(this, function() { + appIcon.actor.opacity = 255; + delete appIcon.isDragged; + this._updateAppIcons(); + })); + } + + appIcon.connect('menu-state-changed', + Lang.bind(this, function(appIcon, opened) { + this._itemMenuStateChanged(item, opened); + })); + + let item = new TaskbarItemContainer(); + + item._dtpPanel = this.dtpPanel + extendDashItemContainer(item); + + item.setChild(appIcon.actor); + appIcon._dashItemContainer = item; + + appIcon.actor.connect('notify::hover', Lang.bind(this, function() { + if (appIcon.actor.hover){ + this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ + Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize); + this._ensureAppIconVisibilityTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(1); + else if (!appIcon.isDragged && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._updateIconAnimations(); + } else { + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(0); + } + })); + + appIcon.actor.connect('clicked', + Lang.bind(this, function(actor) { + Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + })); + + appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { + let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + + // This signal is triggered also by mouse click. The popup menu is opened at the original + // coordinates. Thus correct for the shift which is going to be applied to the scrollview. + if (appIcon._menu) { + appIcon._menu._boxPointer.xOffset = -x_shift; + appIcon._menu._boxPointer.yOffset = -y_shift; + } + })); + + // Override default AppIcon label_actor, now the + // accessible_name is set at DashItemContainer.setLabelText + appIcon.actor.label_actor = null; + item.setLabelText(app.get_name()); + + appIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(item, appIcon); + + return item; + }, + + // Return an array with the "proper" appIcons currently in the taskbar + _getAppIcons: function() { + // Only consider children which are "proper" icons and which are not + // animating out (which means they will be destroyed at the end of + // the animation) + return this._getTaskbarIcons().map(function(actor){ + return actor.child._delegate; + }); + }, + + _getTaskbarIcons: function(includeAnimated) { + return this._box.get_children().filter(function(actor) { + return actor.child && + actor.child._delegate && + actor.child._delegate.icon && + (includeAnimated || !actor.animatingOut); + }); + }, + + _updateAppIcons: function() { + let appIcons = this._getAppIcons(); + + appIcons.filter(icon => icon.constructor === AppIcons.taskbarAppIcon).forEach(icon => { + icon.updateIcon(); + }); + }, + + _itemMenuStateChanged: function(item, opened) { + // When the menu closes, it calls sync_hover, which means + // that the notify::hover handler does everything we need to. + if (opened) { + if (this._showLabelTimeoutId > 0) { + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + } + + item.hideLabel(); + } else { + // I want to listen from outside when a menu is closed. I used to + // add a custom signal to the appIcon, since gnome 3.8 the signal + // calling this callback was added upstream. + this.emit('menu-closed'); + + // The icon menu grabs the events and, once it is closed, the pointer is maybe + // no longer over the taskbar and the animations are not dropped. + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + this._scrollView.sync_hover(); + if (!this._scrollView.hover) + this._dropIconAnimations(); + } + } + }, + + _syncLabel: function (item, syncHandler) { + let shouldShow = syncHandler ? syncHandler.shouldShowTooltip() : item.child.get_hover(); + + if (shouldShow) { + if (this._showLabelTimeoutId == 0) { + let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; + this._showLabelTimeoutId = Mainloop.timeout_add(timeout, + Lang.bind(this, function() { + this._labelShowing = true; + item.showLabel(); + this._showLabelTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); + if (this._resetHoverTimeoutId > 0) { + Mainloop.source_remove(this._resetHoverTimeoutId); + this._resetHoverTimeoutId = 0; + } + } + } else { + if (this._showLabelTimeoutId > 0) + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + item.hideLabel(); + if (this._labelShowing) { + this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, + Lang.bind(this, function() { + this._labelShowing = false; + this._resetHoverTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing'); + } + } + }, + + _adjustIconSize: function() { + const thisMonitorIndex = this.dtpPanel.monitor.index; + let panelSize = PanelSettings.getPanelSize(Me.settings, thisMonitorIndex); + let availSize = panelSize - Me.settings.get_int('appicon-padding') * 2; + let minIconSize = MIN_ICON_SIZE + panelSize % 2; + + if (availSize == this.iconSize) + return; + + if (availSize < minIconSize) { + availSize = minIconSize; + } + + // For the icon size, we only consider children which are "proper" + // icons and which are not animating out (which means they will be + // destroyed at the end of the animation) + let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon]); + let scale = this.iconSize / availSize; + + this.iconSize = availSize; + + for (let i = 0; i < iconChildren.length; i++) { + let icon = iconChildren[i].child._delegate.icon; + + // Set the new size immediately, to keep the icons' sizes + // in sync with this.iconSize + icon.setIconSize(this.iconSize); + + // Don't animate the icon size change when the overview + // is transitioning, or when initially filling + // the taskbar + if (Main.overview.animationInProgress || + !this._shownInitially) + continue; + + let [targetWidth, targetHeight] = icon.icon.get_size(); + + // Scale the icon's texture to the previous size and + // tween to the new size + icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale); + + Utils.animate(icon.icon, + { width: targetWidth, + height: targetHeight, + time: DASH_ANIMATION_TIME, + transition: 'easeOutQuad', + }); + } + }, + + sortAppsCompareFunction: function(appA, appB) { + return getAppStableSequence(appA, this.dtpPanel.monitor) - + getAppStableSequence(appB, this.dtpPanel.monitor); + }, + + getAppInfos: function() { + //get the user's favorite apps + let favoriteApps = this._checkIfShowingFavorites() ? AppFavorites.getAppFavorites().getFavorites() : []; + + //find the apps that should be in the taskbar: the favorites first, then add the running apps + // When using isolation, we filter out apps that have no windows in + // the current workspace (this check is done in AppIcons.getInterestingWindows) + let runningApps = this._checkIfShowingRunningApps() ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this)) : []; + + if (!this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers')) { + return this._createAppInfos(favoriteApps, [], true) + .concat(this._createAppInfos(runningApps) + .filter(appInfo => appInfo.windows.length)); + } else { + return this._createAppInfos(favoriteApps.concat(runningApps.filter(app => favoriteApps.indexOf(app) < 0))) + .filter(appInfo => appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0); + } + }, + + _redisplay: function () { + if (!this._signalsHandler) { + return; + } + + //get the currently displayed appIcons + let currentAppIcons = this._getTaskbarIcons(); + let expectedAppInfos = this.getAppInfos(); + + //remove the appIcons which are not in the expected apps list + for (let i = currentAppIcons.length - 1; i > -1; --i) { + let appIcon = currentAppIcons[i].child._delegate; + let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app && + appInfo.isLauncher == appIcon.isLauncher); + + if (appIndex < 0 || + (appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) || + (!appIcon.window && !appIcon.isLauncher && + !this.isGroupApps && expectedAppInfos[appIndex].windows.length)) { + currentAppIcons[i][this._shownInitially ? 'animateOutAndDestroy' : 'destroy'](); + currentAppIcons.splice(i, 1); + } + } + + //if needed, reorder the existing appIcons and create the missing ones + let currentPosition = 0; + for (let i = 0, l = expectedAppInfos.length; i < l; ++i) { + let neededAppIcons = this.isGroupApps || !expectedAppInfos[i].windows.length ? + [{ app: expectedAppInfos[i].app, window: null, isLauncher: expectedAppInfos[i].isLauncher }] : + expectedAppInfos[i].windows.map(window => ({ app: expectedAppInfos[i].app, window: window, isLauncher: false })); + + for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) { + //check if the icon already exists + let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app && + appIcon.child._delegate.window == neededAppIcons[j].window); + + if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) { + //moved icon, reposition it + this._box.remove_child(currentAppIcons[matchingAppIconIndex]); + this._box.insert_child_at_index(currentAppIcons[matchingAppIconIndex], currentPosition); + } else if (matchingAppIconIndex < 0) { + //the icon doesn't exist yet, create a new one + let newAppIcon = this._createAppItem(neededAppIcons[j].app, neededAppIcons[j].window, neededAppIcons[j].isLauncher); + + this._box.insert_child_at_index(newAppIcon, currentPosition); + currentAppIcons.splice(currentPosition, 0, newAppIcon); + + // Skip animations on first run when adding the initial set + // of items, to avoid all items zooming in at once + newAppIcon.show(this._shownInitially); + } + + ++currentPosition; + } + } + + this._adjustIconSize(); + + // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 + // Without it, StBoxLayout may use a stale size cache + this._box.queue_relayout(); + + // This is required for icon reordering when the scrollview is used. + this._updateAppIcons(); + + // This will update the size, and the corresponding number for each icon on the primary panel + if (this.dtpPanel.isPrimary) { + this._updateNumberOverlay(); + } + + this._shownInitially = true; + }, + + _checkIfShowingRunningApps: function() { + return Me.settings.get_boolean('show-running-apps'); + }, + + _checkIfShowingFavorites: function() { + return Me.settings.get_boolean('show-favorites') && + (this.dtpPanel.isPrimary || Me.settings.get_boolean('show-favorites-all-monitors')); + }, + + _getRunningApps: function() { + let tracker = Shell.WindowTracker.get_default(); + let windows = global.get_window_actors(); + let apps = []; + + for (let i = 0, l = windows.length; i < l; ++i) { + let app = tracker.get_window_app(windows[i].metaWindow); + + if (app && apps.indexOf(app) < 0) { + apps.push(app); + } + } + + return apps; + }, + + _createAppInfos: function(apps, defaultWindows, defaultIsLauncher) { + return apps.map(app => ({ + app: app, + isLauncher: defaultIsLauncher || false, + windows: defaultWindows || AppIcons.getInterestingWindows(app, this.dtpPanel.monitor) + .sort(sortWindowsCompareFunction) + })); + }, + + // Reset the displayed apps icon to mantain the correct order + resetAppIcons : function(geometryChange) { + let children = this._getTaskbarIcons(true); + + for (let i = 0; i < children.length; i++) { + let item = children[i]; + item.destroy(); + } + + // to avoid ugly animations, just suppress them like when taskbar is first loaded. + this._shownInitially = false; + this._redisplay(); + + if (geometryChange && this.dtpPanel.checkIfVertical()) { + this.previewMenu._updateClip(); + } + }, + + _updateNumberOverlay: function() { + let seenApps = {}; + let counter = 0; + + this._getAppIcons().forEach(function(icon) { + if (!seenApps[icon.app]) { + seenApps[icon.app] = 1; + counter++; + } + + if (counter <= 10) { + icon.setNumberOverlay(counter == 10 ? 0 : counter); + } else { + // No overlay after 10 + icon.setNumberOverlay(-1); + } + + icon.updateHotkeyNumberOverlay(); + }); + + if (Me.settings.get_boolean('hot-keys') && + Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.toggleNumberOverlay(true); + }, + + toggleNumberOverlay: function(activate) { + let appIcons = this._getAppIcons(); + appIcons.forEach(function(icon) { + icon.toggleNumberOverlay(activate); + }); + }, + + _clearEmptyDropTarget: function() { + if (this._emptyDropTarget) { + this._emptyDropTarget.animateOutAndDestroy(); + this._emptyDropTarget = null; + } + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) + return DND.DragMotionResult.CONTINUE; + + // Don't allow favoriting of transient apps + if (source.app == null || source.app.is_window_backed()) + return DND.DragMotionResult.NO_DROP; + + if (!this._settings.is_writable('favorite-apps')) + return DND.DragMotionResult.NO_DROP; + + let sourceActor = source instanceof St.Widget ? source : source.actor; + let isVertical = this.dtpPanel.checkIfVertical(); + + if (!this._box.contains(sourceActor) && !source._dashItemContainer) { + //not an appIcon of the taskbar, probably from the applications view + source._dashItemContainer = new DragPlaceholderItem(source, this.iconSize, isVertical); + this._box.insert_child_above(source._dashItemContainer, null); + } + + let sizeProp = isVertical ? 'height' : 'width'; + let posProp = isVertical ? 'y' : 'x'; + let pos = isVertical ? y : x; + + let currentAppIcons = this._getAppIcons(); + let sourceIndex = currentAppIcons.indexOf(source); + let hoveredIndex = Utils.findIndex(currentAppIcons, + appIcon => pos >= appIcon._dashItemContainer[posProp] && + pos <= (appIcon._dashItemContainer[posProp] + appIcon._dashItemContainer[sizeProp])); + + if (!this._dragInfo) { + this._dragInfo = [sourceIndex, source]; + } + + if (hoveredIndex >= 0) { + let isLeft = pos < currentAppIcons[hoveredIndex]._dashItemContainer[posProp] + currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * .5; + + // Don't allow positioning before or after self and between icons of same app + if (!(hoveredIndex === sourceIndex || + (isLeft && hoveredIndex - 1 == sourceIndex) || + (isLeft && hoveredIndex - 1 >= 0 && source.app != currentAppIcons[hoveredIndex - 1].app && + currentAppIcons[hoveredIndex - 1].app == currentAppIcons[hoveredIndex].app) || + (!isLeft && hoveredIndex + 1 == sourceIndex) || + (!isLeft && hoveredIndex + 1 < currentAppIcons.length && source.app != currentAppIcons[hoveredIndex + 1].app && + currentAppIcons[hoveredIndex + 1].app == currentAppIcons[hoveredIndex].app))) { + this._box.set_child_at_index(source._dashItemContainer, hoveredIndex); + + // Ensure the next and previous icon are visible when moving the icon + // (I assume there's room for both of them) + if (hoveredIndex > 1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize); + if (hoveredIndex < this._box.get_children().length-1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize); + } + } + + return this._dragInfo[0] !== sourceIndex ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.CONTINUE; + }, + + // Draggable target interface + acceptDrop : function(source, actor, x, y, time) { + // Don't allow favoriting of transient apps + if (!source.app || source.app.is_window_backed() || !this._settings.is_writable('favorite-apps')) { + return false; + } + + let appIcons = this._getAppIcons(); + let sourceIndex = appIcons.indexOf(source); + let usingLaunchers = !this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers'); + + // dragging the icon to its original position + if (this._dragInfo[0] === sourceIndex) { + return true; + } + + let appFavorites = AppFavorites.getAppFavorites(); + let sourceAppId = source.app.get_id(); + let appIsFavorite = appFavorites.isFavorite(sourceAppId); + let replacingIndex = sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1); + let favoriteIndex = replacingIndex >= 0 ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app) : 0; + let sameApps = appIcons.filter(a => a != source && a.app == source.app); + let showingFavorites = this._checkIfShowingFavorites(); + let favoritesCount = 0; + let position = 0; + let interestingWindows = {}; + let getAppWindows = app => { + if (!interestingWindows[app]) { + interestingWindows[app] = AppIcons.getInterestingWindows(app, this.dtpPanel.monitor); + } + + let appWindows = interestingWindows[app]; //prevents "reference to undefined property Symbol.toPrimitive" warning + return appWindows; + }; + + if (sameApps.length && + ((!appIcons[sourceIndex - 1] || appIcons[sourceIndex - 1].app !== source.app) && + (!appIcons[sourceIndex + 1] || appIcons[sourceIndex + 1].app !== source.app))) { + appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length); + Array.prototype.splice.apply(appIcons, [sourceIndex + 1, 0].concat(sameApps)); + } + + for (let i = 0, l = appIcons.length; i < l; ++i) { + let windows = []; + + if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) { + windows = appIcons[i].window ? [appIcons[i].window] : getAppWindows(appIcons[i].app); + } + + windows.forEach(w => w._dtpPosition = position++); + + if (showingFavorites && + ((usingLaunchers && appIcons[i].isLauncher) || + (!usingLaunchers && appFavorites.isFavorite(appIcons[i].app.get_id())))) { + ++favoritesCount; + } + } + + if (sourceIndex < favoritesCount) { + if (appIsFavorite) { + appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex); + } else { + appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex); + } + } else if (appIsFavorite && showingFavorites && (!usingLaunchers || source.isLauncher)) { + appFavorites.removeFavorite(sourceAppId); + } + + appFavorites.emit('changed'); + + return true; + }, + + _onShowAppsButtonToggled: function() { + // Sync the status of the default appButtons. Only if the two statuses are + // different, that means the user interacted with the extension provided + // application button, cutomize the behaviour. Otherwise the shell has changed the + // status (due to the _syncShowAppsButtonToggled function below) and it + // has already performed the desired action. + let selector = SearchController; + + if (selector._showAppsButton && + selector._showAppsButton.checked !== this.showAppsButton.checked) { + // find visible view + + if (this.showAppsButton.checked) { + if (Me.settings.get_boolean('show-apps-override-escape')) { + //override escape key to return to the desktop when entering the overview using the showapps button + SearchController._onStageKeyPress = function(actor, event) { + if (Main.modalCount == 1 && event.get_key_symbol() === Clutter.KEY_Escape) { + this._searchActive ? this.reset() : Main.overview.hide(); + + return Clutter.EVENT_STOP; + } + + return this.__proto__._onStageKeyPress.call(this, actor, event); + }; + } + + // force spring animation triggering.By default the animation only + // runs if we are already inside the overview. + if (!Main.overview._shown) { + this.forcedOverview = true; + let grid = AppDisplay._grid; + let onShownCb; + let overviewSignal = Config.PACKAGE_VERSION > '3.38.1' ? 'showing' : 'shown'; + let overviewShowingId = Main.overview.connect(overviewSignal, () => { + Main.overview.disconnect(overviewShowingId); + onShownCb(); + }); + + onShownCb = () => grid.emit('animation-done'); + } + + //temporarily use as primary the monitor on which the showapps btn was clicked, this is + //restored by the panel when exiting the overview + this.dtpPanel.panelManager.setFocusedMonitor(this.dtpPanel.monitor); + + let overviewHiddenId = Main.overview.connect('hidden', () => { + Main.overview.disconnect(overviewHiddenId); + delete SearchController._onStageKeyPress; + }); + + // Finally show the overview + selector._showAppsButton.checked = true; + Main.overview.show(2 /*APP_GRID*/); + } + else { + if (this.forcedOverview) { + // force exiting overview if needed + + Main.overview.hide(); + this.forcedOverview = false; + } + else { + selector._showAppsButton.checked = false; + this.forcedOverview = false; + } + } + } + }, + + _syncShowAppsButtonToggled: function() { + let status = SearchController._showAppsButton.checked; + if (this.showAppsButton.checked !== status) + this.showAppsButton.checked = status; + }, + + showShowAppsButton: function() { + this.showAppsButton.visible = true; + this.showAppsButton.set_width(-1); + this.showAppsButton.set_height(-1); + }, + + popupFocusedAppSecondaryMenu: function() { + let appIcons = this._getAppIcons(); + let tracker = Shell.WindowTracker.get_default(); + + for(let i in appIcons) { + if(appIcons[i].app == tracker.focus_app) { + let appIcon = appIcons[i]; + if(appIcon._menu && appIcon._menu.isOpen) + appIcon._menu.close(); + else + appIcon.popupMenu(); + + appIcon.sync_hover(); + break; + } + } + }, +}); + +Signals.addSignalMethods(taskbar.prototype); + +const CloneContainerConstraint = Utils.defineClass({ + Name: 'DashToPanel-CloneContainerConstraint', + Extends: Clutter.BindConstraint, + + vfunc_update_allocation: function(actor, actorBox) { + if (!this.source) + return; + + let [stageX, stageY] = this.source.get_transformed_position(); + let [width, height] = this.source.get_transformed_size(); + + actorBox.set_origin(stageX, stageY); + actorBox.set_size(width, height); + }, +}); + +var TaskbarItemContainer = Utils.defineClass({ + Name: 'DashToPanel-TaskbarItemContainer', + Extends: Dash.DashItemContainer, + + vfunc_allocate: function(box, flags) { + if (this.child == null) + return; + + Utils.setAllocation(this, box, flags); + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; + let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = this.child.get_preferred_size(); + let [childScaleX, childScaleY] = this.child.get_scale(); + + let childWidth = Math.min(natChildWidth * childScaleX, availWidth); + let childHeight = Math.min(natChildHeight * childScaleY, availHeight); + let childBox = new Clutter.ActorBox(); + + childBox.x1 = (availWidth - childWidth) / 2; + childBox.y1 = (availHeight - childHeight) / 2; + childBox.x2 = childBox.x1 + childWidth; + childBox.y2 = childBox.y1 + childHeight; + + Utils.allocate(this.child, childBox, flags); + }, + + // In case appIcon is removed from the taskbar while it is hovered, + // restore opacity before dashItemContainer.animateOutAndDestroy does the destroy animation. + animateOutAndDestroy: function() { + if (this._raisedClone) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + } + + this.callParent('animateOutAndDestroy'); + }, + + // For ItemShowLabel + _getIconAnimationOffset: function() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return 0; + + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + return this._dtpPanel.dtpSize * (travel + (zoom - 1) / 2); + }, + + _updateCloneContainerPosition: function(cloneContainer) { + let [stageX, stageY] = this.get_transformed_position(); + + if (Config.PACKAGE_VERSION >= '3.36') + cloneContainer.set_position(stageX - this.translation_x, stageY - this.translation_y); + else + cloneContainer.set_position(stageX, stageY); + }, + + _createRaisedClone: function() { + let [width, height] = this.get_transformed_size(); + + // "clone" of this child (appIcon actor) + let cloneButton = this.child._delegate.getCloneButton(); + + // "clone" of this (taskbarItemContainer) + let cloneContainer = new St.Bin({ + child: cloneButton, + width: width, height: height, + reactive: false, + }); + + this._updateCloneContainerPosition(cloneContainer); + + // For the stretch animation + if (Config.PACKAGE_VERSION >= '3.36') { + let boundProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + this.bind_property(boundProperty, cloneContainer, boundProperty, GObject.BindingFlags.SYNC_CREATE); + } else { + let constraint = new CloneContainerConstraint({ source: this }); + cloneContainer.add_constraint(constraint); + } + + // The clone follows its source when the taskbar is scrolled. + let taskbarScrollView = this.get_parent().get_parent(); + let adjustment = this._dtpPanel.checkIfVertical() ? taskbarScrollView.vscroll.get_adjustment() : taskbarScrollView.hscroll.get_adjustment(); + let adjustmentChangedId = adjustment.connect('notify::value', () => this._updateCloneContainerPosition(cloneContainer)); + + // Update clone position when an item is added to / removed from the taskbar. + let taskbarBox = this.get_parent(); + let taskbarBoxAllocationChangedId = taskbarBox.connect('notify::allocation', () => this._updateCloneContainerPosition(cloneContainer)); + + // The clone itself + this._raisedClone = cloneButton.child; + this._raisedClone.connect('destroy', () => { + adjustment.disconnect(adjustmentChangedId); + taskbarBox.disconnect(taskbarBoxAllocationChangedId); + Mainloop.idle_add(() => cloneContainer.destroy()); + delete this._raisedClone; + }); + + this._raisedClone.source.opacity = 0; + Main.uiGroup.add_actor(cloneContainer); + }, + + // Animate the clone. + // AppIcon actors cannot go outside the taskbar so the animation is done with a clone. + // If level is zero, the clone is dropped and destroyed. + raise: function(level) { + if (this._raisedClone) + Utils.stopAnimations(this._raisedClone); + else if (level) + this._createRaisedClone(); + else + return; + + let panelPosition = this._dtpPanel.getPosition(); + let panelElementPositions = this._dtpPanel.panelManager.panelsElementPositions[this._dtpPanel.monitor.index] || Pos.defaults; + let taskbarPosition = panelElementPositions.filter(pos => pos.element == 'taskbar')[0].position; + + let vertical = panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT; + let translationDirection = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT ? 1 : -1; + let rotationDirection; + if (panelPosition == St.Side.LEFT || taskbarPosition == Pos.STACKED_TL) + rotationDirection = -1; + else if (panelPosition == St.Side.RIGHT || taskbarPosition == Pos.STACKED_BR) + rotationDirection = 1; + else { + let items = this.get_parent().get_children(); + let index = items.indexOf(this); + rotationDirection = (index - (items.length - 1) / 2) / ((items.length - 1) / 2); + } + + let duration = iconAnimationSettings.duration / 1000; + let rotation = iconAnimationSettings.rotation; + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + + // level is about 1 for the icon that is hovered, less for others. + // time depends on the translation to do. + let [width, height] = this._raisedClone.source.get_transformed_size(); + let translationMax = (vertical ? width : height) * (travel + (zoom - 1) / 2); + let translationEnd = translationMax * level; + let translationDone = vertical ? this._raisedClone.translation_x : this._raisedClone.translation_y; + let translationTodo = Math.abs(translationEnd - translationDone); + let scale = 1 + (zoom - 1) * level; + let rotationAngleZ = rotationDirection * rotation * level; + let time = duration * translationTodo / translationMax; + + let options = { + scale_x: scale, scale_y: scale, + rotation_angle_z: rotationAngleZ, + time: time, + transition: 'easeOutQuad', + onComplete: () => { + if (!level) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + delete this._raisedClone; + } + }, + }; + options[vertical ? 'translation_x' : 'translation_y'] = translationDirection * translationEnd; + + Utils.animate(this._raisedClone, options); + }, + + // Animate this and cloneContainer, since cloneContainer translation is bound to this. + stretch: function(translation) { + let duration = iconAnimationSettings.duration / 1000; + let zoom = iconAnimationSettings.zoom; + let animatedProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + let isShowing = this.opacity != 255 || this.child.opacity != 255; + + if (isShowing) { + // Do no stop the animation initiated in DashItemContainer.show. + this[animatedProperty] = zoom * translation; + } else { + let options = { + time: duration, + transition: 'easeOutQuad', + }; + options[animatedProperty] = zoom * translation; + + Utils.stopAnimations(this); + Utils.animate(this, options); + } + }, +}); + +var DragPlaceholderItem = Utils.defineClass({ + Name: 'DashToPanel-DragPlaceholderItem', + Extends: St.Widget, + + _init: function(appIcon, iconSize, isVertical) { + this.callParent('_init', { style: AppIcons.getIconContainerStyle(isVertical), layout_manager: new Clutter.BinLayout() }); + + this.child = { _delegate: appIcon }; + + this._clone = new Clutter.Clone({ + source: appIcon.icon._iconBin, + width: iconSize, + height: iconSize + }); + + this.add_actor(this._clone); + }, + + destroy: function() { + this._clone.destroy(); + this.callParent('destroy'); + }, +}); + +function getAppStableSequence(app, monitor) { + let windows = AppIcons.getInterestingWindows(app, monitor); + + return windows.reduce((prevWindow, window) => { + return Math.min(prevWindow, getWindowStableSequence(window)); + }, Infinity); +} + +function sortWindowsCompareFunction(windowA, windowB) { + return getWindowStableSequence(windowA) - getWindowStableSequence(windowB); +} + +function getWindowStableSequence(window) { + return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence()); +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js new file mode 100644 index 0000000..aa86d7a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js @@ -0,0 +1,269 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Lang = imports.lang; +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const St = imports.gi.St; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +var DynamicTransparency = Utils.defineClass({ + Name: 'DashToPanel.DynamicTransparency', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._proximityManager = dtpPanel.panelManager.proximityManager; + this._proximityWatchId = 0; + this._windowOverlap = false; + this.currentBackgroundColor = 0; + + this._initialPanelStyle = dtpPanel.panel.actor.get_style(); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._initialPanelCornerStyle = dtpPanel.panel._leftCorner.actor.get_style(); + } + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._bindSignals(); + + this._updateAnimationDuration(); + this._updateAllAndSet(); + this._updateProximityWatch(); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._proximityManager.removeWatch(this._proximityWatchId); + + this._dtpPanel.panel.actor.set_style(this._initialPanelStyle); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(this._initialPanelCornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(this._initialPanelCornerStyle); + } + }, + + updateExternalStyle: function() { + this._updateComplementaryStyles(); + this._setBackground(); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + Utils.getStageTheme(), + 'changed', + () => this._updateAllAndSet() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-bg', + 'changed::trans-bg-color' + ], + () => this._updateColorAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-opacity', + 'changed::trans-panel-opacity', + 'changed::trans-bg-color', + 'changed::trans-dynamic-anim-target', + 'changed::trans-use-dynamic-opacity' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-gradient', + 'changed::trans-gradient-top-color', + 'changed::trans-gradient-bottom-color', + 'changed::trans-gradient-top-opacity', + 'changed::trans-gradient-bottom-opacity' + ], + () => this._updateGradientAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-dynamic-behavior', + 'changed::trans-use-dynamic-opacity', + 'changed::trans-dynamic-distance' + ], + () => this._updateProximityWatch() + ], + [ + Me.settings, + 'changed::trans-dynamic-anim-time', + () => this._updateAnimationDuration() + ] + ); + }, + + _updateProximityWatch: function() { + this._proximityManager.removeWatch(this._proximityWatchId); + + if (Me.settings.get_boolean('trans-use-dynamic-opacity')) { + let isVertical = this._dtpPanel.checkIfVertical(); + let threshold = Me.settings.get_int('trans-dynamic-distance'); + + this._proximityWatchId = this._proximityManager.createWatch( + this._dtpPanel.panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('trans-dynamic-behavior')], + isVertical ? threshold : 0, + isVertical ? 0 : threshold, + overlap => { + this._windowOverlap = overlap; + this._updateAlphaAndSet(); + } + ); + } + }, + + _updateAnimationDuration: function() { + this.animationDuration = (Me.settings.get_int('trans-dynamic-anim-time') * 0.001) + 's;'; + }, + + _updateAllAndSet: function() { + let themeBackground = this._getThemeBackground(true); + + this._updateColor(themeBackground); + this._updateAlpha(themeBackground); + this._updateComplementaryStyles(); + this._updateGradient(); + this._setBackground(); + this._setGradient(); + }, + + _updateColorAndSet: function() { + this._updateColor(); + this._setBackground(); + }, + + _updateAlphaAndSet: function() { + this._updateAlpha(); + this._setBackground(); + }, + + _updateGradientAndSet: function() { + this._updateGradient(); + this._setGradient(); + }, + + _updateComplementaryStyles: function() { + let panelThemeNode = this._dtpPanel.panel.actor.get_theme_node(); + + this._complementaryStyles = 'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;'; + }, + + _updateColor: function(themeBackground) { + this.backgroundColorRgb = Me.settings.get_boolean('trans-use-custom-bg') ? + Me.settings.get_string('trans-bg-color') : + (themeBackground || this._getThemeBackground()); + }, + + _updateAlpha: function(themeBackground) { + if (this._windowOverlap && !Main.overview.visibleTarget && Me.settings.get_boolean('trans-use-dynamic-opacity')) { + this.alpha = Me.settings.get_double('trans-dynamic-anim-target'); + } else { + this.alpha = Me.settings.get_boolean('trans-use-custom-opacity') ? + Me.settings.get_double('trans-panel-opacity') : + (themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569 + } + }, + + _updateGradient: function() { + this._gradientStyle = ''; + + if (Me.settings.get_boolean('trans-use-custom-gradient')) { + this._gradientStyle += 'background-gradient-direction: ' + (this._dtpPanel.checkIfVertical() ? 'horizontal;' : 'vertical;') + + 'background-gradient-start: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-top-color'), + Me.settings.get_double('trans-gradient-top-opacity')) + + 'background-gradient-end: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-bottom-color'), + Me.settings.get_double('trans-gradient-bottom-opacity')); + } + }, + + _setBackground: function() { + this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha); + + let transition = 'transition-duration:' + this.animationDuration; + let cornerStyle = '-panel-corner-background-color: ' + this.currentBackgroundColor + transition; + + this._dtpPanel.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(cornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(cornerStyle); + } + }, + + _setGradient: function() { + this._dtpPanel.panel.actor.set_style( + 'background: none; ' + + 'border-image: none; ' + + 'background-image: none; ' + + this._gradientStyle + + 'transition-duration:' + this.animationDuration + ); + }, + + _getThemeBackground: function(reload) { + if (reload || !this._themeBackground) { + let fakePanel = new St.Bin({ name: 'panel' }); + Main.uiGroup.add_child(fakePanel); + let fakeTheme = fakePanel.get_theme_node() + this._themeBackground = this._getBackgroundImageColor(fakeTheme) || fakeTheme.get_background_color(); + Main.uiGroup.remove_child(fakePanel); + } + + return this._themeBackground; + }, + + _getBackgroundImageColor: function(theme) { + let bg = null; + + try { + let imageFile = theme.get_background_image() || theme.get_border_image().get_file(); + + if (imageFile) { + let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path()); + let pixels = imageBuf.get_pixels(); + + bg = { red: pixels[0], green: pixels[1], blue: pixels[2], alpha: pixels[3] }; + } + } catch (error) {} + + return bg; + } +}); \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js new file mode 100644 index 0000000..d90d2cc --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js @@ -0,0 +1,1040 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gi = imports._gi; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const Main = imports.ui.main; +const MessageTray = imports.ui.messageTray; +const Util = imports.misc.util; + +var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain']; +var SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1); + +//Clutter implicit animations are available since 3.34 +//prefer those over Tweener if available +if (Config.PACKAGE_VERSION < '3.34') { + var Tweener = imports.ui.tweener; +} + +var defineClass = function (classDef) { + let parentProto = classDef.Extends ? classDef.Extends.prototype : null; + + if (Config.PACKAGE_VERSION < '3.31.9') { + if (parentProto && (classDef.Extends.name || classDef.Extends.toString()).indexOf('DashToPanel.') < 0) { + classDef.callParent = function() { + let args = Array.prototype.slice.call(arguments); + let func = args.shift(); + + classDef.Extends.prototype[func].apply(this, args); + }; + } + + return new imports.lang.Class(classDef); + } + + let isGObject = parentProto instanceof GObject.Object; + let needsSuper = parentProto && !isGObject; + let getParentArgs = function(args) { + let parentArgs = []; + + (classDef.ParentConstrParams || parentArgs).forEach(p => { + if (p.constructor === Array) { + let param = args[p[0]]; + + parentArgs.push(p[1] ? param[p[1]] : param); + } else { + parentArgs.push(p); + } + }); + + return parentArgs; + }; + + let C = eval( + '(class C ' + (needsSuper ? 'extends Object' : '') + ' { ' + + ' constructor(...args) { ' + + (needsSuper ? 'super(...getParentArgs(args));' : '') + + (needsSuper || !parentProto ? 'this._init(...args);' : '') + + ' }' + + ' callParent(...args) { ' + + ' let func = args.shift(); ' + + ' if (!(func === \'_init\' && needsSuper))' + + ' super[func](...args); ' + + ' }' + + '})' + ); + + if (parentProto) { + Object.setPrototypeOf(C.prototype, parentProto); + Object.setPrototypeOf(C, classDef.Extends); + } + + Object.defineProperty(C, 'name', { value: classDef.Name }); + Object.keys(classDef) + .filter(k => classDef.hasOwnProperty(k) && classDef[k] instanceof Function) + .forEach(k => C.prototype[k] = classDef[k]); + + if (isGObject) { + C = GObject.registerClass({ Signals: classDef.Signals || {} }, C); + } + + return C; +}; + +// simplify global signals and function injections handling +// abstract class +var BasicHandler = defineClass({ + Name: 'DashToPanel.BasicHandler', + + _init: function(){ + this._storage = new Object(); + }, + + add: function(/*unlimited 3-long array arguments*/){ + + // convert arguments object to array, concatenate with generic + let args = [].concat('generic', [].slice.call(arguments)); + // call addWithLabel with ags as if they were passed arguments + this.addWithLabel.apply(this, args); + }, + + destroy: function() { + for( let label in this._storage ) + this.removeWithLabel(label); + }, + + addWithLabel: function( label /* plus unlimited 3-long array arguments*/) { + + if(this._storage[label] == undefined) + this._storage[label] = new Array(); + + // skip first element of the arguments + for( let i = 1; i < arguments.length; i++ ) { + let item = this._storage[label]; + let handlers = this._create(arguments[i]); + + for (let j = 0, l = handlers.length; j < l; ++j) { + item.push(handlers[j]); + } + } + + }, + + removeWithLabel: function(label){ + + if(this._storage[label]) { + for( let i = 0; i < this._storage[label].length; i++ ) { + this._remove(this._storage[label][i]); + } + + delete this._storage[label]; + } + }, + + /* Virtual methods to be implemented by subclass */ + // create single element to be stored in the storage structure + _create: function(item){ + throw new Error('no implementation of _create in ' + this); + }, + + // correctly delete single element + _remove: function(item){ + throw new Error('no implementation of _remove in ' + this); + } +}); + +// Manage global signals +var GlobalSignalsHandler = defineClass({ + Name: 'DashToPanel.GlobalSignalsHandler', + Extends: BasicHandler, + + _create: function(item) { + let handlers = []; + + item[1] = [].concat(item[1]); + + for (let i = 0, l = item[1].length; i < l; ++i) { + let object = item[0]; + let event = item[1][i]; + let callback = item[2] + try { + let id = object.connect(event, callback); + + handlers.push([object, id]); + } catch (e) + { + + } + } + + return handlers; + }, + + _remove: function(item){ + item[0].disconnect(item[1]); + } +}); + +/** + * Manage function injection: both instances and prototype can be overridden + * and restored + */ +var InjectionsHandler = defineClass({ + Name: 'DashToPanel.InjectionsHandler', + Extends: BasicHandler, + + _create: function(item) { + let object = item[0]; + let name = item[1]; + let injectedFunction = item[2]; + let original = object[name]; + + object[name] = injectedFunction; + return [[object, name, injectedFunction, original]]; + }, + + _remove: function(item) { + let object = item[0]; + let name = item[1]; + let original = item[3]; + object[name] = original; + } +}); + +/** + * Manage timeouts: the added timeouts have their id reset on completion + */ +var TimeoutsHandler = defineClass({ + Name: 'DashToPanel.TimeoutsHandler', + Extends: BasicHandler, + + _create: function(item) { + let name = item[0]; + let delay = item[1]; + let timeoutHandler = item[2]; + + this._remove(item); + + this[name] = Mainloop.timeout_add(delay, () => { + this[name] = 0; + timeoutHandler(); + }); + + return [[name]]; + }, + + remove: function(name) { + this._remove([name]) + }, + + _remove: function(item) { + let name = item[0]; + + if (this[name]) { + Mainloop.source_remove(this[name]); + this[name] = 0; + } + }, + + getId: function(name) { + return this[name] ? this[name] : 0; + } +}); + +// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as +// previous versions. +var DisplayWrapper = { + getScreen: function() { + return global.screen || global.display; + }, + + getWorkspaceManager: function() { + return global.screen || global.workspace_manager; + }, + + getMonitorManager: function() { + return global.screen || Meta.MonitorManager.get(); + } +}; + +var getCurrentWorkspace = function() { + return DisplayWrapper.getWorkspaceManager().get_active_workspace(); +}; + +var getWorkspaceByIndex = function(index) { + return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index); +}; + +var getWorkspaceCount = function() { + return DisplayWrapper.getWorkspaceManager().n_workspaces; +}; + +var getStageTheme = function() { + return St.ThemeContext.get_for_stage(global.stage); +}; + +var getScaleFactor = function() { + return getStageTheme().scale_factor || 1; +}; + +var getAppDisplayViews = function() { + //gnome-shell 3.38 only has one view and it is now the appDisplay + return imports.ui.appDisplay._views || [{ view: imports.ui.appDisplay }]; +}; + +var findIndex = function(array, predicate) { + if (Array.prototype.findIndex) { + return array.findIndex(predicate); + } + + for (let i = 0, l = array.length; i < l; ++i) { + if (predicate(array[i])) { + return i; + } + } + + return -1; +}; + +var find = function(array, predicate) { + let index = findIndex(array, predicate); + + if (index > -1) { + return array[index]; + } +}; + +var mergeObjects = function(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +var hookVfunc = function(proto, symbol, func) { + if (Gi.hook_up_vfunc_symbol && func) { + //gjs > 1.53.3 + proto[Gi.hook_up_vfunc_symbol](symbol, func); + } else { + //On older gjs, this is how to hook vfunc. It is buggy and can't be used reliably to replace + //already hooked functions. Since it's our only use for it, disabled for now (and probably forever) + //Gi.hook_up_vfunc(proto, symbol, func); + } +}; + +var wrapActor = function(actor) { + if (actor) { + Object.defineProperty(actor, 'actor', { + value: actor instanceof Clutter.Actor ? actor : actor.actor + }); + } +}; + +var getTransformedAllocation = function(actor) { + if (Config.PACKAGE_VERSION < '3.37') { + return Shell.util_get_transformed_allocation(actor); + } + + let extents = actor.get_transformed_extents(); + let topLeft = extents.get_top_left(); + let bottomRight = extents.get_bottom_right(); + + return { x1: topLeft.x, x2: bottomRight.x, y1: topLeft.y, y2: bottomRight.y }; +}; + +var allocate = function(actor, box, flags, useParent) { + let allocateObj = useParent ? actor.__proto__ : actor; + + allocateObj.allocate.apply(actor, getAllocationParams(box, flags)); +}; + +var setAllocation = function(actor, box, flags) { + actor.set_allocation.apply(actor, getAllocationParams(box, flags)); +}; + +var getAllocationParams = function(box, flags) { + let params = [box]; + + if (Config.PACKAGE_VERSION < '3.37') { + params.push(flags); + } + + return params; +}; + +var setClip = function(actor, x, y, width, height) { + actor.set_clip(0, 0, width, height); + actor.set_position(x, y); + actor.set_size(width, height); +}; + +var addKeybinding = function(key, settings, handler, modes) { + if (!Main.wm._allowedKeybindings[key]) { + Main.wm.addKeybinding( + key, + settings, + Meta.KeyBindingFlags.NONE, + modes || (Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW), + handler + ); + } +}; + +var removeKeybinding = function(key) { + if (Main.wm._allowedKeybindings[key]) { + Main.wm.removeKeybinding(key); + } +}; + +var getrgbColor = function(color) { + color = typeof color === 'string' ? Clutter.color_from_string(color)[1] : color; + + return { red: color.red, green: color.green, blue: color.blue }; +}; + +var getrgbaColor = function(color, alpha, offset) { + if (alpha <= 0) { + return 'transparent; '; + } + + let rgb = getrgbColor(color); + + if (offset) { + ['red', 'green', 'blue'].forEach(k => { + rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset)); + + if (rgb[k] == color[k]) { + rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset)); + } + }); + } + + return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; +}; + +var checkIfColorIsBright = function(color) { + let rgb = getrgbColor(color); + let brightness = 0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue; + + return brightness > 128; +}; + +var getMouseScrollDirection = function(event) { + let direction; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + direction = 'up'; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + direction = 'down'; + break; + } + + return direction; +}; + +var checkIfWindowHasTransient = function(window) { + let hasTransient; + + window.foreach_transient(t => !(hasTransient = true)); + + return hasTransient; +}; + +var activateSiblingWindow = function(windows, direction, startWindow) { + let windowIndex = windows.indexOf(global.display.focus_window); + let nextWindowIndex = windowIndex < 0 ? + startWindow ? windows.indexOf(startWindow) : 0 : + windowIndex + (direction == 'up' ? 1 : -1); + + if (nextWindowIndex == windows.length) { + nextWindowIndex = 0; + } else if (nextWindowIndex < 0) { + nextWindowIndex = windows.length - 1; + } + + if (windowIndex != nextWindowIndex) { + Main.activateWindow(windows[nextWindowIndex]); + } +}; + +var animateWindowOpacity = function(window, tweenOpts) { + //there currently is a mutter bug with the windowactor opacity, starting with 3.34 + //https://gitlab.gnome.org/GNOME/mutter/issues/836 + + if (Config.PACKAGE_VERSION > '3.35') { + //on 3.36, a workaround is to use the windowactor's child for the fade animation + //this leaves a "shadow" on the desktop, so the windowactor needs to be hidden + //when the animation is complete + let visible = tweenOpts.opacity > 0; + let windowActor = window; + + window = windowActor.get_first_child() || windowActor; + + if (!windowActor.visible && visible) { + window.opacity = 0; + windowActor.visible = visible; + } + + if (!visible) { + let initialOpacity = window.opacity; + + tweenOpts.onComplete = () => { + windowActor.visible = visible; + window.opacity = initialOpacity; + }; + } + } else if (Config.PACKAGE_VERSION > '3.33') { + //the workaround only works on 3.35+, so on 3.34, let's just hide the + //window without animation + return window.visible = (tweenOpts.opacity == 255); + } + + animate(window, tweenOpts); +}; + +var animate = function(actor, options) { + if (Tweener) { + return Tweener.addTween(actor, options); + } + + //to support both Tweener and Clutter animations, we use Tweener "time" + //and "delay" properties defined in seconds, as opposed to Clutter animations + //"duration" and "delay" which are defined in milliseconds + if (options.delay) { + options.delay = options.delay * 1000; + } + + options.duration = options.time * 1000; + delete options.time; + + if (options.transition) { + //map Tweener easing equations to Clutter animation modes + options.mode = { + 'easeInCubic': Clutter.AnimationMode.EASE_IN_CUBIC, + 'easeInOutCubic': Clutter.AnimationMode.EASE_IN_OUT_CUBIC, + 'easeInOutQuad': Clutter.AnimationMode.EASE_IN_OUT_QUAD, + 'easeOutQuad': Clutter.AnimationMode.EASE_OUT_QUAD + }[options.transition] || Clutter.AnimationMode.LINEAR; + + delete options.transition; + } + + let params = [options]; + + if ('value' in options && actor instanceof St.Adjustment) { + params.unshift(options.value); + delete options.value; + } + + actor.ease.apply(actor, params); +} + +var isAnimating = function(actor, prop) { + if (Tweener) { + return Tweener.isTweening(actor); + } + + return !!actor.get_transition(prop); +} + +var stopAnimations = function(actor) { + if (Tweener) { + return Tweener.removeTweens(actor); + } + + actor.remove_all_transitions(); +} + +var getIndicators = function(delegate) { + if (delegate instanceof St.BoxLayout) { + return delegate; + } + + return delegate.indicators; +} + +var getPoint = function(coords) { + if (Config.PACKAGE_VERSION > '3.35.1') { + return new imports.gi.Graphene.Point(coords); + } + + return new Clutter.Point(coords); +} + +var getPanelGhost = function() { + if (!Main.overview._panelGhost) { + return Main.overview._overview.get_first_child(); + } + + return Main.overview._panelGhost; +} + +var notify = function(text, iconName, action, isTransient) { + let source = new MessageTray.SystemNotificationSource(); + let notification = new MessageTray.Notification(source, 'Dash to Panel', text); + let notifyFunc = source.showNotification || source.notify; + + if (iconName) { + source.createIcon = function() { + return new St.Icon({ icon_name: iconName }); + }; + } + + if (action) { + if (!(action instanceof Array)) { + action = [action]; + } + + action.forEach(a => notification.addAction(a.text, a.func)); + } + + Main.messageTray.add(source); + + notification.setTransient(isTransient); + notifyFunc.call(source, notification); +}; + +/* + * This is a copy of the same function in utils.js, but also adjust horizontal scrolling + * and perform few further cheks on the current value to avoid changing the values when + * it would be clamp to the current one in any case. + * Return the amount of shift applied +*/ +var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) { + let vadjustment = scrollView.vscroll.adjustment; + let hadjustment = scrollView.hscroll.adjustment; + let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values(); + let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values(); + + let [hvalue0, vvalue0] = [hvalue, vvalue]; + + let voffset = fadeSize; + let hoffset = fadeSize; + + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2; + + let parent = actor.get_parent(); + while (parent != scrollView) { + if (!parent) + throw new Error("actor not in scroll view"); + + let box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + x1 += box.x1; + x2 += box.x1; + parent = parent.get_parent(); + } + + if (y1 < vvalue + voffset) + vvalue = Math.max(0, y1 - voffset); + else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset) + vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize); + + if (x1 < hvalue + hoffset) + hvalue = Math.max(0, x1 - hoffset); + else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset) + hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize); + + let tweenOpts = { + time: SCROLL_TIME, + onComplete: onComplete || (() => {}), + transition: 'easeOutQuad' + }; + + if (vvalue !== vvalue0) { + animate(vadjustment, mergeObjects(tweenOpts, { value: vvalue })); + } + + if (hvalue !== hvalue0) { + animate(hadjustment, mergeObjects(tweenOpts, { value: hvalue })); + } + + return [hvalue- hvalue0, vvalue - vvalue0]; +} + +/** + * ColorUtils is adapted from https://github.com/micheleg/dash-to-dock + */ +var ColorUtils = { + colorLuminance: function(r, g, b, dlum) { + // Darken or brighten color by a fraction dlum + // Each rgb value is modified by the same fraction. + // Return "#rrggbb" strin + + let rgbString = '#'; + + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2); + + return rgbString; + }, + + _decimalToHex: function(d, padding) { + // Convert decimal to an hexadecimal string adding the desired padding + + let hex = d.toString(16); + while (hex.length < padding) + hex = '0'+ hex; + return hex; + }, + + HSVtoRGB: function(h, s, v) { + // Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (h,s,v) independently or {h:h, s:s, v:v} object. + // Return {r:r, g:g, b:b} object. + + if (arguments.length === 1) { + s = h.s; + v = h.v; + h = h.h; + } + + let r,g,b; + let c = v*s; + let h1 = h*6; + let x = c*(1 - Math.abs(h1 % 2 - 1)); + let m = v - c; + + if (h1 <=1) + r = c + m, g = x + m, b = m; + else if (h1 <=2) + r = x + m, g = c + m, b = m; + else if (h1 <=3) + r = m, g = c + m, b = x + m; + else if (h1 <=4) + r = m, g = x + m, b = c + m; + else if (h1 <=5) + r = x + m, g = m, b = c + m; + else + r = c + m, g = m, b = x + m; + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; + }, + + RGBtoHSV: function(r, g, b) { + // Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (r,g,b) independently or {r:r, g:g, b:b} object. + // Return {h:h, s:s, v:v} object. + + if (arguments.length === 1) { + r = r.r; + g = r.g; + b = r.b; + } + + let h,s,v; + + let M = Math.max(r, g, b); + let m = Math.min(r, g, b); + let c = M - m; + + if (c == 0) + h = 0; + else if (M == r) + h = ((g-b)/c) % 6; + else if (M == g) + h = (b-r)/c + 2; + else + h = (r-g)/c + 4; + + h = h/6; + v = M/255; + if (M !== 0) + s = c/M; + else + s = 0; + + return {h: h, s: s, v: v}; + } +}; + +/** + * DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock + */ +let themeLoader = null; +let iconCacheMap = new Map(); +const MAX_CACHED_ITEMS = 1000; +const BATCH_SIZE_TO_DELETE = 50; +const DOMINANT_COLOR_ICON_SIZE = 64; + +var DominantColorExtractor = defineClass({ + Name: 'DashToPanel.DominantColorExtractor', + + _init: function(app){ + this._app = app; + }, + + /** + * Try to get the pixel buffer for the current icon, if not fail gracefully + */ + _getIconPixBuf: function() { + let iconTexture = this._app.create_icon_texture(16); + + if (themeLoader === null) { + let ifaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" }); + + themeLoader = new Gtk.IconTheme(), + themeLoader.set_custom_theme(ifaceSettings.get_string('icon-theme')); // Make sure the correct theme is loaded + } + + // Unable to load the icon texture, use fallback + if (iconTexture instanceof St.Icon === false) { + return null; + } + + iconTexture = iconTexture.get_gicon(); + + // Unable to load the icon texture, use fallback + if (iconTexture === null) { + return null; + } + + if (iconTexture instanceof Gio.FileIcon) { + // Use GdkPixBuf to load the pixel buffer from the provided file path + return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path()); + } + + // Get the pixel buffer from the icon theme + let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0); + if (icon_info !== null) + return icon_info.load_icon(); + else + return null; + }, + + /** + * The backlight color choosing algorithm was mostly ported to javascript from the + * Unity7 C++ source of Canonicals: + * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp + * so it more or less works the same way. + */ + _getColorPalette: function() { + if (iconCacheMap.get(this._app.get_id())) { + // We already know the answer + return iconCacheMap.get(this._app.get_id()); + } + + let pixBuf = this._getIconPixBuf(); + if (pixBuf == null) + return null; + + let pixels = pixBuf.get_pixels(), + offset = 0; + + let total = 0, + rTotal = 0, + gTotal = 0, + bTotal = 0; + + let resample_y = 1, + resample_x = 1; + + // Resampling of large icons + // We resample icons larger than twice the desired size, as the resampling + // to a size s + // DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE, + // most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally + // a multiple of it. + let width = pixBuf.get_width(); + let height = pixBuf.get_height(); + + // Resample + if (height >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE); + + if (width >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE); + + if (resample_x !==1 || resample_y !== 1) + pixels = this._resamplePixels(pixels, resample_x, resample_y); + + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length; + for (let offset = 0; offset < limit; offset+=4) { + let r = pixels[offset], + g = pixels[offset + 1], + b = pixels[offset + 2], + a = pixels[offset + 3]; + + let saturation = (Math.max(r,g, b) - Math.min(r,g, b)); + let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation; + + rTotal += r * relevance; + gTotal += g * relevance; + bTotal += b * relevance; + + total += relevance; + } + + total = total * 255; + + let r = rTotal / total, + g = gTotal / total, + b = bTotal / total; + + let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255); + + if (hsv.s > 0.15) + hsv.s = 0.65; + hsv.v = 0.90; + + let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v); + + // Cache the result. + let backgroundColor = { + lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2), + original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0), + darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5) + }; + + if (iconCacheMap.size >= MAX_CACHED_ITEMS) { + //delete oldest cached values (which are in order of insertions) + let ctr=0; + for (let key of iconCacheMap.keys()) { + if (++ctr > BATCH_SIZE_TO_DELETE) + break; + iconCacheMap.delete(key); + } + } + + iconCacheMap.set(this._app.get_id(), backgroundColor); + + return backgroundColor; + }, + + /** + * Downsample large icons before scanning for the backlight color to + * improve performance. + * + * @param pixBuf + * @param pixels + * @param resampleX + * @param resampleY + * + * @return []; + */ + _resamplePixels: function (pixels, resampleX, resampleY) { + let resampledPixels = []; + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length / (resampleX * resampleY) / 4; + for (let i = 0; i < limit; i++) { + let pixel = i * resampleX * resampleY; + + resampledPixels.push(pixels[pixel * 4]); + resampledPixels.push(pixels[pixel * 4 + 1]); + resampledPixels.push(pixels[pixel * 4 + 2]); + resampledPixels.push(pixels[pixel * 4 + 3]); + } + + return resampledPixels; + } + +}); + +var drawRoundedLine = function(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { + if (height > width) { + y += Math.floor((height - width) / 2.0); + height = width; + } + + height = 2.0 * Math.floor(height / 2.0); + + var leftRadius = isRoundLeft ? height / 2.0 : 0.0; + var rightRadius = isRoundRight ? height / 2.0 : 0.0; + + cr.moveTo(x + width - rightRadius, y); + cr.lineTo(x + leftRadius, y); + if (isRoundLeft) + cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2); + else + cr.lineTo(x, y + height); + cr.lineTo(x + width - rightRadius, y + height); + if (isRoundRight) + cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2); + else + cr.lineTo(x + width, y); + cr.closePath(); + + if (fill != null) { + cr.setSource(fill); + cr.fillPreserve(); + } + if (stroke != null) + cr.setSource(stroke); + cr.stroke(); +} + +/** + * Check if an app exists in the system. + */ +var checkedCommandsMap = new Map(); + +function checkIfCommandExists(app) { + let answer = checkedCommandsMap.get(app); + if (answer === undefined) { + // Command is a shell built in, use shell to call it. + // Quotes around app value are important. They let command operate + // on the whole value, instead of having shell interpret it. + let cmd = "sh -c 'command -v \"" + app + "\"'"; + try { + let out = GLib.spawn_command_line_sync(cmd); + // out contains 1: stdout, 2: stderr, 3: exit code + answer = out[3] == 0; + } catch (ex) { + answer = false; + } + + checkedCommandsMap.set(app, answer); + } + return answer; +} diff --git a/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js new file mode 100644 index 0000000..45d08a0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js @@ -0,0 +1,1145 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Meta = imports.gi.Meta; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +//timeout intervals +const ENSURE_VISIBLE_MS = 200; + +//timeout names +const T1 = 'openMenuTimeout'; +const T2 = 'closeMenuTimeout'; +const T3 = 'peekTimeout'; +const T4 = 'ensureVisibleTimeout'; + +const MAX_TRANSLATION = 40; +const HEADER_HEIGHT = 38; +const MAX_CLOSE_BUTTON_SIZE = 30; +const MIN_DIMENSION = 100; +const FOCUSED_COLOR_OFFSET = 24; +const HEADER_COLOR_OFFSET = -12; +const FADE_SIZE = 36; +const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; + +let headerHeight = 0; +let alphaBg = 0; +let isLeftButtons = false; +let isTopHeader = true; +let isManualStyling = false; +let scaleFactor = 1; +let animationTime = 0; +let aspectRatio = {}; + +var PreviewMenu = Utils.defineClass({ + Name: 'DashToPanel-PreviewMenu', + Extends: St.Widget, + Signals: { 'open-state-changed': {} }, + + _init: function(panel) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + let geom = panel.geom; + this.panel = panel; + this.currentAppIcon = null; + this._focusedPreview = null; + this._peekedWindow = null; + this.peekInitialWorkspaceIndex = -1; + this.opened = false; + this.isVertical = geom.position == St.Side.LEFT || geom.position == St.Side.RIGHT; + this._translationProp = 'translation_' + (this.isVertical ? 'x' : 'y'); + this._translationDirection = (geom.position == St.Side.TOP || geom.position == St.Side.LEFT ? -1 : 1); + this._translationOffset = Math.min(panel.dtpSize, MAX_TRANSLATION) * this._translationDirection; + + this.menu = new St.Widget({ + name: 'preview-menu', + layout_manager: new Clutter.BinLayout(), + reactive: true, + track_hover: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign[geom.position != St.Side.RIGHT ? 'START' : 'END'], + y_align: Clutter.ActorAlign[geom.position != St.Side.BOTTOM ? 'START' : 'END'] + }); + this._box = new St.BoxLayout({ vertical: this.isVertical }); + this._scrollView = new St.ScrollView({ + name: 'dashtopanelPreviewScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true, + y_expand: !this.isVertical + }); + + this._scrollView.add_actor(this._box); + this.menu.add_child(this._scrollView); + this.add_child(this.menu); + }, + + enable: function() { + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + Main.layoutManager.addChrome(this, { affectsInputRegion: false }); + Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); + + this._resetHiddenState(); + this._refreshGlobals(); + this._updateClip(); + this.menu.set_position(1, 1); + + this._signalsHandler.add( + [ + this.menu, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._scrollView, + 'scroll-event', + this._onScrollEvent.bind(this) + ], + [ + this.panel.panelBox, + 'style-changed', + () => this._updateClip() + ], + [ + Utils.DisplayWrapper.getScreen(), + 'in-fullscreen-changed', + () => { + if (global.display.focus_window && global.display.focus_window.is_fullscreen()) { + this.close(true); + } + } + ], + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::window-preview-size', + 'changed::window-preview-padding', + 'changed::window-preview-show-title' + ], + () => { + this._refreshGlobals(); + this._updateClip(); + } + ] + ); + }, + + disable: function() { + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + + this.close(true); + + Main.layoutManager.untrackChrome(this.menu); + Main.layoutManager.removeChrome(this); + }, + + requestOpen: function(appIcon) { + let timeout = Me.settings.get_int('show-window-previews-timeout'); + + if (this.opened) { + timeout = Math.min(100, timeout); + } + + this._endOpenCloseTimeouts(); + this._timeoutsHandler.add([T1, timeout, () => this.open(appIcon)]); + }, + + requestClose: function() { + this._endOpenCloseTimeouts(); + this._addCloseTimeout(); + }, + + open: function(appIcon) { + if (this.currentAppIcon != appIcon) { + this.currentAppIcon = appIcon; + + if (!this.opened) { + this._refreshGlobals(); + + this.set_height(this.clipHeight); + this.menu.show(); + + setStyle(this.menu, 'background: ' + Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, alphaBg)); + } + + this._mergeWindows(appIcon); + this._updatePosition(); + this._animateOpenOrClose(true); + + this._setReactive(true); + this._setOpenedState(true); + } + }, + + close: function(immediate) { + this._endOpenCloseTimeouts(); + this._removeFocus(); + this._endPeek(); + + if (immediate) { + Utils.stopAnimations(this.menu); + this._resetHiddenState(); + } else { + this._animateOpenOrClose(false, () => this._resetHiddenState()); + } + + this._setReactive(false); + this.currentAppIcon = null; + }, + + update: function(appIcon, windows) { + if (this.currentAppIcon == appIcon) { + if (windows && !windows.length) { + this.close(); + } else { + this._addAndRemoveWindows(windows); + this._updatePosition(); + } + } + }, + + updatePosition: function() { + this._updatePosition(); + }, + + focusNext: function() { + let previews = this._box.get_children(); + let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1; + let nextIndex = currentIndex + 1; + + nextIndex = previews[nextIndex] ? nextIndex : 0; + + if (previews[nextIndex]) { + this._removeFocus(); + previews[nextIndex].setFocus(true); + this._focusedPreview = previews[nextIndex]; + } + + return nextIndex; + }, + + activateFocused: function() { + if (this.opened && this._focusedPreview) { + this._focusedPreview.activate(); + } + }, + + requestPeek: function(window) { + this._timeoutsHandler.remove(T3); + + if (Me.settings.get_boolean('peek-mode')) { + if (this.peekInitialWorkspaceIndex < 0) { + this._timeoutsHandler.add([T3, Me.settings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]); + } else { + this._peek(window); + } + } + }, + + endPeekHere: function() { + this._endPeek(true); + }, + + ensureVisible: function(preview) { + let [ , upper, pageSize] = this._getScrollAdjustmentValues(); + + if (upper > pageSize) { + this._timeoutsHandler.add([ + T4, + ENSURE_VISIBLE_MS, + () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION, () => this._updateScrollFade()) + ]); + } + }, + + getCurrentAppIcon: function() { + return this.currentAppIcon; + }, + + _setReactive: function(reactive) {  + this._box.get_children().forEach(c => c.reactive = reactive); + this.menu.reactive = reactive; + }, + + _setOpenedState: function(opened) { + this.opened = opened; + this.emit('open-state-changed'); + }, + + _resetHiddenState: function() { + this.menu.hide(); + this.set_height(0); + this._setOpenedState(false); + this.menu.opacity = 0; + this.menu[this._translationProp] = this._translationOffset; + this._box.get_children().forEach(c => c.destroy()); + }, + + _removeFocus: function() { + if (this._focusedPreview) { + this._focusedPreview.setFocus(false); + this._focusedPreview = null; + } + }, + + _mergeWindows: function(appIcon, windows) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + windows.sort(Taskbar.sortWindowsCompareFunction); + + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); + + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i]) { + currentPreviews[i].assignWindow(windows[i], this.opened); + } else if (!currentPreviews[i]) { + this._addNewPreview(windows[i]); + } else if (!windows[i]) { + currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); + } + } + }, + + _addAndRemoveWindows: function(windows) { + let currentPreviews = this._box.get_children(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + + for (let i = 0, l = windows.length; i < l; ++i) { + let currentIndex = Utils.findIndex(currentPreviews, c => c.window == windows[i]); + + if (currentIndex < 0) { + this._addNewPreview(windows[i]); + } else { + currentPreviews[currentIndex].assignWindow(windows[i]); + currentPreviews.splice(currentIndex, 1); + + if (this._peekedWindow && this._peekedWindow == windows[i]) { + this.requestPeek(windows[i]); + } + } + } + + currentPreviews.forEach(c => c.animateOut()); + }, + + _addNewPreview: function(window) { + let preview = new Preview(this); + + this._box.add_child(preview); + preview.adjustOnStage(); + preview.assignWindow(window, this.opened); + }, + + _addCloseTimeout: function() { + this._timeoutsHandler.add([T2, Me.settings.get_int('leave-timeout'), () => this.close()]); + }, + + _onHoverChanged: function() { + this._endOpenCloseTimeouts(); + + if (this.currentAppIcon && !this.menu.hover) { + this._addCloseTimeout(); + this._endPeek(); + } + }, + + _onScrollEvent: function(actor, event) { + if (!event.is_pointer_emulated()) { + let vOrh = this.isVertical ? 'v' : 'h'; + let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment(); + let increment = adjustment.step_increment; + let delta = increment; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + delta = -increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy * increment; + delta += dx * increment; + break; + } + + adjustment.set_value(adjustment.get_value() + delta); + this._updateScrollFade(); + } + + return Clutter.EVENT_STOP; + }, + + _endOpenCloseTimeouts: function() { + this._timeoutsHandler.remove(T1); + this._timeoutsHandler.remove(T2); + this._timeoutsHandler.remove(T4); + }, + + _refreshGlobals: function() { + isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + isTopHeader = Me.settings.get_string('window-preview-title-position') == 'TOP'; + isManualStyling = Me.settings.get_boolean('window-preview-manual-styling'); + scaleFactor = Utils.getScaleFactor(); + headerHeight = Me.settings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; + animationTime = Me.settings.get_int('window-preview-animation-time') * .001; + aspectRatio.x = { + size: Me.settings.get_int('window-preview-aspect-ratio-x'), + fixed: Me.settings.get_boolean('window-preview-fixed-x') + }; + aspectRatio.y = { + size: Me.settings.get_int('window-preview-aspect-ratio-y'), + fixed: Me.settings.get_boolean('window-preview-fixed-y') + }; + + alphaBg = Me.settings.get_boolean('preview-use-custom-opacity') ? + Me.settings.get_int('preview-custom-opacity') * .01 : + this.panel.dynamicTransparency.alpha; + }, + + _updateClip: function() { + let x, y, w; + let geom = this.panel.getGeometry(); + let panelBoxTheme = this.panel.panelBox.get_theme_node(); + let previewSize = (Me.settings.get_int('window-preview-size') + + Me.settings.get_int('window-preview-padding') * 2) * scaleFactor; + + if (this.isVertical) { + w = previewSize; + this.clipHeight = this.panel.monitor.height; + y = this.panel.monitor.y; + } else { + w = this.panel.monitor.width; + this.clipHeight = (previewSize + headerHeight); + x = this.panel.monitor.x; + } + + if (geom.position == St.Side.LEFT) { + x = this.panel.monitor.x + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.LEFT); + } else if (geom.position == St.Side.RIGHT) { + x = this.panel.monitor.x + this.panel.monitor.width - (this.panel.dtpSize + previewSize) - panelBoxTheme.get_padding(St.Side.RIGHT); + } else if (geom.position == St.Side.TOP) { + y = this.panel.monitor.y + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.TOP); + } else { //St.Side.BOTTOM + y = this.panel.monitor.y + this.panel.monitor.height - (this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.BOTTOM) + previewSize + headerHeight); + } + + Utils.setClip(this, x, y, w, this.clipHeight); + }, + + _updatePosition: function() { + let sourceNode = this.currentAppIcon.actor.get_theme_node(); + let sourceContentBox = sourceNode.get_content_box(this.currentAppIcon.actor.get_allocation_box()); + let sourceAllocation = Utils.getTransformedAllocation(this.currentAppIcon.actor); + let [previewsWidth, previewsHeight] = this._getPreviewsSize(); + let appIconMargin = Me.settings.get_int('appicon-margin') / scaleFactor; + let x = 0, y = 0; + + previewsWidth = Math.min(previewsWidth, this.panel.monitor.width); + previewsHeight = Math.min(previewsHeight, this.panel.monitor.height); + this._updateScrollFade(previewsWidth < this.panel.monitor.width && previewsHeight < this.panel.monitor.height); + + if (this.isVertical) { + y = sourceAllocation.y1 + appIconMargin - this.panel.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; + y = Math.max(y, 0); + y = Math.min(y, this.panel.monitor.height - previewsHeight); + } else { + x = sourceAllocation.x1 + appIconMargin - this.panel.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; + x = Math.max(x, 0); + x = Math.min(x, this.panel.monitor.width - previewsWidth); + } + + if (!this.opened) { + this.menu.set_position(x, y); + this.menu.set_size(previewsWidth, previewsHeight); + } else { + Utils.animate(this.menu, getTweenOpts({ x: x, y: y, width: previewsWidth, height: previewsHeight })); + } + }, + + _updateScrollFade: function(remove) { + let [value, upper, pageSize] = this._getScrollAdjustmentValues(); + let needsFade = Math.round(upper) > Math.round(pageSize); + let fadeWidgets = this.menu.get_children().filter(c => c != this._scrollView); + + if (!remove && needsFade) { + if (!fadeWidgets.length) { + fadeWidgets.push(this._getFadeWidget()); + fadeWidgets.push(this._getFadeWidget(true)); + + this.menu.add_child(fadeWidgets[0]); + this.menu.add_child(fadeWidgets[1]); + } + + fadeWidgets[0].visible = value > 0; + fadeWidgets[1].visible = value + pageSize < upper; + } else if (remove || (!needsFade && fadeWidgets.length)) { + fadeWidgets.forEach(fw => fw.destroy()); + } + }, + + _getScrollAdjustmentValues: function() { + let [value , , upper, , , pageSize] = this._scrollView[(this.isVertical ? 'v' : 'h') + 'scroll'].adjustment.get_values(); + + return [value, upper, pageSize]; + }, + + _getFadeWidget: function(end) { + let x = 0, y = 0; + let startBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, Math.min(alphaBg + .1, 1)); + let endBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, 0) + let fadeStyle = 'background-gradient-start:' + startBg + + 'background-gradient-end:' + endBg + + 'background-gradient-direction:' + this.panel.getOrientation(); + + if (this.isVertical) { + y = end ? this.panel.monitor.height - FADE_SIZE : 0; + } else { + x = end ? this.panel.monitor.width - FADE_SIZE : 0; + } + + let fadeWidget = new St.Widget({ + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: end ? 180 : 0, + style: fadeStyle, + x: x, y: y, + width: this.isVertical ? this.width : FADE_SIZE, + height: this.isVertical ? FADE_SIZE : this.height + }); + + return fadeWidget; + }, + + _getPreviewsSize: function() { + let previewsWidth = 0; + let previewsHeight = 0; + + this._box.get_children().forEach(c => { + if (!c.animatingOut) { + let [width, height] = c.getSize(); + + if (this.isVertical) { + previewsWidth = Math.max(width, previewsWidth); + previewsHeight += height; + } else { + previewsWidth += width; + previewsHeight = Math.max(height, previewsHeight); + } + } + }); + + return [previewsWidth, previewsHeight]; + }, + + _animateOpenOrClose: function(show, onComplete) { + let isTranslationAnimation = this.menu[this._translationProp] != 0; + let tweenOpts = { + opacity: show ? 255 : 0, + transition: show ? 'easeInOutQuad' : 'easeInCubic', + onComplete: () => { + if (isTranslationAnimation) { + Main.layoutManager._queueUpdateRegions(); + } + + (onComplete || (() => {}))(); + } + }; + + tweenOpts[this._translationProp] = show ? this._translationDirection : this._translationOffset; + + Utils.animate(this.menu, getTweenOpts(tweenOpts)); + }, + + _peek: function(window) { + let currentWorkspace = Utils.getCurrentWorkspace(); + let windowWorkspace = window.get_workspace(); + let focusWindow = () => this._focusMetaWindow(Me.settings.get_int('peek-mode-opacity'), window); + + this._restorePeekedWindowStack(); + this._peekedWindow = window; + + if (currentWorkspace != windowWorkspace) { + this._switchToWorkspaceImmediate(windowWorkspace.index()); + this._timeoutsHandler.add([T3, 100, focusWindow]); + } else { + focusWindow(); + } + + if (this.peekInitialWorkspaceIndex < 0) { + this.peekInitialWorkspaceIndex = currentWorkspace.index(); + } + }, + + _endPeek: function(stayHere) { + this._timeoutsHandler.remove(T3); + + if (this._peekedWindow) { + let immediate = !stayHere && this.peekInitialWorkspaceIndex != Utils.getCurrentWorkspace().index(); + + this._restorePeekedWindowStack(); + this._focusMetaWindow(255, this._peekedWindow, immediate, true); + this._peekedWindow = null; + + if (!stayHere) { + this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); + } + + this.peekInitialWorkspaceIndex = -1; + } + }, + + _switchToWorkspaceImmediate: function(workspaceIndex) { + let workspace = Utils.getWorkspaceByIndex(workspaceIndex); + let shouldAnimate = Main.wm._shouldAnimate; + + if (!workspace || (!workspace.list_windows().length && + workspaceIndex < Utils.getWorkspaceCount() - 1)) { + workspace = Utils.getCurrentWorkspace(); + } + + Main.wm._shouldAnimate = () => false; + workspace.activate(global.display.get_current_time_roundtrip()); + Main.wm._shouldAnimate = shouldAnimate; + }, + + _focusMetaWindow: function(dimOpacity, window, immediate, ignoreFocus) { + window.get_workspace().list_windows().forEach(mw => { + let wa = mw.get_compositor_private(); + let isFocused = !ignoreFocus && mw == window; + + if (wa) { + if (isFocused) { + mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa); + wa.get_parent().set_child_above_sibling(wa, null); + } + + if (isFocused && mw.minimized) { + wa.show(); + } + + if (!mw.minimized) { + let tweenOpts = getTweenOpts({ opacity: isFocused ? 255 : dimOpacity }); + + if (immediate && !mw.is_on_all_workspaces()) { + tweenOpts.time = 0; + } + + Utils.animateWindowOpacity(wa, tweenOpts); + } + } + }); + }, + + _restorePeekedWindowStack: function() { + let windowActor = this._peekedWindow ? this._peekedWindow.get_compositor_private() : null; + + if (windowActor) { + if (this._peekedWindow.hasOwnProperty(PEEK_INDEX_PROP)) { + windowActor.get_parent().set_child_at_index(windowActor, this._peekedWindow[PEEK_INDEX_PROP]); + delete this._peekedWindow[PEEK_INDEX_PROP]; + } + + if (this._peekedWindow.minimized) { + windowActor.hide(); + } + } + }, +}); + +var Preview = Utils.defineClass({ + Name: 'DashToPanel-Preview', + Extends: St.Widget, + + _init: function(previewMenu) { + this.callParent('_init', { + style_class: 'preview-container', + reactive: true, + track_hover: true, + layout_manager: new Clutter.BinLayout() + }); + + this.window = null; + this._waitWindowId = 0; + this._needsCloseButton = true; + this.cloneWidth = this.cloneHeight = 0; + this._previewMenu = previewMenu; + this._padding = Me.settings.get_int('window-preview-padding') * scaleFactor; + this._previewDimensions = this._getPreviewDimensions(); + this.animatingOut = false; + + let box = new St.Widget({ layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL }), y_expand: true }); + let [previewBinWidth, previewBinHeight] = this._getBinSize(); + let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); + + if (Config.PACKAGE_VERSION >= '3.31.9') { + closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); + } + + this._closeButtonBin = new St.Widget({ + style_class: 'preview-close-btn-container', + layout_manager: new Clutter.BinLayout(), + opacity: 0, + x_expand: true, y_expand: true, + x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + this._closeButtonBin.add_child(closeButton); + + this._previewBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + style: 'padding: ' + this._padding / scaleFactor + 'px;' + }); + + this._previewBin.set_size(previewBinWidth, previewBinHeight); + + box.add_child(this._previewBin); + + if (headerHeight) { + let headerBox = new St.Widget({ + style_class: 'preview-header-box', + layout_manager: new Clutter.BoxLayout(), + x_expand: true, + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + setStyle(headerBox, this._getBackgroundColor(HEADER_COLOR_OFFSET, 1)); + this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); + this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); + + this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._iconBin.set_size(headerHeight, headerHeight); + + headerBox.add_child(this._iconBin); + headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1); + headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); + + box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1); + } + + this.add_child(box); + this.add_child(this._closeButtonBin); + + closeButton.connect('clicked', () => this._onCloseBtnClick()); + this.connect('notify::hover', () => this._onHoverChanged()); + this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); + this.connect('destroy', () => this._onDestroy()); + }, + + adjustOnStage: function() { + let closeButton = this._closeButtonBin.get_first_child(); + let closeButtonHeight = closeButton.height; + let maxCloseButtonSize = MAX_CLOSE_BUTTON_SIZE * scaleFactor; + let closeButtonBorderRadius = ''; + + if (closeButtonHeight > maxCloseButtonSize) { + closeButtonHeight = maxCloseButtonSize; + closeButton.set_size(closeButtonHeight, closeButtonHeight); + } + + if (!headerHeight) { + closeButtonBorderRadius = 'border-radius: '; + + if (isTopHeader) { + closeButtonBorderRadius += (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + } else { + closeButtonBorderRadius += (isLeftButtons ? '0 4px 0 0;' : '4px 0 0 0;'); + } + } + + setStyle( + this._closeButtonBin, + 'padding: ' + (headerHeight ? Math.round((headerHeight - closeButtonHeight) * .5 / scaleFactor) : 4) + 'px;' + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + + closeButtonBorderRadius + ); + }, + + assignWindow: function(window, animateSize) { + if (this.window != window) { + let _assignWindowClone = () => { + if (window.get_compositor_private()) { + let cloneBin = this._getWindowCloneBin(window); + + this._resizeClone(cloneBin, window); + this._addClone(cloneBin, animateSize); + this._previewMenu.updatePosition(); + } else if (!this._waitWindowId) { + this._waitWindowId = Mainloop.idle_add(() => { + this._waitWindowId = 0; + + if (this._previewMenu.opened) { + _assignWindowClone(); + } + }); + } + }; + + _assignWindowClone(); + } + + this._cancelAnimateOut(); + this._removeWindowSignals(); + this.window = window; + this._needsCloseButton = window.can_close() && !Utils.checkIfWindowHasTransient(window); + this._updateHeader(); + }, + + animateOut: function() { + if (!this.animatingOut) { + let tweenOpts = getTweenOpts({ opacity: 0, width: 0, height: 0, onComplete: () => this.destroy() }); + + this.animatingOut = true; + + Utils.stopAnimations(this); + Utils.animate(this, tweenOpts); + } + }, + + getSize: function() { + let [binWidth, binHeight] = this._getBinSize(); + + binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2); + binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight; + + return [binWidth, binHeight]; + }, + + setFocus: function(focused) { + this._hideOrShowCloseButton(!focused); + setStyle(this, this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); + + if (focused) { + this._previewMenu.ensureVisible(this); + this._previewMenu.requestPeek(this.window); + } + }, + + activate: function() { + this._previewMenu.endPeekHere(); + this._previewMenu.close(); + Main.activateWindow(this.window); + }, + + _onDestroy: function() { + if (this._waitWindowId) { + GLib.source_remove(this._waitWindowId); + this._waitWindowId = 0; + } + + this._removeWindowSignals(); + }, + + _onHoverChanged: function() { + this.setFocus(this.hover); + }, + + _onCloseBtnClick: function() { + this._hideOrShowCloseButton(true); + this.reactive = false; + + if (!Me.settings.get_boolean('group-apps')) { + this._previewMenu.close(); + } else { + this._previewMenu.endPeekHere(); + } + + this.window.delete(global.get_current_time()); + }, + + _onButtonReleaseEvent: function(e) { + switch (e.get_button()) { + case 1: // Left click + this.activate(); + break; + case 2: // Middle click + if (Me.settings.get_boolean('preview-middle-click-close')) { + this._onCloseBtnClick(); + } + break; + case 3: // Right click + this._showContextMenu(e); + break; + } + + return Clutter.EVENT_STOP; + }, + + _cancelAnimateOut: function() { + if (this.animatingOut) { + this.animatingOut = false; + + Utils.stopAnimations(this); + Utils.animate(this, getTweenOpts({ opacity: 255, width: this.cloneWidth, height: this.cloneHeight })); + } + }, + + _showContextMenu: function(e) { + let coords = e.get_coords(); + let currentWorkspace = this._previewMenu.peekInitialWorkspaceIndex < 0 ? + Utils.getCurrentWorkspace() : + Utils.getWorkspaceByIndex(this._previewMenu.peekInitialWorkspaceIndex); + + Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, { + x: coords[0], + y: coords[1], + width: 0, + height: 0 + }); + + let ctxMenuData = Main.wm._windowMenuManager._manager._menus[0]; + + ctxMenuData.menu.connect('open-state-changed', () => this._previewMenu.menu.sync_hover()); + + if (this.window.get_workspace() != currentWorkspace) { + let menuItem = new PopupMenu.PopupMenuItem(_('Move to current Workspace') + ' [' + (currentWorkspace.index() + 1) + ']'); + let menuItems = ctxMenuData.menu.box.get_children(); + let insertIndex = Utils.findIndex(menuItems, c => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem); + + insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1; + ctxMenuData.menu.addMenuItem(menuItem, insertIndex); + menuItem.connect('activate', () => this.window.change_workspace(currentWorkspace)); + } + }, + + _removeWindowSignals: function() { + if (this._titleWindowChangeId) { + this.window.disconnect(this._titleWindowChangeId); + this._titleWindowChangeId = 0; + } + }, + + _updateHeader: function() { + if (headerHeight) { + let iconTextureSize = Me.settings.get_boolean('window-preview-use-custom-icon-size') ? + Me.settings.get_int('window-preview-custom-icon-size') : + headerHeight / scaleFactor * .6; + let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize); + let workspaceIndex = ''; + let workspaceStyle = null; + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let commonTitleStyles = 'color: ' + Me.settings.get_string('window-preview-title-font-color') + ';' + + 'font-size: ' + Me.settings.get_int('window-preview-title-font-size') * fontScale + 'px;' + + 'font-weight: ' + Me.settings.get_string('window-preview-title-font-weight') + ';'; + + this._iconBin.destroy_all_children(); + this._iconBin.add_child(icon); + + if (!Me.settings.get_boolean('isolate-workspaces')) { + workspaceIndex = (this.window.get_workspace().index() + 1).toString(); + workspaceStyle = 'margin: 0 4px 0 ' + (isLeftButtons ? Math.round((headerHeight - icon.width) * .5) + 'px' : '0') + '; padding: 0 4px;' + + 'border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px;' + commonTitleStyles; + } + + this._workspaceIndicator.text = workspaceIndex; + setStyle(this._workspaceIndicator, workspaceStyle); + + this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle()); + setStyle(this._windowTitle, 'max-width: 0px; padding-right: 4px;' + commonTitleStyles); + this._updateWindowTitle(); + } + }, + + _updateWindowTitle: function() { + this._windowTitle.text = this.window.title; + }, + + _hideOrShowCloseButton: function(hide) { + if (this._needsCloseButton) { + Utils.animate(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + } + }, + + _getBackgroundColor: function(offset, alpha) { + return 'background-color: ' + this._getRgbaColor(offset, alpha) + + 'transition-duration:' + this._previewMenu.panel.dynamicTransparency.animationDuration; + }, + + _getRgbaColor: function(offset, alpha) { + alpha = Math.abs(alpha); + + if (isNaN(alpha)) { + alpha = alphaBg; + } + + return Utils.getrgbaColor(this._previewMenu.panel.dynamicTransparency.backgroundColorRgb, alpha, offset); + }, + + _addClone: function(newCloneBin, animateSize) { + let currentClones = this._previewBin.get_children(); + let newCloneOpts = getTweenOpts({ opacity: 255 }); + + this._previewBin.add_child(newCloneBin); + + if (currentClones.length) { + let currentCloneBin = currentClones.pop(); + let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentCloneBin.destroy() }); + + if (newCloneBin.width > currentCloneBin.width) { + newCloneOpts.width = newCloneBin.width; + newCloneBin.width = currentCloneBin.width; + } else { + currentCloneOpts.width = newCloneBin.width; + } + + if (newCloneBin.height > currentCloneBin.height) { + newCloneOpts.height = newCloneBin.height; + newCloneBin.height = currentCloneBin.height; + } else { + currentCloneOpts.height = newCloneBin.height; + } + + currentClones.forEach(c => c.destroy()); + Utils.animate(currentCloneBin, currentCloneOpts); + } else if (animateSize) { + newCloneBin.width = 0; + newCloneBin.height = 0; + newCloneOpts.width = this.cloneWidth; + newCloneOpts.height = this.cloneHeight; + } + + Utils.animate(newCloneBin, newCloneOpts); + }, + + _getWindowCloneBin: function(window) { + let frameRect = window.get_frame_rect(); + let bufferRect = window.get_buffer_rect(); + let clone = new Clutter.Clone({ source: window.get_compositor_private() }); + let cloneBin = new St.Widget({ + opacity: 0, + layout_manager: frameRect.width != bufferRect.width || + frameRect.height != bufferRect.height ? + new WindowCloneLayout(frameRect, bufferRect) : + new Clutter.BinLayout() + }); + + cloneBin.add_child(clone); + + return cloneBin; + }, + + _getBinSize: function() { + let [fixedWidth, fixedHeight] = this._previewDimensions; + + return [ + aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1, + aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1 + ]; + }, + + _resizeClone: function(cloneBin, window) { + let frameRect = cloneBin.layout_manager.frameRect || window.get_frame_rect(); + let [fixedWidth, fixedHeight] = this._previewDimensions; + let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1); + let cloneWidth = frameRect.width * ratio; + let cloneHeight = frameRect.height * ratio; + + let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; + let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0; + let clonePaddingTop = clonePaddingTB * .5; + let clonePaddingLeft = clonePaddingLR * .5; + + this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor; + this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor; + + cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;'); + cloneBin.layout_manager.ratio = ratio; + cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor]; + + cloneBin.get_first_child().set_size(cloneWidth, cloneHeight); + }, + + _getPreviewDimensions: function() { + let size = Me.settings.get_int('window-preview-size') * scaleFactor; + let w, h; + + if (this._previewMenu.isVertical) { + w = size; + h = w * aspectRatio.y.size / aspectRatio.x.size; + } else { + h = size; + w = h * aspectRatio.x.size / aspectRatio.y.size; + } + + return [w, h]; + } +}); + +var WindowCloneLayout = Utils.defineClass({ + Name: 'DashToPanel-WindowCloneLayout', + Extends: Clutter.BinLayout, + + _init: function(frameRect, bufferRect) { + this.callParent('_init'); + + //the buffer_rect contains the transparent padding that must be removed + this.frameRect = frameRect; + this.bufferRect = bufferRect; + }, + + vfunc_allocate: function(actor, box, flags) { + let [width, height] = box.get_size(); + + box.set_origin( + (this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0], + (this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1] + ); + + box.set_size( + width + (this.bufferRect.width - this.frameRect.width) * this.ratio, + height + (this.bufferRect.height - this.frameRect.height) * this.ratio + ); + + Utils.allocate(actor.get_first_child(), box, flags); + } +}); + +function setStyle(actor, style) { + if (!isManualStyling) { + actor.set_style(style); + } +} + +function getTweenOpts(opts) { + let defaults = { + time: animationTime, + transition: 'easeInOutQuad' + }; + + return Utils.mergeObjects(opts || {}, defaults); +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE @@ -0,0 +1,674 @@ + 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 +. diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js new file mode 100644 index 0000000..904c7de --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js @@ -0,0 +1,52 @@ +/* exported init */ + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils + +class Extension { + constructor() { + this.available_mods = Self.imports.src.modsList.get() + } + + _refresh_mod(name) { + if (!this.available_mods[name]) return + + if (this.settings.get_boolean(name)) { // enable + if (this.mods[name]) return + + const mod = new this.available_mods[name]() + mod.enable() + this.mods[name] = mod + } else if (this.mods[name]) { //disable + this.mods[name].disable() + delete this.mods[name] + } + } + + enable() { + this.mods = {} + + this.settings = extensionUtils.getSettings() + + Object.keys(this.available_mods).forEach(name => { + this.settings.connect('changed::' + name, () => { + this._refresh_mod(name) + }); + this._refresh_mod(name) + }) + } + + disable() { + for (const key in this.mods) { + if (!this.mods.hasOwnProperty(key)) continue; + this.mods[key].disable() + } + + delete this.mods + delete this.settings + } +} + +function init() { + return new Extension(); +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..a042c9c Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..5791425 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..985e2ef Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0c2d259 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..9f6dc63 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..f657030 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0bcf35d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..74449f3 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json new file mode 100644 index 0000000..326c5f5 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json @@ -0,0 +1,14 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Tunes gnome 40-43 Overview UI to make it more usable.\n\nChanges:\n- Search textbox is hidden by default and shown only when user begins to type-to-search\n- Scale of workspaces' thumbnails increased 2x\n- Restores wallpaper on workspaces' thumbnails. No more gray background\n- Show workspaces' thumbnails even when there is only one workspace\n- Firefox's PIP (picture in picture) window is now displayed on the overview screen\n\nAll modifications can be disabled in the extension's settings.\n\nATTENTION!\nAfter extension update, gnome-shell restart is required:\nX11: Alt+F2 => r\nWayland: logout => login", + "name": "Gnome 4x UI Improvements", + "settings-schema": "org.gnome.shell.extensions.gnome-ui-tune", + "shell-version": [ + "40", + "41", + "42" + ], + "url": "https://github.com/axxapy/gnome-ui-tune", + "uuid": "gnome-ui-tune@itstime.tech", + "version": 13 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js new file mode 100644 index 0000000..f7b8669 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js @@ -0,0 +1,55 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Gtk = imports.gi.Gtk; + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils +const _ = imports.gettext.domain(Self.metadata.uuid).gettext + + +function init() { +} + +function buildPrefsWidget() { + extensionUtils.initTranslations(Self.metadata.uuid); + + const settings = extensionUtils.getSettings() + + let prefsWidget = new Gtk.Grid({ + margin_top: 18, + margin_bottom: 18, + margin_start: 18, + margin_end: 18, + column_spacing: 12, + row_spacing: 22, + visible: true + }); + + let title = new Gtk.Label({ + label: `${_('settings-mods-list')}`, + halign: Gtk.Align.START, + use_markup: true, + visible: true + }); + prefsWidget.attach(title, 0, 0, 2, 1); + + const mods = Self.imports.src.modsList.getNames() + + for (let modNum = 0; modNum < mods.length; modNum++) { + const key = mods[modNum] + + const row = modNum + 1 + + const label = new Gtk.Label({label: _(key), halign: Gtk.Align.START}) + const toggle = new Gtk.Switch({halign: Gtk.Align.END, active: settings.get_boolean(key)}) + + prefsWidget.attach(label, 0, row, 1, 1); + prefsWidget.attach(toggle, 1, row, 1, 1); + + settings.bind(key, toggle, 'active', Gio.SettingsBindFlags.DEFAULT) + } + + + return prefsWidget +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled new file mode 100644 index 0000000..86313cb Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml new file mode 100644 index 0000000..659d656 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml @@ -0,0 +1,30 @@ + + + + + true + Hide search input + Hide search input on overview screen. Search input will be shown when user starts to type-to-search. + + + true + Increase thumbnails size + Increases thumbnails size twice to make them actually usable. + + + true + Restore thumbnails background + Use desktop wallpaper for thumbnails background instead of solid grey color. + + + true + Always show thumbnails + Show workspaces' thumbnails even when there is only single workspace. + + + true + Show firefox's Picture-In-Picture window in desktop overview + By default, firefox's PiP window (for instance, extracted media player) is not displayed in overview. Fix it. + + + diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js new file mode 100644 index 0000000..7dc6b77 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js @@ -0,0 +1,8 @@ + +var Base = /*abstract*/ class { + constructor() { + //this.enable() + } + enable() {} + disable() {} +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js new file mode 100644 index 0000000..26c30c0 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js @@ -0,0 +1,21 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const ThumbnailsBox = imports.ui.workspaceThumbnail.ThumbnailsBox + +var Mod = class extends mod.Base { + enable() { + this.bkp = ThumbnailsBox.prototype._updateShouldShow + ThumbnailsBox.prototype._updateShouldShow = function() { + if (!this._shouldShow) { + this._shouldShow = true; + this.notify('should-show'); + } + } + } + + disable() { + if (this.bkp) { + ThumbnailsBox.prototype._updateShouldShow = this.bkp + } + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js new file mode 100644 index 0000000..f79bd5c --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js @@ -0,0 +1,22 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Workspace = imports.ui.workspace.Workspace + +var Mod = class extends mod.Base { + enable() { + this.bkp_isOverviewWindow = Workspace.prototype._isOverviewWindow + const _isOverviewWindow = this.bkp_isOverviewWindow + Workspace.prototype._isOverviewWindow = function(win) { + if (win.title && win.title === 'Picture-in-Picture') { + if (win.get_wm_class && win.get_wm_class().includes("firefox")) return true; + } + return _isOverviewWindow.call(this, win); + } + } + + disable() { + if (this.bkp_isOverviewWindow) { + Workspace.prototype._isOverviewWindow = this.bkp_isOverviewWindow + } + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js new file mode 100644 index 0000000..1b56a12 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js @@ -0,0 +1,30 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main + +var Mod = class extends mod.Base { + enable() { + this.c = { + searchEntry: Main.overview.searchEntry, + searchController: Main.overview._overview.controls._searchController, + } + + this.c.searchEntry.hide() + + this.connectedId = this.c.searchController.connect('notify::search-active', () => { + if (this.c.searchController.searchActive) { + this.c.searchEntry.show(); + } else { + this.c.searchEntry.hide(); + } + }) + } + + disable() { + if (this.connectedId) { + this.c.searchController.disconnect(this.connectedId) + } + + this.c.searchEntry.show() + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js new file mode 100644 index 0000000..693ba74 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js @@ -0,0 +1,73 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main +const workspaceThumbnail = imports.ui.workspaceThumbnail +const BackgroundManager = imports.ui.background.BackgroundManager + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_thumb_init = workspaceThumbnail.WorkspaceThumbnail.prototype._init; + const _init = this.bkp_thumb_init + workspaceThumbnail.WorkspaceThumbnail.prototype._init = function(metaWorkspace, monitorIndex) { + _init.call(this, metaWorkspace, monitorIndex) + this._bgManager = new BackgroundManager({ + monitorIndex: monitorIndex, + container: this._contents, + vignette: false + }); + } + + this.bkp_thumb_onDestroy = workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy; + const _onDestroy = this.bkp_thumb_onDestroy + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = function() { + _onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + + // Thumbnails on second monitor + if (!imports.ui.workspacesView.ThumbnailsBox) return; // gnome 42 does not require this hack + this.bkp_layoutManager_thumbnailsBox_updateStates = imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates + const layoutManager_thumbnailsBox_updateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = function() { + layoutManager_thumbnailsBox_updateStates.call(this) + + this._thumbnails.forEach(thumbnail => { + if (thumbnail._bgManager && thumbnail._bgManager.HACKED) { + return + } + thumbnail._bgManager = new BackgroundManager({ + monitorIndex: this._monitorIndex, + container: thumbnail._contents, + vignette: false + }); + thumbnail._bgManager.HACKED = true + const onDestroy = this._thumbnails[0]._onDestroy + thumbnail._onDestroy = function() { + onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + }) + } + } + + disable() { + if (this.bkp_thumb_init) { + workspaceThumbnail.WorkspaceThumbnail.prototype._init = this.bkp_thumb_init + } + + if (this.bkp_thumb_onDestroy) { + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = this.bkp_thumb_onDestroy + } + + if (this.bkp_layoutManager_thumbnailsBox_updateStates) { + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + } + } +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js new file mode 100644 index 0000000..04dea1b --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js @@ -0,0 +1,40 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const workspaceThumbnail = imports.ui.workspaceThumbnail +let SecondaryMonitorDisplay = imports.ui.workspacesView.SecondaryMonitorDisplay + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_MAX_THUMBNAIL_SCALE = workspaceThumbnail.MAX_THUMBNAIL_SCALE + workspaceThumbnail.MAX_THUMBNAIL_SCALE = 0.1 + + // Thumbnails on second monitor + + // for gnome 42: SecondaryMonitorDisplay may get initialized after extension code is loaded => import above will not work + SecondaryMonitorDisplay = SecondaryMonitorDisplay ?? imports.ui.workspacesView.SecondaryMonitorDisplay + + this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight = SecondaryMonitorDisplay.prototype._getThumbnailsHeight + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = function(box) { + if (!this._thumbnails.visible) + return 0; + + const [width, height] = box.get_size(); + const { expandFraction } = this._thumbnails; + const [thumbnailsHeight] = this._thumbnails.get_preferred_height(width); + return Math.min( + thumbnailsHeight * expandFraction, + height * workspaceThumbnail.MAX_THUMBNAIL_SCALE); + } + } + + disable() { + if (this.bkp_MAX_THUMBNAIL_SCALE) { + workspaceThumbnail.MAX_THUMBNAIL_SCALE = this.bkp_MAX_THUMBNAIL_SCALE + } + + if (this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight) { + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight + } + } +} diff --git a/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js new file mode 100644 index 0000000..f5d7203 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js @@ -0,0 +1,23 @@ + +// This func can not be used from prefs.js due to mods being actually loaded when they're imported +function get() { + const src = imports.misc.extensionUtils.getCurrentExtension().imports.src + return { + 'hide-search': src.modHideSearchInput.Mod, + 'increase-thumbnails-size': src.modScaleThumbnails.Mod, + 'restore-thumbnails-background': src.modRestoreThumbnailsBackground.Mod, + 'always-show-thumbnails': src.modAlwaysShowThumbnails.Mod, + 'overview-firefox-pip': src.modFirefoxPipInOverview.Mod, + } +} + +// This func is safe to use from prefs.js as it has no external dependencies +function getNames() { + return [ + 'hide-search', + 'increase-thumbnails-size', + 'restore-thumbnails-background', + 'always-show-thumbnails', + 'overview-firefox-pip', + ]; +} diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README new file mode 100644 index 0000000..1f14023 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README @@ -0,0 +1,6 @@ +Dependencies: +libclutter, libgtop and NetworkManager gir bindings, and gnome-system-monitor + on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gnome-system-monitor + on Fedora: libgtop2-devel NetworkManager-libnm-devel, gnome-system-monitor + on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor + on Arch Linux: libgtop, networkmanager, gnome-system-monitor diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js new file mode 100644 index 0000000..2e1be07 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js @@ -0,0 +1,51 @@ +const Config = imports.misc.config; +const Clutter = imports.gi.Clutter; + +/** Compare two dotted version strings (like '10.2.3'). + * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2 + */ +function versionCompare(v1, v2) { + let v1parts = ('' + v1).split('.') + let v2parts = ('' + v2).split('.') + let minLength = Math.min(v1parts.length, v2parts.length) + let i, p1, p2; + // Compare tuple pair-by-pair. + for (i = 0; i < minLength; i++) { + // Convert to integer if possible, because "8" > "10". + p1 = parseInt(v1parts[i], 10); + p2 = parseInt(v2parts[i], 10); + if (isNaN(p1)) { + p1 = v1parts[i]; + } + if (isNaN(p2)) { + p2 = v2parts[i]; + } + if (p1 === p2) { + continue; + } else if (p1 > p2) { + return 1; + } else if (p1 < p2) { + return -1; + } + // one operand is NaN + return NaN; + } + // The longer tuple is always considered 'greater' + if (v1parts.length === v2parts.length) { + return 0; + } + return (v1parts.length < v2parts.length) ? -1 : 1; +} + +function color_from_string(color) { + let clutterColor, res; + + if (!Clutter.Color.from_string) { + clutterColor = new Clutter.Color(); + clutterColor.from_string(color); + } else { + [res, clutterColor] = Clutter.Color.from_string(color); + } + + return clutterColor; +} diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js new file mode 100644 index 0000000..79b85c1 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js @@ -0,0 +1,94 @@ +/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (c) 2011-2012, Giovanni Campagna + + 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 the GNOME 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 HOLDER 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. +*/ + +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) { + Gettext.bindtextdomain(domain, localeDir.get_path()); + } else { + Gettext.bindtextdomain(domain, Config.LOCALEDIR); + } +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) { + throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); + } + + return new Gio.Settings({settings_schema: schemaObj}); +} diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js new file mode 100644 index 0000000..1c56f0d --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js @@ -0,0 +1,2592 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// system-monitor: Gnome shell extension displaying system informations in gnome shell status bar, such as memory usage, cpu usage, network rates… +// Copyright (C) 2011 Florian Mounier aka paradoxxxzero + +// 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 . + +// Author: Florian Mounier aka paradoxxxzero + +/* Ugly. This is here so that we don't crash old libnm-glib based shells unnecessarily + * by loading the new libnm.so. Should go away eventually */ + +var libnm_glib = imports.gi.GIRepository.Repository.get_default().is_registered('NMClient', '1.0'); + +var smDepsGtop = true; +var smDepsNM = true; + +var Config = imports.misc.config; +var Clutter = imports.gi.Clutter; +var GLib = imports.gi.GLib; +var GObject = imports.gi.GObject; +var Lang = imports.lang; + +var Gio = imports.gi.Gio; +var Shell = imports.gi.Shell; +var St = imports.gi.St; +const UPower = imports.gi.UPowerGlib; + +// const System = imports.system; +var ModalDialog = imports.ui.modalDialog; + +var ByteArray = imports.byteArray; + +var ExtensionSystem = imports.ui.extensionSystem; +var ExtensionUtils = imports.misc.extensionUtils; + +var Me = ExtensionUtils.getCurrentExtension(); +var Convenience = Me.imports.convenience; +var Compat = Me.imports.compat; + +var Background, GTop, IconSize, Locale, MountsMonitor, NM, NetworkManager, Schema, StatusArea, Style, gc_timeout, menu_timeout; + +try { + GTop = imports.gi.GTop; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsGtop = false; +} + +try { + NM = libnm_glib ? imports.gi.NMClient : imports.gi.NM; + NetworkManager = libnm_glib ? imports.gi.NetworkManager : NM; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsNM = false; +} + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const Gettext = imports.gettext.domain('system-monitor'); +const Mainloop = imports.mainloop; +const Util = imports.misc.util; +const _ = Gettext.gettext; + +const MESSAGE = _('Dependencies Missing\n\ +Please install: \n\ +gnome-system-monitor and libgtop, clutter and Network Manager gir bindings \n\ +\t on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gir1.2-clutter-1.0, gnome-system-monitor \n\ +\t on Fedora: libgtop2-devel, NetworkManager-libnm-devel, gnome-system-monitor \n\ +\t on Arch: libgtop, networkmanager, gnome-system-monitor\n\ +\t on openSUSE: typelib-1_0-GTop-2_0, typelib-1_0-NetworkManager-1_0, gnome-system-monitor \n\ +\t on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor\n'); + +// stale network shares will cause the shell to freeze, enable this with caution +const ENABLE_NETWORK_DISK_USAGE = false; + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let metadata = extension.metadata; +let shell_Version = Config.PACKAGE_VERSION; + +Clutter.Actor.prototype.raise_top = function raise_top() { + const parent = this.get_parent(); + if (!parent) { + return; + } + parent.set_child_above_sibling(this, null); +} +Clutter.Actor.prototype.reparent = function reparent(newParent) { + const parent = this.get_parent(); + if (parent) { + parent.remove_child(this); + } + newParent.add_child(this); +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function l_limit(t) { + return (t > 0) ? t : 1000; +} + +function change_text() { + this.label.visible = Schema.get_boolean(this.elt + '-show-text'); +} + +function change_style() { + let style = Schema.get_string(this.elt + '-style'); + this.text_box.visible = style === 'digit' || style === 'both'; + this.chart.actor.visible = style === 'graph' || style === 'both'; +} + +function build_menu_info() { + let elts = Main.__sm.elts; + let tray_menu = Main.__sm.tray.menu; + + if (tray_menu._getMenuItems().length && + typeof tray_menu._getMenuItems()[0].actor.get_last_child() !== 'undefined') { + tray_menu._getMenuItems()[0].actor.get_last_child().destroy_all_children(); + for (let elt in elts) { + elts[elt].menu_items = elts[elt].create_menu_items(); + } + } else { + return; + } + + let menu_info_box_table = new St.Widget({ + style: 'padding: 10px 0px 10px 0px; spacing-rows: 10px; spacing-columns: 15px;', + layout_manager: new Clutter.GridLayout({orientation: Clutter.Orientation.VERTICAL}) + }); + let menu_info_box_table_layout = menu_info_box_table.layout_manager; + + // Populate Table + let row_index = 0; + for (let elt in elts) { + if (!elts[elt].menu_visible) { + continue; + } + + // Add item name to table + menu_info_box_table_layout.attach( + new St.Label({ + text: elts[elt].item_name, + style_class: Style.get('sm-title'), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER + }), 0, row_index, 1, 1); + + // Add item data to table + let col_index = 1; + for (let item in elts[elt].menu_items) { + menu_info_box_table_layout.attach( + elts[elt].menu_items[item], col_index, row_index, 1, 1); + + col_index++; + } + + row_index++; + } + if (shell_Version < '3.36') { + tray_menu._getMenuItems()[0].actor.get_last_child().add(menu_info_box_table, {expand: true}); + } else { + tray_menu._getMenuItems()[0].actor.get_last_child().add_child(menu_info_box_table); + } +} + +function change_menu() { + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + build_menu_info(); +} + +function change_usage() { + let usage = Schema.get_string('disk-usage-style'); + Main.__sm.pie.show(usage === 'pie'); + Main.__sm.bar.show(usage === 'bar'); +} +let color_from_string = Compat.color_from_string; + +function interesting_mountpoint(mount) { + if (mount.length < 3) { + return false; + } + + return ((mount[0].indexOf('/dev/') === 0 || mount[2].toLowerCase() === 'nfs') && mount[2].toLowerCase() !== 'udf'); +} + + +const smStyleManager = class SystemMonitor_smStyleManager { + constructor() { + this._extension = ''; + this._iconsize = 1; + this._diskunits = _('MiB/s'); + this._netunits_kbytes = _('KiB/s'); + this._netunits_mbytes = _('MiB/s'); + this._netunits_gbytes = _('GiB/s'); + this._netunits_kbits = _('kbit/s'); + this._netunits_mbits = _('Mbit/s'); + this._netunits_gbits = _('Gbit/s'); + this._pie_size = 300; + this._pie_fontsize = 14; + this._bar_width = 300; + this._bar_thickness = 15; + this._bar_fontsize = 14; + this._compact = Schema.get_boolean('compact-display'); + + if (this._compact) { + this._extension = '-compact'; + this._iconsize = 3 / 5; + this._diskunits = _('MB'); + this._netunits_kbytes = _('kB'); + this._netunits_mbytes = _('MB'); + this._netunits_gbytes = _('GB'); + this._netunits_kbits = 'kb'; + this._netunits_mbits = 'Mb'; + this._netunits_gbits = 'Gb'; + this._pie_size *= 4 / 5; + this._pie_fontsize = 12; + this._bar_width *= 3 / 5; + this._bar_thickness = 12; + this._bar_fontsize = 12; + } + } + get(style) { + return style + this._extension; + } + iconsize() { + return this._iconsize; + } + diskunits() { + return this._diskunits; + } + netunits_kbytes() { + return this._netunits_kbytes; + } + netunits_mbytes() { + return this._netunits_mbytes; + } + netunits_gbytes() { + return this._netunits_gbytes; + } + netunits_kbits() { + return this._netunits_kbits; + } + netunits_mbits() { + return this._netunits_mbits; + } + netunits_gbits() { + return this._netunits_gbits; + } + pie_size() { + return this._pie_size; + } + pie_fontsize() { + return this._pie_fontsize; + } + bar_width() { + return this._bar_width; + } + bar_thickness() { + return this._bar_thickness; + } + bar_fontsize() { + return this._bar_fontsize; + } +} + +const smDialog = class SystemMonitor_smDialog extends ModalDialog.ModalDialog { + constructor() { + super({styleClass: 'prompt-dialog'}); + let mainContentBox = new St.BoxLayout({style_class: 'prompt-dialog-main-layout', + vertical: false}); + this.contentLayout.add(mainContentBox, + {x_fill: true, + y_fill: true}); + + let messageBox = new St.BoxLayout({style_class: 'prompt-dialog-message-layout', + vertical: true}); + mainContentBox.add(messageBox, + {y_align: St.Align.START}); + + this._subjectLabel = new St.Label({style_class: 'prompt-dialog-headline', + text: _('System Monitor Extension')}); + + messageBox.add(this._subjectLabel, + {y_fill: false, + y_align: St.Align.START}); + + this._descriptionLabel = new St.Label({style_class: 'prompt-dialog-description', + text: MESSAGE}); + + messageBox.add(this._descriptionLabel, + {y_fill: true, + y_align: St.Align.START}); + + + this.setButtons([ + { + label: _('Cancel'), + action: () => { + this.close(); + }, + key: Clutter.Escape + } + ]); + } +} + +const Chart = class SystemMonitor_Chart { + constructor(width, height, parent) { + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.parentC = parent; + this.width = width; + let themeContext = St.ThemeContext.get_for_stage(global.stage); + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); + this.actor.set_height(height); + this.data = []; + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = []; + } + themeContext.connect('notify::scale-factor', this.rescale.bind(this)); + this.actor.connect('repaint', this._draw.bind(this)); + } + update() { + let data_a = this.parentC.vals; + if (data_a.length !== this.parentC.colors.length) { + return; + } + let accdata = []; + for (let l = 0; l < data_a.length; l++) { + accdata[l] = (l === 0) ? data_a[0] : accdata[l - 1] + ((data_a[l] > 0) ? data_a[l] : 0); + this.data[l].push(accdata[l]); + if (this.data[l].length > this.width) { + this.data[l].shift(); + } + } + if (!this.actor.visible) { + return; + } + this.actor.queue_repaint(); + } + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let max; + if (this.parentC.max) { + max = this.parentC.max; + } else { + max = Math.max.apply(this, this.data[this.data.length - 1]); + max = Math.max(1, Math.pow(2, Math.ceil(Math.log(max) / Math.log(2)))); + } + Clutter.cairo_set_source_color(cr, Background); + cr.rectangle(0, 0, width, height); + cr.fill(); + for (let i = this.parentC.colors.length - 1; i >= 0; i--) { + let samples = this.data[i].length - 1; + if (samples > 0) { + cr.moveTo(width, height); // bottom right + let x = width - 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][samples] / max) * height); + x -= 0.5 * this.scale_factor; + for (let j = samples; j >= 0; j--) { + let y = (1 - this.data[i][j] / max) * height; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + } + x += 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][0] / max) * height); + cr.lineTo(x, height); + cr.closePath(); + Clutter.cairo_set_source_color(cr, this.parentC.colors[i]); + cr.fill(); + } + } + cr.$dispose(); + } + resize(width) { + if (this.width === width) { + return; + } + this.width = width; + if (this.width < this.data[0].length) { + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = this.data[i].slice(-this.width); + } + } + this.actor.set_width(this.width * this.scale_factor); // repaints + } + rescale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); // repaints + } +} + +// Class to deal with volumes insertion / ejection +const smMountsMonitor = class SystemMonitor_smMountsMonitor { + constructor() { + this.files = []; + this.num_mounts = -1; + this.listeners = []; + this.connected = false; + + this._volumeMonitor = Gio.VolumeMonitor.get(); + let sys_mounts = ['/home', '/tmp', '/boot', '/usr', '/usr/local']; + this.base_mounts = ['/']; + sys_mounts.forEach((sMount) => { + if (this.is_sys_mount(sMount + '/')) { + this.base_mounts.push(sMount); + } + }); + this.connect(); + } + refresh() { + // try check that number of volumes has changed + // try { + // let num_mounts = this.manager.getMounts().length; + // if (num_mounts == this.num_mounts) + // return; + // this.num_mounts = num_mounts; + // } catch (e) {}; + + // Can't get mountlist: + // GTop.glibtop_get_mountlist + // Error: No symbol 'glibtop_get_mountlist' in namespace 'GTop' + // Getting it with mtab + // let mount_lines = Shell.get_file_contents_utf8_sync('/etc/mtab').split("\n"); + // this.mounts = []; + // for(let mount_line in mount_lines) { + // let mount = mount_lines[mount_line].split(" "); + // if(interesting_mountpoint(mount) && this.mounts.indexOf(mount[1]) < 0) { + // this.mounts.push(mount[1]); + // } + // } + // log("[System monitor] old mounts: " + this.mounts); + this.mounts = []; + for (let base in this.base_mounts) { + // log("[System monitor] " + this.base_mounts[base]); + this.mounts.push(this.base_mounts[base]); + } + let mount_lines = this._volumeMonitor.get_mounts(); + mount_lines.forEach((mount) => { + if ((!this.is_net_mount(mount) || ENABLE_NETWORK_DISK_USAGE) && + !this.is_ro_mount(mount)) { + let mpath = mount.get_root().get_path() || mount.get_default_location().get_path(); + if (mpath) { + this.mounts.push(mpath); + } + } + }); + // log("[System monitor] base: " + this.base_mounts); + // log("[System monitor] mounts: " + this.mounts); + for (let i in this.listeners) { + this.listeners[i](this.mounts); + } + } + add_listener(cb) { + this.listeners.push(cb); + } + remove_listener(cb) { + this.listeners.pop(cb); + } + get_mounts() { + return this.mounts; + } + is_sys_mount(mpath) { + let file = Gio.file_new_for_path(mpath); + let info = file.query_info(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT, + Gio.FileQueryInfoFlags.NONE, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT); + } + is_ro_mount(mount) { + // FIXME: running this function after "login after waking from suspend" + // can make login hang. Actual issue seems to occur when a former net + // mount got broken (e.g. due to a VPN connection terminated or + // otherwise broken connection) + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY); + } catch (e) { + return false; + } + } + is_net_mount(mount) { + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE, null); + let result = info.get_attribute_string(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE); + let net_fs = ['nfs', 'smbfs', 'cifs', 'ftp', 'sshfs', 'sftp', 'mtp', 'mtpfs']; + return !file.is_native() || net_fs.indexOf(result) > -1; + } catch (e) { + return false; + } + } + connect() { + if (this.connected) { + return; + } + try { + this.manager = this._volumeMonitor; + this.mount_added_id = this.manager.connect('mount-added', this.refresh.bind(this)); + this.mount_removed_id = this.manager.connect('mount-removed', this.refresh.bind(this)); + // need to add the other signals here + this.connected = true; + } catch (e) { + log('[System monitor] Failed to register on placesManager notifications'); + log('[System monitor] Got exception : ' + e); + } + this.refresh(); + } + disconnect() { + if (!this.connected) { + return; + } + this.manager.disconnect(this.mount_added_id); + this.manager.disconnect(this.mount_removed_id); + this.connected = false; + } + destroy() { + this.disconnect(); + } +} + +const Graph = class SystemMonitor_Graph { + constructor(width, height) { + this.menu_item = ''; + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.width = width; + this.height = height; + this.gtop = new GTop.glibtop_fsusage(); + this.colors = ['#888', '#aaa', '#ccc']; + for (let color in this.colors) { + this.colors[color] = color_from_string(this.colors[color]); + } + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + themeContext.connect('notify::scale-factor', this.set_scale.bind(this)); + this.scale_factor = themeContext.scale_factor; + let interfaceSettings = new Gio.Settings({ + schema: 'org.gnome.desktop.interface' + }); + interfaceSettings.connect('changed', this.set_text_scaling.bind(this)); + this.text_scaling = interfaceSettings.get_double('text-scaling-factor'); + if (!this.text_scaling) { + this.text_scaling = 1; + } + + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + this.actor.connect('repaint', this._draw.bind(this)); + } + create_menu_item() { + this.menu_item = new PopupMenu.PopupBaseMenuItem({reactive: false}); + if (shell_Version < '3.36') { + this.menu_item.actor.add(this.actor, {span: -1, expand: true}); + } else { + this.menu_item.actor.add_child(this.actor); + } + // tray.menu.addMenuItem(this.menu_item); + } + show(visible) { + this.menu_item.actor.visible = visible; + } + set_scale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } + set_text_scaling(interfaceSettings, key) { + // FIXME: for some reason we only get this signal once, not on later + // changes to the setting + //log('[System monitor] got text scaling signal'); + this.text_scaling = interfaceSettings.get_double(key); + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } +} + +const Bar = class SystemMonitor_Bar extends Graph { + constructor() { + // Height doesn't matter, it gets set on every draw. + super(Style.bar_width(), 100); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + _draw() { + if (!this.actor.visible) { + return; + } + let thickness = Style.bar_thickness() * this.scale_factor * this.text_scaling; + let fontsize = Style.bar_fontsize() * this.scale_factor * this.text_scaling; + this.actor.set_height(this.mounts.length * (3 * thickness)); + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + + let x0 = width / 8; + let y0 = thickness / 2; + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + let perc_full = (this.gtop.blocks - this.gtop.bfree) / this.gtop.blocks; + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y0 + thickness / 3); + cr.showText(text); + cr.moveTo(width - x0, y0 + thickness / 3); + cr.showText(Math.round(perc_full * 100).toString() + '%'); + y0 += (5 * thickness) / 4; + + cr.moveTo(0, y0); + cr.relLineTo(perc_full * width, 0); + cr.stroke(); + y0 += (7 * thickness) / 4; + } + cr.$dispose(); + } + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +const Pie = class SystemMonitor_Pie extends Graph { + constructor() { + super(Style.pie_size(), Style.pie_size()); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let xc = width / 2; + let yc = height / 2; + let pi = Math.PI; + function arc(r, value, max, angle) { + if (max === 0) { + return angle; + } + let new_angle = angle + (value * 2 * pi / max); + cr.arc(xc, yc, r, angle, new_angle); + return new_angle; + } + + // Set the ring thickness so that at least 7 rings can be displayed. If + // there are more mounts, make the rings thinner. If the rings are too + // thin to have a line height of 1.2 for the labels, shrink the labels. + let rings = Math.max(this.mounts.length, 7); + let ring_width = width / (2 * rings); + let fontsize = Style.pie_fontsize() * this.scale_factor * this.text_scaling; + if (ring_width < 1.2 * fontsize) { + fontsize = ring_width / 1.2; + } + let thickness = ring_width / 1.5; + + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + let r = (height - ring_width) / 2; + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + arc(r, this.gtop.blocks - this.gtop.bfree, this.gtop.blocks, -pi / 2); + cr.stroke(); + r -= ring_width; + } + let y = (ring_width + fontsize) / 2; + for (let mount in this.mounts) { + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y); + cr.showText(text); + y += ring_width; + } + cr.$dispose(); + } + + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +var TipItem = null; + +if (shell_Version < '3.36') { + TipItem = class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + constructor() { + super(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } +} else { + TipItem = GObject.registerClass( + { + GTypeName: 'TipItem' + }, + class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + _init() { + super._init(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } + ); +} +const TipMenu = class SystemMonitor_TipMenu extends PopupMenu.PopupMenuBase { + constructor(sourceActor) { + // PopupMenu.PopupMenuBase.prototype._init.call(this, sourceActor, 'sm-tooltip-box'); + super(sourceActor, 'sm-tooltip-box'); + this.actor = new Clutter.Actor(); + // this.actor.connect('get-preferred-width', + // this._boxGetPreferredWidth).bind(this); + // this.actor.connect('get-preferred-height', + // this._boxGetPreferredHeight.bind(this)); + this.actor.add_actor(this.box); + } + // _boxGetPreferredWidth (actor, forHeight, alloc) { + // // let columnWidths = this.getColumnWidths(); + // // this.setColumnWidths(columnWidths); + // + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_width(forHeight); + // } + // _boxGetPreferredHeight (actor, forWidth, alloc) { + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_height(forWidth); + // } + // _boxAllocate (actor, box, flags) { + // this.box.allocate(box, flags); + // } + _shift() { + // Probably old but works + let node = this.sourceActor.get_theme_node(); + let contentbox = node.get_content_box(this.sourceActor.get_allocation_box()); + + let sourceTopLeftX = 0; + let sourceTopLeftY = 0; + if (typeof this.sourceActor.get_transformed_extents === 'function') { + let extents = this.sourceActor.get_transformed_extents(); + let sourceTopLeft = extents.get_top_left(); + sourceTopLeftY = sourceTopLeft.y; + sourceTopLeftX = sourceTopLeft.x; + } else { + let allocation = Shell.util_get_transformed_allocation(this.sourceActor); + sourceTopLeftY = allocation.y1; + sourceTopLeftX = allocation.x1; + } + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + let [x, y] = [sourceTopLeftX + contentbox.x1, + sourceTopLeftY + contentbox.y1]; + let [cx, cy] = [sourceTopLeftX + (contentbox.x1 + contentbox.x2) / 2, + sourceTopLeftY + (contentbox.y1 + contentbox.y2) / 2]; + let [xm, ym] = [sourceTopLeftX + contentbox.x2, + sourceTopLeftY + contentbox.y2]; + let [width, height] = this.actor.get_size(); + let tipx = cx - width / 2; + tipx = Math.max(tipx, monitor.x); + tipx = Math.min(tipx, monitor.x + monitor.width - width); + let tipy = Math.floor(ym); + // Hacky condition to determine if the status bar is at the top or at the bottom of the screen + if (sourceTopLeftY / monitor.height > 0.3) { + tipy = sourceTopLeftY - height; // If it is at the bottom, place the tooltip above instead of below + } + this.actor.set_position(tipx, tipy); + } + open(animate) { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this.actor.show(); + this._shift(); + this.actor.raise_top(); + this.emit('open-state-changed', true); + } + close(animate) { + this.isOpen = false; + this.actor.hide(); + this.emit('open-state-changed', false); + } +} + +const TipBox = class SystemMonitor_TipBox { + constructor() { + this.actor = new St.BoxLayout({reactive: true}); + this.actor._delegate = this; + this.set_tip(new TipMenu(this.actor)); + this.in_to = this.out_to = 0; + this.actor.connect('enter-event', this.on_enter.bind(this)); + this.actor.connect('leave-event', this.on_leave.bind(this)); + } + set_tip(tipmenu) { + if (this.tipmenu) { + this.tipmenu.destroy(); + } + this.tipmenu = tipmenu; + if (this.tipmenu) { + Main.uiGroup.add_actor(this.tipmenu.actor); + this.hide_tip(); + } + } + show_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.open(); + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + hide_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.close(); + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + on_enter() { + let show_tooltip = Schema.get_boolean('show-tooltip'); + + if (!show_tooltip) { + return; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (!this.in_to) { + this.in_to = Mainloop.timeout_add(500, + this.show_tip.bind(this)); + } + } + on_leave() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + if (!this.out_to) { + this.out_to = Mainloop.timeout_add(500, + this.hide_tip.bind(this)); + } + } + destroy() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + + this.actor.destroy(); + } +} + +const ElementBase = class SystemMonitor_ElementBase extends TipBox { + constructor(properties) { + super(); + this.elt = ''; + this.item_name = _(''); + this.color_name = []; + this.text_items = []; + this.menu_items = []; + this.menu_visible = true; + + Object.assign(this, properties); + + // TipBox.prototype._init.apply(this, arguments); + this.vals = []; + this.tip_labels = []; + this.tip_vals = []; + this.tip_unit_labels = []; + + this.colors = []; + for (let color in this.color_name) { + let name = this.elt + '-' + this.color_name[color] + '-color'; + let clutterColor = color_from_string(Schema.get_string(name)); + Schema.connect('changed::' + name, (schema, key) => { + this.clutterColor = color_from_string(Schema.get_string(key)); + }); + Schema.connect('changed::' + name, () => { + this.chart.actor.queue_repaint(); + }); + this.colors.push(clutterColor); + } + + let element_width = Schema.get_int(this.elt + '-graph-width'); + if (Style.get('') === '-compact') { + element_width = Math.round(element_width / 1.5); + } + this.chart = new Chart(element_width, IconSize, this); + + Schema.connect('changed::background', () => { + this.chart.actor.queue_repaint(); + }); + + this.actor.visible = Schema.get_boolean(this.elt + '-display'); + Schema.connect( + 'changed::' + this.elt + '-display', (schema, key) => { + this.actor.visible = Schema.get_boolean(key); + }); + + this.interval = l_limit(Schema.get_int(this.elt + '-refresh-time')); + this.timeout = Mainloop.timeout_add( + this.interval, + this.update.bind(this), + GLib.PRIORITY_DEFAULT_IDLE + ); + + Schema.connect( + 'changed::' + this.elt + '-refresh-time', + (schema, key) => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.interval = l_limit(Schema.get_int(key)); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + Schema.connect('changed::' + this.elt + '-graph-width', this.resize.bind(this)); + + if (this.elt === 'thermal') { + Schema.connect('changed::thermal-threshold', + () => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.reset_style(); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + } + + this.label = new St.Label({text: this.elt === 'memory' ? _('mem') : _(this.elt), + style_class: Style.get('sm-status-label')}); + change_text.call(this); + Schema.connect('changed::' + this.elt + '-show-text', change_text.bind(this)); + + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + Schema.connect('changed::' + this.elt + '-show-menu', change_menu.bind(this)); + + this.actor.add_actor(this.label); + this.text_box = new St.BoxLayout(); + + this.actor.add_actor(this.text_box); + this.text_items = this.create_text_items(); + for (let item in this.text_items) { + this.text_box.add_actor(this.text_items[item]); + } + this.actor.add_actor(this.chart.actor); + change_style.call(this); + Schema.connect('changed::' + this.elt + '-style', change_style.bind(this)); + this.menu_items = this.create_menu_items(); + } + tip_format(unit) { + if (typeof (unit) === 'undefined') { + unit = '%'; + } + if (typeof (unit) === 'string') { + let all_unit = unit; + unit = []; + for (let i = 0; i < this.color_name.length; i++) { + unit.push(all_unit); + } + } + for (let i = 0; i < this.color_name.length; i++) { + let tipline = new TipItem(); + this.tipmenu.addMenuItem(tipline); + tipline.actor.add(new St.Label({text: _(this.color_name[i])})); + this.tip_labels[i] = new St.Label({text: ''}); + tipline.actor.add(this.tip_labels[i]); + + this.tip_unit_labels[i] = new St.Label({text: unit[i]}); + tipline.actor.add(this.tip_unit_labels[i]); + this.tip_vals[i] = 0; + } + } + // set_tip_unit: function(unit) { + // for (let i = 0;i < this.tip_unit_labels.length;i++) { + // this.tip_unit_labels[i].text = unit[i]; + // } + // } + update() { + if (!this.menu_visible && !this.actor.visible) { + return false; + } + this.refresh(); + this._apply(); + if (this.elt === 'thermal') { + this.threshold(); + } + this.chart.update(); + for (let i = 0; i < this.tip_vals.length; i++) { + if (this.tip_labels[i]) { + this.tip_labels[i].text = this.tip_vals[i].toString(); + } + } + return true; + } + reset_style() { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + threshold() { + if (Schema.get_int('thermal-threshold')) { + if (this.temp_over_threshold) { + this.text_items[0].set_style('color: rgba(255, 0, 0, 1)'); + } else { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + } + } + resize(schema, key) { + let width = Schema.get_int(key); + if (Style.get('') === '-compact') { + width = Math.round(width / 1.5); + } + this.chart.resize(width); + } + destroy() { + TipBox.prototype.destroy.call(this); + if (this.timeout) { + Mainloop.source_remove(this.timeout); + this.timeout = null; + } + } +} + +const Battery = class SystemMonitor_Battery extends ElementBase { + constructor() { + super({ + elt: 'battery', + item_name: _('Battery'), + color_name: ['batt0'], + icon: '. GThemedIcon battery-good-symbolic battery-good' + }); + + this.max = 100; + this.icon_hidden = false; + this.percentage = 0; + this.timeString = '-- '; + this._proxy = StatusArea.aggregateMenu._power._proxy; + if (typeof (this._proxy) === 'undefined') { + this._proxy = StatusArea.battery._proxy; + } + this.powerSigID = this._proxy.connect('g-properties-changed', this.update_battery.bind(this)); + + // need to specify a default icon, since the contructor completes before UPower callback + this.gicon = Gio.icon_new_for_string(this.icon); + + this.tip_format('%'); + + this.update_battery(); + this.update_tips(); + // this.hide_system_icon(); + this.update(); + + // Schema.connect('changed::' + this.elt + '-hidesystem', this.hide_system_icon.bind(this)); + Schema.connect('changed::' + this.elt + '-time', this.update_tips.bind(this)); + } + refresh() { + // do nothing here? + } + update_battery() { + // callback function for when battery stats updated. + let battery_found = false; + let isBattery = false; + if (typeof (this._proxy.GetDevicesRemote) === 'undefined') { + let device_type = this._proxy.Type; + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + let icon = this._proxy.IconName; + let percentage = this._proxy.Percentage; + let seconds = this._proxy.TimeToEmpty; + this.update_battery_value(seconds, percentage, icon); + } else { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + } else { + this._proxy.GetDevicesRemote((devices, error) => { + if (error) { + log('[System monitor] Power proxy error: ' + error); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + return; + } + + let [result] = devices; + for (let i = 0; i < result.length; i++) { + let [device_id, device_type, icon, percentage, state, seconds] = result[i]; + + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + this.update_battery_value(seconds, percentage, icon); + break; + } + } + + if (!battery_found) { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + }); + } + } + update_battery_value(seconds, percentage, icon) { + if (seconds > 60) { + let time = Math.round(seconds / 60); + let minutes = time % 60; + let hours = Math.floor(time / 60); + this.timeString = C_('battery time remaining', '%d:%02d').format(hours, minutes); + } else { + this.timeString = '-- '; + } + this.percentage = Math.ceil(percentage); + this.gicon = Gio.icon_new_for_string(icon); + + if (Schema.get_boolean(this.elt + '-display')) { + this.actor.show() + } + if (Schema.get_boolean(this.elt + '-show-menu') && !this.menu_visible) { + this.menu_visible = true; + build_menu_info(); + } + } + hide_system_icon(override) { + let value = Schema.get_boolean(this.elt + '-hidesystem'); + if (!override) { + value = false; + } + if (value && Schema.get_boolean(this.elt + '-display')) { + if (shell_Version > '3.5') { + if (StatusArea.battery.actor.visible) { + StatusArea.battery.destroy(); + this.icon_hidden = true; + } + } else { + for (let Index = 0; Index < Main.panel._rightBox.get_children().length; Index++) { + if (StatusArea.battery === Main.panel._rightBox.get_children()[Index]._delegate) { + Main.panel._rightBox.get_children()[Index].destroy(); + StatusArea.battery = null; + this.icon_hidden = true; + break; + } + } + } + } else if (this.icon_hidden) { + if (shell_Version < '3.5') { + let Indicator = new Panel.STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION.battery(); + Main.panel.addToStatusArea('battery', Indicator, Panel.STANDARD_STATUS_AREA_ORDER.indexOf('battery')); + } else { + let Indicator = new Panel.PANEL_ITEM_IMPLEMENTATIONS.battery(); + Main.panel.addToStatusArea('battery', Indicator, Main.sessionMode.panel.right.indexOf('battery'), 'right'); + } + this.icon_hidden = false; + // Main.panel._updatePanel('right'); + } + } + get_battery_unit() { + let unitString; + let value = Schema.get_boolean(this.elt + '-time'); + + if (value) { + unitString = 'h'; + } else { + unitString = '%'; + } + + return unitString; + } + update_tips() { + let unitString = this.get_battery_unit(); + + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[2].text = unitString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[1].text = unitString; + } + + this.update(); + } + _apply() { + let displayString; + let value = Schema.get_boolean(this.elt + '-time'); + if (value) { + displayString = this.timeString; + } else { + displayString = this.percentage.toString() + } + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[0].gicon = this.gicon; + this.text_items[1].text = displayString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[0].text = displayString; + } + this.vals = [this.percentage]; + this.tip_vals[0] = Math.round(this.percentage); + } + create_text_items() { + return [ + new St.Icon({ + gicon: Gio.icon_new_for_string(this.icon), + style_class: Style.get('sm-status-icon')}), + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-label')}) + ]; + } + destroy() { + ElementBase.prototype.destroy.call(this); + this._proxy.disconnect(this.powerSigID); + } +} + +const Cpu = class SystemMonitor_Cpu extends ElementBase { + constructor(cpuid) { + super({ + elt: 'cpu', + item_name: _('CPU'), + color_name: ['user', 'system', 'nice', 'iowait', 'other'], + cpuid: -1 // cpuid is -1 when all cores are displayed in the same graph + }); + this.max = 100; + + this.cpuid = cpuid; + this.gtop = new GTop.glibtop_cpu(); + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + try { + this.total_cores = GTop.glibtop_get_sysinfo().ncpu; + if (cpuid === -1) { + this.max *= this.total_cores; + } + } catch (e) { + this.total_cores = this.get_cores(); + global.logError(e) + } + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + this.item_name = _('Cpu'); + if (cpuid !== -1) { + this.item_name += ' ' + (cpuid + 1); + } // append cpu number to cpu name in popup + // ElementBase.prototype._init.call(this); + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_cpu(this.gtop); + // display global cpu usage on 1 graph + if (this.cpuid === -1) { + this.current[0] = this.gtop.user; + this.current[1] = this.gtop.sys; + this.current[2] = this.gtop.nice; + this.current[3] = this.gtop.idle; + this.current[4] = this.gtop.iowait; + let delta = (this.gtop.total - this.last_total) / (100 * this.total_cores); + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.total; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } else { + // display per cpu data + this.current[0] = this.gtop.xcpu_user[this.cpuid]; + this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + let delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total) / 100; + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.xcpu_total[this.cpuid]; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } + + // GTop.glibtop_get_cpu(this.gtop); + // // display global cpu usage on 1 graph + // if (this.cpuid == -1) { + // this.current[0] = this.gtop.user; + // this.current[1] = this.gtop.sys; + // this.current[2] = this.gtop.nice; + // this.current[3] = this.gtop.idle; + // this.current[4] = this.gtop.iowait; + // } else { + // // display cpu usage for given core + // this.current[0] = this.gtop.xcpu_user[this.cpuid]; + // this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + // this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + // this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + // this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + // } + // + // let delta = 0; + // if (this.cpuid == -1) + // delta = (this.gtop.total - this.last_total)/(100*this.total_cores); + // else + // delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total)/100; + // + // if (delta > 0) { + // for (let i = 0;i < 5;i++) { + // this.usage[i] = Math.round((this.current[i] - this.last[i])/delta); + // this.last[i] = this.current[i]; + // } + // if (this.cpuid == -1) + // this.last_total = this.gtop.total; + // else + // this.last_total = this.gtop.xcpu_total[this.cpuid]; + // } + } + _apply() { + let percent = 0; + if (this.cpuid === -1) { + percent = Math.round(((100 * this.total_cores) - this.usage[3]) / + this.total_cores); + } else { + percent = Math.round((100 - this.usage[3])); + } + + this.text_items[0].text = this.menu_items[0].text = percent.toString(); + let other = 100; + for (let i = 0; i < this.usage.length; i++) { + other -= this.usage[i]; + } + // Not to be confusing + other = Math.max(0, other); + this.vals = [this.usage[0], this.usage[1], + this.usage[2], this.usage[4], other]; + for (let i = 0; i < 5; i++) { + this.tip_vals[i] = Math.round(this.vals[i]); + } + } + + get_cores() { + // Getting xcpu_total makes gjs 1.29.18 segfault + // let cores = 0; + // GTop.glibtop_get_cpu(this.gtop); + // let gtop_total = this.gtop.xcpu_total + // for (let i = 0; i < gtop_total.length;i++) { + // if (gtop_total[i] > 0) + // cores++; + // } + // return cores; + return 1; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}) + ]; + } +} + +// Check if one graph per core must be displayed and create the +// appropriate number of cpu items +function createCpus() { + let array = []; + let numcores = 1; + + if (Schema.get_boolean('cpu-individual-cores')) { + // get number of cores + let gtop = new GTop.glibtop_cpu(); + try { + numcores = GTop.glibtop_get_sysinfo().ncpu; + } catch (e) { + global.logError(e); + numcores = 1; + } + } + + // there are several cores to display, + // instantiate each cpu + if (numcores > 1) { + for (let i = 0; i < numcores; i++) { + array.push(new Cpu(i)); + } + } else { + // individual cores option is not set or we failed to + // get the number of cores, create a global cpu item + array.push(new Cpu(-1)); + } + + return array; +} + +const Disk = class SystemMonitor_Disk extends ElementBase { + constructor() { + super({ + elt: 'disk', + item_name: _('Disk'), + color_name: ['read', 'write'] + }); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + this.last = [0, 0]; + this.usage = [0, 0]; + this.last_time = 0; + this.tip_format(_('MiB/s')); + this.update(); + } + update_mounts(mounts) { + this.mounts = mounts; + } + refresh() { + let accum = [0, 0]; + + let file = Gio.file_new_for_path('/proc/diskstats'); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result); + let lines = parse_bytearray(as_r[1]).toString().split('\n'); + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let entry = line.trim().split(/[\s]+/); + if (typeof (entry[1]) === 'undefined') { + break; + } + accum[0] += parseInt(entry[5]); + accum[1] += parseInt(entry[9]); + } + + let time = GLib.get_monotonic_time() / 1000; + let delta = (time - this.last_time) / 1000; + if (delta > 0) { + for (let i = 0; i < 2; i++) { + this.usage[i] = ((accum[i] - this.last[i]) / delta / 1024 / 8); + this.last[i] = accum[i]; + } + } + this.last_time = time; + }); + } + _apply() { + this.vals = this.usage.slice(); + for (let i = 0; i < 2; i++) { + if (this.usage[i] < 10) { + this.usage[i] = Math.round(10 * this.usage[i]) / 10; + } else { + this.usage[i] = Math.round(this.usage[i]); + } + } + this.tip_vals = [this.usage[0], this.usage[1]]; + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toLocaleString(Locale); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[1].toLocaleString(Locale); + } + create_text_items() { + return [ + new St.Label({ + text: _('R'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('W'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _('R'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: ' ' + _('W'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Freq = class SystemMonitor_Freq extends ElementBase { + constructor() { + super({ + elt: 'freq', + item_name: _('Freq'), + color_name: ['freq'] + }); + this.freq = 0; + this.tip_format('MHz'); + this.update(); + } + refresh() { + let total_frequency = 0; + let num_cpus = GTop.glibtop_get_sysinfo().ncpu; + let i = 0; + let file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + var that = this; + file.load_contents_async(null, function cb(source, result) { + let as_r = source.load_contents_finish(result); + total_frequency += parseInt(parse_bytearray(as_r[1])); + + if (++i >= num_cpus) { + that.freq = Math.round(total_frequency / num_cpus / 1000); + } else { + file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + file.load_contents_async(null, cb.bind(that)); + } + }); + } + _apply() { + let value = this.freq.toString(); + this.text_items[0].text = value + ' '; + this.vals[0] = value; + this.tip_vals[0] = value; + if (Style.get('') !== '-compact') { + this.menu_items[0].text = value; + } else { + this.menu_items[0].text = this._pad(value, 4); + } + } + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-big-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: 'MHz', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: 'MHz', + style_class: Style.get('sm-label')}) + ]; + } +} + +const Mem = class SystemMonitor_Mem extends ElementBase { + constructor() { + super({ + elt: 'memory', + item_name: _('Memory'), + color_name: ['program', 'buffer', 'cache'] + }); + this.max = 1; + + this.gtop = new GTop.glibtop_mem(); + this.mem = [0, 0, 0]; + + GTop.glibtop_get_mem(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_mem(this.gtop); + if (this.useGiB) { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[0] /= this._decimals; + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[1] /= this._decimals; + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.mem[2] /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0, 0, 0]; + } else { + for (let i = 0; i < 3; i++) { + this.vals[i] = this.mem[i] / this.total; + this.tip_vals[i] = Math.round(this.vals[i] * 100); + } + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem[0]) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.mem[0]) + + '/' + this._pad(this.total); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Net = class SystemMonitor_Net extends ElementBase { + constructor() { + super({ + elt: 'net', + item_name: _('Net'), + color_name: ['down', 'downerrors', 'up', 'uperrors', 'collisions'] + }); + this.speed_in_bits = false; + this.ifs = []; + this.client = libnm_glib ? NM.Client.new() : NM.Client.new(null); + this.update_iface_list(); + + if (!this.ifs.length) { + let net_lines = Shell.get_file_contents_utf8_sync('/proc/net/dev').split('\n'); + for (let i = 2; i < net_lines.length - 1; i++) { + let ifc = net_lines[i].replace(/^\s+/g, '').split(':')[0]; + if (Shell.get_file_contents_utf8_sync('/sys/class/net/' + ifc + '/operstate') + .replace(/\s/g, '') === 'up' && + ifc.indexOf('br') < 0 && + ifc.indexOf('lo') < 0) { + this.ifs.push(ifc); + } + } + } + this.gtop = new GTop.glibtop_netload(); + this.last = [0, 0, 0, 0, 0]; + this.usage = [0, 0, 0, 0, 0]; + this.last_time = 0; + this.tip_format([_('KiB/s'), '/s', _('KiB/s'), '/s', '/s']); + this.update_units(); + Schema.connect('changed::' + this.elt + '-speed-in-bits', this.update_units.bind(this)); + try { + let iface_list = this.client.get_devices(); + this.NMsigID = []; + for (let j = 0; j < iface_list.length; j++) { + this.NMsigID[j] = iface_list[j].connect('state-changed', this.update_iface_list.bind(this)); + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings: ' + e); + } + this.update(); + } + update_units() { + this.speed_in_bits = Schema.get_boolean(this.elt + '-speed-in-bits'); + } + update_iface_list() { + try { + this.ifs = []; + let iface_list = this.client.get_devices(); + for (let j = 0; j < iface_list.length; j++) { + if (iface_list[j].state === NetworkManager.DeviceState.ACTIVATED) { + this.ifs.push(iface_list[j].get_ip_iface() || iface_list[j].get_iface()); + } + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings'); + } + } + refresh() { + let accum = [0, 0, 0, 0, 0]; + + for (let ifn in this.ifs) { + GTop.glibtop_get_netload(this.gtop, this.ifs[ifn]); + accum[0] += this.gtop.bytes_in; + accum[1] += this.gtop.errors_in; + accum[2] += this.gtop.bytes_out; + accum[3] += this.gtop.errors_out; + accum[4] += this.gtop.collisions; + } + + let time = GLib.get_monotonic_time() * 0.001024; + let delta = time - this.last_time; + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((accum[i] - this.last[i]) / delta); + this.last[i] = accum[i]; + this.vals[i] = this.usage[i]; + } + } + this.last_time = time; + } + + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + + _apply() { + this.tip_vals = this.usage; + if (this.speed_in_bits) { + this.tip_vals[0] = Math.round(this.tip_vals[0] * 8.192); + this.tip_vals[2] = Math.round(this.tip_vals[2] * 8.192); + if (this.tip_vals[0] < 1000) { + this.text_items[2].text = Style.netunits_kbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('kbit/s'); + } else if (this.tip_vals[0] < 1000000) { + this.text_items[2].text = Style.netunits_mbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Mbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Gbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000000).toPrecision(3); + } + if (this.tip_vals[2] < 1000) { + this.text_items[5].text = Style.netunits_kbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('kbit/s'); + } else if (this.tip_vals[2] < 1000000) { + this.text_items[5].text = Style.netunits_mbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Mbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Gbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000000).toPrecision(3); + } + } else { + if (this.tip_vals[0] < 1024) { + this.text_items[2].text = Style.netunits_kbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('KiB/s'); + } else if (this.tip_vals[0] < 1048576) { + this.text_items[2].text = Style.netunits_mbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('MiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1024).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('GiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1048576).toPrecision(3); + } + if (this.tip_vals[2] < 1024) { + this.text_items[5].text = Style.netunits_kbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('KiB/s'); + } else if (this.tip_vals[2] < 1048576) { + this.text_items[5].text = Style.netunits_mbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('MiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1024).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('GiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1048576).toPrecision(3); + } + } + + if (Style.get('') !== '-compact') { + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toString(); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[2].toString(); + } else { + this.menu_items[0].text = this.text_items[1].text = this._pad(this.tip_vals[0].toString(), 4); + this.menu_items[3].text = this.text_items[4].text = this._pad(this.tip_vals[2].toString(), 4); + } + } + create_text_items() { + return [ + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-down-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-up-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↓'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(' KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↑'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Swap = class SystemMonitor_Swap extends ElementBase { + constructor() { + super({ + elt: 'swap', + item_name: _('Swap'), + color_name: ['used'] + }); + this.max = 1; + this.gtop = new GTop.glibtop_swap(); + + GTop.glibtop_get_swap(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_swap(this.gtop); + if (this.useGiB) { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.swap /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0]; + } else { + this.vals[0] = this.swap / this.total; + this.tip_vals[0] = Math.round(this.vals[0] * 100); + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toString(); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.swap) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.swap) + + '/' + this._pad(this.total); + } + } + + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = 'MiB'; + if (this.useGiB) { + unit = 'GiB'; + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(unit), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Thermal = class SystemMonitor_Thermal extends ElementBase { + constructor() { + super({ + elt: 'thermal', + item_name: _('Thermal'), + color_name: ['tz0'] + }); + this.max = 100; + + this.item_name = _('Thermal'); + this.temperature = '-- '; + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + this.display_error = true; + this.tip_format(this.temperature_symbol()); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.temperature = Math.round(parseInt(parse_bytearray(as_r[1])) / 1000); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + } + _apply() { + this.text_items[0].text = this.menu_items[0].text = this.temperature_text(); + this.temp_over_threshold = this.temperature > Schema.get_int('thermal-threshold'); + this.vals = [this.temperature]; + this.tip_vals[0] = this.temperature_text(); + this.text_items[1].text = this.menu_items[1].text = this.temperature_symbol(); + this.tip_unit_labels[0].text = _(this.temperature_symbol()); + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-temp-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-label')}) + ]; + } + temperature_text() { + let temperature = this.temperature; + if (this.fahrenheit_unit) { + temperature = Math.round(temperature * 1.8 + 32); + } + return temperature.toString(); + } + temperature_symbol() { + return this.fahrenheit_unit ? '°F' : '°C'; + } +} + +const Fan = class SystemMonitor_Fan extends ElementBase { + constructor() { + super({ + elt: 'fan', + item_name: _('Fan'), + color_name: ['fan0'] + }); + this.rpm = 0; + this.display_error = true; + this.tip_format(_('rpm')); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.rpm = parseInt(parse_bytearray(as_r[1])); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + } + _apply() { + this.text_items[0].text = this.rpm.toString(); + this.menu_items[0].text = this.rpm.toString(); + this.vals = [this.rpm / 10]; + this.tip_vals[0] = this.rpm; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('rpm'), style_class: Style.get('sm-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('rpm'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Gpu = class SystemMonitor_Gpu extends ElementBase { + constructor() { + super({ + elt: 'gpu', + item_name: _('GPU'), + color_name: ['used', 'memory'] + }); + this.max = 100; + + this.item_name = _('GPU'); + this.mem = 0; + this.total = 0; + this.tip_format(); + this.update(); + } + _unit(total) { + this.total = total; + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + } + refresh() { + // Run asynchronously, to avoid shell freeze + try { + let path = Me.dir.get_path(); + let script = ['/bin/bash', path + '/gpu_usage.sh']; + + // Create subprocess and capture STDOUT + let proc = new Gio.Subprocess({argv: script, flags: Gio.SubprocessFlags.STDOUT_PIPE}); + proc.init(null); + // Asynchronously call the output handler when script output is ready + proc.communicate_utf8_async(null, null, Lang.bind(this, this._handleOutput)); + } catch (err) { + global.logError(err.message); + } + } + _handleOutput(proc, result) { + let [ok, output, ] = proc.communicate_utf8_finish(result); + if (ok) { + this._readTemperature(output); + } else { + global.logError('gpu_usage.sh invocation failed'); + } + } + _sanitizeUsageValue(val) { + val = parseInt(val); + if (isNaN(val)) { + val = 0 + } + return val; + } + _readTemperature(procOutput) { + let usage = procOutput.split('\n'); + let memTotal = this._sanitizeUsageValue(usage[0]); + let memUsed = this._sanitizeUsageValue(usage[1]); + this.percentage = this._sanitizeUsageValue(usage[2]); + if (typeof this.useGiB === 'undefined') { + this._unit(memTotal); + this._update_unit(); + } + + if (this.useGiB) { + this.mem = Math.round(memUsed / this._unitConversion); + this.mem /= this._decimals; + this.total = Math.round(memTotal / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem = Math.round(memUsed / this._unitConversion); + this.total = Math.round(memTotal / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toFixed(2); + } + // examples: 5.85, 16.0, 128 + return number.toPrecision(3); + } + + return number; + } + _update_unit() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + this.menu_items[4].text = unit; + } + _apply() { + this.tip_unit_labels[1].text = "/ " + this.total + " " + this.menu_items[4].text; + if (this.total === 0) { + this.vals = [0, 0]; + this.tip_vals = [0, 0]; + } else { + // we subtract percentage from memory because we do not want memory to be + // "accumulated" in the chart with utilization; these two measures should be + // independent + this.vals = [this.percentage, this.mem / this.total * 100 - this.percentage]; + this.tip_vals = [Math.round(this.vals[0]), this.mem]; + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + ' / ' + this._pad(this.total).toLocaleString(Locale); + } else { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + '/' + this._pad(this.total).toLocaleString(Locale); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Icon = class SystemMonitor_Icon { + constructor() { + this.actor = new St.Icon({ + icon_name: 'org.gnome.SystemMonitor-symbolic', + style_class: 'system-status-icon' + }); + this.actor.visible = Schema.get_boolean('icon-display'); + Schema.connect( + 'changed::icon-display', + () => { + this.actor.visible = Schema.get_boolean('icon-display'); + } + ); + } +} + +function init() { + log('[System monitor] applet init from ' + extension.path); + + Convenience.initTranslations(); + // Get locale, needed as an argument for toLocaleString() since GNOME Shell 3.24 + // See: mozjs library bug https://bugzilla.mozilla.org/show_bug.cgi?id=999003 + Locale = GLib.get_language_names()[0]; + if (Locale.indexOf('_') !== -1) { + Locale = Locale.split('_')[0]; + } + + IconSize = Math.round(Panel.PANEL_ICON_SIZE * 4 / 5); +} + +function enable() { + log('[System monitor] applet enabling'); + Schema = Convenience.getSettings(); + + Style = new smStyleManager(); + MountsMonitor = new smMountsMonitor(); + + Background = color_from_string(Schema.get_string('background')); + + if (!(smDepsGtop && smDepsNM)) { + Main.__sm = { + smdialog: new smDialog() + }; + + let dialog_timeout = Mainloop.timeout_add_seconds( + 1, + () => { + Main.__sm.smdialog.open(); + Mainloop.source_remove(dialog_timeout); + return true; + }); + } else { + let panel = Main.panel._rightBox; + StatusArea = Main.panel._statusArea; + if (typeof (StatusArea) === 'undefined') { + StatusArea = Main.panel.statusArea; + } + if (Schema.get_boolean('center-display')) { + panel = Main.panel._centerBox; + } + + MountsMonitor.connect(); + + // Debug + Main.__sm = { + tray: new PanelMenu.Button(0.5), + icon: new Icon(), + pie: new Pie(), + bar: new Bar(), + elts: [], + }; + + // Items to Monitor + Main.__sm.elts = createCpus(); + Main.__sm.elts.push(new Freq()); + Main.__sm.elts.push(new Mem()); + Main.__sm.elts.push(new Swap()); + Main.__sm.elts.push(new Net()); + Main.__sm.elts.push(new Disk()); + Main.__sm.elts.push(new Gpu()); + Main.__sm.elts.push(new Thermal()); + Main.__sm.elts.push(new Fan()); + Main.__sm.elts.push(new Battery()); + + let tray = Main.__sm.tray; + let elts = Main.__sm.elts; + + if (Schema.get_boolean('move-clock')) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._centerBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, -1, Main.panel._rightBox); + tray.clockMoved = true; + } + + Schema.connect('changed::background', (schema, key) => { + Background = color_from_string(Schema.get_string(key)); + }); + Main.panel._addToPanelBox('system-monitor', tray, 1, panel); + + // The spacing adds a distance between the graphs/text on the top bar + let spacing = Schema.get_boolean('compact-display') ? '1' : '4'; + let box = new St.BoxLayout({style: 'spacing: ' + spacing + 'px;'}); + if (shell_Version < '3.36') { + tray.actor.add_actor(box); + } else { + tray.add_actor(box); + } + box.add_actor(Main.__sm.icon.actor); + // Add items to panel box + for (let elt in elts) { + box.add_actor(elts[elt].actor); + } + + // Build Menu Info Box Table + let menu_info = new PopupMenu.PopupBaseMenuItem({reactive: false}); + let menu_info_box = new St.BoxLayout(); + menu_info.actor.add(menu_info_box); + Main.__sm.tray.menu.addMenuItem(menu_info, 0); + + build_menu_info(); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + let pie_item = Main.__sm.pie; + pie_item.create_menu_item(); + tray.menu.addMenuItem(pie_item.menu_item); + + let bar_item = Main.__sm.bar; + bar_item.create_menu_item(); + tray.menu.addMenuItem(bar_item.menu_item); + + change_usage(); + Schema.connect('changed::disk-usage-style', change_usage); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + tray.menu.connect( + 'open-state-changed', + function (menu, isOpen) { + if (isOpen) { + Main.__sm.pie.actor.queue_repaint(); + + menu_timeout = Mainloop.timeout_add_seconds( + 5, + () => { + Main.__sm.pie.actor.queue_repaint(); + return true; + }); + } else { + Mainloop.source_remove(menu_timeout); + } + } + ); + + let _appSys = Shell.AppSystem.get_default(); + let _gsmApp = _appSys.lookup_app('gnome-system-monitor.desktop'); + let _gsmPrefs = _appSys.lookup_app('gnome-shell-extension-prefs.desktop'); + if (_gsmPrefs === null) { + _gsmPrefs = _appSys.lookup_app('org.gnome.Extensions.desktop'); + } + let item; + item = new PopupMenu.PopupMenuItem(_('System Monitor...')); + item.connect('activate', () => { + _gsmApp.activate(); + }); + tray.menu.addMenuItem(item); + + item = new PopupMenu.PopupMenuItem(_('Preferences...')); + item.connect('activate', () => { + if (typeof ExtensionUtils.openPrefs === 'function') { + ExtensionUtils.openPrefs(); + } else if (_gsmPrefs.get_state() === _gsmPrefs.SHELL_APP_STATE_RUNNING) { + _gsmPrefs.activate(); + } else { + let info = _gsmPrefs.get_app_info(); + let timestamp = global.display.get_current_time_roundtrip(); + info.launch_uris([metadata.uuid], global.create_app_launch_context(timestamp, -1)); + } + }); + tray.menu.addMenuItem(item); + Main.panel.menuManager.addMenu(tray.menu); + } + log('[System monitor] applet enabling done'); +} + +function disable() { + // restore clock + if (Main.__sm.tray.clockMoved) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._rightBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, Main.sessionMode.panel.center.indexOf('dateMenu'), Main.panel._centerBox); + } + // restore system power icon if necessary + // workaround bug introduced by multiple cpus init : + // if (Schema.get_boolean('battery-hidesystem') && Main.__sm.elts.battery.icon_hidden) { + // Main.__sm.elts.battery.hide_system_icon(false); + // } + // for (let i in Main.__sm.elts) { + // if (Main.__sm.elts[i].elt == 'battery') + // Main.__sm.elts[i].hide_system_icon(false); + // } + + if (MountsMonitor) { + MountsMonitor.disconnect(); + MountsMonitor = null; + } + + if (Style) { + Style = null; + } + + Schema.run_dispose(); + for (let eltName in Main.__sm.elts) { + Main.__sm.elts[eltName].destroy(); + } + if (shell_Version < '3.36') { + Main.__sm.tray.actor.destroy(); + } else { + Main.__sm.tray.destroy(); + } + Main.__sm = null; + + log('[System monitor] applet disable'); +} diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh new file mode 100644 index 0000000..de840b9 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh @@ -0,0 +1,49 @@ +#!/bin/sh +################################################################################## +# This file is part of System Monitor Gnome extension. +# System Monitor Gnome extension 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. +# System Monitor Gnome extension 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 System Monitor. If not, see . +# Copyright 2017 Fran Glais, David King, indigohedgehog@github. +################################################################################## + +################################## +# # +# Check for GPU memory usage # +# # +################################## + +checkcommand() +{ + command -v "$1" > /dev/null 2>&1 +} + +# This will print three lines. The first one is the the total vRAM available, +# the second one is the used vRAM and the third on is the GPU usage in %. +if checkcommand nvidia-smi; then + nvidia-smi -i 0 --query-gpu=memory.total,memory.used,utilization.gpu --format=csv,noheader,nounits | while IFS=', ' read -r a b c; do echo "$a"; echo "$b"; echo "$c"; done + +elif lsmod | grep amdgpu > /dev/null; then + total=$(cat /sys/class/drm/card0/device/mem_info_vram_total) + echo $((total / 1024 / 1024)) + + used=$(cat /sys/class/drm/card0/device/mem_info_vram_used) + echo $((used / 1024 / 1024)) + + cat /sys/class/drm/card0/device/gpu_busy_percent + +elif checkcommand glxinfo; then + TOTALVRAM=$(glxinfo | grep -A2 -i GL_NVX_gpu_memory_info | grep -E -i "dedicated" | cut -f2- -d ':' | gawk '{print $1}') + AVAILVRAM=$(glxinfo | grep -A4 -i GL_NVX_gpu_memory_info | grep -E -i "available dedicated" | cut -f2- -d ':' | gawk '{print $1}') + FREEVRAM=$((TOTALVRAM-AVAILVRAM)) + echo "$TOTALVRAM" + echo "$FREEVRAM" + +fi diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ed116be Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ab48c30 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..be4ab2d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..a14e961 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7302234 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7f3d4b3 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b1ccb17 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7623fac Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..e567368 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..5ffcee0 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..8fb4592 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..4e96e8e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..94c2ce3 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..472482f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9537a6e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b756a3d Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7d79d27 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c789c33 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..3bca914 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c362e0e Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..1d4ff15 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9169a1f Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..09f9162 Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json new file mode 100644 index 0000000..44e737a --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json @@ -0,0 +1,19 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Display system information in GNOME Shell status bar, such as memory, CPU, disk and battery usages, network rates\u2026", + "gettext-domain": "system-monitor", + "name": "system-monitor", + "settings-schema": "org.gnome.shell.extensions.system-monitor", + "shell-version": [ + "3.26", + "3.28", + "3.30", + "3.34", + "3.32", + "3.36", + "40" + ], + "url": "https://github.com/paradoxxxzero/gnome-shell-system-monitor-applet", + "uuid": "system-monitor@paradoxxx.zero.gmail.com", + "version": 40 +} \ No newline at end of file diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js new file mode 100644 index 0000000..388f512 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js @@ -0,0 +1,553 @@ +const Gtk = imports.gi.Gtk; +const Gio = imports.gi.Gio; +const Gdk = imports.gi.Gdk; +const GLib = imports.gi.GLib; +const ByteArray = imports.byteArray; +const Config = imports.misc.config; + +const Gettext = imports.gettext.domain('system-monitor'); + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let convenience = extension.imports.convenience; + +const _ = Gettext.gettext; +const N_ = function (e) { + return e; +}; + +let Schema; + +const shellMajorVersion = parseInt(Config.PACKAGE_VERSION.split('.')[0]); + +function init() { + convenience.initTranslations(); + Schema = convenience.getSettings(); +} + +String.prototype.capitalize = function () { + return this.replace(/(^|\s)([a-z])/g, function (m, p1, p2) { + return p1 + p2.toUpperCase(); + }); +}; + +function color_to_hex(color) { + var output = N_('#%02x%02x%02x%02x').format( + 255 * color.red, + 255 * color.green, + 255 * color.blue, + 255 * color.alpha); + return output; +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function check_sensors(sensor_type) { + const hwmon_path = '/sys/class/hwmon/'; + const hwmon_dir = Gio.file_new_for_path(hwmon_path); + + const sensor_files = []; + const sensor_labels = []; + + function get_label_from(file) { + if (file.query_exists(null)) { + // load_contents (and even cat) fails with "Invalid argument" for some label files + try { + let [success, contents] = file.load_contents(null); + if (success) { + return String(parse_bytearray(contents)).split('\n')[0]; + } + } catch (e) { + log('[System monitor] error loading label from file ' + file.get_path() + ': ' + e); + } + } + return null; + } + + function add_sensors_from(chip_dir, chip_label) { + const chip_children = chip_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!chip_children) { + log('[System monitor] error enumerating children of chip ' + chip_dir.get_path()); + return false; + } + + const input_entry_regex = new RegExp('^' + sensor_type + '(\\d+)_input$'); + let info; + let added = false; + while ((info = chip_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.REGULAR) { + continue; + } + const matches = info.get_name().match(input_entry_regex); + if (!matches) { + continue; + } + const input_ordinal = matches[1]; + const input = chip_children.get_child(info); + const input_label = get_label_from(chip_dir.get_child(sensor_type + input_ordinal + '_label')); + + sensor_files.push(input.get_path()); + sensor_labels.push(chip_label + ' - ' + (input_label || input_ordinal)); + added = true; + } + return added; + } + + const hwmon_children = hwmon_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!hwmon_children) { + log('[System monitor] error enumerating hwmon children'); + return [[], []]; + } + + let info; + while ((info = hwmon_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.DIRECTORY || !info.get_name().match(/^hwmon\d+$/)) { + continue; + } + const chip = hwmon_children.get_child(info); + const chip_label = get_label_from(chip.get_child('name')) || chip.get_basename(); + + if (!add_sensors_from(chip, chip_label)) { + // This is here to provide compatibility with previous code, but I can't find any + // information about sensors being stored in chip/device directory. Can we delete it? + const chip_device = chip.get_child('device'); + if (chip_device.query_exists(null)) { + add_sensors_from(chip_device, chip_label); + } + } + } + return [sensor_files, sensor_labels]; +} + +/** + * @param args.hasBorder Whether the box has a border (true) or not + * @param args.horizontal Whether the box is horizontal (true) + * or vertical (false) + * @param args.shouldPack Determines whether a horizontal box should have + * uniform spacing for its children. Only applies to horizontal boxes + * @param args.spacing The amount of spacing for a given box + * @returns a new Box with settings specified by args + */ +function box(args = {}) { + const options = { }; + + if (typeof args.spacing !== 'undefined') { + options.spacing = args.spacing; + } + + if (shellMajorVersion < 40) { + if (args.hasBorder) { + options.border_width = 10; + } + + return args.horizontal ? + new Gtk.HBox(options) : new Gtk.VBox(options); + } + + if (args.hasBorder) { + options.margin_top = 10; + options.margin_bottom = 10; + options.margin_start = 10; + options.margin_end = 10; + } + + options.orientation = args.horizontal ? + Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL; + + const aliasBox = new Gtk.Box(options); + + if (args.shouldPack) { + aliasBox.set_homogeneous(true); + } + + + aliasBox.add = aliasBox.append; + aliasBox.pack_start = aliasBox.prepend; + // normally, this would be append; it is aliased to prepend because + // that appears to yield the same behavior as version < 40 + aliasBox.pack_end = aliasBox.prepend; + + return aliasBox; +} + +const ColorSelect = class SystemMonitor_ColorSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.picker = new Gtk.ColorButton(); + this.actor = box({horizontal: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.picker); + this.picker.set_use_alpha(true); + } + set_value(value) { + let color = new Gdk.RGBA(); + + if (Gtk.get_major_version() >= 4) { + // GDK did not support parsing hex colours with alpha before GTK 4. + color.parse(value); + } else { + // Use the Compat only when GTK 4 is not available, + // since it depends on the deprecated Clutter library. + let Compat = extension.imports.compat; + let clutterColor = Compat.color_from_string(value); + let ctemp = [clutterColor.red, clutterColor.green, clutterColor.blue, clutterColor.alpha / 255]; + color.parse('rgba(' + ctemp.join(',') + ')'); + } + + this.picker.set_rgba(color); + } +} + +const IntSelect = class SystemMonitor_IntSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.spin = new Gtk.SpinButton(); + this.actor = box({horizontal: true, shouldPack: true, }); + this.actor.add(this.label); + this.actor.add(this.spin); + this.spin.set_numeric(true); + } + set_args(minv, maxv, incre, page) { + this.spin.set_range(minv, maxv); + this.spin.set_increments(incre, page); + } + set_value(value) { + this.spin.set_value(value); + } +} + +const Select = class SystemMonitor_Select { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + // this.label.set_justify(Gtk.Justification.RIGHT); + this.selector = new Gtk.ComboBoxText(); + this.actor = box({horizontal: true, shouldPack: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.selector); + } + set_value(value) { + this.selector.set_active(value); + } + add(items) { + items.forEach((item) => { + this.selector.append_text(item); + }) + } +} + +function set_enum(combo, schema, name) { + Schema.set_enum(name, combo.get_active()); +} + +function set_color(color, schema, name) { + Schema.set_string(name, color_to_hex(color.get_rgba())) +} + +function set_string(combo, schema, name, _slist) { + Schema.set_string(name, _slist[combo.get_active()]); +} + +const SettingFrame = class SystemMonitor { + constructor(name, schema) { + this.schema = schema; + this.label = new Gtk.Label({label: name}); + + this.vbox = box({horizontal: false, shouldPack: true, spacing: 20}); + this.hbox0 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox1 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox2 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox3 = box({horizontal: true, shouldPack: true, spacing: 20}); + + if (shellMajorVersion < 40) { + this.frame = new Gtk.Frame({border_width: 10}); + this.frame.add(this.vbox); + } else { + this.frame = new Gtk.Frame({ + margin_top: 10, + margin_bottom: 10, + margin_start: 10, + margin_end: 10 + }); + this.frame.set_child(this.vbox); + } + + + if (shellMajorVersion < 40) { + this.vbox.pack_start(this.hbox0, true, false, 0); + this.vbox.pack_start(this.hbox1, true, false, 0); + this.vbox.pack_start(this.hbox2, true, false, 0); + this.vbox.pack_start(this.hbox3, true, false, 0); + } else { + this.vbox.append(this.hbox0); + this.vbox.append(this.hbox1); + this.vbox.append(this.hbox2); + this.vbox.append(this.hbox3); + } + } + + /** Enforces child ordering of first 2 boxes by label */ + _reorder() { + if (shellMajorVersion < 40) { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_children) { + return labelOf(el.get_children()[0]); + } + return el && el.label || ''; + }; + [this.hbox0, this.hbox1].forEach(hbox => { + hbox.get_children() + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))) + .forEach((child, index) => hbox.reorder_child(child, index)); + }); + } else { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_label) { + return el.get_label(); + } + return labelOf(el.get_first_child()); + } + + [this.hbox0, this.hbox1].forEach(hbox => { + const children = []; + let next = hbox.get_first_child(); + + while (next !== null) { + children.push(next); + next = next.get_next_sibling(); + } + + const sorted = children + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))); + + sorted + .forEach((child, index) => { + hbox.reorder_child_after(child, sorted[index - 1] || null); + }); + }); + } + } + + add(key) { + const configParent = key.substring(0, key.indexOf('-')); + const config = key.substring(configParent.length + 1); + + // hbox0 + if (config === 'display') { + let item = new Gtk.CheckButton({label: _('Display')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-text') { + let item = new Gtk.CheckButton({label: _('Show Text')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-menu') { + let item = new Gtk.CheckButton({label: _('Show In Menu')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox1 + } else if (config === 'refresh-time') { + let item = new IntSelect(_('Refresh Time')); + item.set_args(50, 100000, 1000, 5000); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'graph-width') { + let item = new IntSelect(_('Graph Width')); + item.set_args(1, 1000, 1, 10); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'style') { + let item = new Select(_('Display Style')); + item.add([_('digit'), _('graph'), _('both')]); + item.set_value(this.schema.get_enum(key)); + this.hbox1.add(item.actor); + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + // Schema.bind(key, item.selector, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox2 + } else if (config.match(/-color$/)) { + let item = new ColorSelect(_(config.split('-')[0].capitalize())); + item.set_value(this.schema.get_string(key)); + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else if (config.match(/sensor/)) { + let sensor_type = configParent === 'fan' ? 'fan' : 'temp'; + let [_slist, _strlist] = check_sensors(sensor_type); + let item = new Select(_('Sensor')); + if (_slist.length === 0) { + item.add([_('Please install lm-sensors')]); + } else if (_slist.length === 1) { + this.schema.set_string(key, _slist[0]); + } + item.add(_strlist); + try { + item.set_value(_slist.indexOf(this.schema.get_string(key))); + } catch (e) { + item.set_value(0); + } + // this.hbox3.add(item.actor); + if (configParent === 'fan') { + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + } else if (shellMajorVersion < 40) { + this.hbox2.pack_start(item.actor, true, false, 0); + } else { + this.hbox2.prepend(item.actor); + } + item.selector.connect('changed', function (combo) { + set_string(combo, Schema, key, _slist); + }); + // hbox3 + } else if (config === 'speed-in-bits') { + let item = new Gtk.CheckButton({label: _('Show network speed in bits')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'individual-cores') { + let item = new Gtk.CheckButton({label: _('Display Individual Cores')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'time') { + let item = new Gtk.CheckButton({label: _('Show Time Remaining')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'hidesystem') { + let item = new Gtk.CheckButton({label: _('Hide System Icon')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'usage-style') { + let item = new Select(_('Usage Style')); + item.add([_('pie'), _('bar'), _('none')]); + item.set_value(this.schema.get_enum(key)); + if (shellMajorVersion < 40) { + this.hbox3.pack_end(item.actor, false, false, 20); + } else { + this.hbox3.append(item.actor); + } + + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + } else if (config === 'fahrenheit-unit') { + let item = new Gtk.CheckButton({label: _('Display temperature in Fahrenheit')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'threshold') { + let item = new IntSelect(_('Temperature threshold (0 to disable)')); + item.set_args(0, 300, 5, 5); + this.hbox3.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } + if (configParent.indexOf('gpu') !== -1 && + config === 'display') { + let item = new Gtk.Label({label: _('** Only Nvidia GPUs supported so far **')}); + this.hbox3.add(item); + } + this._reorder(); + } +} + +const App = class SystemMonitor_App { + constructor() { + let setting_items = ['cpu', 'memory', 'swap', 'net', 'disk', 'gpu', 'thermal', 'fan', 'freq', 'battery']; + let keys = Schema.list_keys(); + + this.items = []; + this.settings = []; + + setting_items.forEach((setting) => { + this.settings[setting] = new SettingFrame(_(setting.capitalize()), Schema); + }); + + this.main_vbox = box({ + hasBorder: true, horizontal: false, spacing: 10}); + this.hbox1 = box({ + hasBorder: true, horizontal: true, shouldPack: true, spacing: 20}); + if (shellMajorVersion < 40) { + this.main_vbox.pack_start(this.hbox1, false, false, 0); + } else { + this.main_vbox.prepend(this.hbox1); + } + + keys.forEach((key) => { + if (key === 'icon-display') { + let item = new Gtk.CheckButton({label: _('Display Icon')}); + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'center-display') { + let item = new Gtk.CheckButton({label: _('Display in the Middle')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'compact-display') { + let item = new Gtk.CheckButton({label: _('Compact Display')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'show-tooltip') { + let item = new Gtk.CheckButton({label: _('Show tooltip')}) + item.set_active(Schema.get_boolean(key)) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'move-clock') { + let item = new Gtk.CheckButton({label: _('Move the clock')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'background') { + let item = new ColorSelect(_('Background Color')) + item.set_value(Schema.get_string(key)) + this.items.push(item) + if (shellMajorVersion < 40) { + this.hbox1.pack_start(item.actor, true, false, 0) + } else { + this.hbox1.prepend(item.actor) + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else { + let sections = key.split('-'); + if (setting_items.indexOf(sections[0]) >= 0) { + this.settings[sections[0]].add(key); + } + } + }); + this.notebook = new Gtk.Notebook() + setting_items.forEach((setting) => { + this.notebook.append_page(this.settings[setting].frame, this.settings[setting].label) + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + this.main_vbox.pack_start(this.notebook, true, true, 0) + } else { + this.main_vbox.append(this.notebook); + } + }); + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + } + } +} + +function buildPrefsWidget() { + let widget = new App(); + return widget.main_vbox; +} diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled new file mode 100644 index 0000000..aeef9ca Binary files /dev/null and b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled differ diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml new file mode 100644 index 0000000..6247263 --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + true + Display system monitor icon + Set to true to display system monitor icon in status bar.(NOTICE: The icon will be shown when none of the others is shown.) + + + true + Display memory + Set to false to remove memory display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refresh of memory + + + 100 + Memory graph width + Graph width in pixel + + + true + Display 'mem' + Set to true to show 'mem' before memory display + + + true + Display Memory In Menu + Set to true to show memory in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display swap + Set to false to remove swap display in status bar + + + 5000 + Swap refresh time + Time in ms between 2 refresh of swap + + + 100 + Swap graph width + Graph width in pixel + + + true + Display 'swap' + Set to true to show 'swap' before swap display + + + true + Display Swap In Menu + Set to true to show swap in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display cpu + Set to false to remove cpu display in status bar + + + 1500 + Cpu refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu graph width + Graph width in pixel + + + true + Display 'cpu' + Set to true to show 'cpu' before cpu display + + + true + Display Cpu In Menu + Set to true to show cpu in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display one graph per cpu core + Set to true to display one graph per cpu core + + + false + Display GPU usage + Set to false to remove GPU display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refreshes of GPU usage + + + 100 + GPU usage graph width + Graph width in pixel + + + true + Display 'gpu' + Set to true to show 'gpu' before GPU display + + + false + Display GPU In Menu + Set to true to show GPU in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display freq + Set to false to remove freq display in status bar + + + 1500 + Cpu frequency refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu frequency graph width + Graph width in pixel + + + false + Display freq' + Set to true to show 'freq' before cpu frequency display + + + false + Display Freq In Menu + Set to true to show freq in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display net + Set to false to remove net display in status bar + + + 1000 + Net refresh time + Time in ms between 2 refresh of net + + + 100 + Net graph width + Graph width in pixel + + + true + Display 'net' + Set to true to show 'net' before net display + + + true + Display Net In Menu + Set to true to show net in pop-up menu + + + 'graph' + Choose the display style. + + + false + Show network speed in bits/sec + + + false + Display disk io speed + Set to false to remove disk display in status bar + + + 2000 + Disk IO refresh time + Time in ms between 2 refresh of Disk IO + + + 100 + Disk IO graph width + Graph width in pixel + + + true + Display 'disk' + Set to true to show 'disk' before disk io display + + + true + Display Disk In Menu + Set to true to show disk in pop-up menu + + + 'graph' + Choose the display style. + + + 'pie' + Choose the disk usage display style. + + + false + Display thermal + Set to false to remove thermal display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'thermal' + Set to true to show 'thermal' before thermal display + + + true + Display Temps In Menu + Set to true to show thermal in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/thermal_zone0/temp' + Sensor File + Location of the sensor file for cpu temp + + + 0 + Thermal threshold + When the temprature passes the threshold, the text is set to red as an alert. + + + false + Display fan + Set to false to remove fan display in status bar + + + 5000 + fan refresh time + Time in ms between 2 refresh of fan + + + 100 + fan graph width + Graph width in pixel + + + true + Display 'fan' + Set to true to show 'fan' before fan display + + + true + Display Fans In Menu + Set to true to show fan in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/cooling_device0/cur_state' + Sensor File + Location of the sensor file for fan + + + '#f2002e' + Color of fan in the chart + + + false + Display informations next to the clock + True: Set information at the center, False: Set information in status bar (at top right) + + + false + Move the clock to the right when center-display is true + True: Move the clock to the right, False: Keep it in center + + + false + Enable or disable the tooltip + True: show tool tip on mouse hover + + + false + Optimize view for small displays + Optimize texts sizes to fit on a small display + + + '#00b35b' + Color of program memory in the chart + + + '#00ff82' + Color of buffer memory in the chart + + + '#aaf5d0' + Color of cache memory in the chart + + + '#fce94f' + Color of download speed in the chart + + + '#fb74fb' + Color of upload speed in the chart + + + '#ff6e00' + Color of download errors + + + '#e0006e' + Color of upload errors + + + '#ff0000' + Color of collisions + + + '#0072b3' + Color of user cpu in the chart + + + '#0092e6' + Color of system cpu in the chart + + + '#00a3ff' + Color of nice cpu in the chart + + + '#002f3d' + Color of iowait in the chart + + + '#001d26' + Color of other cpu in the chart + + + '#001d26' + Color of freq in the chart + + + '#8b00c3' + Color of used swap in the chart + + + '#c65000' + Color of disk reading speed in the chart + + + '#ff6700' + Color of disk writing speed in the chart + + + '#00b35b' + Color of program GPU usage in the chart + + + '#00ff82' + Color of program GPU memory in the chart + + + '#f2002e' + Color of user thermal in the chart + + + false + Display temperature in Fahrenheit + Set to true to show temperature in Fahrenheit + + + '#ffffff16' + Color of background + + + false + Display battery + Set to false to remove battery display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'batt' + Set to true to show 'batt' before net display + + + false + Display 'batt' + Set to true to show battery in pop-up menu + + + 'digit' + Choose the display style. + + + '#f2002e' + Color of battery + + + false + Display battery time remaining rather than percentage + + + false + Hide system battery icon + + + + diff --git a/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css new file mode 100644 index 0000000..5f7120e --- /dev/null +++ b/UIDev/ansibleshed/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css @@ -0,0 +1,204 @@ +.sm-title { + font-size: 1em; + padding: 0px 25px 0px 0px; +} + +.sm-label { + color: #bbb; + font-size: 0.75em; + padding-top: 5px; + font-family: monospace; +} + +.sm-label-left { + color: #bbb; + font-size: 0.75em; + padding: 5px 5px 0 0; +} + +.sm-value { + text-align: right; + min-width: 40px; + padding: 2px 5px 0 0; + font-family: monospace; +} + +.sm-status-label { + color: #bbb; + font-size: 0.625em; + padding: 0 2px 0 5px; +} + +.sm-unit-label, +.sm-net-unit-label { + color: #aaa; + font-size: 0.5em; + padding: 0 5px 0 2px; +} + +.sm-disk-unit-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-net-unit-label { + min-width: 25px; +} + +.sm-perc-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-temp-label { + color: #aaa; + font-size: 0.6875em; + padding: 0 5px 0 2px; +} + +.sm-status-value { + min-width: 25px; + text-align: right; +} + +.sm-net-value { + min-width: 40px; + text-align: center; +} + +.sm-disk-value { + min-width: 25px; + text-align: right; +} + +.sm-big-status-value { + min-width: 42px; + text-align: right; +} + +.sm-chart { + padding: 0 2px; +} + +.sm-tooltip-box { + font-size: 0.85em; + font-weight: bold; + color: rgba(255, 255, 255, 0.9); + background-color: rgba(10, 10, 10, 0.7); + border-radius: 5px; + padding: 3px; + border: 1px solid #a5a5a5; +} + +.sm-tooltip-item { + padding: 0px; + spacing: 10px; +} +.sm-status-icon { + padding: 0px 2px; + icon-size: 1.14em; +} + +.sm-popup-menu-item-compact { +} + +/* style definition when 'compact-display' option is activated */ + +.sm-title-compact { + font-size: 0.75em; +} + +.sm-label-compact { + color: #bbb; + font-size: 0.6875em; + font-family: monospace; +} /* Bat, Net... units in menu items */ + +.sm-value-compact { + font-size: 0.6875em; + text-align: right; + font-family: monospace; +} /* Values in menu items */ + +.sm-status-label-compact { + color: #bbb; + font-size: 0.5em; + padding: 2px 0px 0 0px; +} /* names and Disk R and W signs in text items */ + +.sm-unit-label-compact, +.sm-net-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 1px; + text-align: right; + font-size: 0.4375em; +} /* Bat, Net... units in text items */ + +.sm-disk-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 0px; + text-align: right; + font-size: 0.4375em; +} /* Disk units in text items */ + +.sm-perc-label-compact { + padding: 0 3px 0 0px; + color: #aaa; + font-size: 0.5em; +} /* Cpu, Mem ... % sign in text items */ + +.sm-temp-label-compact { + font-size: 0.625em; + color: #aaa; + padding: 0 1px 0 1px; +} /* Thermal °C sign in text items */ + +.sm-status-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:16px; +} /* Cpu, Mem... value in text items */ + +.sm-net-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:24px; +} /* Net value in text items */ + +.sm-disk-value-compact { + padding: 0 1px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width: 20px; +} /* Disk value in text items */ + +.sm-big-status-value-compact { + padding: 0 0px 0px 1px; + font-size: 0.6875em; + min-width: 38px; + text-align: right; +} /* freq in text_items */ + +.sm-chart-compact { + padding: 0 2px; +} + +.sm-tooltip-item-compact { + padding: 0px; + spacing: 10px; +} + +.sm-status-icon-compact { + padding: 1px 0 0 2px; + icon-size: 1.00em; +} /* BAT icon in text_items */ + +.sm-popup-menu-item-compact { + font-size: 0.6875em; + width: 20px; + padding: 1px 2px 1px 7px; +} diff --git a/UIDev/ansibleshed/gnome-ui-setup.yaml b/UIDev/ansibleshed/gnome-ui-setup.yaml new file mode 100644 index 0000000..01ae4c8 --- /dev/null +++ b/UIDev/ansibleshed/gnome-ui-setup.yaml @@ -0,0 +1,83 @@ +--- +- name: Install UI Improvements + hosts: all + become: yes + + tasks: +# Install Nautilus Extension + - name: Copy Nautilus Extension + copy: + src: "nautilus-extensions/nautilus-copy-path" + dest: "/usr/share/nautilus-python/extensions" + + - name: Copy Nautilus Extension + copy: + src: "nautilus-extensions/nautilus-copy-path.py" + dest: "/usr/share/nautilus-python/extensions" + +# Install Gnome Extensions +# Install Dash to Panel + - name: Copy Dash to Panel + copy: + src: "gnome-extensions/dash-to-panel@jderose9.github.com" + dest: "/usr/share/gnome-shell/extensions" + + - name: Copy Dash to Panel + copy: + src: "gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml" + dest: "/usr/share/glib-2.0/schemas" + +# Install System Monitor + - name: Copy System Monitor + copy: + src: "gnome-extensions/system-monitor@paradoxxx.zero.gmail.com" + dest: "/usr/share/gnome-shell/extensions" + + - name: Copy System Monitor + copy: + src: "gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml" + dest: "/usr/share/glib-2.0/schemas" + +# Install Arch Menu + - name: Copy Arch Menu + copy: + src: "gnome-extensions/arcmenu@arcmenu.com" + dest: "/usr/share/gnome-shell/extensions" + + - name: Copy Arch Menu + copy: + src: "gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml" + dest: "/usr/share/glib-2.0/schemas" + +# Install Gnome 4x UI Improvements + - name: Copy Gnome 4x UI Improvements + copy: + src: "gnome-extensions/gnome-ui-tune@itstime.tech" + dest: "/usr/share/gnome-shell/extensions" + + - name: Copy Gnome 4x UI Improvements + copy: + src: "gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml" + dest: "/usr/share/glib-2.0/schemas" + +# Install Blur My Shell + - name: Copy Blur My Shell + copy: + src: "gnome-extensions/blur-my-shell@aunetx" + dest: "/usr/share/gnome-shell/extensions" + + - name: Copy Blur My Shell + copy: + src: "gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml" + dest: "/usr/share/glib-2.0/schemas" + + - name: Compile Schemas + shell: glib-compile-schemas /usr/share/glib-2.0/schemas/ + + - name: Copy dconf profile file + copy: + src: '01-creative_gnome_defaults' + dest: '/etc/dconf/db/local.d/' + + - name: Update dconf + shell: dconf update diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path.py b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path.py new file mode 100644 index 0000000..2af9157 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path.py @@ -0,0 +1,4 @@ +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'nautilus-copy-path')) +from nautilus_copy_path import NautilusCopyPath diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/config.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/config.json new file mode 100644 index 0000000..64384f3 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/config.json @@ -0,0 +1,11 @@ +{ + "items": { + "path": true + }, + "selections": { + "clipboard": true, + "primary": true + }, + "language": "auto", + "separator": ", " +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py new file mode 100644 index 0000000..2a0570e --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py @@ -0,0 +1,73 @@ +import os +import json +from translation import Translation +from gi.repository import Nautilus, GObject, Gtk, Gdk +from gi import require_version + +require_version('Gtk', '3.0') +require_version('Nautilus', '3.0') + + +class NautilusCopyPath(Nautilus.MenuProvider, GObject.GObject): + + def __init__(self): + self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + self.clipboard_primary = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY) + + self.config = { + "items": { + "path": True, + }, + "selections": { + "clipboard": True, + "primary": True + }, + "language": "auto", + "separator": ", " + } + + with open(os.path.join(os.path.dirname(__file__), "config.json")) as json_file: + try: + self.config.update(json.load(json_file)) + if self.config["language"]: + Translation.select_language(self.config["language"]) + except: + pass + + def get_file_items(self, window, files): + return self._create_menu_items(files, "File") + + def get_background_items(self, window, file): + return self._create_menu_items([file], "Background") + + def _create_menu_items(self, files, group): + plural = len(files) > 1 + config_items = self.config["items"] + active_items = [] + + if config_items["path"]: + item_path = Nautilus.MenuItem( + name="NautilusCopyPath::CopyPath" + group, + label=Translation.t("copy_paths" if plural else "copy_path"), + ) + item_path.connect("activate", self._copy_paths, files) + active_items.append(item_path) + + return active_items + + def _copy_paths(self, menu, files): + self._copy_value(list(map(lambda f: f.get_location().get_path(), files))) + + def _copy_uris(self, menu, files): + self._copy_value(list(map(lambda f: f.get_uri(), files))) + + def _copy_names(self, menu, files): + self._copy_value(list(map(lambda x: os.path.basename(x.get_location().get_path()), files))) + + def _copy_value(self, value): + if len(value) > 0: + new_value = self.config["separator"].join(value) + if self.config["selections"]["clipboard"]: + self.clipboard.set_text(new_value, -1) + if self.config["selections"]["primary"]: + self.clipboard_primary.set_text(new_value, -1) diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translation.py b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translation.py new file mode 100644 index 0000000..6ee1f26 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translation.py @@ -0,0 +1,52 @@ +import locale +import json +import glob +import os + + +class Translation: + _translations_path = os.path.join(os.path.dirname(__file__), 'translations') + _translations = [] + _default_translations = [] + + @staticmethod + def select_language(lang_code="auto"): + if not lang_code or lang_code == "auto": + default_locale = locale.getdefaultlocale()[0] + try: + lang = default_locale.split("_") + lang_code = lang[0] if len(lang) else "en" + except AttributeError: + lang_code = "en" + + if lang_code in Translation.available_languages(): + Translation.lang_code = lang_code + else: + Translation.lang_code = "en" + + Translation._load_lang(Translation.lang_code) + + @staticmethod + def _load_lang(lang_code): + file_path = Translation._translations_path + '/' + lang_code + ".json" + if os.path.isfile(file_path): + with open(file_path) as json_file: + Translation._translations = json.load(json_file) + + file_path_en = Translation._translations_path + "/en.json" + if os.path.isfile(file_path_en): + with open(file_path_en) as json_file: + Translation._default_translations = json.load(json_file) + + @staticmethod + def available_languages(): + return [os.path.splitext(os.path.basename(x))[0] for x in glob.glob(Translation._translations_path + '/*.json')] + + @staticmethod + def t(translation): + if not Translation._translations: + Translation.select_language() + if translation in Translation._translations: + return Translation._translations[translation] + elif translation in Translation._default_translations: + return Translation._default_translations[translation] diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ar.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ar.json new file mode 100644 index 0000000..6bb6c71 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ar.json @@ -0,0 +1,8 @@ +{ + "copy_path": "نسخ مسار الملف", + "copy_paths": "نسخ مسارات الملفات", + "copy_name": "نسخ اسم الملف", + "copy_names": "نسخ اسماء الملفات", + "copy_uri": "نسخ معرّف المصادر الموحد", + "copy_uris": "نسخ معرفي المصادر الموحدة" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/da.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/da.json new file mode 100644 index 0000000..50e3498 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/da.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiér sti", + "copy_paths": "Kopiér stier", + "copy_name": "Kopiér navn", + "copy_names": "Kopiér navne", + "copy_uri": "Kopiér URI", + "copy_uris": "Kopiér URIer" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/de.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/de.json new file mode 100644 index 0000000..1e49c74 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/de.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Pfad kopieren", + "copy_paths": "Pfade kopieren", + "copy_name": "Name kopieren", + "copy_names": "Namen kopieren", + "copy_uri": "URI kopieren", + "copy_uris": "URIs kopieren" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/el.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/el.json new file mode 100644 index 0000000..d11cdbe --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/el.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Αντιγραφή Διαδρομής", + "copy_paths": "Αντιγραφή Διαδρομών", + "copy_name": "Αντιγραφή Ονόματος", + "copy_names": "Αντιγραφή Ονομάτων", + "copy_uri": "Αντιγραφή URI", + "copy_uris": "Αντιγραφή URIs" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/en.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/en.json new file mode 100644 index 0000000..d0b7a3b --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/en.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copy Path", + "copy_paths": "Copy Paths", + "copy_name": "Copy Name", + "copy_names": "Copy Names", + "copy_uri": "Copy URI", + "copy_uris": "Copy URIs" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/es.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/es.json new file mode 100644 index 0000000..5b12ffe --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/es.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiar ruta", + "copy_paths": "Copiar rutas", + "copy_name": "Copiar nombre", + "copy_names": "Copiar nombres" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/fr.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/fr.json new file mode 100644 index 0000000..d98d1ad --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/fr.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copier le chemin", + "copy_paths": "Copier les chemins", + "copy_name": "Copier le nom", + "copy_names": "Copier les noms" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/it.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/it.json new file mode 100644 index 0000000..8a31219 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/it.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copia Percorso", + "copy_paths": "Copia Percorsi", + "copy_name": "Copia Nome", + "copy_names": "Copia Nomi" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ja.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ja.json new file mode 100644 index 0000000..664f124 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ja.json @@ -0,0 +1,8 @@ +{ + "copy_path": "パスをコピー", + "copy_paths": "パスをコピー", + "copy_name": "ファイル名をコピー", + "copy_names": "ファイル名をコピー", + "copy_uri": "URIをコピー", + "copy_uris": "URIをコピー" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/no.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/no.json new file mode 100644 index 0000000..2965771 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/no.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopier sti", + "copy_paths": "Kopier stier", + "copy_name": "Kopier navn", + "copy_names": "Kopier navn", + "copy_uri": "Kopier URI", + "copy_uris": "Kopier URIer" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pl.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pl.json new file mode 100644 index 0000000..45830ad --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pl.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Skopiuj ścieżkę", + "copy_paths": "Skopiuj ścieżki", + "copy_name": "Skopiuj nazwę", + "copy_names": "Skopiuj nazwy", + "copy_uri": "Skopiuj URI", + "copy_uris": "Skopiuj URI" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pt.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pt.json new file mode 100644 index 0000000..dd7aed4 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/pt.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copiar endereço", + "copy_paths": "Copiar endereços", + "copy_name": "Copiar nome", + "copy_names": "Copiar nomes", + "copy_uri": "Copiar URI", + "copy_uris": "Copiar URIs" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ro.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ro.json new file mode 100644 index 0000000..47327a6 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ro.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiază locația", + "copy_paths": "Copiază locațiile", + "copy_name": "Copiază nume", + "copy_names": "Copiază numele" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ru.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ru.json new file mode 100644 index 0000000..7a0ca43 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/ru.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Скопировать путь", + "copy_paths": "Скопировать пути", + "copy_name": "Скопировать имя", + "copy_names": "Скопировать имена", + "copy_uri": "Скопировать URI", + "copy_uris": "Скопировать URIs" +} diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/se.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/se.json new file mode 100644 index 0000000..f9ac706 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/se.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiera stig", + "copy_paths": "Kopiera stigar", + "copy_name": "Kopiera namn", + "copy_names": "Kopiera namn", + "copy_uri": "Kopiera URI", + "copy_uris": "Kopiera URIer" +} \ No newline at end of file diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/tr.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/tr.json new file mode 100644 index 0000000..a0aead1 --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/tr.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Yolu Kopyala", + "copy_paths": "Yolları Kopyala", + "copy_name": "İsmi Kopyala", + "copy_names": "İsimleri Kopyala", + "copy_uri": "URI'yi Kopyala", + "copy_uris": "URI'leri Kopyala" + } \ No newline at end of file diff --git a/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/zh.json b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/zh.json new file mode 100644 index 0000000..a534d3e --- /dev/null +++ b/UIDev/ansibleshed/nautilus-extensions/nautilus-copy-path/translations/zh.json @@ -0,0 +1,8 @@ +{ + "copy_path": "复制路径", + "copy_paths": "复制各个路径", + "copy_name": "复制文件名", + "copy_names": "复制各个文件名", + "copy_uri": "复制URI", + "copy_uris": "复制各个URI" +} diff --git a/UIDev/ansibleshed/script_to_convert.sh b/UIDev/ansibleshed/script_to_convert.sh new file mode 100644 index 0000000..eb81774 --- /dev/null +++ b/UIDev/ansibleshed/script_to_convert.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +################################ +### Nautilus + +# Install Nautilus Extension +mkdir -p '/usr/share/nautilus-python/extensions' +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/nautilus-extensions/nautilus-copy-path' '/usr/share/nautilus-python/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/nautilus-extensions/nautilus-copy-path.py' '/usr/share/nautilus-python/extensions' + +################################ +### Install Gnome Extensions + +# Install Dash to Panel +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/dash-to-panel@jderose9.github.com' '/usr/share/gnome-shell/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml' '/usr/share/glib-2.0/schemas' + +# Install System Monitor +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com' '/usr/share/gnome-shell/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml' '/usr/share/glib-2.0/schemas' + +# Install Arch Menu +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/arcmenu@arcmenu.com' '/usr/share/gnome-shell/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml' '/usr/share/glib-2.0/schemas' + +# Install Gnome 4x UI Improvements +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/gnome-ui-tune@itstime.tech' '/usr/share/gnome-shell/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml' '/usr/share/glib-2.0/schemas' + +# Install Blur My Shell +cp -r '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/blur-my-shell@aunetx' '/usr/share/gnome-shell/extensions' +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml' '/usr/share/glib-2.0/schemas' + +# Compile Schemas +glib-compile-schemas /usr/share/glib-2.0/schemas/ + +################################ +### dconf + +# Copy dconf profile file +cp '/Y/Ansible/Linux/EL9/3D/SHEDLook/01-shed_gnome_defaults' '/etc/dconf/db/local.d' + +# Update dconf +dconf update diff --git a/docs/index.html b/docs/index.html index 33de829..5006765 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1037,13 +1037,16 @@

Audio & Music

🎮

Game Development

-
3 apps
+
6 apps
Godot Engine Epic Asset Manager Asset Manager Studio + Open 3D Engine + Unreal Engine 5.8 + Unigine
diff --git a/docs/superpowers/plans/2026-07-01-new-apps-o3de-unreal-unigine.md b/docs/superpowers/plans/2026-07-01-new-apps-o3de-unreal-unigine.md new file mode 100644 index 0000000..b5601a4 --- /dev/null +++ b/docs/superpowers/plans/2026-07-01-new-apps-o3de-unreal-unigine.md @@ -0,0 +1,948 @@ +# New Apps (O3DE, Unreal Engine 5.8, Unigine) Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add three game engines to the installer catalog (Open 3D Engine via COPR, Unreal Engine 5.8 and Unigine via guided installs) plus a reusable BETA badge. + +**Architecture:** Each app gets a bespoke install type in the single-file PyQt GUI (`src/almalinux-creative-installer`) and matching `install_` / `remove_` functions in the root helper (`src/almalinux-creative-installer-helper`), exactly like the existing `resolve` / `3dcoat` / `jangafx` / `gaffer` types. The BETA badge is a new optional `"beta": True` app field rendered as a chip next to the app name, same construction as the existing EL chip. + +**Tech Stack:** Python 3 + PyQt5/PyQt6 (via `src/qtcompat.py`), Bash root helper dispatched over pkexec, dnf/COPR. + +**Spec:** `docs/superpowers/specs/2026-07-01-new-apps-o3de-unreal-unigine-design.md` + +## Global Constraints + +- No em dashes in prose (README, docs, comments, commit messages). Use periods, commas, colons, or parentheses. The `→` arrow in UI subtitle strings is an existing convention and is fine. +- No `Co-Authored-By` trailers on commits. +- Branch: `feat/new-apps-o3de-unreal-unigine` (already created, spec committed). +- Commit with explicit paths only (`git add `); a stray modified `.gitignore` exists in the working tree and must NOT be committed. +- No test suite exists in this repo. Every task's test cycle is: `python3 -m py_compile src/almalinux-creative-installer` for the GUI and `bash -n src/almalinux-creative-installer-helper` for the helper, plus the behavior probes given per task. Run them exactly as written. +- Qt idioms in this codebase (both PyQt5 and PyQt6 compatible): `QMessageBox.StandardButton.Ok`, `QMessageBox.ButtonRole.ActionRole`, `msg.exec()`, `msg.clickedButton()` compared with `==`. +- Desktop entries go in the invoking user's `~/.local/share/applications` (JangaFX/Gaffer convention), NOT `/usr/share/applications`. This deviates from the spec text on purpose: follow the codebase convention. +- Helper style: `set -euo pipefail` is active; every function logs via `log "..."`; user resolution via `require_invoking_user` / `require_invoking_user_home`. + +--- + +### Task 1: BETA chip + app entries + maintainer guide + +**Files:** +- Modify: `src/almalinux-creative-installer` (constants ~line 33, maintainer guide comment ~lines 41-54, `APPS` ~line 99, `_make_app_row` ~line 1095) + +**Interfaces:** +- Produces: app dicts with ids `"o3de"`, `"unreal"`, `"unigine"` and types of the same names; optional `"beta": True` field rendered as a chip. Later tasks wire buttons, subtitles, state, flows, and helper actions to these ids/types. + +- [ ] **Step 1: Add URL constants** + +In `src/almalinux-creative-installer`, directly after the `GAFFER_URL` line (line 33), add: + +```python +UNREAL_URL = "https://www.unrealengine.com/linux" +UNIGINE_URL = "https://developer.unigine.com/en/downloads" +UNIGINE_EULA_URL = "https://developer.unigine.com/en/eula" +``` + +(The EULA URL was verified live on 2026-07-01: HTTP 200.) + +- [ ] **Step 2: Update the maintainer guide comment** + +In the "HOW TO ADD / EDIT APPS" comment block, change line 45 from: + +```python +# 2) Pick a supported "type": dnf, flatpak, resolve, 3dcoat +``` + +to: + +```python +# 2) Pick a supported "type": dnf, flatpak, resolve, 3dcoat, o3de, unreal, unigine +``` + +and after the `"el"` bullet (line 52 ends `...both.`), add a new bullet before bullet 6: + +```python +# 5b) Optional: add "beta": True for pre-release or experimental apps. +# The row shows an amber BETA chip next to the app name. +``` + +- [ ] **Step 3: Add the three APPS entries** + +Insert after the `godots` entry (line 99), before `appimagelauncher`: + +```python + {"id": "o3de", "name": "Open 3D Engine", "type": "o3de", "icon_appid": "org.o3de.O3DE", "category": "Game Engines", "el": [10], "beta": True}, + {"id": "unreal", "name": "Unreal Engine 5.8","type": "unreal", "icon_appid": "com.epicgames.UnrealEngine", "category": "Game Engines", "beta": True}, + {"id": "unigine", "name": "Unigine", "type": "unigine", "icon_appid": "com.unigine.Browser", "category": "Game Engines"}, +``` + +Notes: `"el": [10]` on O3DE only (the COPR has only a `centos-stream-10-x86_64` chroot). Unreal and Unigine omit `el` (works on EL9 and EL10, existing convention). The `icon_appid` values match the PNG filenames Task 6 ships; if the PNGs are absent the UI falls back to a colored letter badge, which is acceptable. + +- [ ] **Step 4: Render the BETA chip** + +In `_make_app_row`, the EL chip block ends with `name_row.addWidget(el_chip)` followed by `name_row.addStretch()` (line 1096). Insert between them, at the same indent level as the `el_versions = app.get("el")` statement: + +```python + if app.get("beta"): + beta_chip = QLabel("BETA") + beta_chip.setStyleSheet( + "background: rgba(230,160,50,0.20); color: #d29a3d;" + " border-radius: 4px; padding: 1px 5px;" + " font-size: 10px; font-weight: 600;" + ) + beta_chip.setToolTip("Pre-release / experimental build") + name_row.addWidget(beta_chip) +``` + +The fixed amber (#d29a3d) reads on both the dark and light themes, mirroring how the EL chip uses one fixed rgba background. + +- [ ] **Step 5: Verify syntax** + +Run: `python3 -m py_compile src/almalinux-creative-installer && echo OK` +Expected: `OK` + +- [ ] **Step 6: Commit** + +```bash +git add src/almalinux-creative-installer +git commit -m "feat(ui): add BETA chip and catalog entries for O3DE, Unreal Engine 5.8, Unigine" +``` + +--- + +### Task 2: Open 3D Engine (GUI wiring + helper) + +**Files:** +- Modify: `src/almalinux-creative-installer` (button wiring ~line 1159, `_subtitle_for_app` ~line 1213, `refresh_app_state` ~line 1443, new methods after `remove_gaffer_flow` ~line 2358) +- Modify: `src/almalinux-creative-installer-helper` (new functions after `remove_3dcoat` ~line 871, dispatcher ~line 922, usage text ~line 934) + +**Interfaces:** +- Consumes: app id `"o3de"` / type `"o3de"` from Task 1; existing `run_helper_with_callback(args, on_success, app_id, progress_segment)`, `set_app_busy`, `_set_app_progress_fraction`, `_finish_app_action`, `_set_status_badge`. +- Produces: GUI methods `_o3de_installed()`, `install_o3de_flow()`, `remove_o3de_flow()`; helper actions `install_o3de` (no args), `remove_o3de` (no args). + +- [ ] **Step 1: Wire the row buttons** + +In `_make_app_row`, after the `elif app["type"] == "gaffer":` block (line 1159), add: + +```python + elif app["type"] == "o3de": + install_btn.clicked.connect(lambda: self.install_o3de_flow()) + remove_btn.clicked.connect(lambda: self.remove_o3de_flow()) +``` + +- [ ] **Step 2: Add the subtitle** + +In `_subtitle_for_app`, after the `gaffer` case (line 1213), add: + +```python + if app["type"] == "o3de": + return "Installed via COPR (hellaenergy/o3de), latest release line" +``` + +- [ ] **Step 3: Add the state branch** + +In `refresh_app_state`, after the `gaffer` branch (ends line 1443), add: + +```python + if app["type"] == "o3de": + installed = self._o3de_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Not installed", + "installed" if installed else "missing") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return +``` + +("Not installed"/"missing" rather than "Guided install"/"available": O3DE is a one-click dnf-style install, not a guided flow.) + +- [ ] **Step 4: Add detection and flows** + +After `remove_gaffer_flow` (line 2358), before the `_THEME_COLORS` module globals, add: + +```python + + def _o3de_installed(self): + out = subprocess.run( + ["rpm", "-qa", "--qf", "%{NAME}\n", "o3de*"], + stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, + ).stdout + return any(re.fullmatch(r"o3de\d{4}", line.strip()) for line in out.splitlines()) + + def install_o3de_flow(self): + self.set_app_busy("o3de", True, "Installing…") + self._set_app_progress_fraction("o3de", 0.02) + self.run_helper_with_callback( + ["install_o3de"], + on_success=lambda: self._finish_app_action("o3de"), + app_id="o3de", + progress_segment=(0.02, 0.98), + ) + + def remove_o3de_flow(self): + if not self._o3de_installed(): + self.append_log("ℹ️ Open 3D Engine does not appear to be installed.\n") + self.refresh_app_state("o3de") + return + reply = QMessageBox.question( + self, "Uninstall Open 3D Engine?", + "This will remove all installed o3de packages and disable the hellaenergy/o3de COPR repo.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("o3de", True, "Removing…") + self._set_app_progress_fraction("o3de", 0.02) + self.run_helper_with_callback( + ["remove_o3de"], + on_success=lambda: self._finish_app_action("o3de"), + app_id="o3de", + progress_segment=(0.02, 0.98), + ) +``` + +(`re` and `subprocess` are already imported at module top.) + +- [ ] **Step 5: Add the helper functions** + +In `src/almalinux-creative-installer-helper`, after `remove_3dcoat` (line 871), before the Dispatcher comment, add: + +```bash +# ------------------------------------------------- +# Open 3D Engine (COPR) +# ------------------------------------------------- +O3DE_COPR="hellaenergy/o3de" +# The COPR publishes EL builds only for the centos-stream-10 chroot; a bare +# "copr enable" on AlmaLinux 10 would look for epel-10, which does not exist +# in this project, so the chroot must be passed explicitly. +O3DE_COPR_CHROOT="centos-stream-10-x86_64" + +install_o3de() { + log "Ensuring dnf copr plugin..." + dnf -y install 'dnf-command(copr)' + + log "Enabling COPR ${O3DE_COPR} (chroot ${O3DE_COPR_CHROOT})..." + dnf -y copr enable "${O3DE_COPR}" "${O3DE_COPR_CHROOT}" + + # Packages use versioned-major naming (o3deNNNN, NNNN = YYMM). Majors are + # co-installable; install the newest release line. + log "Detecting the latest Open 3D Engine release line..." + local latest + latest="$(dnf -q repoquery --qf '%{name}\n' 'o3de[0-9][0-9][0-9][0-9]' 2>/dev/null \ + | grep -E '^o3de[0-9]{4}$' | sort -u -V | tail -1 || true)" + if [[ -z "${latest}" ]]; then + echo "ERROR: no o3deNNNN package found in ${O3DE_COPR} (repo unreachable or chroot missing)." >&2 + exit 4 + fi + + log "Installing ${latest}..." + dnf -y install "${latest}" + log "Open 3D Engine installed (${latest})." +} + +remove_o3de() { + log "Removing Open 3D Engine packages..." + local pkgs + mapfile -t pkgs < <(rpm -qa --qf '%{NAME}\n' 'o3de*' | grep -E '^o3de[0-9]{4}(-devel)?$' || true) + if (( ${#pkgs[@]} )); then + dnf -y remove "${pkgs[@]}" + else + log "No o3de packages installed." + fi + + log "Disabling COPR ${O3DE_COPR}..." + dnf -y copr remove "${O3DE_COPR}" || true + log "Open 3D Engine removed." +} +``` + +- [ ] **Step 6: Register in the dispatcher and usage text** + +In the dispatcher `case` block, after the Gaffer pair (line 922), add: + +```bash + # Open 3D Engine + install_o3de) install_o3de;; + remove_o3de) remove_o3de;; +``` + +In the usage heredoc at the bottom of the file, after the Gaffer action lines, add exactly: + +``` + install_o3de + remove_o3de +``` + +- [ ] **Step 7: Verify syntax** + +Run: `python3 -m py_compile src/almalinux-creative-installer && bash -n src/almalinux-creative-installer-helper && echo OK` +Expected: `OK` + +Also run shellcheck if available (non-blocking): +`shellcheck -x src/almalinux-creative-installer-helper || true` + +- [ ] **Step 8: Commit** + +```bash +git add src/almalinux-creative-installer src/almalinux-creative-installer-helper +git commit -m "feat(o3de): install Open 3D Engine from the hellaenergy COPR, latest release line (closes #73)" +``` + +--- + +### Task 3: Unreal Engine 5.8 (GUI wiring + helper) + +**Files:** +- Modify: `src/almalinux-creative-installer` (button wiring, subtitle, state branch, flows; same anchor points as Task 2) +- Modify: `src/almalinux-creative-installer-helper` (new functions + dispatcher + usage) + +**Interfaces:** +- Consumes: app id `"unreal"` / type `"unreal"`, `UNREAL_URL` from Task 1; same GUI helpers as Task 2. +- Produces: GUI methods `_unreal_installed()`, `install_unreal_flow()`, `pick_unreal_zip()`, `remove_unreal_flow()`; helper actions `install_unreal `, `remove_unreal`. + +- [ ] **Step 1: Wire the row buttons** + +After the `o3de` elif added in Task 2: + +```python + elif app["type"] == "unreal": + install_btn.clicked.connect(lambda: self.install_unreal_flow()) + remove_btn.clicked.connect(lambda: self.remove_unreal_flow()) +``` + +- [ ] **Step 2: Add the subtitle** + +After the `o3de` subtitle case: + +```python + if app["type"] == "unreal": + return "Guided install: log in to Epic → download Linux zip → extracts to /opt/unreal-engine (EL9 and EL10)" +``` + +- [ ] **Step 3: Add the state branch** + +After the `o3de` branch in `refresh_app_state`: + +```python + if app["type"] == "unreal": + installed = self._unreal_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Guided install", + "installed" if installed else "available") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return +``` + +- [ ] **Step 4: Add detection and flows** + +After the `remove_o3de_flow` method added in Task 2: + +```python + + def _unreal_installed(self): + return Path("/opt/unreal-engine/Engine/Binaries/Linux/UnrealEditor").is_file() + + def install_unreal_flow(self): + self.set_app_busy("unreal", True, "Waiting for file…") + self._set_app_progress_fraction("unreal", 0.02) + if shutil.which("xdg-open"): + subprocess.Popen(["xdg-open", UNREAL_URL]) + self.append_log("Opened the Unreal Engine Linux page (Epic account required).\n") + self.append_log( + "Download the Linux zip (e.g. Linux_Unreal_Engine_5.8.0_preview-1.zip), then select it below.\n" + ) + self.pick_unreal_zip() + + def pick_unreal_zip(self): + path, _ = QFileDialog.getOpenFileName( + self, + "Select Unreal Engine Linux zip", + "", + "Zip archives (*.zip);;All files (*)", + ) + if not path: + self._finish_app_action("unreal") + return + self._set_app_progress_fraction("unreal", 0.05) + self.run_helper_with_callback( + ["install_unreal", path], + on_success=lambda: self._finish_app_action("unreal"), + app_id="unreal", + progress_segment=(0.05, 0.98), + ) + + def remove_unreal_flow(self): + if not self._unreal_installed(): + self.append_log("ℹ️ Unreal Engine does not appear to be installed.\n") + self.refresh_app_state("unreal") + return + reply = QMessageBox.question( + self, "Uninstall Unreal Engine?", + "This will remove /opt/unreal-engine and the desktop entry.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("unreal", True, "Removing…") + self._set_app_progress_fraction("unreal", 0.02) + self.run_helper_with_callback( + ["remove_unreal"], + on_success=lambda: self._finish_app_action("unreal"), + app_id="unreal", + progress_segment=(0.02, 0.98), + ) +``` + +- [ ] **Step 5: Add the helper functions** + +After `remove_o3de` in the helper: + +```bash +# ------------------------------------------------- +# Unreal Engine (guided zip install) +# ------------------------------------------------- +install_unreal() { + local zip_path="${1:-}" + local install_dir="/opt/unreal-engine" + local tmp_dir + + [[ -n "${zip_path}" ]] || { echo "ERROR: missing zip path" >&2; exit 2; } + [[ -f "${zip_path}" ]] || { echo "ERROR: zip not found: ${zip_path}" >&2; exit 2; } + case "${zip_path}" in + *.zip) ;; + *) echo "ERROR: expected a .zip archive, got: ${zip_path}" >&2; exit 2;; + esac + + log "Ensuring unzip is available..." + command -v unzip >/dev/null 2>&1 || dnf -y install unzip + + local user home + user="$(require_invoking_user)" + home="$(require_invoking_user_home)" + + # Extract under /opt, not /tmp: the engine is tens of GB and /tmp is + # commonly a size-limited tmpfs. Same filesystem also makes mv instant. + tmp_dir="$(mktemp -d /opt/.unreal-tmp-XXXXXX)" + # shellcheck disable=SC2064 + trap "rm -rf '${tmp_dir}'" EXIT + + log "Extracting Unreal Engine archive (large, this can take several minutes)..." + unzip -q "${zip_path}" -d "${tmp_dir}" + + # The zip either contains Engine/ at the root or a single top-level + # versioned folder (e.g. Linux_Unreal_Engine_5.8.0_preview-1/). + local src_dir + if [[ -d "${tmp_dir}/Engine" ]]; then + src_dir="${tmp_dir}" + else + src_dir="$(find "${tmp_dir}" -maxdepth 1 -mindepth 1 -type d | head -1)" + fi + if [[ -z "${src_dir}" || ! -d "${src_dir}/Engine" ]]; then + echo "ERROR: no Engine/ directory found in the archive." >&2 + exit 2 + fi + + local editor="Engine/Binaries/Linux/UnrealEditor" + [[ -f "${src_dir}/${editor}" ]] || { echo "ERROR: ${editor} not found in the archive." >&2; exit 2; } + + log "Installing to ${install_dir}..." + rm -rf "${install_dir}" + mv "${src_dir}" "${install_dir}" + chmod +x "${install_dir}/${editor}" + + # The editor writes into its own tree (DerivedDataCache, Intermediate), + # so the invoking user must own it. + log "Setting ownership (large tree, this can take a moment)..." + chown -R "${user}:${user}" "${install_dir}" + + local desktop_dir="${home}/.local/share/applications" + mkdir -p "${desktop_dir}" + chown "${user}:${user}" "${desktop_dir}" + local icon_png="/usr/share/almalinux-creative-installer/icons/apps/com.epicgames.UnrealEngine.png" + cat > "${desktop_dir}/UnrealEngine.desktop" < + remove_unreal +``` + +- [ ] **Step 7: Verify syntax + a dry helper probe** + +Run: `python3 -m py_compile src/almalinux-creative-installer && bash -n src/almalinux-creative-installer-helper && echo OK` +Expected: `OK` + +Probe the validation path without root (must fail cleanly before any privileged work): + +Run: `bash src/almalinux-creative-installer-helper install_unreal /nonexistent.zip; echo "exit=$?"` +Expected: `ERROR: zip not found: /nonexistent.zip` and `exit=2` + +Run: `bash src/almalinux-creative-installer-helper install_unreal /etc/hostname; echo "exit=$?"` +Expected: `ERROR: expected a .zip archive...` and `exit=2` + +- [ ] **Step 8: Commit** + +```bash +git add src/almalinux-creative-installer src/almalinux-creative-installer-helper +git commit -m "feat(unreal): guided Unreal Engine 5.8 install from the Epic Linux zip (closes #70)" +``` + +--- + +### Task 4: Unigine (GUI wiring with EULA gate + helper) + +**Files:** +- Modify: `src/almalinux-creative-installer` (button wiring, subtitle, state branch, flows) +- Modify: `src/almalinux-creative-installer-helper` (new functions + dispatcher + usage) + +**Interfaces:** +- Consumes: app id `"unigine"` / type `"unigine"`, `UNIGINE_URL`, `UNIGINE_EULA_URL` from Task 1. +- Produces: GUI methods `_unigine_installed()`, `install_unigine_flow()`, `pick_unigine_run()`, `remove_unigine_flow()`; helper actions `install_unigine `, `remove_unigine`. + +- [ ] **Step 1: Wire the row buttons** + +After the `unreal` elif: + +```python + elif app["type"] == "unigine": + install_btn.clicked.connect(lambda: self.install_unigine_flow()) + remove_btn.clicked.connect(lambda: self.remove_unigine_flow()) +``` + +- [ ] **Step 2: Add the subtitle** + +After the `unreal` subtitle case: + +```python + if app["type"] == "unigine": + return "Guided install: agree to EULA → pick vendor .run → SDK Browser in /opt/unigine" +``` + +- [ ] **Step 3: Add the state branch** + +After the `unreal` branch in `refresh_app_state`: + +```python + if app["type"] == "unigine": + installed = self._unigine_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Guided install", + "installed" if installed else "available") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return +``` + +- [ ] **Step 4: Add detection and flows (with the EULA gate)** + +After the `remove_unreal_flow` method: + +```python + + def _unigine_installed(self): + base = Path("/opt/unigine") + return base.is_dir() and any(base.iterdir()) + + def install_unigine_flow(self): + msg = QMessageBox(self) + msg.setWindowTitle("UNIGINE SDK License Agreement") + msg.setTextFormat(Qt.TextFormat.RichText) + msg.setText( + 'Installing Unigine runs the vendor installer, which is governed by the ' + 'UNIGINE SDK License Agreement.'.format(UNIGINE_EULA_URL) + ) + msg.setInformativeText( + "The vendor installer normally shows this EULA in a terminal. Because the " + "install runs unattended here, it will be accepted on your behalf.\n\n" + 'Click "I Agree" only if you have read and accept the EULA.' + ) + msg.setIcon(QMessageBox.Icon.Question) + btn_agree = msg.addButton("I Agree", QMessageBox.ButtonRole.AcceptRole) + msg.addButton(QMessageBox.StandardButton.Cancel) + msg.exec() + if msg.clickedButton() != btn_agree: + return + + self.set_app_busy("unigine", True, "Waiting for file…") + self._set_app_progress_fraction("unigine", 0.02) + if shutil.which("xdg-open"): + subprocess.Popen(["xdg-open", UNIGINE_URL]) + self.append_log("Opened the UNIGINE downloads page.\n") + self.append_log( + "Download the Linux .run installer (the filename changes with each version), then select it below.\n" + ) + self.pick_unigine_run() + + def pick_unigine_run(self): + path, _ = QFileDialog.getOpenFileName( + self, + "Select UNIGINE .run installer", + "", + "Run installers (*.run);;All files (*)", + ) + if not path: + self._finish_app_action("unigine") + return + self._set_app_progress_fraction("unigine", 0.05) + self.run_helper_with_callback( + ["install_unigine", path], + on_success=lambda: self._finish_app_action("unigine"), + app_id="unigine", + progress_segment=(0.05, 0.98), + ) + + def remove_unigine_flow(self): + if not self._unigine_installed(): + self.append_log("ℹ️ Unigine does not appear to be installed.\n") + self.refresh_app_state("unigine") + return + reply = QMessageBox.question( + self, "Uninstall Unigine?", + "This will remove /opt/unigine (including the SDK Browser and any SDKs " + "downloaded into it) and the desktop entry.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("unigine", True, "Removing…") + self._set_app_progress_fraction("unigine", 0.02) + self.run_helper_with_callback( + ["remove_unigine"], + on_success=lambda: self._finish_app_action("unigine"), + app_id="unigine", + progress_segment=(0.02, 0.98), + ) +``` + +- [ ] **Step 5: Add the helper functions** + +After `remove_unreal` in the helper: + +```bash +# ------------------------------------------------- +# Unigine (guided .run install) +# ------------------------------------------------- +install_unigine() { + local run_path="${1:-}" + local install_dir="/opt/unigine" + + [[ -n "${run_path}" ]] || { echo "ERROR: missing .run path" >&2; exit 2; } + [[ -f "${run_path}" ]] || { echo "ERROR: file not found: ${run_path}" >&2; exit 2; } + case "${run_path}" in + *.run) ;; + *) echo "ERROR: expected a .run installer, got: ${run_path}" >&2; exit 2;; + esac + + local user home + user="$(require_invoking_user)" + home="$(require_invoking_user_home)" + + log "Preparing ${install_dir}..." + rm -rf "${install_dir}" + mkdir -p "${install_dir}" + + # The vendor installer creates the SDK Browser folder next to the .run + # file, so run it from inside the install dir. + local run_copy + run_copy="${install_dir}/$(basename "${run_path}")" + cp "${run_path}" "${run_copy}" + chmod +x "${run_copy}" + + # The installer shows its EULA on the terminal and asks for confirmation. + # The GUI already collected explicit agreement, so feed the acceptance + # here. "yes" dies with SIGPIPE when the installer stops reading, which + # pipefail would misreport as failure, so toggle it around the pipeline. + log "Running the UNIGINE installer (EULA accepted in the GUI)..." + local status=0 + set +o pipefail + ( cd "${install_dir}" && yes | "${run_copy}" ) || status=$? + set -o pipefail + rm -f "${run_copy}" + if (( status != 0 )); then + echo "ERROR: UNIGINE installer exited with status ${status}." >&2 + rm -rf "${install_dir}" + exit 1 + fi + + # Locate the Browser (launcher) executable the installer created. + local browser_exe + browser_exe="$(find "${install_dir}" -maxdepth 3 -type f -perm -u+x \ + \( -iname '*browser*' -o -iname '*launcher*' \) 2>/dev/null | sort | head -1)" + if [[ -z "${browser_exe}" ]]; then + browser_exe="$(find "${install_dir}" -maxdepth 3 -type f -perm -u+x \ + ! -name '*.so*' ! -name '*.run' 2>/dev/null | sort | head -1)" + fi + if [[ -z "${browser_exe}" ]]; then + echo "ERROR: UNIGINE Browser executable not found under ${install_dir}." >&2 + exit 2 + fi + log "Found Browser executable: ${browser_exe}" + + # The Browser self-updates and downloads SDKs into its own folder, so the + # invoking user must own the tree. + chown -R "${user}:${user}" "${install_dir}" + + # Under pkexec the vendor writes its nameless, iconless desktop entry into + # root's home. Discard it and write a proper one for the invoking user. + rm -f /root/.local/share/applications/*nigine*.desktop 2>/dev/null || true + + local desktop_dir="${home}/.local/share/applications" + mkdir -p "${desktop_dir}" + chown "${user}:${user}" "${desktop_dir}" + local icon_png="/usr/share/almalinux-creative-installer/icons/apps/com.unigine.Browser.png" + cat > "${desktop_dir}/UnigineBrowser.desktop" < + remove_unigine +``` + +- [ ] **Step 7: Verify syntax + validation probes** + +Run: `python3 -m py_compile src/almalinux-creative-installer && bash -n src/almalinux-creative-installer-helper && echo OK` +Expected: `OK` + +Run: `bash src/almalinux-creative-installer-helper install_unigine /etc/hostname; echo "exit=$?"` +Expected: `ERROR: expected a .run installer...` and `exit=2` + +- [ ] **Step 8: Commit** + +```bash +git add src/almalinux-creative-installer src/almalinux-creative-installer-helper +git commit -m "feat(unigine): guided Unigine install with GUI EULA gate (closes #67)" +``` + +**KNOWN VERIFICATION GAP (carry to the manual QA step, Task 7):** the auto-accept behavior of the real UNIGINE `.run` (whether `yes |` satisfies its EULA prompt, and the actual name of the Browser executable/folder) has not been tested against a real installer. This must be exercised manually before merge. + +--- + +### Task 5: README and website updates + +**Files:** +- Modify: `README.md` (EL availability table ~line 191, Game Engines bullets ~line 245) +- Modify: `docs/index.html` (Game Development card ~lines 1035-1048) + +**Interfaces:** +- Consumes: final app names and install methods from Tasks 2-4. + +- [ ] **Step 1: README EL table rows** + +After the `| Natron ... |` row (line 191), add: + +```markdown +| Open 3D Engine | ❌ | ✅ | Via COPR (hellaenergy/o3de), BETA | +| Unreal Engine 5.8 | ✅ | ✅ | Guided vendor install (Epic account), preview build | +| Unigine | ✅ | ✅ | Guided vendor install (.run) | +``` + +- [ ] **Step 2: README Game Engines bullets** + +Under `- **Game Engines**` (after the `Godots` bullet, line 245), add: + +```markdown + - Open 3D Engine *(via COPR, EL10 only, BETA)* + - Unreal Engine 5.8 *(guided vendor install, preview build)* + - Unigine *(guided vendor install)* +``` + +- [ ] **Step 3: Website Game Development card** + +In `docs/index.html`, change the count on line 1040 from `
3 apps
` to `
6 apps
`, and after `Asset Manager Studio` (line 1046) add: + +```html + Open 3D Engine + Unreal Engine 5.8 + Unigine +``` + +- [ ] **Step 4: Verify** + +Run: `grep -c "Open 3D Engine" README.md docs/index.html` +Expected: `README.md:2` and `docs/index.html:1` + +- [ ] **Step 5: Commit** + +```bash +git add README.md docs/index.html +git commit -m "docs: list O3DE, Unreal Engine 5.8, and Unigine in README and site" +``` + +--- + +### Task 6: App icons (best effort, non-blocking) + +**Files:** +- Create: `src/icons/apps/org.o3de.O3DE.png` +- Create: `src/icons/apps/com.epicgames.UnrealEngine.png` +- Create: `src/icons/apps/com.unigine.Browser.png` + +**Interfaces:** +- Consumes: `icon_appid` values from Task 1. The RPM packaging globs `src/icons/apps/*.png`, so no packaging changes are needed. + +- [ ] **Step 1: Source official logos** + +Try, in order, for each app; stop at the first that yields a valid PNG around 64x64 or larger: + +- O3DE: the o3de GitHub org avatar: `curl -fLo /tmp/o3de.png https://avatars.githubusercontent.com/u/84449732?s=128` +- Unreal: the EpicGames GitHub org avatar: `curl -fLo /tmp/unreal.png https://avatars.githubusercontent.com/u/3732406?s=128` +- Unigine: the Unigine GitHub org avatar: `curl -fLo /tmp/unigine.png https://avatars.githubusercontent.com/u/40636663?s=128` + +Verify each with: `file /tmp/.png` (expected: `PNG image data`). If a download fails or is not a PNG, skip that icon: the UI falls back to a colored letter badge and nothing breaks. + +- [ ] **Step 2: Install into the repo** + +```bash +cp /tmp/o3de.png src/icons/apps/org.o3de.O3DE.png +cp /tmp/unreal.png src/icons/apps/com.epicgames.UnrealEngine.png +cp /tmp/unigine.png src/icons/apps/com.unigine.Browser.png +``` + +(Only the ones that downloaded successfully.) + +- [ ] **Step 3: Commit whatever landed** + +```bash +git add src/icons/apps/org.o3de.O3DE.png src/icons/apps/com.epicgames.UnrealEngine.png src/icons/apps/com.unigine.Browser.png +git commit -m "feat(icons): bundle O3DE, Unreal Engine, and Unigine app icons" +``` + +If none landed, skip this commit entirely and note it in the final report. + +--- + +### Task 7: End-to-end verification + +**Files:** none modified; verification only. + +- [ ] **Step 1: Full syntax pass** + +Run: +```bash +python3 -m py_compile src/almalinux-creative-installer && \ +bash -n src/almalinux-creative-installer-helper && echo SYNTAX-OK +``` +Expected: `SYNTAX-OK` + +- [ ] **Step 2: O3DE COPR logic in an EL10 container (needs network)** + +```bash +podman run --rm quay.io/almalinuxorg/almalinux:10 bash -c " + dnf -y -q install 'dnf-command(copr)' && + dnf -y -q copr enable hellaenergy/o3de centos-stream-10-x86_64 && + dnf -q repoquery --qf '%{name}\n' 'o3de[0-9][0-9][0-9][0-9]' | grep -E '^o3de[0-9]{4}$' | sort -u -V | tail -1 +" +``` +Expected: prints the newest release line (currently `o3de2605`). If podman is unavailable, record that this check was skipped and why. + +- [ ] **Step 3: GUI smoke test (requires a desktop session)** + +Run `src/almalinux-creative-installer` locally and confirm: +- The three new rows appear under Game Engines. +- O3DE shows the EL10 chip plus the BETA chip; on an EL9 host it shows "Not compatible". +- Unreal shows the BETA chip and "Guided install"; Unigine shows "Guided install". +- Clicking Install on Unigine shows the EULA dialog first, and Cancel aborts cleanly. + +If no desktop session is available, record the gap; this becomes part of manual QA. + +- [ ] **Step 4: Manual QA items that need real artifacts (record, do not block)** + +- Unigine: run a real vendor `.run` through the helper; confirm `yes |` satisfies the EULA prompt and the Browser executable discovery finds the right binary. Adjust `install_unigine` if the vendor prompt differs. +- Unreal: confirm the 5.8 preview zip layout (top-level folder vs root `Engine/`) against the real download. + +--- + +### Task 8: Pre-PR review gates + +Not part of this plan's code. After all tasks above are complete and committed: + +1. Run a code-review pass over the branch diff (the repo's `/code-review` skill). +2. Run `/security-review` on the branch. Expected sensitive areas: root helper COPR enable, archive extraction under `/opt`, `chown -R`, executing a user-supplied `.run` as root behind the GUI EULA gate and pkexec authentication. +3. Fix findings, then open the PR referencing #73, #70, #67 (do not push without the user's go-ahead). diff --git a/docs/superpowers/specs/2026-07-01-new-apps-o3de-unreal-unigine-design.md b/docs/superpowers/specs/2026-07-01-new-apps-o3de-unreal-unigine-design.md new file mode 100644 index 0000000..86065ae --- /dev/null +++ b/docs/superpowers/specs/2026-07-01-new-apps-o3de-unreal-unigine-design.md @@ -0,0 +1,177 @@ +# Design: add O3DE, Unreal Engine 5.8, and Unigine + +Date: 2026-07-01 +Issues: #73 (Open 3D Engine), #70 (Unreal Engine 5.8), #67 (Unigine) +Branch: `feat/new-apps-o3de-unreal-unigine` (off `main`) + +## Goal + +Add three game engines to the installer catalog, following the bespoke +per-app install-type pattern already used by `resolve`, `3dcoat`, +`jangafx`, and `gaffer`. Introduce one new shared UI mechanism: a BETA +badge for pre-release or experimental apps. + +Decisions already made during brainstorming: + +- One combined branch for all three apps (like PR #65). +- Bespoke install types per app; no generic "copr" or "archive" type (YAGNI). +- BETA badge is a reusable flag; applied to O3DE and Unreal 5.8. +- O3DE auto-detects the latest versioned major from the COPR at install time. +- Unigine installs to `/opt/unigine` via the root helper, then chowns to the + invoking user. +- No per-app `arch` field. PR #71 (arch gating) was closed intentionally per + the maintainer's decision on issue #68; this design follows that decision. +- Unreal and Unigine run on EL9 and EL10: omit the `el` field (existing + convention). O3DE is EL10-only (hard constraint: the COPR only has a + `centos-stream-10-x86_64` chroot). + +## Surfaces touched + +Mirrors PR #65: + +- `src/almalinux-creative-installer` (APPS entries, BETA pill, detection, + guided flows, subtitles) +- `src/almalinux-creative-installer-helper` (install/remove functions, + dispatch table) +- `README.md` and `docs/index.html` (app list updates) +- `src/icons/apps/` (three new icon PNGs) +- `src/packaging/build-rpm.sh` if the icon file list is explicit + +## 1. BETA pill (shared mechanism) + +- New optional app field `"beta": True`. +- Rendered as a small pill next to the app name in the list row, built the + same way as the existing EL chip but amber-tinted, text `BETA`, tooltip + "Pre-release / experimental build". +- Applied to O3DE (experimental EL10 COPR) and Unreal 5.8 (preview-1 build). + +## 2. Open 3D Engine (`type: "o3de"`) + +App entry: category "Game Engines", `"el": [10]`, `"beta": True`. + +COPR facts (verified via the COPR API on 2026-07-01): + +- Project: `hellaenergy/o3de`, maintained by a Red Hat employee. +- Chroots: `fedora-rawhide-x86_64`, `fedora-44-x86_64`, + `centos-stream-10-x86_64`. No EL9, no epel-10 chroot. +- Packages use versioned-major naming: `o3deNNNN` where NNNN is YYMM + (currently `o3de2605`). Majors are co-installable under + `/opt/O3DE//`. There is no unversioned `o3de` package. +- An `o3de-dependencies` repo auto-enables alongside the main repo. + +Helper `install_o3de`: + +1. `dnf copr enable -y hellaenergy/o3de centos-stream-10-x86_64`. The + explicit chroot argument is required: a bare `copr enable` on + AlmaLinux 10 resolves to an epel-10 chroot that does not exist in this + project. +2. Auto-detect the latest major: `dnf repoquery` for package names matching + `o3de[0-9][0-9][0-9][0-9]`, sort, take the highest. +3. `dnf install -y` the detected package. + +Helper `remove_o3de`: remove all installed `o3de[0-9]*` packages, then +`dnf copr remove hellaenergy/o3de`. + +GUI detection: `rpm -qa` glob for `o3de[0-9]*` (no root needed). +Subtitle: "Installed via COPR (hellaenergy/o3de), latest release line". + +## 3. Unreal Engine 5.8 (`type: "unreal"`) + +App entry: category "Game Engines", no `el` field, `"beta": True`. + +Guided install, 3DCoat-style: + +1. Install opens https://www.unrealengine.com/linux (Epic account required + for the download; account creation is the user's step). +2. User downloads `Linux_Unreal_Engine_5.8.0_preview-1.zip` and picks it in + a file dialog (filter `*.zip`). +3. Helper `install_unreal `: + - Validate the path (same checks as `install_local_file`). + - Unzip to `/opt/unreal-engine/`. + - `chown -R` to the invoking user (the editor writes into its own tree: + DerivedDataCache, Intermediate; resolved via the existing PKEXEC_UID + logic). + - Write a desktop entry in `/usr/share/applications` pointing at + `Engine/Binaries/Linux/UnrealEditor`. + - Install the shipped icon into hicolor. + +GUI detection: `/opt/unreal-engine` exists. +Remove: delete the tree, the desktop file, and the icon. +Subtitle: "Guided install: log in to Epic → download Linux zip → pick it +(EL9 and EL10)". + +## 4. Unigine (`type: "unigine"`) + +App entry: category "Game Engines", no `el` field, no beta flag. + +Vendor installer quirks (from issue #67): + +- The `.run` filename changes with each version. +- It shows an EULA in the terminal that the user must read and agree to. +- It creates the Browser (launcher) folder next to the `.run` file itself. +- It writes a `.desktop` entry with no name and no icon. +- Account creation happens inside the Browser app after install, per vendor + policy. + +Guided install with an EULA gate: + +1. GUI shows an EULA consent dialog first: link to Unigine's EULA and an + explicit "I agree" button. This satisfies "the user should be able to + read and agree to it" because the root helper runs non-interactively + under pkexec. +2. GUI opens https://developer.unigine.com/en/downloads; user picks the + downloaded `.run` in a file dialog (filter `*.run`). +3. Helper `install_unigine `: + - Validate the path. + - Copy the `.run` into `/opt/unigine/` and execute it there with + auto-accept, so the Browser folder is created under `/opt/unigine`. + - `chown -R` to the invoking user so the Browser can self-update. + - Write our own desktop entry (with Name and our shipped icon) in + `/usr/share/applications`. The vendor entry lands nameless in root's + home under pkexec and is discarded. + - Log a post-install note: create the Unigine account inside the + Browser app. + +Implementation-time verification item: the exact auto-accept mechanism for +the `.run` (a flag vs piped input) must be tested against the real +installer before the PR is finalized. + +GUI detection: `/opt/unigine` exists and is non-empty. +Remove: delete the tree, the desktop file, and the icon. +Subtitle: "Guided install: agree to EULA → download .run → installs Browser +to /opt/unigine". + +## 5. Icons + +Ship three PNGs in `src/icons/apps/` following the existing naming +pattern, sourced from official project artwork: + +- O3DE (o3de.org press kit) +- Unreal Engine (Epic branding asset) +- Unigine (vendor logo) + +The list UI falls back to the colored-letter badge if a PNG is missing, so +icons are non-blocking. + +## 6. Error handling + +- O3DE: if `copr enable` or the repoquery finds no `o3deNNNN` package, + fail with a clear log line (repo unreachable or chroot missing) rather + than installing nothing silently. +- Unreal: reject non-zip picks; unzip failures leave no partial + `/opt/unreal-engine` (extract to a temp dir, move into place). +- Unigine: if the `.run` exits nonzero, remove the partial + `/opt/unigine` and report the exit code. + +## 7. Testing and review gates + +- O3DE: verify COPR enable + repoquery + install in an EL10 container. +- Unreal and Unigine: manual smoke test of the guided flows where + feasible; at minimum, dry-run the helper functions with a dummy archive. +- Before the PR: + 1. Code-review pass against current architecture (helper dispatch table, + badge rendering, EL gating, packaging file lists). + 2. `/security-review` on the branch. Sensitive spots are all in the root + helper: COPR enable, archive extraction to `/opt` (zip-slip, path + validation on user-picked files), `chown -R`, and executing a + user-supplied `.run` as root. diff --git a/src/almalinux-creative-installer b/src/almalinux-creative-installer index e258934..10fd1de 100755 --- a/src/almalinux-creative-installer +++ b/src/almalinux-creative-installer @@ -31,6 +31,9 @@ THREEDC_URL = "https://3dcoat.com/#auth" INSTAMATERIAL_URL = "https://instamaterial.com/" JANGAFX_URL = "https://jangafx.com/software/elemental-suite/try" GAFFER_URL = "https://github.com/GafferHQ/gaffer/releases" +UNREAL_URL = "https://www.unrealengine.com/linux" +UNIGINE_URL = "https://developer.unigine.com/en/downloads" +UNIGINE_EULA_URL = "https://developer.unigine.com/en/eula" APPIMAGELAUNCHER_VERSION = "3.0.0-beta-2-gha287.96cb937" APPIMAGELAUNCHER_RPM_URL = ( "https://github.com/TheAssassin/AppImageLauncher/releases/download/" @@ -42,7 +45,7 @@ APPIMAGELAUNCHER_RPM_URL = ( # HOW TO ADD / EDIT APPS (quick maintainer guide) # ----------------------------------------------------------------------------- # 1) Add or update an item inside APPS with a unique "id". -# 2) Pick a supported "type": dnf, flatpak, resolve, 3dcoat +# 2) Pick a supported "type": dnf, flatpak, resolve, 3dcoat, o3de, unreal, unigine # 3) Set metadata keys used by the UI for that type: # - dnf: pkg # - flatpak: appid @@ -50,6 +53,8 @@ APPIMAGELAUNCHER_RPM_URL = ( # 4) Optional: add the app id to VERSION_SELECTABLE_APPS. # 5) Optional: add "el": [9] or "el": [10] if the app only works on one EL # version. Omit (or use [9, 10]) for apps that work on both. +# 5b) Optional: add "beta": True for pre-release or experimental apps. +# The row shows an amber BETA chip next to the app name. # 6) If adding a truly new app type, update type handlers here and in the helper. # ----------------------------------------------------------------------------- @@ -97,6 +102,9 @@ APPS = [ {"id": "epicassetmanager", "name": "Epic Asset Manager","type": "flatpak", "appid": "io.github.achetagames.epic_asset_manager", "category": "Game Engines"}, {"id": "assetmanagerstudio","name": "Asset Manager Studio","type": "flatpak","appid": "studio.assetmanager.ams", "category": "Game Engines"}, {"id": "godots", "name": "Godots", "type": "flatpak", "appid": "io.github.MakovWait.Godots", "category": "Game Engines"}, + {"id": "o3de", "name": "Open 3D Engine", "type": "o3de", "icon_appid": "org.o3de.O3DE", "category": "Game Engines", "beta": True}, + {"id": "unreal", "name": "Unreal Engine 5.8","type": "unreal", "category": "Game Engines", "beta": True}, + {"id": "unigine", "name": "Unigine", "type": "unigine", "category": "Game Engines"}, {"id": "appimagelauncher", "name": "AppImageLauncher", "type": "dnf", "pkg": "appimagelauncher", "install_target": APPIMAGELAUNCHER_RPM_URL, "category": "Productivity", "el": [10]}, {"id": "resolve", "name": "DaVinci Resolve", "type": "resolve", "category": "Animation & Video"}, @@ -563,6 +571,20 @@ class AlmaCreativeInstaller(QMainWindow): req_layout.addStretch() setup_layout.addWidget(req_frame) + # ---- Desktop Environment frame (GNOME only) ---- + de_frame = QFrame() + de_frame.setObjectName("reqFrame") + de_layout = QVBoxLayout(de_frame) + de_layout.setContentsMargins(10, 10, 10, 10) + de_layout.setSpacing(6) + + de_title = QLabel("Desktop Environment") + de_title.setObjectName("rowTitle") + de_layout.addWidget(de_title) + de_layout.addWidget(self._make_gnome_ui_row()) + de_layout.addStretch() + setup_layout.addWidget(de_frame) + self.ready_banner = QLabel("✓ System ready — all required repositories are enabled. Head to the Apps tab to install.") self.ready_banner.setObjectName("readyBanner") self.ready_banner.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -686,8 +708,49 @@ class AlmaCreativeInstaller(QMainWindow): if not Path(HELPER).exists(): self.append_log("\nWARNING: Helper not found at {}\n".format(HELPER)) + self._ensure_polkit_agent() self.refresh_all_states() + # ------------------------------------------------------------------------- + # Polkit agent bootstrap + # ------------------------------------------------------------------------- + def _ensure_polkit_agent(self): + """Make sure a polkit auth agent is running so pkexec can prompt for password. + + On Wayland+GNOME, gnome-shell IS the agent — nothing to start. + On X11+GNOME, polkit-gnome-authentication-agent-1 must be running. + """ + # Wayland: gnome-shell handles authentication natively. + if os.environ.get("WAYLAND_DISPLAY"): + return + + # Already running? + if subprocess.run( + ["pgrep", "-f", "polkit.*agent"], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + ).returncode == 0: + return + + # Try to start the GNOME polkit agent (polkit-gnome package). + candidates = [ + "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1", + "/usr/libexec/polkit-gnome-authentication-agent-1", + ] + for path in candidates: + if os.path.exists(path): + try: + subprocess.Popen([path]) + self.append_log("ℹ️ Started polkit authentication agent ({}).\n".format(path)) + except Exception as e: + self.append_log("⚠️ Could not start polkit agent: {}\n".format(e)) + return + + self.append_log( + "⚠️ No polkit authentication agent found.\n" + " Install it with: sudo dnf install polkit-gnome\n" + " Without it, Install buttons will show 'Not authorized'.\n" + ) + # ------------------------------------------------------------------------- # Logging # ------------------------------------------------------------------------- @@ -732,6 +795,11 @@ class AlmaCreativeInstaller(QMainWindow): label.style().polish(label) label.update() + @staticmethod + def _is_gnome_de(): + de = os.environ.get("XDG_CURRENT_DESKTOP", "").upper() + return any(x in de for x in ("GNOME", "UNITY")) + @staticmethod def _is_system_dark(): try: @@ -749,6 +817,9 @@ class AlmaCreativeInstaller(QMainWindow): except Exception: return False + def _gnome_ui_installed(self): + return Path("/etc/dconf/db/local.d/01-creative_gnome_defaults").exists() + def _update_ready_banner(self): if not hasattr(self, "ready_banner"): return @@ -967,6 +1038,104 @@ class AlmaCreativeInstaller(QMainWindow): self._set_selinux_requirement_state(None) return row + def _make_gnome_ui_row(self): + row = QFrame() + row.setObjectName("appRow") + hl = QHBoxLayout(row) + hl.setContentsMargins(8, 6, 8, 6) + + icon_lbl = QLabel("") + icon_lbl.setFixedWidth(28) + hl.addWidget(icon_lbl) + + text_col = QVBoxLayout() + title_lbl = QLabel("Windows-style UI (Dash to Panel, ArcMenu, System Monitor, Blur My Shell)") + title_lbl.setObjectName("rowTitle") + text_col.addWidget(title_lbl) + sub_lbl = QLabel( + "Installs GNOME Tweaks, extensions, and Nautilus copy-path. " + "Applies system-wide dconf defaults. Requires GNOME Desktop." + ) + sub_lbl.setObjectName("rowSubtitle") + text_col.addWidget(sub_lbl) + hl.addLayout(text_col, stretch=1) + + status_lbl = QLabel("Checking…") + status_lbl.setProperty("badge", "checking") + status_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter) + hl.addWidget(status_lbl) + + install_btn = QPushButton("Install") + install_btn.setObjectName("enableBtn") + remove_btn = QPushButton("Remove") + remove_btn.setObjectName("removeBtn") + + on_gnome = self._is_gnome_de() + on_el9 = (_EL_VERSION == 9) + + if not on_el9: + install_btn.setEnabled(False) + remove_btn.setEnabled(False) + self._set_status_badge(status_lbl, "AlmaLinux 9 only", "warning") + elif not on_gnome: + install_btn.setEnabled(False) + remove_btn.setEnabled(False) + self._set_status_badge(status_lbl, "GNOME only", "warning") + else: + def _on_install(): + install_btn.setEnabled(False) + remove_btn.setEnabled(False) + self._set_status_badge(status_lbl, "Working…", "busy") + self.run_helper_with_callback( + ["install_gnome_ui"], + on_success=lambda: self._refresh_gnome_ui_state(), + on_failure=lambda: self._refresh_gnome_ui_state(), + ) + + def _on_remove(): + install_btn.setEnabled(False) + remove_btn.setEnabled(False) + self._set_status_badge(status_lbl, "Working…", "busy") + self.run_helper_with_callback( + ["remove_gnome_ui"], + on_success=lambda: self._refresh_gnome_ui_state(), + on_failure=lambda: self._refresh_gnome_ui_state(), + ) + + install_btn.clicked.connect(_on_install) + remove_btn.clicked.connect(_on_remove) + + hl.addWidget(install_btn) + hl.addWidget(remove_btn) + + available = on_el9 and on_gnome + self.repo_widgets["GNOME_UI"] = { + "icon": icon_lbl, + "status": status_lbl, + "install_btn": install_btn, + "remove_btn": remove_btn, + "on_gnome": available, + } + + if available: + self._refresh_gnome_ui_state() + + return row + + def _refresh_gnome_ui_state(self): + w = self.repo_widgets.get("GNOME_UI") + if not w or not w.get("on_gnome"): + return + applied = self._gnome_ui_installed() + if applied: + self._set_status_badge(w["status"], "Applied", "installed") + w["install_btn"].setEnabled(False) + w["remove_btn"].setEnabled(True) + else: + self._set_status_badge(w["status"], "Not applied", "missing") + w["install_btn"].setEnabled(True) + w["remove_btn"].setEnabled(False) + def _set_requirement_state(self, key, state): self.repo_states[key] = state w = self.repo_widgets.get(key) @@ -1093,6 +1262,15 @@ class AlmaCreativeInstaller(QMainWindow): ) ) name_row.addWidget(el_chip) + if app.get("beta"): + beta_chip = QLabel("BETA") + beta_chip.setStyleSheet( + "background: rgba(230,160,50,0.20); color: #d29a3d;" + " border-radius: 4px; padding: 1px 5px;" + " font-size: 10px; font-weight: 600;" + ) + beta_chip.setToolTip("Pre-release / experimental build") + name_row.addWidget(beta_chip) name_row.addStretch() left.addLayout(name_row) @@ -1157,6 +1335,15 @@ class AlmaCreativeInstaller(QMainWindow): elif app["type"] == "gaffer": install_btn.clicked.connect(lambda: self.install_gaffer_flow()) remove_btn.clicked.connect(lambda: self.remove_gaffer_flow()) + elif app["type"] == "o3de": + install_btn.clicked.connect(lambda: self.install_o3de_flow()) + remove_btn.clicked.connect(lambda: self.remove_o3de_flow()) + elif app["type"] == "unreal": + install_btn.clicked.connect(lambda: self.install_unreal_flow()) + remove_btn.clicked.connect(lambda: self.remove_unreal_flow()) + elif app["type"] == "unigine": + install_btn.clicked.connect(lambda: self.install_unigine_flow()) + remove_btn.clicked.connect(lambda: self.remove_unigine_flow()) pulse_timer = QTimer() pulse_timer.setInterval(120) @@ -1211,6 +1398,12 @@ class AlmaCreativeInstaller(QMainWindow): return "Guided install: download suite zip → extracts EmberGen, GeoGen, IlluGen, LiquiGen to /opt/jangafx" if app["type"] == "gaffer": return "Guided install: download Linux tarball from GitHub → extracts to /opt/gaffer (EL9 and EL10)" + if app["type"] == "o3de": + return "Installed via COPR (hellaenergy/o3de), latest release line" + if app["type"] == "unreal": + return "Guided install: log in to Epic → download Linux zip → extracts to /opt/unreal-engine (EL9 and EL10)" + if app["type"] == "unigine": + return "Guided install: agree to EULA → pick vendor .run → SDK Browser in /opt/unigine" return "" # ------------------------------------------------------------------------- @@ -1387,6 +1580,7 @@ class AlmaCreativeInstaller(QMainWindow): # ------------------------------------------------------------------------- def refresh_all_states(self): self.refresh_repo_state() + self._refresh_gnome_ui_state() self.refresh_app_versions() for app in APPS: self.refresh_app_state(app["id"]) @@ -1442,6 +1636,30 @@ class AlmaCreativeInstaller(QMainWindow): w["remove"].setEnabled(installed) return + if app["type"] == "o3de": + installed = self._o3de_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Not installed", + "installed" if installed else "missing") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return + + if app["type"] == "unreal": + installed = self._unreal_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Guided install", + "installed" if installed else "available") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return + + if app["type"] == "unigine": + installed = self._unigine_installed() + self._set_status_badge(w["status"], "Installed" if installed else "Guided install", + "installed" if installed else "available") + w["install"].setEnabled(not installed) + w["remove"].setEnabled(installed) + return + if app["type"] == "dnf": installed = subprocess.run( ["rpm", "-q", app["pkg"]], @@ -1968,6 +2186,8 @@ class AlmaCreativeInstaller(QMainWindow): "", "Installers (*.run *.rpm);;All files (*)", ) + self.raise_() + self.activateWindow() if not path: self.set_app_busy("resolve", False) return @@ -2147,6 +2367,8 @@ class AlmaCreativeInstaller(QMainWindow): "", "Tarballs (*.tar *.tar.bz2 *.tar.gz *.tar.xz *.tar.zst *.tgz);;All files (*)", ) + self.raise_() + self.activateWindow() if not path: self._finish_app_action("3dcoat") return @@ -2211,6 +2433,8 @@ class AlmaCreativeInstaller(QMainWindow): "", "Zip archives (*.zip);;All files (*)", ) + self.raise_() + self.activateWindow() if not path: self._finish_app_action("instamaterial") return @@ -2271,6 +2495,8 @@ class AlmaCreativeInstaller(QMainWindow): "", "Zip archives (*.zip);;All files (*)", ) + self.raise_() + self.activateWindow() if not path: self._finish_app_action("jangafx") return @@ -2325,6 +2551,8 @@ class AlmaCreativeInstaller(QMainWindow): "", "Tarballs (*.tar.gz *.tgz);;All files (*)", ) + self.raise_() + self.activateWindow() if not path: self._finish_app_action("gaffer") return @@ -2357,6 +2585,175 @@ class AlmaCreativeInstaller(QMainWindow): progress_segment=(0.02, 0.98), ) + def _o3de_installed(self): + out = subprocess.run( + ["rpm", "-qa", "--qf", "%{NAME}\n", "o3de*"], + stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, + ).stdout + return any(re.fullmatch(r"o3de\d{4}", line.strip()) for line in out.splitlines()) + + def install_o3de_flow(self): + self.set_app_busy("o3de", True, "Installing…") + self._set_app_progress_fraction("o3de", 0.02) + self.run_helper_with_callback( + ["install_o3de"], + on_success=lambda: self._finish_app_action("o3de"), + app_id="o3de", + progress_segment=(0.02, 0.98), + ) + + def remove_o3de_flow(self): + if not self._o3de_installed(): + self.append_log("ℹ️ Open 3D Engine does not appear to be installed.\n") + self.refresh_app_state("o3de") + return + reply = QMessageBox.question( + self, "Uninstall Open 3D Engine?", + "This will remove all installed o3de packages and disable the hellaenergy/o3de COPR repo.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("o3de", True, "Removing…") + self._set_app_progress_fraction("o3de", 0.02) + self.run_helper_with_callback( + ["remove_o3de"], + on_success=lambda: self._finish_app_action("o3de"), + app_id="o3de", + progress_segment=(0.02, 0.98), + ) + + def _unreal_installed(self): + return Path("/opt/unreal-engine/Engine/Binaries/Linux/UnrealEditor").is_file() + + def install_unreal_flow(self): + self.set_app_busy("unreal", True, "Waiting for file…") + self._set_app_progress_fraction("unreal", 0.02) + if shutil.which("xdg-open"): + subprocess.Popen(["xdg-open", UNREAL_URL]) + self.append_log("Opened the Unreal Engine Linux page (Epic account required).\n") + self.append_log( + "Download the Linux zip (e.g. Linux_Unreal_Engine_5.8.0.zip), then select it below.\n" + ) + self.pick_unreal_zip() + + def pick_unreal_zip(self): + path, _ = QFileDialog.getOpenFileName( + self, + "Select Unreal Engine Linux zip", + "", + "Zip archives (*.zip);;All files (*)", + ) + self.raise_() + self.activateWindow() + if not path: + self._finish_app_action("unreal") + return + self._set_app_progress_fraction("unreal", 0.05) + self.run_helper_with_callback( + ["install_unreal", path], + on_success=lambda: self._finish_app_action("unreal"), + app_id="unreal", + progress_segment=(0.05, 0.98), + ) + + def remove_unreal_flow(self): + if not self._unreal_installed(): + self.append_log("ℹ️ Unreal Engine does not appear to be installed.\n") + self.refresh_app_state("unreal") + return + reply = QMessageBox.question( + self, "Uninstall Unreal Engine?", + "This will remove /opt/unreal-engine and the desktop entry.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("unreal", True, "Removing…") + self._set_app_progress_fraction("unreal", 0.02) + self.run_helper_with_callback( + ["remove_unreal"], + on_success=lambda: self._finish_app_action("unreal"), + app_id="unreal", + progress_segment=(0.02, 0.98), + ) + + def _unigine_installed(self): + base = Path("/opt/unigine") + return base.is_dir() and any(base.iterdir()) + + def install_unigine_flow(self): + msg = QMessageBox(self) + msg.setWindowTitle("UNIGINE SDK License Agreement") + msg.setTextFormat(Qt.TextFormat.RichText) + msg.setText( + 'Installing Unigine runs the vendor installer, which is governed by the ' + 'UNIGINE SDK License Agreement.'.format(UNIGINE_EULA_URL) + ) + msg.setInformativeText( + "The vendor installer normally shows this EULA in a terminal. Because the " + "install runs unattended here, it will be accepted on your behalf.\n\n" + 'Click "I Agree" only if you have read and accept the EULA.' + ) + msg.setIcon(QMessageBox.Icon.Question) + btn_agree = msg.addButton("I Agree", QMessageBox.ButtonRole.AcceptRole) + msg.addButton(QMessageBox.StandardButton.Cancel) + msg.exec() + if msg.clickedButton() != btn_agree: + return + + self.set_app_busy("unigine", True, "Waiting for file…") + self._set_app_progress_fraction("unigine", 0.02) + if shutil.which("xdg-open"): + subprocess.Popen(["xdg-open", UNIGINE_URL]) + self.append_log("Opened the UNIGINE downloads page.\n") + self.append_log( + "Download the Linux .run installer (the filename changes with each version), then select it below.\n" + ) + self.pick_unigine_run() + + def pick_unigine_run(self): + path, _ = QFileDialog.getOpenFileName( + self, + "Select UNIGINE .run installer", + "", + "Run installers (*.run);;All files (*)", + ) + self.raise_() + self.activateWindow() + if not path: + self._finish_app_action("unigine") + return + self._set_app_progress_fraction("unigine", 0.05) + self.run_helper_with_callback( + ["install_unigine", path], + on_success=lambda: self._finish_app_action("unigine"), + app_id="unigine", + progress_segment=(0.05, 0.98), + ) + + def remove_unigine_flow(self): + if not self._unigine_installed(): + self.append_log("ℹ️ Unigine does not appear to be installed.\n") + self.refresh_app_state("unigine") + return + reply = QMessageBox.question( + self, "Uninstall Unigine?", + "This will remove /opt/unigine (including the SDK Browser and any SDKs " + "downloaded into it) and the desktop entry.", + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel, + ) + if reply != QMessageBox.StandardButton.Ok: + return + self.set_app_busy("unigine", True, "Removing…") + self._set_app_progress_fraction("unigine", 0.02) + self.run_helper_with_callback( + ["remove_unigine"], + on_success=lambda: self._finish_app_action("unigine"), + app_id="unigine", + progress_segment=(0.02, 0.98), + ) + _THEME_COLORS = _DARK # set by main() before window creation _ICON_CACHE = {} # app["id"] → QPixmap | None, populated on first build diff --git a/src/almalinux-creative-installer-helper b/src/almalinux-creative-installer-helper index 822fc54..0a4c84e 100755 --- a/src/almalinux-creative-installer-helper +++ b/src/almalinux-creative-installer-helper @@ -820,6 +820,86 @@ EOF log "Gaffer installation complete." } +# ------------------------------------------------- +# GNOME UI Extensions & Tweaks (Windows-style taskbar look) +# ------------------------------------------------- +install_gnome_ui() { + local data_dir="/usr/share/almalinux-creative-installer/gnome-ui" + + # Dev mode: look next to the helper script + if [[ ! -d "${data_dir}" ]]; then + local script_dir + script_dir="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" + data_dir="${script_dir}/gnome-ui" + fi + + [[ -d "${data_dir}" ]] || { echo "ERROR: gnome-ui data directory not found (looked in ${data_dir})" >&2; exit 2; } + + log "Installing GNOME UI prerequisites..." + dnf -y install gnome-tweaks + dnf -y install python3-nautilus 2>/dev/null || dnf -y install nautilus-python 2>/dev/null || true + + log "Installing Nautilus copy-path extension..." + mkdir -p /usr/share/nautilus-python/extensions + cp -r "${data_dir}/nautilus-extensions/nautilus-copy-path" /usr/share/nautilus-python/extensions/ + cp "${data_dir}/nautilus-extensions/nautilus-copy-path.py" /usr/share/nautilus-python/extensions/ + + log "Installing GNOME shell extensions..." + mkdir -p /usr/share/gnome-shell/extensions + for ext_dir in "${data_dir}/gnome-extensions"/*/; do + [[ -d "${ext_dir}" ]] || continue + ext_name="$(basename "${ext_dir}")" + log " ${ext_name}" + cp -r "${ext_dir}" /usr/share/gnome-shell/extensions/ + for schema in "${ext_dir}schemas/"*.gschema.xml; do + [[ -f "${schema}" ]] && cp "${schema}" /usr/share/glib-2.0/schemas/ || true + done + done + + log "Compiling GLib schemas..." + glib-compile-schemas /usr/share/glib-2.0/schemas/ + + log "Deploying dconf profile..." + mkdir -p /etc/dconf/db/local.d + cp "${data_dir}/01-creative_gnome_defaults" /etc/dconf/db/local.d/ + + log "Updating dconf database..." + dconf update + + log "GNOME UI setup complete. Log out and back in to apply all changes." +} + +remove_gnome_ui() { + log "Removing GNOME UI customizations..." + + if [[ -f /etc/dconf/db/local.d/01-creative_gnome_defaults ]]; then + rm -f /etc/dconf/db/local.d/01-creative_gnome_defaults + log "Removed dconf profile." + dconf update + fi + + local ext + for ext in dash-to-panel@jderose9.github.com system-monitor@paradoxxx.zero.gmail.com \ + arcmenu@arcmenu.com gnome-ui-tune@itstime.tech blur-my-shell@aunetx; do + if [[ -d "/usr/share/gnome-shell/extensions/${ext}" ]]; then + rm -rf "/usr/share/gnome-shell/extensions/${ext}" + log "Removed extension: ${ext}" + fi + done + + local np_dir="/usr/share/nautilus-python/extensions" + if [[ -d "${np_dir}/nautilus-copy-path" ]]; then + rm -rf "${np_dir}/nautilus-copy-path" + log "Removed nautilus-copy-path extension." + fi + if [[ -f "${np_dir}/nautilus-copy-path.py" ]]; then + rm -f "${np_dir}/nautilus-copy-path.py" + log "Removed nautilus-copy-path.py." + fi + + log "GNOME UI customizations removed. Log out and back in to apply." +} + remove_gaffer() { local user home user="$(require_invoking_user)" @@ -870,6 +950,324 @@ remove_3dcoat() { log "3DCoat removed." } +# ------------------------------------------------- +# Open 3D Engine (COPR) +# ------------------------------------------------- +O3DE_COPR="hellaenergy/o3de" + +install_o3de() { + log "Ensuring dnf copr plugin..." + dnf -y install 'dnf-command(copr)' + + # The COPR publishes EL builds under centos-stream chroots; a bare + # "copr enable" would look for epel-, which does not exist in this + # project, so the chroot must be passed explicitly per EL version. + local el_version chroot + el_version="$(rpm -E %rhel)" + case "${el_version}" in + 9) chroot="centos-stream-9-x86_64" ;; + 10) chroot="centos-stream-10-x86_64" ;; + *) echo "ERROR: unsupported EL version for O3DE: ${el_version}" >&2; exit 4 ;; + esac + + log "Enabling COPR ${O3DE_COPR} (chroot ${chroot})..." + dnf -y copr enable "${O3DE_COPR}" "${chroot}" + + # Packages use versioned-major naming (o3deNNNN, NNNN = YYMM). Majors are + # co-installable; install the newest release line. + log "Detecting the latest Open 3D Engine release line..." + local latest + latest="$(dnf -q repoquery --qf '%{name}\n' 'o3de[0-9][0-9][0-9][0-9]' 2>/dev/null \ + | grep -E '^o3de[0-9]{4}$' | sort -u -V | tail -1 || true)" + if [[ -z "${latest}" ]]; then + echo "ERROR: no o3deNNNN package found in ${O3DE_COPR} (repo unreachable or chroot missing)." >&2 + exit 4 + fi + + log "Installing ${latest}..." + dnf -y install "${latest}" + log "Open 3D Engine installed (${latest})." +} + +remove_o3de() { + log "Removing Open 3D Engine packages..." + local pkgs + mapfile -t pkgs < <(rpm -qa --qf '%{NAME}\n' 'o3de*' | grep -E '^o3de[0-9]{4}(-devel)?$' || true) + if (( ${#pkgs[@]} )); then + dnf -y remove "${pkgs[@]}" + else + log "No o3de packages installed." + fi + + log "Disabling COPR ${O3DE_COPR}..." + dnf -y copr remove "${O3DE_COPR}" || true + log "Open 3D Engine removed." +} + +# ------------------------------------------------- +# Unreal Engine (guided zip install) +# ------------------------------------------------- +install_unreal() { + local zip_path="${1:-}" + local install_dir="/opt/unreal-engine" + local tmp_dir + + [[ -n "${zip_path}" ]] || { echo "ERROR: missing zip path" >&2; exit 2; } + [[ -f "${zip_path}" ]] || { echo "ERROR: zip not found: ${zip_path}" >&2; exit 2; } + case "${zip_path}" in + *.zip) ;; + *) echo "ERROR: expected a .zip archive, got: ${zip_path}" >&2; exit 2;; + esac + + log "Ensuring unzip is available..." + command -v unzip >/dev/null 2>&1 || dnf -y install unzip + + local user home + user="$(require_invoking_user)" + home="$(require_invoking_user_home)" + + # Extract under /opt, not /tmp: the engine is tens of GB and /tmp is + # commonly a size-limited tmpfs. Same filesystem also makes mv instant. + tmp_dir="$(mktemp -d /opt/.unreal-tmp-XXXXXX)" + # shellcheck disable=SC2064 + trap "rm -rf '${tmp_dir}'" EXIT + + log "Extracting Unreal Engine archive (large, this can take several minutes)..." + # unzip 6.0 on EL9 can fail on ZIP64 large archives; fall back to python3 zipfile module. + if ! unzip -o "${zip_path}" -d "${tmp_dir}" 2>&1; then + log "unzip failed, retrying with python3 zipfile module..." + python3 -c " +import zipfile, sys +with zipfile.ZipFile(sys.argv[1]) as z: + z.extractall(sys.argv[2]) +" "${zip_path}" "${tmp_dir}" || { echo "ERROR: extraction failed with both unzip and python3 zipfile" >&2; exit 1; } + fi + + # The zip either contains Engine/ at the root or a single top-level + # versioned folder (e.g. Linux_Unreal_Engine_5.8.0_preview-1/). + local src_dir + if [[ -d "${tmp_dir}/Engine" ]]; then + src_dir="${tmp_dir}" + else + src_dir="$(find "${tmp_dir}" -maxdepth 1 -mindepth 1 -type d | head -1)" + fi + if [[ -z "${src_dir}" || ! -d "${src_dir}/Engine" ]]; then + echo "ERROR: no Engine/ directory found in the archive." >&2 + exit 2 + fi + + local editor="Engine/Binaries/Linux/UnrealEditor" + [[ -f "${src_dir}/${editor}" ]] || { echo "ERROR: ${editor} not found in the archive." >&2; exit 2; } + + log "Installing to ${install_dir}..." + rm -rf "${install_dir}" + mv "${src_dir}" "${install_dir}" + chmod +x "${install_dir}/${editor}" + + # The editor writes into its own tree (DerivedDataCache, Intermediate), + # so the invoking user must own it. + log "Setting ownership (large tree, this can take a moment)..." + chown -R "${user}:${user}" "${install_dir}" + + local desktop_dir="${home}/.local/share/applications" + mkdir -p "${desktop_dir}" + chown "${user}:${user}" "${desktop_dir}" + cat > "${desktop_dir}/UnrealEngine.desktop" <&2; exit 2; } + [[ -f "${run_path}" ]] || { echo "ERROR: file not found: ${run_path}" >&2; exit 2; } + case "${run_path}" in + *.run) ;; + *) echo "ERROR: expected a .run installer, got: ${run_path}" >&2; exit 2;; + esac + + local user home + user="$(require_invoking_user)" + home="$(require_invoking_user_home)" + + log "Preparing ${install_dir}..." + rm -rf "${install_dir}" + mkdir -p "${install_dir}" + + # The vendor installer creates the SDK Browser folder next to the .run + # file, so run it from inside the install dir. + local run_copy + run_copy="${install_dir}/$(basename "${run_path}")" + cp "${run_path}" "${run_copy}" + chmod +x "${run_copy}" + # Allow execution in /opt under SELinux enforcing (best-effort). + chcon -t bin_t "${run_copy}" 2>/dev/null || true + + # The installer shows its EULA on the terminal and asks for confirmation. + # The GUI already collected explicit agreement, so feed the acceptance + # here. Piping "yes" leaves stdin/stdout as plain pipes, and this + # installer's isatty() check on that non-tty path leads it into a + # different (broken) argument-parsing branch that dies with + # "Unknown option -title". Run it under a real pty and auto-answer "y" + # so it takes the same code path as an interactive terminal session. + log "Running the UNIGINE installer (EULA accepted in the GUI)..." + local status=0 + ( cd "${install_dir}" && python3 -c " +import os, pty, select, sys, termios + +pid, master_fd = pty.fork() +if pid == 0: + os.execvp(sys.argv[1], sys.argv[1:]) + +# Disable local echo so our own writes to master_fd don't loop back as +# fake 'readable' output and trigger a self-sustaining write/read storm. +attrs = termios.tcgetattr(master_fd) +attrs[3] &= ~termios.ECHO +termios.tcsetattr(master_fd, termios.TCSANOW, attrs) + +exit_status = None +while True: + try: + r, _, _ = select.select([master_fd], [], [], 1.0) + except InterruptedError: + r = [] + if master_fd in r: + try: + data = os.read(master_fd, 4096) + except OSError: + data = b'' + if data: + os.write(1, data) + try: + os.write(master_fd, b'y\n') + except OSError: + pass + else: + break + try: + wpid, wstatus = os.waitpid(pid, os.WNOHANG) + except ChildProcessError: + break + if wpid == pid: + exit_status = wstatus + break + +if exit_status is None: + _, exit_status = os.waitpid(pid, 0) +sys.exit(os.WEXITSTATUS(exit_status) if os.WIFEXITED(exit_status) else 1) +" "${run_copy}" ) || status=$? + rm -f "${run_copy}" + if (( status != 0 )); then + echo "ERROR: UNIGINE installer exited with status ${status}." >&2 + rm -rf "${install_dir}" + exit 1 + fi + + # Locate the Browser (launcher) executable the installer created. + local browser_exe + browser_exe="$(find "${install_dir}" -maxdepth 3 -type f -perm -u+x \ + \( -iname '*browser*' -o -iname '*launcher*' \) 2>/dev/null | sort | head -1)" + if [[ -z "${browser_exe}" ]]; then + browser_exe="$(find "${install_dir}" -maxdepth 3 -type f -perm -u+x \ + ! -name '*.so*' ! -name '*.run' 2>/dev/null | sort | head -1)" + fi + if [[ -z "${browser_exe}" ]]; then + echo "ERROR: UNIGINE Browser executable not found under ${install_dir}." >&2 + exit 2 + fi + log "Found Browser executable: ${browser_exe}" + + # UNIGINE's bundled Qt binaries use text relocations (execmod), which the + # default /opt label (usr_t) doesn't permit under SELinux enforcing. The + # Browser also self-updates and replaces its own binaries post-install, + # so per-file chcon/semanage labeling doesn't stick. Enable the + # selinuxuser_execmod boolean instead: it grants execmod for usr_t files + # to unconfined desktop sessions regardless of which file gets rewritten + # (best-effort, no-op on permissive/disabled). + setsebool -P selinuxuser_execmod 1 2>/dev/null || true + + # The Browser self-updates and downloads SDKs into its own folder, so the + # invoking user must own the tree. + chown -R "${user}:${user}" "${install_dir}" + + # Under pkexec the vendor writes its nameless, iconless desktop entry into + # root's home. Discard it and write a proper one for the invoking user. + rm -f /root/.local/share/applications/*nigine*.desktop 2>/dev/null || true + + local desktop_dir="${home}/.local/share/applications" + mkdir -p "${desktop_dir}" + chown "${user}:${user}" "${desktop_dir}" + cat > "${desktop_dir}/UnigineBrowser.desktop" <&2 <<'EOF' Usage: almalinux-creative-installer-helper @@ -967,6 +1381,26 @@ InstaMaterial: JangaFX Elemental Suite: install_jangafx remove_jangafx + +Gaffer: + install_gaffer + remove_gaffer + +Open 3D Engine: + install_o3de + remove_o3de + +Unreal Engine: + install_unreal + remove_unreal + +Unigine: + install_unigine + remove_unigine + +GNOME UI Extensions & Tweaks: + install_gnome_ui + remove_gnome_ui EOF exit 1 ;; diff --git a/src/gnome-ui/01-creative_gnome_defaults b/src/gnome-ui/01-creative_gnome_defaults new file mode 100644 index 0000000..fbd1a8f --- /dev/null +++ b/src/gnome-ui/01-creative_gnome_defaults @@ -0,0 +1,96 @@ +########################### +### Window Management + +[org/gnome/desktop/wm/preferences] + +button-layout='appmenu:minimize,maximize,close' +resize-with-right-button=true + +########################### +### Interface + +[org/gnome/desktop/interface] + +gtk-theme='Adwaita-dark' +enable-hot-corners=false + +########################### +### File Browser (Nautilus) + +[org/gnome/nautilus/preferences] + +always-use-location-entry=true +default-folder-viewer='list-view' + +[org/gnome/nautilus/list-view] + +default-zoom-level='small' +use-tree-view=true +default-visible-columns=['name', 'size', 'date_modified', 'type', 'starred'] + +########################### +### Workspace + +[org/gnome/mutter] + +workspaces-only-on-primary=false + +########################## +### Favorite Apps +[org/gnome/shell] +favorite-apps=['google-chrome.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Terminal.desktop', 'com.slack.Slack.desktop', 'almalinux-creative-installer.desktop'] + +########################## +### Gnome Extensions +[org/gnome/shell] + +# Set default Enabled Extensions +enabled-extensions=['top-icons@gnome-shell-extensions.gcampax.github.com', 'background-logo@fedorahosted.org', 'dash-to-panel@jderose9.github.com', 'system-monitor@paradoxxx.zero.gmail.com', 'arcmenu@arcmenu.com', 'gnome-ui-tune@itstime.tech', 'blur-my-shell@aunetx'] + +# Dash to Panel +[org/gnome/shell/extensions/dash-to-panel] + +multi-monitors=true +isolate-monitors=false +isolate-workspaces=true +scroll-panel-action='NOTHING' +dot-style-focused='SEGMENTED' +dot-style-unfocused='DASHES' +dot-color-override=true +dot-color-1='#5294e2' +dot-color-2='#5294e2' +dot-color-3='#5294e2' +dot-color-4='#5294e2' +dot-color-unfocused-different=true +dot-color-unfocused-1='#c0bfbc' +dot-color-unfocused-2='#c0bfbc' +dot-color-unfocused-3='#c0bfbc' +dot-color-unfocused-4='#c0bfbc' +click-action='TOGGLE-SHOWPREVIEW' +hide-overview-on-startup=true +appicon-padding=4 +appicon-margin=1 +panel-sizes='{"0":40,"1":40}' +panel-element-positions='{"0":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}],"1":[{"element":"showAppsButton","visible":false,"position":"stackedTL"},{"element":"activitiesButton","visible":false,"position":"stackedTL"},{"element":"leftBox","visible":true,"position":"stackedTL"},{"element":"taskbar","visible":true,"position":"stackedTL"},{"element":"centerBox","visible":true,"position":"stackedBR"},{"element":"rightBox","visible":true,"position":"stackedBR"},{"element":"dateMenu","visible":true,"position":"stackedBR"},{"element":"systemMenu","visible":true,"position":"stackedBR"},{"element":"desktopButton","visible":true,"position":"stackedBR"}]}' + +# System Monitor +[org/gnome/shell/extensions/system-monitor] + +compact-display=true +center-display=true +net-display=false +swap-display=true +icon-display=false + +# Arc Menu +[org/gnome/shell/extensions/arcmenu] + +multi-monitor=true +menu-button-icon='Distro_Icon' +menu-layout='Redmond' +enable-horizontal-flip=true + +# Gnome 4x UI Improvement +[org/gnome/shell/extensions/gnome-ui-tune] + +hide-search=false diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/COPYING b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/COPYING new file mode 100644 index 0000000..0cf672a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/README.md b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/README.md new file mode 100644 index 0000000..a81ec23 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/README.md @@ -0,0 +1,148 @@ +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_WideBanner.png) + +----- + +![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/ArcMenu_Banner.png) + +----- + +### Introduction + +ArcMenu is an application menu for GNOME Shell, designed to provide a more traditional user experience and workflow. This extension has many features, including multiple menu layout styles, GNOME search, quick access to system shorctus, and more! If you are a new user to GNOME and are looking for a Windows style start menu, this extension will be perfect for you! + +**For ArcMenu to work properly, you may need [these dependencies](https://gitlab.com/arcmenu/ArcMenu/-/wikis/ArcMenu-Dependencies).** + +----- + +### Support ArcMenu + +ArcMenu is provided free of charge. If you enjoy using ArcMenu and wish to help support the project, feel free to use the link below! + +[![Donate via Paypal](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/paypal_donate.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url) + + +----- + +### Installation + +#### To install the most recent official release: Visit ArcMenu on the [Official GNOME Extensions](https://extensions.gnome.org/extension/3628/arcmenu/) website. + +- **To install ArcMenu from source**: Please see the: [Install From Source wiki Guide](https://gitlab.com/arcmenu/ArcMenu/-/wikis/Install-From-Source-Guide). + +

+ + + + +----- + +### Bugs + +Bugs should be reported [here](https://gitlab.com/arcmenu/ArcMenu/issues) on the GitLab issues page. + +When reporting a bug, please provide as much information as you can about the issue and make sure to include your Linux distribution, GNOME Shell version, and ArcMenu version. + +----- + +### Credits: + +**@[AndrewZaech](https://gitlab.com/AndrewZaech) - Current Project Maintainer and Developer** + +**@[AndyC](https://gitlab.com/LinxGem33) - Founder of ArcMenu and former project maintainer** + +**@[lexruee](https://github.com/lexruee) - Former UI/UX Designer | @[Thomas Ingvarsson](https://gitlab.com/tingvarsson) - Former Developer** + +Additional credits: +* The 'ArcMenu' layout design is insipired by the Zorin OS menu extension. +* ArcMenu utilizes various code from GNOME Shell and the GNOME Shell extensions package. +* Borrowed code from Dash-to-Dock's extension 'location.js' file to implement a trash shortcut in ArcMenu. + +----- + +### Contributors: + +#### Thanks to the following people for contributing via pull requests: + +**@[fishears](https://github.com/fishears/Arc-Menu)** | **@[JasonLG1979](https://github.com/JasonLG1979)** | **@[itmitica](https://github.com/itmitica)** | **@[vikaig](https://gitlab.com/vikaig)** | **@[MagneFire](https://gitlab.com/MagneFire)** + +**@[tognee](https://gitlab.com/tognee)** | **@[hlechner](https://gitlab.com/hlechner)** | **@[vanillajonathan](https://gitlab.com/vanillajonathan)** | **@[epskampie](https://gitlab.com/epskampie)** | **@[GnomeBook](https://gitlab.com/GnomeBook)** + +**@[charlesg99](https://github.com/charlesg99)** | **@[harshadgavali](https://gitlab.com/harshadgavali)** | **@[O. Giesmann ](https://gitlab.com/Etamuk)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Bug Fixes: + +**@[JasonLG1979](https://github.com/JasonLG1979)** | **@[lexruee](https://github.com/lexruee/Arc-Menu)** | **@[aleayr ](https://gitlab.com/aleayr)** + + +#### Translators: + +**@[Nilvus](https://gitlab.com/Nilvus) - French** | **@[Etamuk](https://gitlab.com/Etamuk) - German** | **@[alex4401](https://gitlab.com/alex4401) - Polish** | **@[frnogueira](https://gitlab.com/frnogueira), @[Z Bed](https://gitlab.com/zbed) - Brazilian Portuguese** | **@[sigbjokj](https://gitlab.com/sigbjokj), @[sssandum](https://gitlab.com/sssandum) - Norwegian** + + **@[Ivan](https://gitlab.com/vantu5z), @[Ser82-png](https://gitlab.com/Ser82-png) - Russian** | **@[gkkulik](https://gitlab.com/gkkulik) - Silesian** | **@[vikaig](https://gitlab.com/vikaig) - Ukrainian** | **@[jordim](https://gitlab.com/jordim) - Catalan** | **@[aylinux](https://gitlab.com/aylinux) - Turkish** + + +**@[MorganAntonsson](https://gitlab.com/MorganAntonsson) - Swedish** | **@[jiri.doubravsky](https://gitlab.com/jiri.doubravsky), @[panmourovaty ](https://gitlab.com/panmourovaty) - Czech** | **@[juanlucer](https://gitlab.com/juanlucer) - Spanish** | **@[plesry](https://gitlab.com/plesry) - Chinese (Taiwan)** | **@[Vombato](https://gitlab.com/Vombato), @[matguidi](https://gitlab.com/matguidi) - Italian** + +**@[skygmin](https://gitlab.com/skygmin) - Simplified Chinese** | **@[Vistaus](https://gitlab.com/Vistaus), @[vinno97](https://gitlab.com/vinno97) - Dutch** | **@[artnay](https://gitlab.com/artnay) - Finnish** | **@[rimasx](https://gitlab.com/rimasx) - Estonian** | **@[stevendobay](https://gitlab.com/stevendobay) - Hungarian** + +**@[omeritzics](https://gitlab.com/omeritzics) - Hebrew** | **@[prescott66](https://gitlab.com/prescott66) - Slovak** | **@[Mejans](https://gitlab.com/Mejans) - Occitan** | **@[KuroeHanako](https://gitlab.com/KuroeHanako) - Korean** | **@[sayuri](https://gitlab.com/sayuri-) - Sinhalese** + +**@[Latgardi](https://gitlab.com/Latgardi) - Belarusian** + +----- + +### License & Terms + +ArcMenu is available under the terms of the GPL-2.0 license See [`COPYING`](https://gitlab.com/arcmenu/ArcMenu/blob/master/COPYING) for details. + +Most of ArcMenu's image assets including, but not limited to, custom menu button icons, wire frame svgs, and custom settings icons, are created by [LinxGem33](https://gitlab.com/LinxGem33) and licensed under; [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) + +**Legal disclaimer for brand icons and trademarks:** + +*" All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer. "* + +

+Read More... + +

+ +* **UBUNTU ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Ubuntu name and Ubuntu logo is a trademark of Canonical ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Ltd. + +* **FEDORA ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Fedora and the Infinity design logo are trademarks of Red Hat, Inc. + +* **DEBIAN ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project. + +* **MANJARO ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - (logo) and name is a trademark of Manjaro GmbH & Co. KG + +* **POP_OS! ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - Name and (logo) is a trademark of system 76 ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Inc. + +* **ARCH LINUX ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** - The stylized Arch Linux logo are recognised trademarks of Arch Linux, copyright 2002-2017 Judd Vinet and Aaron Griffin + +* **SOLUS** - name and logo is Copyright ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) 2014-2018 by Solus Project + +* **KALI LINUX** - logo and name is part of ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) OffSec Services Limited 2020 + +* **PUREOS** - name and logo is developed by members of the Purism community + +* **RASPBERRY PI** ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) - Logo and name is part of Raspberry Pi Foundation +UK Registered Charity 1129409 + +* **Gentoo Authors![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2001–2020 +Gentoo is a trademark of the Gentoo Foundation, Inc. + +* **Voyager ![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg) Linux** +(name) and (logo) + +* **MXLinux![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** 2020 - +Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries. + +* **Red Hat, Inc.![](https://gitlab.com/arcmenu/arcmenu-assets/raw/master/images/copyright2.svg)** Copyright 2020 +(name) and (logo) + +* **ZORIN OS** - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd + +

+
+ +----- diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/constants.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/constants.js new file mode 100644 index 0000000..082cb4b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/constants.js @@ -0,0 +1,460 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var SearchbarLocation = { + BOTTOM: 0, + TOP: 1 +} + +var MenuItemLocation = { + BOTTOM: 0, + TOP: 1 +} + +var DisplayType = { + LIST: 0, + GRID: 1, + BUTTON: 2, + SIMPLE_CATEGORY: 3, + SUBMENU_CATEGORY: 4, +} + +var CategoryType = { + FAVORITES: 0, + FREQUENT_APPS: 1, + ALL_PROGRAMS: 2, + PINNED_APPS: 3, + RECENT_FILES: 4, + HOME_SCREEN: 5, + SEARCH_RESULTS: 6, + CATEGORIES_LIST: 7, +}; + +var DefaultMenuView = { + PINNED_APPS: 0, + CATEGORIES_LIST: 1, + FREQUENT_APPS: 2, + ALL_PROGRAMS: 3 +} + +var PrefsVisiblePage = { + MAIN: 0, + MENU_LAYOUT: 1, + BUTTON_APPEARANCE: 2, + LAYOUT_TWEAKS: 3, + ABOUT: 4, + CUSTOMIZE_MENU: 5, + RUNNER_TWEAKS: 6 +} + +var DefaultMenuViewTognee = { + CATEGORIES_LIST: 0, + ALL_PROGRAMS: 1 +} + +var SoftwareManagerIDs = ['org.manjaro.pamac.manager.desktop', 'pamac-manager.desktop', 'io.elementary.appcenter.desktop', + 'snap-store_ubuntu-software.desktop', 'snap-store_snap-store.desktop', 'org.gnome.Software.desktop']; + +var Categories = [ + {CATEGORY: CategoryType.FAVORITES, NAME: _("Favorites"), ICON: 'emblem-favorite-symbolic', FULL_COLOR_ICON: 'emblem-favorite'}, + {CATEGORY: CategoryType.FREQUENT_APPS, NAME: _("Frequent Apps"), ICON: 'user-bookmarks-symbolic', FULL_COLOR_ICON: 'user-bookmarks'}, + {CATEGORY: CategoryType.ALL_PROGRAMS, NAME: _("All Apps"), ICON: 'view-grid-symbolic', FULL_COLOR_ICON: 'view-grid-symbolic'}, + {CATEGORY: CategoryType.PINNED_APPS, NAME: _("Pinned Apps"), ICON: 'view-pin-symbolic', FULL_COLOR_ICON: 'view-pin-symbolic'}, + {CATEGORY: CategoryType.RECENT_FILES, NAME: _("Recent Files"), ICON: 'document-open-recent-symbolic', FULL_COLOR_ICON: 'document-open-recent'} +] + +var ArcMenuPlacement = { + PANEL: 0, + DTP: 1, + DASH: 2 +}; + +var TooltipLocation = { + TOP_CENTERED: 0, + BOTTOM_CENTERED: 1, + BOTTOM: 2, +}; + +var SeparatorAlignment = { + VERTICAL: 0, + HORIZONTAL: 1 +}; + +var SeparatorStyle = { + SHORT: 0, + MEDIUM: 1, + LONG: 2, + MAX: 3, + HEADER_LABEL: 4, + NORMAL: 5, + ALWAYS_SHOW: 6, +}; + +var CaretPosition = { + END: -1, + START: 0, + MIDDLE: 2, +}; + +var CategoryIconType = { + FULL_COLOR: 0, + SYMBOLIC: 1, +} + +var ForcedMenuLocation = { + OFF: 0, + TOP_CENTERED: 1, + BOTTOM_CENTERED: 2, +} + +var IconSize = { + DEFAULT: 0, + EXTRA_SMALL: 1, + SMALL: 2, + MEDIUM: 3, + LARGE: 4, + EXTRA_LARGE: 5, +} + +var GridIconSize = { + DEFAULT: 0, + SMALL: 1, + MEDIUM: 2, + LARGE: 3, + SMALL_RECT: 4, + MEDIUM_RECT: 5, + LARGE_RECT: 6, +}; + +var GridIconInfo = [ + { NAME: 'SmallIconGrid', SIZE: 90, ICON_SIZE: 36, ENUM: GridIconSize.SMALL }, + { NAME: 'MediumIconGrid', SIZE: 97, ICON_SIZE: 42, ENUM: GridIconSize.MEDIUM }, + { NAME: "LargeIconGrid", SIZE: 105, ICON_SIZE: 52, ENUM: GridIconSize.LARGE }, + { NAME: 'SmallRectIconGrid', SIZE: 95, ICON_SIZE: 28, ENUM: GridIconSize.SMALL_RECT }, + { NAME: 'MediumRectIconGrid', SIZE: 102, ICON_SIZE: 34, ENUM: GridIconSize.MEDIUM_RECT }, + { NAME: 'LargeRectIconGrid', SIZE: 105, ICON_SIZE: 42, ENUM: GridIconSize.LARGE_RECT }, +] + +var EXTRA_SMALL_ICON_SIZE = 16; +var SMALL_ICON_SIZE = 20; +var MEDIUM_ICON_SIZE = 25; +var LARGE_ICON_SIZE = 30; +var EXTRA_LARGE_ICON_SIZE = 35; +var MISC_ICON_SIZE = 24; + +var SUPER_L = 'Super_L'; +var SUPER_R = 'Super_R'; +var EMPTY_STRING = ''; + +var HotKey = { + UNDEFINED: 0, + SUPER_L: 1, + CUSTOM: 2, + // Inverse mapping + 0: EMPTY_STRING, + 1: SUPER_L, +}; + +var RunnerHotKey = { + SUPER_L: 0, + CUSTOM: 1, + 0: SUPER_L, +}; + +var HotCornerAction = { + DEFAULT: 0, + DISABLED: 1, + TOGGLE_ARCMENU: 2, + CUSTOM: 3 +} + +var SECTIONS = [ + 'devices', + 'network', + 'bookmarks', +]; + +var MenuPosition = { + LEFT: 0, + CENTER: 1, + RIGHT: 2 +}; + +var RavenPosition = { + LEFT: 0, + RIGHT: 1 +}; + +var DiaglogType = { + DEFAULT: 0, + OTHER: 1, + APPLICATIONS: 2, + DIRECTORIES: 3 +}; + +var MenuButtonAppearance = { + ICON: 0, + TEXT: 1, + ICON_TEXT: 2, + TEXT_ICON: 3, + NONE: 4 +}; + +var MenuIcon = { + ARC_MENU: 0, + DISTRO_ICON: 1, + CUSTOM: 2 +}; + +var PowerType = { + LOGOUT: 0, + LOCK: 1, + RESTART: 2, + POWER_OFF: 3, + SUSPEND: 4, + HYBRID_SLEEP: 5, + HIBERNATE: 6, +}; + +var SleepIcon = { + PATH: '/media/icons/menu_icons/sleep-symbolic.svg' +}; + +var PowerOptions = [ + { TYPE: PowerType.LOGOUT, IMAGE: 'application-exit-symbolic', TITLE: _("Log Out") }, + { TYPE: PowerType.LOCK, IMAGE: 'changes-prevent-symbolic', TITLE: _("Lock") }, + { TYPE: PowerType.RESTART, IMAGE: 'system-reboot-symbolic', TITLE: _("Restart") }, + { TYPE: PowerType.POWER_OFF, IMAGE: 'system-shutdown-symbolic', TITLE: _("Power Off") }, + { TYPE: PowerType.SUSPEND, IMAGE: 'media-playback-pause-symbolic', TITLE: _("Suspend") }, + { TYPE: PowerType.HYBRID_SLEEP, IMAGE: Me.path + SleepIcon.PATH, TITLE: _("Hybrid Sleep") }, + { TYPE: PowerType.HIBERNATE, IMAGE: 'document-save-symbolic', TITLE: _("Hibernate") }, +]; + +var MenuIcons = [ + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/curved-a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/focus-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sums-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/arrow-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/lins-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/search-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/transform-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3d-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/alien-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cloud-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/fly-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pacman-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peaks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pie-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pointer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/toxic-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/tree-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/zegon-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/apps-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bug-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/cita-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/eclipse-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/heddy-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/helmet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/palette-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/peeks-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/record-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/saucer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/step-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vancer-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/vibe-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/start-box-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dolphin-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dota-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/football2-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/loveheart-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/rewind-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/snap-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/time-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/3D-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/a-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/bat-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/dra-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/equal-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/gnacs-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/groove-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/kaaet-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/launcher-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/pac-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/robots-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/sheild-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/somnia-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/utool-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/swirl-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/icons/round-symbolic.svg'}, +] + +var DistroIcons = [ + { PATH: 'start-here-symbolic'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg'}, + { PATH: '/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg'}, +] + +var MenuLayout = { + ARCMENU: 0, + BRISK: 1, + WHISKER: 2, + GNOME_MENU: 3, + MINT: 4, + ELEMENTARY: 5, + GNOME_OVERVIEW: 6, + SIMPLE: 7, + SIMPLE_2: 8, + REDMOND: 9, + UNITY: 10, + BUDGIE: 11, + INSIDER: 12, + RUNNER: 13, + CHROMEBOOK: 14, + RAVEN: 15, + TOGNEE: 16, + PLASMA: 17, + WINDOWS: 18, + LAUNCHER: 19, + ELEVEN: 20, + AZ: 21, +}; + +var TraditionalMenus = [ + { IMAGE: 'arcmenu-layout-symbolic', TITLE: _('ArcMenu'), LAYOUT: MenuLayout.ARCMENU}, + { IMAGE: 'brisk-layout-symbolic', TITLE: _('Brisk'), LAYOUT: MenuLayout.BRISK}, + { IMAGE: 'whisker-layout-symbolic', TITLE: _('Whisker'), LAYOUT: MenuLayout.WHISKER}, + { IMAGE: 'gnomemenu-layout-symbolic', TITLE: _('GNOME Menu'), LAYOUT: MenuLayout.GNOME_MENU}, + { IMAGE: 'mint-layout-symbolic', TITLE: _('Mint'), LAYOUT: MenuLayout.MINT}, + { IMAGE: 'budgie-layout-symbolic', TITLE: _('Budgie'), LAYOUT: MenuLayout.BUDGIE}]; + +var ModernMenus = [ + { IMAGE: 'unity-layout-symbolic', TITLE: _('Unity'), LAYOUT: MenuLayout.UNITY}, + { IMAGE: 'plasma-layout-symbolic', TITLE: _('Plasma'), LAYOUT: MenuLayout.PLASMA}, + { IMAGE: 'tognee-layout-symbolic', TITLE: _('tognee'), LAYOUT: MenuLayout.TOGNEE}, + { IMAGE: 'insider-layout-symbolic', TITLE: _('Insider'), LAYOUT: MenuLayout.INSIDER}, + { IMAGE: 'redmond-layout-symbolic', TITLE: _('Redmond'), LAYOUT: MenuLayout.REDMOND}, + { IMAGE: 'windows-layout-symbolic', TITLE: _('Windows'), LAYOUT: MenuLayout.WINDOWS}, + { IMAGE: 'eleven-layout-symbolic', TITLE: _('11'), LAYOUT: MenuLayout.ELEVEN}, + { IMAGE: 'az-layout-symbolic', TITLE: _('a.z.'), LAYOUT: MenuLayout.AZ}]; + +var TouchMenus = [ + { IMAGE: 'elementary-layout-symbolic', TITLE: _('Elementary'), LAYOUT: MenuLayout.ELEMENTARY}, + { IMAGE: 'chromebook-layout-symbolic', TITLE: _('Chromebook'), LAYOUT: MenuLayout.CHROMEBOOK}]; + +var LauncherMenus = [ + { IMAGE: 'launcher-layout-symbolic', TITLE: _('Launcher'), LAYOUT: MenuLayout.LAUNCHER}, + { IMAGE: 'runner-layout-symbolic', TITLE: _('Runner'), LAYOUT: MenuLayout.RUNNER}, + { IMAGE: 'gnomeoverview-layout-symbolic', TITLE: _('GNOME Overview'), LAYOUT: MenuLayout.GNOME_OVERVIEW}]; + +var SimpleMenus = [ + { IMAGE: 'simple-layout-symbolic', TITLE: _('Simple'), LAYOUT: MenuLayout.SIMPLE}, + { IMAGE: 'simple2-layout-symbolic', TITLE: _('Simple 2'), LAYOUT: MenuLayout.SIMPLE_2}]; + +var AlternativeMenus = [ + { IMAGE: 'raven-layout-symbolic', TITLE: _('Raven'), LAYOUT: MenuLayout.RAVEN}]; + +var MenuStyles = { + STYLES: [ + { IMAGE: 'traditional-category-symbolic', TITLE: _("Traditional"), MENU_TYPE: TraditionalMenus }, + { IMAGE: 'modern-category-symbolic', TITLE: _("Modern"), MENU_TYPE: ModernMenus }, + { IMAGE: 'touch-category-symbolic', TITLE: _("Touch"), MENU_TYPE: TouchMenus }, + { IMAGE: 'simple-category-symbolic', TITLE: _("Simple"), MENU_TYPE: SimpleMenus }, + { IMAGE: 'launcher-category-symbolic', TITLE: _("Launcher"), MENU_TYPE: LauncherMenus }, + { IMAGE: 'alternative-category-symbolic', TITLE: _("Alternative"), MENU_TYPE: AlternativeMenus } + ] +}; + +var ArcMenuSettingsCommand = 'gnome-extensions prefs arcmenu@arcmenu.com'; + +var HamburgerIcon = { + PATH: '/media/icons/menu_icons/hamburger-symbolic.svg' +}; + +var DistroIconsDisclaimer = '"All brand icons are trademarks of their respective owners. The use of these trademarks does not indicate endorsement of the trademark holder by ArcMenu project, nor vice versa. Please do not use brand logos for any purpose except to represent the company, product, or service to which they refer."'+ + '\n\n• Ubuntu® - Ubuntu name and Ubuntu logo are trademarks of Canonical© Ltd.'+ + '\n\n• Fedora® - Fedora and the Infinity design logo are trademarks of Red Hat, Inc.'+ + '\n\n• Debian® - is a registered trademark owned by Software in the Public Interest, Inc. Debian trademark is a registered United States trademark of Software in the Public Interest, Inc., managed by the Debian project.'+ + '\n\n• Manjaro® - logo and name are trademarks of Manjaro GmbH & Co. KG'+ + '\n\n• Pop_OS!® - logo and name are trademarks of system 76© Inc.'+ + '\n\n• Arch Linux™ - The stylized Arch Linux logo is a recognized trademark of Arch Linux, copyright 2002–2017 Judd Vinet and Aaron Griffin.'+ + '\n\n• openSUSE® - logo and name 2001–2020 SUSE LLC, © 2005–2020 openSUSE Contributors & others.'+ + '\n\n• Raspberry Pi® - logo and name are part of Raspberry Pi Foundation UK Registered Charity 1129409'+ + '\n\n• Kali Linux™ - logo and name are part of © OffSec Services Limited 2020'+ + '\n\n• PureOS - logo and name are developed by members of the Purism community'+ + '\n\n• Solus - logo and name are copyright © 2014–2018 by Solus Project'+ + '\n\n• Gentoo Authors© - 2001–2020 Gentoo is a trademark of the Gentoo Foundation, Inc.'+ + '\n\n• Voyager© Linux - name and logo'+ + '\n\n• MX Linux© - 2020 - Linux - is the registered trademark of Linus Torvalds in the U.S. and other countries.'+ + '\n\n• Red Hat, Inc.© - Copyright 2020 name and logo' + + '\n\n• ZORIN OS - The "Z" logomark is a registered trademark of Zorin Technology Group Ltd. Copyright © 2019 - 2021 Zorin Technology Group Ltd'; + +var DEVELOPERS = 'Andrew Zaech @AndrewZaech\nLead Project Developer and Maintainer\t' + + '\n\nLinxGem33 aka Andy C @LinxGem33 - (Inactive)\nArcMenu Founder - Former Maintainer - Former Digital Art Designer'; +var TRANSLATORS = 'Thank you to all translators!\n\n' + + 'For a list of all translators please visit ArcMenu on GitLab'; +var CONTRIBUTORS = 'Thank you to all who contributed to, and/or helped, the developement of ArcMenu!' + +'\n\nFor a list of all contributors please visit ArcMenu on GitLab'; +var ARTWORK = 'LinxGem33 aka Andy C\nWiki Screens, Icons, Wire-Frames, ArcMenu Assets' + + '\n\nAndrew Zaech\nIcons, Wire-Frames'; + +var GNU_SOFTWARE = '' + + 'This program comes with absolutely no warranty.\n' + + 'See the ' + + 'GNU General Public License, version 2 or later for details.' + + ''; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/controller.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/controller.js new file mode 100644 index 0000000..7c35a80 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/controller.js @@ -0,0 +1,749 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Gio, GLib, Gtk, St} = imports.gi; +const Constants = Me.imports.constants; +const Helper = Me.imports.helper; +const Main = imports.ui.main; +const MenuButton = Me.imports.menuButton; +const {StandaloneRunner} = Me.imports.standaloneRunner; +const Utils = Me.imports.utils; + +var MenuSettingsController = class { + constructor(settings, settingsControllers, panel, panelIndex, arcMenuPlacement) { + this._settings = settings; + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this.panel = panel; + this.arcMenuPlacement = arcMenuPlacement; + + global.toggleArcMenu = () => this.toggleMenus(); + + this.currentMonitorIndex = 0; + this._activitiesButton = Main.panel.statusArea.activities; + this.isPrimary = panelIndex === 0 ? true : false; + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel); + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) { + this._menuButton = new MenuButton.MenuButton(settings, this.arcMenuPlacement, panel, panelIndex); + this.menuButtonAdjustedActor = this._menuButton.container; + } + + this._settingsControllers = settingsControllers + + if(this.isPrimary){ + this._menuHotKeybinder = new Helper.MenuHotKeybinder(); + this._keybindingManager = new Helper.KeybindingManager(this._settings); + this._hotCornerManager = new Helper.HotCornerManager(this._settings,() => this.toggleMenus()); + } + this._applySettings(); + } + + // Load and apply the settings from the arc-menu settings + _applySettings() { + if(this.isPrimary){ + this._updateHotCornerManager(); + this._updateHotKeyBinder(); + } + + this._setButtonAppearance(); + this._setButtonText(); + this._setButtonIcon(); + this._setButtonIconSize(); + this._setButtonIconPadding(); + this._configureActivitiesButton(); + } + // Bind the callbacks for handling the settings changes to the event signals + bindSettingsChanges() { + this.settingsChangeIds = [ + this._settings.connect('changed::hot-corners', this._updateHotCornerManager.bind(this)), + this._settings.connect('changed::menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::runner-menu-hotkey', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::enable-standlone-runner-menu', this._updateHotKeyBinder.bind(this)), + this._settings.connect('changed::position-in-panel', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-button-position-offset', this._setButtonPosition.bind(this)), + this._settings.connect('changed::menu-position-alignment', this._setMenuPositionAlignment.bind(this)), + this._settings.connect('changed::menu-button-appearance', this._setButtonAppearance.bind(this)), + this._settings.connect('changed::custom-menu-button-text', this._setButtonText.bind(this)), + this._settings.connect('changed::menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::distro-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::arc-menu-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon', this._setButtonIcon.bind(this)), + this._settings.connect('changed::custom-menu-button-icon-size', this._setButtonIconSize.bind(this)), + this._settings.connect('changed::button-padding', this._setButtonIconPadding.bind(this)), + this._settings.connect('changed::enable-menu-button-arrow', this._setMenuButtonArrow.bind(this)), + this._settings.connect('changed::enable-custom-arc-menu', this._updateStyle.bind(this)), + this._settings.connect('changed::remove-menu-arrow', this._updateStyle.bind(this)), + this._settings.connect('changed::disable-searchbox-border', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-color', this._updateStyle.bind(this)), + this._settings.connect('changed::indicator-text-color', this._updateStyle.bind(this)), + this._settings.connect('changed::directory-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::application-shortcuts-list', this._reload.bind(this)), + this._settings.connect('changed::disable-recently-installed-apps', this._initiateRecentlyInstalledApps.bind(this)), + this._settings.connect('changed::extra-categories', this._reload.bind(this)), + this._settings.connect('changed::power-options', this._reload.bind(this)), + this._settings.connect('changed::show-external-devices', this._reload.bind(this)), + this._settings.connect('changed::show-bookmarks', this._reload.bind(this)), + this._settings.connect('changed::disable-user-avatar', this._reload.bind(this)), + this._settings.connect('changed::enable-activities-shortcut', this._reload.bind(this)), + this._settings.connect('changed::enable-horizontal-flip', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-bottom-location', this._reload.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._plasmaMenuReloadTheme.bind(this)), + this._settings.connect('changed::searchbar-default-top-location', this._reload.bind(this)), + this._settings.connect('changed::multi-lined-labels', this._reload.bind(this)), + this._settings.connect('changed::apps-show-extra-details', this._reload.bind(this)), + this._settings.connect('changed::show-search-result-details', this._reload.bind(this)), + this._settings.connect('changed::search-provider-open-windows', this._reload.bind(this)), + this._settings.connect('changed::search-provider-recent-files', this._reload.bind(this)), + this._settings.connect('changed::disable-scrollview-fade-effect', this._reload.bind(this)), + this._settings.connect('changed::menu-height', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::menu-width-adjustment', this._updateMenuHeight.bind(this)), + this._settings.connect('changed::reload-theme', this._reloadTheme.bind(this)), + this._settings.connect('changed::pinned-app-list',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-unity',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-weather-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::enable-clock-widget-raven',this._updatePinnedApps.bind(this)), + this._settings.connect('changed::brisk-shortcuts-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::mint-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-pinned-app-list',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::unity-separator-index',this._updateExtraPinnedApps.bind(this)), + this._settings.connect('changed::windows-disable-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::windows-disable-pinned-apps', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view', this._reload.bind(this)), + this._settings.connect('changed::default-menu-view-tognee',this._reload.bind(this)), + this._settings.connect('changed::alphabetize-all-programs',this._reload.bind(this)), + this._settings.connect('changed::enable-unity-homescreen',this._setDefaultMenuView.bind(this)), + this._settings.connect('changed::menu-layout', this._updateMenuLayout.bind(this)), + this._settings.connect('changed::menu-item-grid-icon-size', this._reload.bind(this)), + this._settings.connect('changed::menu-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::button-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::quicklinks-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::misc-item-icon-size', this._reload.bind(this)), + this._settings.connect('changed::runner-position', this.updateLocation.bind(this)), + this._settings.connect('changed::runner-show-frequent-apps', this._reload.bind(this)), + this._settings.connect('changed::enable-sub-menus', this._reload.bind(this)), + this._settings.connect('changed::show-activities-button', this._configureActivitiesButton.bind(this)), + this._settings.connect('changed::force-menu-location', this._forceMenuLocation.bind(this)), + this._settings.connect('changed::category-icon-type', this._reload.bind(this)), + this._settings.connect('changed::shortcut-icon-type', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links', this._reload.bind(this)), + this._settings.connect('changed::arcmenu-extra-categories-links-location', this._reload.bind(this)), + ]; + } + + _reload(){ + this._menuButton.reload(); + if(this.runnerMenu) + this.runnerMenu.reload(); + } + + _forceMenuLocation(){ + this._menuButton.forceMenuLocation(); + } + + _initiateRecentlyInstalledApps(){ + this._menuButton.initiateRecentlyInstalledApps(); + this._menuButton.reload(); + if(this.runnerMenu){ + this.runnerMenu.initiateRecentlyInstalledApps(); + this.runnerMenu.reload(); + } + } + + _plasmaMenuReloadTheme(){ + if(this._settings.get_enum('menu-layout') === Constants.MenuLayout.PLASMA){ + if(this._settings.get_boolean('reload-theme')) + this._settings.reset('reload-theme'); + this._settings.set_boolean('reload-theme', true); + } + } + + updateLocation(){ + this._menuButton.updateLocation(); + if(this.runnerMenu) + this.runnerMenu.updateLocation(); + } + + _updateMenuLayout(){ + this._menuButton.updateMenuLayout(); + } + + _setDefaultMenuView(){ + this._menuButton.setDefaultMenuView(); + } + + toggleStandaloneRunner(){ + this._closeAllArcMenus(); + if(this.runnerMenu) + this.runnerMenu.toggleMenu(); + } + + toggleMenus(){ + if(this.runnerMenu && this.runnerMenu.arcMenu.isOpen) + this.runnerMenu.toggleMenu(); + if(global.dashToPanel || this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + const MultipleArcMenus = this._settingsControllers.length > 1; + const ShowArcMenuOnPrimaryMonitor = this._settings.get_boolean('hotkey-open-primary-monitor'); + if(MultipleArcMenus && ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.primaryMonitor); + else if(MultipleArcMenus && !ShowArcMenuOnPrimaryMonitor) + this._toggleMenuOnMonitor(Main.layoutManager.currentMonitor); + else + this._menuButton.toggleMenu(); + } + else + this._menuButton.toggleMenu(); + } + + _toggleMenuOnMonitor(monitor){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + let monitorIndex = this._settingsControllers[i].monitorIndex; + if(monitor.index === monitorIndex) + this.currentMonitorIndex = i; + else{ + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + //open the current monitors menu + this._settingsControllers[this.currentMonitorIndex]._menuButton.toggleMenu(); + } + + _closeAllArcMenus(){ + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + if(menuButton.arcMenu.isOpen) + menuButton.toggleMenu(); + if(menuButton.arcMenuContextMenu.isOpen) + menuButton.toggleArcMenuContextMenu(); + } + } + + _reloadTheme(){ + if(this.isPrimary && this._settings.get_boolean('reload-theme')) { + this._settings.reset('reload-theme'); + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(this._settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + for (let i = 0; i < this._settingsControllers.length; i++) { + let menuButton = this._settingsControllers[i]._menuButton; + menuButton.updateStyle(); + } + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + } + + _updateStyle() { + this._menuButton.updateStyle(); + if(this.runnerMenu) + this.runnerMenu.updateStyle(); + } + + _updateMenuHeight(){ + this._menuButton.updateHeight(); + } + + _updatePinnedApps(){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadPinnedApps(); + + //If the active category is Pinned Apps, redisplay the new Pinned Apps + const activeCategory = this._menuButton.MenuLayout?.activeCategoryType; + if(!activeCategory) + return; + if(activeCategory === Constants.CategoryType.PINNED_APPS || activeCategory === Constants.CategoryType.HOME_SCREEN) + this._menuButton.displayPinnedApps(); + } + + _updateExtraPinnedApps(){ + let layout = this._settings.get_enum('menu-layout'); + if(layout == Constants.MenuLayout.UNITY || layout == Constants.MenuLayout.MINT || layout == Constants.MenuLayout.BRISK){ + if(this._menuButton.shouldLoadPinnedApps()) + this._menuButton.loadExtraPinnedApps(); + } + } + + _updateHotCornerManager() { + if (this.isPrimary) { + let hotCornerAction = this._settings.get_enum('hot-corners'); + if (hotCornerAction === Constants.HotCornerAction.DEFAULT) { + this._hotCornerManager.restoreDefaultHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.DISABLED) { + this._hotCornerManager.disableHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU) { + this._hotCornerManager.modifyHotCorners(); + } + else if(hotCornerAction === Constants.HotCornerAction.CUSTOM) { + this._hotCornerManager.modifyHotCorners(); + } + } + } + + _updateHotKeyBinder() { + if (this.isPrimary) { + const RunnerHotKey = this._settings.get_enum('runner-menu-hotkey'); + const HotKey = this._settings.get_enum('menu-hotkey'); + const EnableStandaloneRunnerMenu = this._settings.get_boolean('enable-standlone-runner-menu'); + + this._keybindingManager.unbind('ToggleArcMenu'); + this._keybindingManager.unbind('ToggleRunnerMenu'); + this._menuHotKeybinder.disableHotKey(); + this._menuKeyBindingKey = null; + this._runnerKeyBindingKey = null; + + if(EnableStandaloneRunnerMenu){ + if(!this.runnerMenu){ + this.runnerMenu = new StandaloneRunner(this._settings); + this.runnerMenu.initiate(); + } + + if(RunnerHotKey === Constants.RunnerHotKey.CUSTOM){ + this._keybindingManager.bind('ToggleRunnerMenu', 'toggle-runner-menu', () => this._onHotkey(() => this.toggleStandaloneRunner())); + this._runnerKeyBindingKey = this._settings.get_strv('toggle-runner-menu').toString(); + } + else if(RunnerHotKey === Constants.RunnerHotKey.SUPER_L){ + this._menuHotKeybinder.enableHotKey(() => this.toggleStandaloneRunner()); + } + } + else if(this.runnerMenu){ + this.runnerMenu.destroy(); + this.runnerMenu = null; + } + + if(HotKey === Constants.HotKey.CUSTOM){ + this._keybindingManager.bind('ToggleArcMenu', 'toggle-arcmenu', () => this._onHotkey(() => this.toggleMenus())); + this._menuKeyBindingKey = this._settings.get_strv('toggle-arcmenu').toString(); + } + else if(HotKey === Constants.HotKey.SUPER_L){ + this._menuHotKeybinder.disableHotKey(); + this._menuHotKeybinder.enableHotKey(() => this.toggleMenus()); + } + + if(this._menuKeyBindingKey){ + this._menuKeyBindingKey = Gtk.accelerator_parse(this._menuKeyBindingKey)[0]; + } + if(this._runnerKeyBindingKey){ + this._runnerKeyBindingKey = Gtk.accelerator_parse(this._runnerKeyBindingKey)[0]; + } + } + } + + _onHotkey(callback) { + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + callback(); + else + this._onHotkeyRelease(callback); + } + + _onHotkeyRelease(callback) { + let activeMenu = this._settingsControllers[this.currentMonitorIndex]._menuButton.getActiveMenu() || ((this.runnerMenu && this.runnerMenu.arcMenu.isOpen) ? this.runnerMenu.arcMenu : null); + let focusPanel; + + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL) + focusPanel = this.panel; + else + focusPanel = this.panel._allDocks[0].dash; + + let focusTarget = activeMenu ? + (activeMenu.actor || activeMenu) : focusPanel; + + this.disconnectKeyRelease(); + + this.keyInfo = { + pressId: focusTarget.connect('key-press-event', () => this.disconnectKeyRelease()), + releaseId: focusTarget.connect('key-release-event', (actor, event) => { + this.disconnectKeyRelease(); + + if (this._menuKeyBindingKey === event.get_key_symbol()) { + callback(); + } + + if (this._runnerKeyBindingKey === event.get_key_symbol()) { + callback(); + } + }), + target: focusTarget + }; + + focusTarget.grab_key_focus(); + } + + disconnectKeyRelease() { + if (this.keyInfo && this.keyInfo.target) { + this.keyInfo.target.disconnect(this.keyInfo.pressId); + this.keyInfo.target.disconnect(this.keyInfo.releaseId); + this.keyInfo = 0; + } + } + + // Place the menu button to main panel as specified in the settings + _setButtonPosition() { + if (this._isButtonEnabled()) { + this._removeMenuButtonFromMainPanel(); + this._addMenuButtonToMainPanel(); + this._setMenuPositionAlignment(); + } + } + + _setMenuPositionAlignment(){ + this._menuButton.setMenuPositionAlignment(); + } + + // Change the menu button appearance as specified in the settings + _setButtonAppearance() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + this._menuButton.container.set_width(-1); + this._menuButton.container.set_height(-1); + menuButtonWidget.actor.show(); + switch (this._settings.get_enum('menu-button-appearance')) { + case Constants.MenuButtonAppearance.TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.showPanelText(); + break; + case Constants.MenuButtonAppearance.ICON_TEXT: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-left: 5px;'); + break; + case Constants.MenuButtonAppearance.TEXT_ICON: + menuButtonWidget.hidePanelIcon(); + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelText(); + menuButtonWidget.setPanelTextStyle('padding-right: 5px;'); + menuButtonWidget.showPanelIcon(); + break; + case Constants.MenuButtonAppearance.NONE: + menuButtonWidget.actor.hide(); + this._menuButton.container.set_width(0); + this._menuButton.container.set_height(0); + break; + case Constants.MenuButtonAppearance.ICON: /* falls through */ + default: + menuButtonWidget.hidePanelText(); + menuButtonWidget.showPanelIcon(); + } + this._setMenuButtonArrow(); + } + } + _setMenuButtonArrow() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + if (this._settings.get_boolean('enable-menu-button-arrow')) { + menuButtonWidget.hideArrowIcon(); + menuButtonWidget.showArrowIcon(); + } else { + menuButtonWidget.hideArrowIcon(); + } + } + } + + // Update the text of the menu button as specified in the settings + _setButtonText() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + // Update the text of the menu button + let menuButtonWidget = this._menuButton.menuButtonWidget; + let label = menuButtonWidget.getPanelLabel(); + + let customTextLabel = this._settings.get_string('custom-menu-button-text'); + label.set_text(customTextLabel); + } + } + + // Update the icon of the menu button as specified in the settings + _setButtonIcon() { + let path = this._settings.get_string('custom-menu-button-icon'); + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + + let iconString = Utils.getMenuButtonIcon(this._settings, path); + stIcon.set_gicon(Gio.icon_new_for_string(iconString)); + } + + // Update the icon of the menu button as specified in the settings + _setButtonIconSize() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let menuButtonWidget = this._menuButton.menuButtonWidget; + let stIcon = menuButtonWidget.getPanelIcon(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let size = iconSize; + stIcon.icon_size = size; + } + } + + _setButtonIconPadding() { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + let padding = this._settings.get_int('button-padding'); + if(padding > -1) + this._menuButton.style = "-natural-hpadding: " + (padding * 2 ) + "px; -minimum-hpadding: " + padding + "px;"; + else + this._menuButton.style = null; + + let parent = this._menuButton.get_parent(); + if(!parent) + return; + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(this._menuButton); + } + + parent.remove_child(this._menuButton); + parent.insert_child_at_index(this._menuButton, actorIndex); + } + } + + // Get the current position of the menu button and its associated position order + _getMenuPosition() { + let offset = this._settings.get_int('menu-button-position-offset'); + switch (this._settings.get_enum('position-in-panel')) { + case Constants.MenuPosition.CENTER: + return [offset, 'center']; + case Constants.MenuPosition.RIGHT: + // get number of childrens in rightBox (without arcmenu) + let n_children = Main.panel._rightBox.get_n_children(); + n_children -= Main.panel.statusArea.ArcMenu !== undefined; + // position where icon should go, + // offset = 0, icon should be last + // offset = 1, icon should be second last + const order = Math.clamp(n_children - offset, 0, n_children); + return [order, 'right']; + case Constants.MenuPosition.LEFT: + default: + return [offset, 'left']; + } + } + + _configureActivitiesButton(){ + let isActivitiesButtonPresent = Main.panel.statusArea.activities && Main.panel.statusArea.activities.container && Main.panel._leftBox.contains(Main.panel.statusArea.activities.container); + let showActivities = this._settings.get_boolean('show-activities-button'); + + let container = Main.panel.statusArea.activities.container; + let parent = container.get_parent(); + let index = 0; + if(this._settings.get_enum('position-in-panel') === Constants.MenuPosition.LEFT && + this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && + this._settings.get_int('menu-button-position-offset') == 0) + index = 1; + + if(showActivities && !isActivitiesButtonPresent){ + parent ? parent.remove_child(container) : null; + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, index); + } + else if(!showActivities && isActivitiesButtonPresent) + Main.panel._leftBox.remove_child(Main.panel.statusArea.activities.container); + } + + // Check if the activities button is present on the main panel + _isActivitiesButtonPresent() { + return (this._activitiesButton && + this._activitiesButton.container && + Main.panel._leftBox.contains(this._activitiesButton.container)); + } + + // Add or restore the activities button on the main panel + _addActivitiesButtonToMainPanel() { + if (!this._isActivitiesButtonPresent()) { + // Retsore the activities button at the default position + let parent = this._activitiesButton.container.get_parent(); + if(!parent) + Main.panel._leftBox.insert_child_at_index(this._activitiesButton.container, 0); + } + } + + // Add the menu button to the main panel + _addMenuButtonToMainPanel() { + let [position, box] = this._getMenuPosition(); + this.panel.addToStatusArea('ArcMenu', this._menuButton, position, box); + } + + // Remove the menu button from the main panel + _removeMenuButtonFromMainPanel() { + this.panel.menuManager.removeMenu(this._menuButton.arcMenu); + this.panel.menuManager.removeMenu(this._menuButton.arcMenuContextMenu); + this.panel.statusArea['ArcMenu'] = null; + } + + // Enable the menu button + enableButton(index) { + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.DASH){ + this.dashIndex = index; + this.reEstablishDash(); + } + if(this.arcMenuPlacement == Constants.ArcMenuPlacement.PANEL){ + this._addMenuButtonToMainPanel(); + } + + this._menuButton.initiate(); + } + + reEstablishDash(){ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + if(!DashToDock){ + global.log("ArcMenu Error - Failed to place ArcMenu in Dash-to-Dock"); + return; + } + + const DashContainer = DashToDock._dashContainer; + + DashToDock.arcMenuEnabled = true; + this.oldShowAppsIcon = DashToDock._showAppsIcon; + + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.menuButtonAdjustedActor; + DashContainer.add_child(DashToDock._showAppsIcon); + + this._setButtonIcon(); + const IconSize = DashToDock.iconSize; + this._menuButton.menuButtonWidget.icon.setIconSize(IconSize); + + DashToDock.updateShowAppsButton(); + + this.hoverID = this.menuButtonAdjustedActor.child.connect('notify::hover', () => { + DashToDock._syncLabel(this.menuButtonAdjustedActor, null); + }); + + this.hidingID = Main.overview.connect('hiding', () => { + DashToDock._labelShowing = false; + this.menuButtonAdjustedActor.hideLabel(); + }); + + if(this.isPrimary){ + this.oldDashOnDestroy = this.panel._deleteDocks; + this.panel._deleteDocks = () => { + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + const AllDocks = this.panel._allDocks; + + if(!AllDocks.length) + return; + + AllDocks.forEach(dock => { + let dash = dock.dash; + if(dash._dashContainer.contains(dash._showAppsIcon)) + dash._dashContainer.remove_child(dash._showAppsIcon); + dash._showAppsIcon = this.oldShowAppsIcon; + dash._dashContainer.add_child(dash._showAppsIcon); + dash.arcMenuEnabled = false; + }); + + this.oldDashOnDestroy.call(this.panel, ...arguments); + this.panel._deleteDocks = this.oldDashOnDestroy; + }; + } + } + + _disableButton() { + this._removeMenuButtonFromMainPanel(); + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + + _isButtonEnabled() { + return this.panel.statusArea['ArcMenu'] !== null; + } + + destroy() { + if(this.runnerMenu){ + this.runnerMenu.destroy(); + } + this.settingsChangeIds.forEach(id => this._settings.disconnect(id)); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.panel === null || this.panel._allDocks.length === 0){ + this._menuButton.destroy(); + } + else{ + const DashToDock = this.panel._allDocks[this.dashIndex].dash; + const DashContainer = DashToDock._dashContainer; + if(this.panel._allDocks[this.dashIndex] && DashToDock && DashToDock.arcMenuEnabled){ + if(this.hoverID){ + this.menuButtonAdjustedActor.child.disconnect(this.hoverID); + this.hoverID = null; + } + + if(this.hidingID){ + Main.overview.disconnect(this.hidingID); + this.hidingID = null; + } + + if(this.panel._allDocks[this.dashIndex]){ + DashToDock.arcMenuEnabled = false; + if(DashContainer.contains(DashToDock._showAppsIcon)) + DashContainer.remove_child(DashToDock._showAppsIcon); + DashToDock._showAppsIcon = this.oldShowAppsIcon; + DashContainer.add_child(DashToDock._showAppsIcon); + this.panel._deleteDocks = this.oldDashOnDestroy; + DashToDock.updateShowAppsButton(); + } + } + this._addActivitiesButtonToMainPanel(); + this._menuButton.destroy(); + } + } + else if(this.panel == undefined) + this._menuButton.destroy(); + else if (this._isButtonEnabled()) { + this._disableButton(); + } + + if(this.isPrimary){ + this.disconnectKeyRelease(); + this._menuHotKeybinder.destroy(); + this._keybindingManager.destroy(); + this._hotCornerManager.destroy(); + } + this._settings = null; + this._activitiesButton = null; + this._menuButton = null; + delete global.toggleArcMenu; + } +}; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/extension.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/extension.js new file mode 100644 index 0000000..d101a31 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/extension.js @@ -0,0 +1,307 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {GLib, Gio, St} = imports.gi; +const Constants = Me.imports.constants; +const Controller = Me.imports.controller; +const Config = imports.misc.config; +const ShellVersion = parseFloat(Config.PACKAGE_VERSION); + +const Main = imports.ui.main; +const Util = imports.misc.util; +const Utils = Me.imports.utils; + +// Initialize panel button variables +let settings; +let settingsControllers; +let extensionChangedId; +let dockToggleID; +let dockExtension; +let enableTimeoutID; + +// Initialize menu language translations +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +// Enable the extension +function enable() { + if (ShellVersion < 3.39 && ShellVersion >= 3.36) + throw new Error(`ArcMenu v${Me.metadata.version} does not work on GNOME Shell version ${ShellVersion}. Please visit https://extensions.gnome.org/extension/3628/arcmenu/ and download ArcMenu v17`); + else if (ShellVersion < 3.36) + throw new Error(`GNOME Shell version ${ShellVersion} is not supported. Please visit https://extensions.gnome.org/extension/1228/arc-menu/ which supports GNOME Shell versions 3.14 - 3.34`); + + enableTimeoutID = GLib.timeout_add(0, 300, () => { + if(imports.gi.Meta.is_wayland_compositor()) + Me.metadata.isWayland = true; + else + Me.metadata.isWayland = false; + + settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + settings.connect('changed::multi-monitor', () => _multiMonitorChanged()); + settings.connect('changed::arc-menu-placement', () => _placementChanged()); + settingsControllers = []; + + let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); + Utils.createStylesheet(settings); + let stylesheet = Utils.getStylesheet(); + if(Me.stylesheet) + theme.unload_stylesheet(Me.stylesheet); + Me.stylesheet = stylesheet; + theme.load_stylesheet(Me.stylesheet); + + let avaliablePlacementArray = settings.get_default_value('available-placement').deep_unpack(); + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + + _enableButtons(); + + // dash to panel might get enabled after Arc-Menu + extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === 'dash-to-panel@jderose9.github.com') { + _disconnectDtpSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + setAvaliablePlacement(Constants.ArcMenuPlacement.DTP, isEnabled); + + if(isEnabled && (arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP)){ + _connectDtpSignals(); + _enableButtons(); + } + } + + if ((extension.uuid === "dash-to-dock@micxgx.gmail.com" || extension.uuid === "ubuntu-dock@ubuntu.com")) { + _disconnectDtdSignals(); + + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + let isEnabled = extension.state === 1 ? true : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!_getDockExtensions() || !isEnabled) + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, false); + else{ + _connectDtdSignals(); + setAvaliablePlacement(Constants.ArcMenuPlacement.DASH, true); + } + _disableButtons(); + _enableButtons(); + } + } + }); + + // listen to dash to panel / dash to dock if they are compatible and already enabled + _connectDtdSignals(); + _connectDtpSignals(); + enableTimeoutID = null; + return GLib.SOURCE_REMOVE; + }); +} + +function disable() { + if(enableTimeoutID){ + GLib.source_remove(enableTimeoutID); + enableTimeoutID = null; + } + if(extensionChangedId){ + Main.extensionManager.disconnect(extensionChangedId); + extensionChangedId = null; + } + + _disconnectDtpSignals(); + _disconnectDtdSignals(); + + _disableButtons(); + settingsControllers = null; + + settings.run_dispose(); + settings = null; +} + +function setAvaliablePlacement(placement, state){ + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + if(avaliablePlacementArray[placement] !== state){ + avaliablePlacementArray[placement] = state; + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); + } +} + +function _connectDtpSignals() { + if(global.dashToPanel) + global.dashToPanel._amPanelsCreatedId = global.dashToPanel.connect('panels-created', () => _enableButtons()); +} + +function _disconnectDtpSignals() { + if(global.dashToPanel?._amPanelsCreatedId){ + global.dashToPanel.disconnect(global.dashToPanel._amPanelsCreatedId); + delete global.dashToPanel._amPanelsCreatedId; + } +} + +function _connectDtdSignals(){ + dockExtension = _getDockExtensions(); + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + dockToggleID = dock.connect("toggled",() => { + _disableButtons(); + _enableButtons(); + }); + } +} + +function _disconnectDtdSignals() { + if(dockExtension){ + let dock = dockExtension.stateObj.dockManager; + if(dock && dockToggleID){ + dock.disconnect(dockToggleID); + dockToggleID = null; + } + } +} + +function _placementChanged() { + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + _disconnectDtdSignals(); + _disconnectDtpSignals(); + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + _connectDtpSignals(); + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + _connectDtdSignals(); + + _disableButtons(); + _enableButtons(); +} + +function _multiMonitorChanged() { + _disableButtons(); + _enableButtons(); +} + +function _getDockExtensions(){ + let dashToDock = Main.extensionManager.lookup("dash-to-dock@micxgx.gmail.com"); + let ubuntuDash = Main.extensionManager.lookup("ubuntu-dock@ubuntu.com"); + let dock; + if(dashToDock?.stateObj?.dockManager) + dock = dashToDock; + if(ubuntuDash?.stateObj?.dockManager) + dock = ubuntuDash; + return dock; +} + +function _enableButtons() { + let avaliablePlacementArray = settings.get_value('available-placement').deep_unpack(); + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = false; + + let multiMonitor = settings.get_boolean('multi-monitor'); + let arcMenuPlacement = settings.get_enum('arc-menu-placement'); + + dockExtension = _getDockExtensions(); + + if(arcMenuPlacement == Constants.ArcMenuPlacement.DASH && dockExtension){ + avaliablePlacementArray[Constants.ArcMenuPlacement.DASH] = true; + + let dock = dockExtension.stateObj.dockManager; + if(dock?._allDocks.length){ + let docksLength = multiMonitor ? dock._allDocks.length : 1; + for(var index = 0; index < docksLength; index++){ + if(!dock._allDocks[index].dash.arcMenuEnabled){ + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, dock, + index, Constants.ArcMenuPlacement.DASH); + settingsController.monitorIndex = dock._allDocks[index].dash._monitorIndex; + settingsController.enableButton(index); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + } + } + else{ + let isDtPLoaded = false; + let panelArray = [Main.panel]; + if(global.dashToPanel && global.dashToPanel.panels){ + panelArray = global.dashToPanel.panels.map(pw => pw); + isDtPLoaded = true; + } + + let panelLength = multiMonitor ? panelArray.length : 1; + for(var index = 0; index < panelLength; index++){ + let panel = isDtPLoaded ? panelArray[index].panel : panelArray[index]; + let panelParent = panelArray[index]; + + let isPrimaryStandAlone = isDtPLoaded ? ('isPrimary' in panelParent && panelParent.isPrimary) && panelParent.isStandalone : false; + + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL && isPrimaryStandAlone){ + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + panel = Main.panel; + } + + if(isDtPLoaded) + avaliablePlacementArray[Constants.ArcMenuPlacement.DTP] = true; + else + avaliablePlacementArray[Constants.ArcMenuPlacement.PANEL] = true; + + if (panel.statusArea['ArcMenu']) + continue; + else if (settingsControllers[index]) + _disableButton(settingsControllers[index], 1); + + let settingsController = new Controller.MenuSettingsController(settings, settingsControllers, panel, + index, Constants.ArcMenuPlacement.PANEL); + + settingsController.monitorIndex = panelParent.monitor?.index; + + if(isDtPLoaded) + panel._amDestroyId = panel.connect('destroy', () => extensionChangedId ? _disableButton(settingsController, 1) : null); + + settingsController.enableButton(); + settingsController.bindSettingsChanges(); + settingsControllers.push(settingsController); + } + } + + if(!Utils.getArraysEqual(settings.get_value('available-placement').deep_unpack(), avaliablePlacementArray)) + settings.set_value('available-placement', new GLib.Variant('ab', avaliablePlacementArray)); +} + +function _disableButtons(){ + for (let i = settingsControllers.length - 1; i >= 0; --i) { + let sc = settingsControllers[i]; + _disableButton(sc, 1); + } +} + +function _disableButton(controller, remove) { + if(controller.panel._amDestroyId){ + controller.panel.disconnect(controller.panel._amDestroyId); + delete controller.panel._amDestroyId; + } + + controller.destroy(); + + if(remove) + settingsControllers.splice(settingsControllers.indexOf(controller), 1); +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/helper.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/helper.js new file mode 100644 index 0000000..9dbc4d2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/helper.js @@ -0,0 +1,227 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gio, GObject, Gtk, Meta, Shell} = imports.gi; +const Constants = Me.imports.constants; +const Main = imports.ui.main; +const Util = imports.misc.util; + +const MUTTER_SCHEMA = 'org.gnome.mutter'; + +var MenuHotKeybinder = class { + constructor() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + + this._mutterSettings = new Gio.Settings({ 'schema': MUTTER_SCHEMA }); + + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + + this._overlayKeyChangedID = this._mutterSettings.connect('changed::overlay-key', () => { + if(!this._ignoreHotKeyChangedEvent) + this._oldOverlayKey = this._mutterSettings.get_value('overlay-key'); + }); + + this._mainStartUpComplete = Main.layoutManager.connect('startup-complete', () => this._setHotKey()); + } + + enableHotKey(menuToggler){ + this._menuToggler = menuToggler; + + this._ignoreHotKeyChangedEvent = true; + + this._mutterSettings.set_string('overlay-key', Constants.SUPER_L); + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + this.hotKeyEnabled = true; + if(!Main.layoutManager._startingUp) + this._setHotKey(); + this._ignoreHotKeyChangedEvent = false; + } + + disableHotKey(){ + this._ignoreHotKeyChangedEvent = true; + this._mutterSettings.set_value('overlay-key', this._oldOverlayKey); + if(this.overlayKeyID){ + global.display.disconnect(this.overlayKeyID); + this.overlayKeyID = null; + } + if(this.defaultOverlayKeyID){ + GObject.signal_handler_unblock(global.display, this.defaultOverlayKeyID); + this.defaultOverlayKeyID = null; + } + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); + + this.hotKeyEnabled = false; + this._ignoreHotKeyChangedEvent = false; + } + + _setHotKey(){ + if(this.hotKeyEnabled){ + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.NORMAL | + Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP); + + //Find signal ID in Main.js that connects 'overlay-key' to global.display and toggles Main.overview + let [bool,signal_id, detail] = GObject.signal_parse_name('overlay-key', global.display, true); + this.defaultOverlayKeyID = GObject.signal_handler_find(global.display, GObject.SignalMatchType.ID, signal_id, detail, null, null, null); + + //If signal ID found, block it and connect new 'overlay-key' to toggle ArcMenu. + if(this.defaultOverlayKeyID){ + GObject.signal_handler_block(global.display, this.defaultOverlayKeyID); + this.overlayKeyID = global.display.connect('overlay-key', () => { + this._menuToggler(); + }); + } + else + global.log("ArcMenu Error - Failed to set Super_L hotkey"); + } + } + + destroy() { + if(this._overlayKeyChangedID){ + this._mutterSettings.disconnect(this._overlayKeyChangedID); + this._overlayKeyChangedID = null; + } + this.disableHotKey(); + if (this._mainStartUpComplete) { + Main.layoutManager.disconnect(this._mainStartUpComplete); + this._mainStartUpComplete = null; + } + } +}; + +var KeybindingManager = class { + constructor(settings) { + this._settings = settings; + this._keybindings = new Map(); + } + + bind(keybindingNameKey, keybindingValueKey, keybindingHandler) { + if (!this._keybindings.has(keybindingNameKey)) { + this._keybindings.set(keybindingNameKey, keybindingValueKey); + + Main.wm.addKeybinding(keybindingValueKey, ExtensionUtils.getSettings(), + Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW | Shell.ActionMode.POPUP, + keybindingHandler); + } + } + + unbind(keybindingNameKey) { + if (this._keybindings.has(keybindingNameKey)) { + let keybindingValueKey = this._keybindings.get(keybindingNameKey); + Main.wm.removeKeybinding(keybindingValueKey); + this._keybindings.delete(keybindingNameKey); + } + } + + unbindAll() { + this._keybindings.forEach((value, key) => { + Main.wm.removeKeybinding(value); + this._keybindings.delete(key); + }); + } + + destroy() { + this.unbindAll(); + } +}; + +var HotCornerManager = class { + constructor(settings, menuToggler) { + this._settings = settings; + this._menuToggler = menuToggler; + this._hotCornersChangedId = Main.layoutManager.connect('hot-corners-changed', () => this._setCustomHotCorners()); + } + + _setCustomHotCorners() { + let hotCornerAction = this._settings.get_enum('hot-corners'); + + if(hotCornerAction === Constants.HotCornerAction.DISABLED) + this.disableHotCorners(); + else if(hotCornerAction === Constants.HotCornerAction.TOGGLE_ARCMENU || hotCornerAction === Constants.HotCornerAction.CUSTOM) + this.modifyHotCorners(); + } + + _getHotCorners() { + return Main.layoutManager.hotCorners; + } + + restoreDefaultHotCorners() { + Main.layoutManager._updateHotCorners(); + } + + disableHotCorners() { + let hotCorners = this._getHotCorners(); + hotCorners.forEach((corner) => { + if(corner){ + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { }; + } + }); + } + + modifyHotCorners() { + let hotCorners = this._getHotCorners(); + let hotCornerAction = this._settings.get_enum('hot-corners'); + + hotCorners.forEach((corner) => { + if (corner) { + corner._toggleOverview = () => { }; + corner._pressureBarrier._trigger = () => { + corner._pressureBarrier._isTriggered = true; + if(corner._ripples) + corner._ripples.playAnimation(corner._x, corner._y); + else + corner._rippleAnimation(); + if(hotCornerAction == Constants.HotCornerAction.TOGGLE_ARCMENU) + this._menuToggler(); + else if(hotCornerAction == Constants.HotCornerAction.CUSTOM){ + let cmd = this._settings.get_string('custom-hot-corner-cmd'); + if(cmd == "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(cmd == "ArcMenu_RunCommand") + Main.openRunDialog(); + else + Util.spawnCommandLine(this._settings.get_string('custom-hot-corner-cmd')); + } + corner._pressureBarrier._reset(); + }; + } + }); + } + + destroy() { + if (this._hotCornersChangedId>0) { + Main.layoutManager.disconnect(this._hotCornersChangedId); + this._hotCornersChangedId = 0; + } + + this.restoreDefaultHotCorners(); + } +}; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f06173f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ar/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..11c483b Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/be/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9cb7eaf Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/bg/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..dd97be3 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ca/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..178df95 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/cs/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7018c94 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/de/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..c08d48e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/el/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..99db3f1 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/es/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..b9d0c76 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/et/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0d4495f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fi/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..6158e6b Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/fr/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ee7d15e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/he/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..7b2cd8b Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hi_IN/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..04eb49e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/hu/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..25f1be6 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/id/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..0f4968c Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/it/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..77836ed Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ja/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9c35974 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ko/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..49572c0 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nb_NO/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..95fa04f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/nl/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8a9f45d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/oc/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef7005a Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pl/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..eb02f6c Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/pt_BR/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..8b0241e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/ru/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..22605ab Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/si/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..151addf Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sk/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9f4b060 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..defd162 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sr@latin/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..f048587 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/sv/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ac057e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/szl/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..9dc0b4d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/tr/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..ef34524 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/uk/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..3ce757e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_CN/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo new file mode 100644 index 0000000..68ad6a2 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/locale/zh_TW/LC_MESSAGES/arcmenu.mo differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/.keep b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/.keep new file mode 100644 index 0000000..e69de29 diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/distro_icons/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg new file mode 100644 index 0000000..b0037ad --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3D-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg new file mode 100644 index 0000000..985702d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/3d-symbolic-1.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_button_icons/icons/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg new file mode 100644 index 0000000..b87c15f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/hamburger-symbolic.svg @@ -0,0 +1 @@ + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg new file mode 100644 index 0000000..ba04343 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/menu_icons/sleep-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg new file mode 100644 index 0000000..27aa967 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/arc-menu-logo.svg @@ -0,0 +1,1412 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg new file mode 100644 index 0000000..43e74e7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/donate-icon.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg new file mode 100644 index 0000000..7e35c7b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/gitlab-icon.svg @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H: 2.5 x + 1/2 x + 1x + 1x + + 1x + + 1x + + + + + + + + + + + H: 2.5 x + + 1/2 x + + 1x + + 1x + + + + 1x + + + + 1x + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg new file mode 100644 index 0000000..b0037ad --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3D-symbolic-1.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg new file mode 100644 index 0000000..985702d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/3d-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg new file mode 100644 index 0000000..ad8d2a5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg new file mode 100644 index 0000000..7d03f0c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alien-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg new file mode 100644 index 0000000..56c7967 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/alternative-category-symbolic.svg @@ -0,0 +1,287 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg new file mode 100644 index 0000000..ebbaa42 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/app-launcher-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg new file mode 100644 index 0000000..16e9d9e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/apps-symbolic.svg @@ -0,0 +1,71 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg new file mode 100644 index 0000000..976ac04 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-alt-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg new file mode 100644 index 0000000..7884f4e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg new file mode 100644 index 0000000..251fe3a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-old2-symbolic.svg @@ -0,0 +1,103 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg new file mode 100644 index 0000000..1179af3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arc-menu-symbolic.svg @@ -0,0 +1,93 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg new file mode 100644 index 0000000..41fce36 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arch-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg new file mode 100644 index 0000000..0a1afe7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-layout-symbolic.svg @@ -0,0 +1,330 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg new file mode 100644 index 0000000..73bea1d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-alt-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg new file mode 100644 index 0000000..2278c4e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arcmenu-logo-symbolic.svg @@ -0,0 +1,92 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg new file mode 100644 index 0000000..a57017e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/arrow-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg new file mode 100644 index 0000000..0687ab4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/az-layout-symbolic.svg @@ -0,0 +1,312 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg new file mode 100644 index 0000000..b271af1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bat-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg new file mode 100644 index 0000000..e26d0b1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/brisk-layout-symbolic.svg @@ -0,0 +1,328 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg new file mode 100644 index 0000000..2955da8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/browse-presets-symbolic.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg new file mode 100644 index 0000000..077fcc7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-layout-symbolic.svg @@ -0,0 +1,202 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg new file mode 100644 index 0000000..aa125be --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/budgie-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg new file mode 100644 index 0000000..d28b713 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/bug-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg new file mode 100644 index 0000000..ff230a7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/button-appearance-symbolic.svg @@ -0,0 +1,45 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg new file mode 100644 index 0000000..46b2317 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/categories-symbolic.svg @@ -0,0 +1,87 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg new file mode 100644 index 0000000..013cc7c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/chromebook-layout-symbolic.svg @@ -0,0 +1,227 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg new file mode 100644 index 0000000..80449b8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cita-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg new file mode 100644 index 0000000..c518e65 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/cloud-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg new file mode 100644 index 0000000..5a34df5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/curved-a-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg new file mode 100644 index 0000000..fc2640d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/debian-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg new file mode 100644 index 0000000..63f45e4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/diamond-square-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg new file mode 100644 index 0000000..a1e5380 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dimond-win-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg new file mode 100644 index 0000000..0760fd0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dolphin-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg new file mode 100644 index 0000000..190f2b7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dota-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg new file mode 100644 index 0000000..d874f4b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dra-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg new file mode 100644 index 0000000..02caa74 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/drag-symbolic.svg @@ -0,0 +1,65 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg new file mode 100644 index 0000000..daba3ed --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragon-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg new file mode 100644 index 0000000..1a583a9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/dragonheart-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg new file mode 100644 index 0000000..de3118c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eclipse-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg new file mode 100644 index 0000000..c969ff2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/elementary-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg new file mode 100644 index 0000000..2eeaae6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/eleven-layout-symbolic.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg new file mode 100644 index 0000000..2e2ac62 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/endeavour-logo-symbolic.svg @@ -0,0 +1,58 @@ + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg new file mode 100644 index 0000000..6c40cec --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/equal-symbolic.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg new file mode 100644 index 0000000..2c82d74 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fedora-logo-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg new file mode 100644 index 0000000..447e292 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fine-tune-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg new file mode 100644 index 0000000..f09fbc5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/fly-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg new file mode 100644 index 0000000..307ee2c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/focus-symbolic.svg @@ -0,0 +1,118 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg new file mode 100644 index 0000000..2ca7f94 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg new file mode 100644 index 0000000..a23a9a9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/football2-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg new file mode 100644 index 0000000..cff31b1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gentoo-logo-symbolic.svg @@ -0,0 +1,35 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg new file mode 100644 index 0000000..4bbe335 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnacs-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg new file mode 100644 index 0000000..78c769b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomemenu-layout-symbolic.svg @@ -0,0 +1,159 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg new file mode 100644 index 0000000..24067fd --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/gnomeoverview-layout-symbolic.svg @@ -0,0 +1,163 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg new file mode 100644 index 0000000..bd6251d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/groove-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg new file mode 100644 index 0000000..21a7907 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/heddy-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg new file mode 100644 index 0000000..42b1780 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/helmet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg new file mode 100644 index 0000000..09f7966 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/homescreen-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg new file mode 100644 index 0000000..eab2c5c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/icon-preview-symbolic.svg @@ -0,0 +1,70 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg new file mode 100644 index 0000000..fc8dd05 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/info-circle-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg new file mode 100644 index 0000000..020a8e3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/insider-layout-symbolic.svg @@ -0,0 +1,322 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg new file mode 100644 index 0000000..7ce4ae4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kaaet-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg new file mode 100644 index 0000000..d3eadd1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/kali-linux-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg new file mode 100644 index 0000000..501012f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-category-symbolic.svg @@ -0,0 +1,297 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg new file mode 100644 index 0000000..ba4c27e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-layout-symbolic.svg @@ -0,0 +1,290 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg new file mode 100644 index 0000000..9924c84 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/launcher-symbolic.svg @@ -0,0 +1,66 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg new file mode 100644 index 0000000..e352453 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/lins-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg new file mode 100644 index 0000000..0844542 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/loveheart-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg new file mode 100644 index 0000000..4ca02dc --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/manjaro-logo-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg new file mode 100644 index 0000000..1e85ea4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-layouts-symbolic.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg new file mode 100644 index 0000000..1d75e16 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-general-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg new file mode 100644 index 0000000..15e9d51 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-settings-symbolic.svg @@ -0,0 +1,76 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg new file mode 100644 index 0000000..49311b4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/menu-theme-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg new file mode 100644 index 0000000..8a69a7b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mint-layout-symbolic.svg @@ -0,0 +1,384 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg new file mode 100644 index 0000000..47fae59 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/misc-symbolic.svg @@ -0,0 +1,42 @@ + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg new file mode 100644 index 0000000..e146519 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/modern-category-symbolic.svg @@ -0,0 +1,298 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg new file mode 100644 index 0000000..f6dfb02 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/mx-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg new file mode 100644 index 0000000..55e657a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/octo-maze-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg new file mode 100644 index 0000000..731c0fd --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/opensuse-logo-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg new file mode 100644 index 0000000..96aa0fb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pac-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg new file mode 100644 index 0000000..0554b40 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pacman-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg new file mode 100644 index 0000000..2325b5d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/palette-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg new file mode 100644 index 0000000..e48c0b9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peaks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg new file mode 100644 index 0000000..a346c66 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/peeks-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg new file mode 100644 index 0000000..a15c420 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pie-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg new file mode 100644 index 0000000..13d524c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pinned-apps-symbolic.svg @@ -0,0 +1,37 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg new file mode 100644 index 0000000..8f94a84 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/plasma-layout-symbolic.svg @@ -0,0 +1,438 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg new file mode 100644 index 0000000..67553a2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pointer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg new file mode 100644 index 0000000..c843522 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pop-os-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg new file mode 100644 index 0000000..763a380 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pureos-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg new file mode 100644 index 0000000..b2aa610 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/pyrimid-symbolic.svg @@ -0,0 +1,67 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg new file mode 100644 index 0000000..42b8470 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raspbian-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg new file mode 100644 index 0000000..2d04fcf --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/raven-layout-symbolic.svg @@ -0,0 +1,307 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/record-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg new file mode 100644 index 0000000..d69ae29 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redhat-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg new file mode 100644 index 0000000..a2e9833 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/redmond-layout-symbolic.svg @@ -0,0 +1,610 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Exit To App + + + + Lock Outline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg new file mode 100644 index 0000000..d6c8cee --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/rewind-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg new file mode 100644 index 0000000..946bb65 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/robots-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg new file mode 100644 index 0000000..a0a2b99 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/round-symbolic.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg new file mode 100644 index 0000000..fae1077 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/runner-layout-symbolic.svg @@ -0,0 +1,208 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg new file mode 100644 index 0000000..8e59598 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/saucer-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg new file mode 100644 index 0000000..c1c819c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/search-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg new file mode 100644 index 0000000..c7c4a15 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sheild-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg new file mode 100644 index 0000000..fdd6224 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/shortcuts-symbolic.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg new file mode 100644 index 0000000..5ccb02c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-category-symbolic.svg @@ -0,0 +1,295 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg new file mode 100644 index 0000000..7acd64d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple-layout-symbolic.svg @@ -0,0 +1,285 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg new file mode 100644 index 0000000..04f57e3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/simple2-layout-symbolic.svg @@ -0,0 +1,210 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg new file mode 100644 index 0000000..8273e6c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/snap-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg new file mode 100644 index 0000000..720fa18 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/solus-logo-symbolic.svg @@ -0,0 +1,53 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg new file mode 100644 index 0000000..82962c4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/somnia-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg new file mode 100644 index 0000000..169bb1a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/start-box-symbolic.svg @@ -0,0 +1,138 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg new file mode 100644 index 0000000..02d87d9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/step-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg new file mode 100644 index 0000000..43a3cb5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/sums-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg new file mode 100644 index 0000000..71052b3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/swirl-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg new file mode 100644 index 0000000..e8bf7d6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/time-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg new file mode 100644 index 0000000..ba1c723 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tognee-layout-symbolic.svg @@ -0,0 +1,99 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg new file mode 100644 index 0000000..830e664 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/touch-category-symbolic.svg @@ -0,0 +1,543 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg new file mode 100644 index 0000000..d4ce9d8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/toxic-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg new file mode 100644 index 0000000..b5219b3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/traditional-category-symbolic.svg @@ -0,0 +1,793 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg new file mode 100644 index 0000000..cfaddfb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/transform-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg new file mode 100644 index 0000000..48cda14 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/tree-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg new file mode 100644 index 0000000..bee800f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/triple-dash-symbolic.svg @@ -0,0 +1,88 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg new file mode 100644 index 0000000..b6b1393 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/ubuntu-logo-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg new file mode 100644 index 0000000..ff813d5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/unity-layout-symbolic.svg @@ -0,0 +1,504 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg new file mode 100644 index 0000000..9474a72 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/utool-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg new file mode 100644 index 0000000..7da31b3 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vancer-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg new file mode 100644 index 0000000..3fbbae0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/vibe-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg new file mode 100644 index 0000000..4903fd2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/voyager-logo-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg new file mode 100644 index 0000000..022435a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/warning-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg new file mode 100644 index 0000000..c646eae --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-circle-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg new file mode 100644 index 0000000..7eddf2b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whirl-symbolic.svg @@ -0,0 +1,55 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg new file mode 100644 index 0000000..75ed8b9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/whisker-layout-symbolic.svg @@ -0,0 +1,392 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + Edit Find + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg new file mode 100644 index 0000000..f29c05d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/windows-layout-symbolic.svg @@ -0,0 +1,86 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg new file mode 100644 index 0000000..08c3ba8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zegon-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg new file mode 100644 index 0000000..6d15f88 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/hicolor/16x16/actions/zorin-logo-symbolic.svg @@ -0,0 +1,62 @@ + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg new file mode 100644 index 0000000..ff8584d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/icons/prefs_icons/keyboard-symbolic.svg @@ -0,0 +1,52 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets new file mode 100644 index 0000000..f2c8e16 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/media/misc/ArcMenuDefaultPresets @@ -0,0 +1,52 @@ +ArcMenu Style//rgba(53,53,53,0.987)//rgb(223,223,223)//rgb(32,32,32)//rgb(21,83,158)//rgba(255,255,255,1)//rgb(32,32,32)//9//1//5//12//24//false// +Simply Dark//rgba(28, 28, 28, 0.98)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Blue//rgb(25,31,34)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Light Blue//rgb(255,255,255)//rgb(51,51,51)//rgb(235,235,235)//rgba(189,230,251,0.9)//rgba(89,89,89,1)//rgba(189,230,251,0.9)//9//1//5//12//24//true// +Silk Desert//rgba(50,52,73,0.820946)//rgba(211, 218, 227, 1)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Breeze//rgb(237,237,243)//rgb(36,36,40)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(36,36,40)//rgb(210,210,215)//9//1//0//0//0//false// +Breeze Dark//rgb(49,53,61)//rgb(237,237,243)//rgba(63,62,64,0.246622)//rgba(61,174,235,0.55)//rgb(237,237,243)//rgb(65,69,73)//9//1//0//0//0//false// +Dark Blue 2//rgb(50,52,61)//rgb(211,217,227)//rgba(211,217,227,0.2)//rgb(81,149,226)//rgba(255,255,255,1)//rgba(211,217,227,0.5)//9//1//4//0//0//false// +Dark Orange//rgb(51,51,51)//rgb(226,224,221)//rgba(174,167,159,0.2)//rgb(233,84,32)//rgba(255,255,255,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Light Orange//rgb(246,246,245)//rgb(76,76,76)//rgba(51,51,51,0.2)//rgb(233,84,32)//rgba(114,114,114,1)//rgba(233,84,32,0.5)//9//1//4//12//24//true// +Blue Orange//rgb(44,62,80)//rgb(189,195,199)//rgba(189,195,199,0.2)//rgb(231,76,60)//rgba(227,233,237,1)//rgba(189,195,199,0.5)//9//1//4//0//0//false// +Light Purple//rgb(237,245,252)//rgb(39,45,45)//rgba(39,45,45,0.2)//rgba(144,112,164,0.5)//rgba(77,83,83,1)//rgba(144,112,164,0.5)//9//1//6//0//0//false// +Dark Green//rgb(27,34,36)//rgb(243,243,243)//rgba(46,149,130,0.2)//rgb(46,149,130)//rgba(255,255,255,1)//rgba(46,149,130,0.35)//9//1//6//0//0//true// +Gray//rgb(142,142,142)//rgb(255,255,255)//rgb(63,62,64)//rgba(238, 238, 236, 0.1)//rgba(255,255,255,1)//rgb(63,62,64)//11//0//0//0//0//false// +Terminal Green//rgba(28, 28, 28, 0.98)//rgb(17,164,40)//rgb(63,62,64)//rgba(17,164,40,0.641892)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Sky Clear//rgba(64,145,191,0.756757)//rgb(243,243,243)//rgb(63,62,64)//rgba(135,64,191,0.253378)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Ubi Purple//rgba(174,64,191,0.523649)//rgb(243,243,243)//rgb(63,62,64)//rgba(189,191,64,0.763514)//rgba(255,255,255,1)//rgb(63,62,64)//9//0//0//0//0//false// +Shade//rgb(46,52,54)//rgb(186,189,182)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Red Shade//rgba(191,64,74,0.753378)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Tilk Blue//rgba(74,179,228,0.716216)//rgb(243,243,243)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Green Blue//rgb(87,121,89)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Gray Blue//rgb(136,138,133)//rgb(189,230,251)//rgb(41,50,55)//rgb(41,50,55)//rgba(255,255,255,1)//rgb(41,50,55)//9//1//5//12//24//true// +Pastel//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 2//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 3//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Pastel 4//rgb(238,238,236)//rgb(46,52,54)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgb(233,185,110)//rgb(173,127,168)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 2//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(191,64,190,0.344595)//rgb(114,159,207)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 3//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,137,191,0.358108)//rgb(78,154,6)//rgb(63,62,64)//9//0//0//0//0//false// +Dark Pastel 4//rgb(46,52,54)//rgb(243,243,243)//rgb(63,62,64)//rgba(64,191,70,0.307432)//rgb(196,160,0)//rgb(63,62,64)//9//0//0//0//0//false// +Yellow Shade//rgb(196,160,0)//rgb(46,52,54)//rgb(63,62,64)//rgb(85,87,83)//rgb(238,238,236)//rgb(63,62,64)//9//0//0//0//0//false// +Adapta//rgb(250,251,252)//rgb(34,45,50)//rgb(81,84,86)//rgba(0,150,136,0.121711)//rgba(72,83,88,1)//rgb(0,150,136)//11//0//8//12//24//true// +Adapta Nokto//rgb(38,50,56)//rgb(205,215,218)//rgb(38,50,56)//rgba(125,131,134,0.207237)//rgba(243,253,255,1)//rgb(0,188,212)//11//0//8//12//24//true// +Arc//rgb(245,246,247)//rgb(55,54,68)//rgba(82,148,226,0.903915)//rgba(56,55,68,0.0782918)//rgba(93,92,106,1)//rgb(82,148,226)//11//0//8//12//24//true// +Arc Dark//rgb(56,60,74)//rgb(188,195,205)//rgba(82,148,226,0.903915)//rgba(188,195,205,0.188612)//rgba(226,233,243,1)//rgb(82,148,226)//11//0//8//12//24//true// +Pop!_OS Dark//rgb(69,63,63)//rgb(188,185,183)//rgb(68,61,58)//rgba(250,164,26,0.885135)//rgba(226,223,221,1)//rgb(50,128,138)//11//0//8//12//24//true// +Pop!_OS//rgb(250,251,252)//rgb(87,79,74)//rgba(188,185,183,0.722973)//rgba(250,164,26,0.885135)//rgba(125,117,112,1)//rgb(72,185,199)//11//0//8//12//24//true// +McOS CTLina//rgba(243,243,243,0.841549)//rgb(32,32,32)//rgba(243,243,243,0.841549)//rgb(203,204,207)//rgba(70,70,70,1)//rgb(61,140,248)//11//0//8//12//24//true// +McOS CTLina Dark//rgba(47,47,46,0.873239)//rgb(198,194,194)//rgb(44,45,44)//rgb(37,87,214)//rgba(236,232,232,1)//rgb(37,87,214)//11//0//8//12//24//true// +Android Dark Blue//rgb(63,62,64)//rgb(243,243,243)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(255,255,255,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Blue//rgb(255,255,255)//rgb(63,62,64)//rgb(0,177,251)//rgba(237,250,12,0.35473)//rgba(101,100,102,1)//rgb(0,177,251)//11//0//4//12//24//true// +Android Light Green//rgb(255,255,255)//rgb(63,62,64)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(101,100,102,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Green//rgb(46,52,54)//rgb(243,243,243)//rgb(4,149,90)//rgba(143,219,207,0.334459)//rgba(255,255,255,1)//rgb(237,250,12)//11//0//4//12//24//true// +Android Dark Yaru//rgb(46,52,54)//rgb(243,243,243)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(255,255,255,1)//rgb(189,86,53)//11//0//4//12//24//true// +Android Light Yaru//rgb(255,255,255)//rgb(63,62,64)//rgb(189,86,53)//rgba(247,186,36,0.405405)//rgba(101,100,102,1)//rgb(189,86,53)//11//0//4//12//24//true// +Adapta 4k Dark//rgb(49,59,67)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Adapta 4k Light//rgb(255,255,255)//rgb(46,52,54)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(84,90,92,1)//rgb(4,149,90)//11//1//4//12//24//true// +Neon Yellow Punk//rgb(49,59,67)//rgb(237,250,12)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(248,255,109,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Blue//rgba(49,59,67,0.841216)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Jade//rgba(24,81,58,0.875)//rgb(243,243,243)//rgb(4,149,90)//rgba(0,177,251,0.337838)//rgba(255,255,255,1)//rgb(4,149,90)//11//1//4//12//24//true// +Halo Dark Amber//rgba(84,34,18,0.881757)//rgb(243,243,243)//rgb(247,186,36)//rgba(247,186,36,0.472973)//rgba(255,255,255,1)//rgb(247,186,36)//11//1//4//12//24//true// +Elegant Purple Haze//rgba(41,1,31,0.881757)//rgb(243,243,243)//rgba(112,8,67,0.425676)//rgba(112,8,67,0.425676)//rgba(255,255,255,1)//rgb(176,52,139)//11//0//4//12//24//true// diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuButton.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuButton.js new file mode 100644 index 0000000..ba9c387 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuButton.js @@ -0,0 +1,875 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, GObject, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var DASH_TO_PANEL_UUID = 'dash-to-panel@jderose9.github.com'; +var DASH_TO_DOCK_UUID = 'dash-to-dock@micxgx.gmail.com'; +var UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +var MenuButton = GObject.registerClass(class Arc_Menu_MenuButton extends PanelMenu.Button{ + _init(settings, arcMenuPlacement, panel, dashIndex) { + super._init(0.5, null, true); + this._settings = settings; + this._panel = panel; + this.menu.destroy(); + this.menu = null; + this.add_style_class_name('arc-menu-panel-menu'); + this.arcMenuPlacement = arcMenuPlacement; + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + let menuManagerParent; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL) + menuManagerParent = this._panel; + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + menuManagerParent = this; + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this, 0.5, St.Side.TOP); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.arcMenuContextMenu = new ArcMenuContextMenu(this, 0.5, St.Side.TOP); + this.arcMenuContextMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(menuManagerParent); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + this.menuManager.addMenu(this.arcMenuContextMenu); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this); + this.subMenuManager._changeMenu = (menu) => {}; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget = new MW.MenuButtonWidget(); + this.x_expand = false; + this.y_expand = false; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this._delegate = this; + this.menuButtonWidget = new MW.DashMenuButtonWidget(this, this._settings); + this.dash = this._panel._allDocks[dashIndex]; + this.style_class = 'dash-item-container'; + this.child = this.menuButtonWidget.actor; + this.icon = this.menuButtonWidget.icon; + this.label = this.menuButtonWidget.label; + this.container.showLabel = () => this.menuButtonWidget.showLabel(); + this.container.hideLabel = () => this.menuButtonWidget.hideLabel(); + this.container.toggleButton = this.menuButtonWidget.actor; + this.toggleButton = this.menuButtonWidget.actor; + this.container.setDragApp = () => {}; + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + } + + //Add Menu Button Widget to Button + this.add_child(this.menuButtonWidget.actor); + } + + initiate(){ + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + //Dash to Panel Integration + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.extensionChangedId = Main.extensionManager.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 1) { + this.dashToPanel = Main.extensionManager.lookup(DASH_TO_PANEL_UUID); + this.syncWithDashToPanel(); + } + if (extension.uuid === DASH_TO_PANEL_UUID && extension.state === 2) { + this.dashToPanel = null; + this.arcMenuContextMenu.removeExtensionSettings(); + this.updateArrowSide(St.Side.TOP); + if(this.dtpPostionChangedID>0 && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = 0; + } + } + }); + if(this.dashToPanel && this.dashToPanel.stateObj){ + this.syncWithDashToPanel(); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + //Dash to Dock Integration + this.dtdPostionChangedID = this._panel._settings.connect('changed::dock-position', ()=> { + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side); + }); + } + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => { + this.updateHeight(); + }); + + this._startupCompleteId = Main.layoutManager.connect('startup-complete', () => { + this.updateHeight(); + }); + + this.initiateRecentlyInstalledApps(); + this.setMenuPositionAlignment(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + setDragApp(){ + } + + handleDragOver(source, _actor, _x, _y, _time) { + return imports.ui.dnd.DragMotionResult.NO_DROP; + } + + acceptDrop(source, _actor, _x, _y, _time) { + return false; + } + + syncWithDashToPanel(){ + this.arcMenuContextMenu.addExtensionSettings(this.arcMenuPlacement); + this.extensionSettingsItem = Utils.getSettings('org.gnome.shell.extensions.dash-to-panel', DASH_TO_PANEL_UUID); + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + let dashToPanelPositionSettings = 'panel-positions' + try{ + this.extensionSettingsItem.get_string(dashToPanelPositionSettings); + } catch(e){ + dashToPanelPositionSettings = 'panel-position' + } + this.dtpPostionChangedID = this.extensionSettingsItem.connect('changed::' + dashToPanelPositionSettings, ()=> { + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side); + }); + if(global.dashToPanel && global.dashToPanel.panels){ + global.dashToPanel.panels.forEach(p => { + if(p.panel === this._panel){ + this.dtpPanel = p; + } + }); + } + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._menuInForcedLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._menuInForcedLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + this.MenuLayout = Utils.getMenuLayout(this, this._settings.get_enum('menu-layout')); + + this.setMenuPositionAlignment(); + this.updateStyle(); + this.forceMenuLocation(); + this.updateHeight(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + setMenuPositionAlignment(){ + let layout = this._settings.get_enum('menu-layout'); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + let arrowAlignment = (this._settings.get_int('menu-position-alignment') / 100); + if(layout != Constants.MenuLayout.RUNNER){ + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + this.arcMenu._boxPointer.setSourceAlignment(.5); + } + else if(this.dashToPanel && this.dashToPanel.stateObj){ + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let side = Utils.getDashToPanelPosition(this.extensionSettingsItem, monitorIndex); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + else{ + this.updateArrowSide(St.Side.TOP, false); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER){ + this.arcMenuContextMenu._arrowAlignment = arrowAlignment + this.arcMenuContextMenu._boxPointer.setSourceAlignment(.5); + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(layout != Constants.MenuLayout.RUNNER){ + let side = this._panel._settings.get_enum('dock-position'); + this.updateArrowSide(side, false); + } + else{ + this.updateArrowSide(St.Side.TOP, false); + } + } + } + + updateArrowSide(side, setAlignment = true){ + let arrowAlignment; + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.updateArrowIconSide(side); + if(side === St.Side.RIGHT || side === St.Side.LEFT) + arrowAlignment = 1.0; + else + arrowAlignment = 0.5; + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH) + arrowAlignment = 0.5; + + this.arcMenuContextMenu._arrowSide = side; + this.arcMenuContextMenu._boxPointer._arrowSide = side; + this.arcMenuContextMenu._boxPointer._userArrowSide = side; + this.arcMenuContextMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenuContextMenu._arrowAlignment = arrowAlignment; + this.arcMenuContextMenu._boxPointer._border.queue_repaint(); + + this.arcMenu._arrowSide = side; + this.arcMenu._boxPointer._arrowSide = side; + this.arcMenu._boxPointer._userArrowSide = side; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = arrowAlignment; + this.arcMenu._boxPointer._border.queue_repaint(); + + if(setAlignment) + this.setMenuPositionAlignment(); + } + + forceMenuLocation(){ + let layout = this._settings.get_enum('menu-layout'); + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + return; + + if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + if(!this._menuInForcedLocation) + return; + this.arcMenu.sourceActor = this; + this.arcMenu.focusActor = this; + this.arcMenu._boxPointer.setPosition(this, 0.5); + this.setMenuPositionAlignment(); + this._menuInForcedLocation = false; + return; + } + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + if(!this.dummyWidget){ + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + } + + if(!this._menuInForcedLocation){ + this.arcMenu.sourceActor = this.dummyWidget; + this.arcMenu.focusActor = this.dummyWidget; + this.arcMenu._boxPointer.setPosition(this.dummyWidget, 0.5); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + this._menuInForcedLocation = true; + } + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let rect = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY; + if(forcedMenuLocation === Constants.ForcedMenuLocation.TOP_CENTERED) + positionY = rect.y + this.rise; + else if(forcedMenuLocation === Constants.ForcedMenuLocation.BOTTOM_CENTERED) + positionY = rect.y + rect.height - this.rise; + this.dummyWidget.set_position(positionX, positionY); + } + + updateStyle(){ + let forcedMenuLocation = this._settings.get_enum('force-menu-location'); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let layout = this._settings.get_enum('menu-layout'); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let gapAdjustment = this._settings.get_int('gap-adjustment'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + this.arcMenuContextMenu.actor.set_style_class_name(null); + this.arcMenuContextMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenuContextMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(layout === Constants.MenuLayout.RAVEN){ + this.MenuLayout?.updateStyle(); + return; + } + + if(removeMenuArrow){ + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px; -boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = "margin:0px;"; + } + else if(forcedMenuLocation === Constants.ForcedMenuLocation.OFF){ + this.arcMenu.actor.style = "-boxpointer-gap: " + gapAdjustment + "px;"; + this.arcMenu.box.style = null; + } + + this.MenuLayout?.updateStyle(); + } + + vfunc_event(event){ + if (event.type() === Clutter.EventType.BUTTON_PRESS){ + if(event.get_button() == 1){ + this.toggleMenu(); + } + else if(event.get_button() == 3){ + this.arcMenuContextMenu.toggle(); + } + } + else if(event.type() === Clutter.EventType.TOUCH_BEGIN){ + this.toggleMenu(); + } + else if(event.type() === Clutter.EventType.ENTER && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + else if(event.type() === Clutter.EventType.LEAVE && this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + return Clutter.EVENT_PROPAGATE; + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + this.forceMenuLocation(); + let layout = this._settings.get_enum('menu-layout'); + if(layout === Constants.MenuLayout.GNOME_OVERVIEW){ + if(this._settings.get_boolean('gnome-dash-show-applications')){ + Main.overview._overview._controls._toggleAppsPage(); + } + else + Main.overview.toggle(); + } + else if(!this.arcMenu.isOpen){ + if(layout === Constants.MenuLayout.RUNNER || layout === Constants.MenuLayout.RAVEN) + this.MenuLayout.updateLocation(); + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(this.dtpPanel){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpPanel.intellihide._revealPanel(true); + this.dtpPanel.intellihide.revealAndHold(1); + } + else if(!this.dtpPanel.panelBox.visible){ + this.dtpPanel.panelBox.visible = true; + this.dtpNeedsHiding = true; + } + } + else if(this._panel === Main.panel && !Main.layoutManager.panelBox.visible){ + Main.layoutManager.panelBox.visible = true; + this.mainPanelNeedsHiding = true; + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(this.dash.getDockState() === 0){ + this.dash._removeAnimations(); + this.dash._animateIn(0, 0); + } + } + this.arcMenu.toggle(); + if(this.arcMenu.isOpen && this.MenuLayout){ + if(this.MenuLayout.activeMenuItem && this.MenuLayout.layoutProperties.SupportsCategoryOnHover) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else if(this.arcMenuContextMenu.isOpen) + return this.arcMenuContextMenu; + else + return null; + } + + toggleArcMenuContextMenu(){ + if(this.arcMenuContextMenu.isOpen) + this.arcMenuContextMenu.toggle(); + } + + updateHeight(){ + let layout = this._settings.get_enum('menu-layout'); + + let monitorIndex = Main.layoutManager.findIndexForActor(this); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor); + + if(height > monitorWorkArea.height){ + height = (monitorWorkArea.height * 8) / 10; + } + + if(!(layout == Constants.MenuLayout.SIMPLE || layout == Constants.MenuLayout.SIMPLE_2 || layout == Constants.MenuLayout.RUNNER) && this.MenuLayout) + this.mainBox.style = `height: ${height}px`; + if(this.MenuLayout?.updateWidth) + this.MenuLayout.updateWidth(true); + } + + _onDestroy(){ + if (this._monitorsChangedId){ + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = null; + } + if (this._startupCompleteId){ + Main.layoutManager.disconnect(this._startupCompleteId); + this._startupCompleteId = null; + } + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + if(this.tooltipShowingID){ + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if(this.tooltipHidingID){ + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.extensionChangedId){ + Main.extensionManager.disconnect(this.extensionChangedId); + this.extensionChangedId = null; + } + if(this.dtpPostionChangedID && this.extensionSettingsItem){ + this.extensionSettingsItem.disconnect(this.dtpPostionChangedID); + this.dtpPostionChangedID = null; + } + if(this.dtdPostionChangedID && this._panel._settings){ + this._panel._settings.disconnect(this.dtdPostionChangedID); + this.dtdPostionChangedID = null; + } + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.arcMenuContextMenu) + this.arcMenuContextMenu.destroy(); + if(this.dummyWidget) + this.dummyWidget.destroy(); + + super._onDestroy(); + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout && this.MenuLayout.updateLocation) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + //Avoid Super L hotkey conflicts with Pop Shell extension by + //setting 'overlay-key' mode to Shell.ActionMode.ALL. + let hotKeyPos = this._settings.get_enum('menu-hotkey'); + if(hotKeyPos === Constants.HotKey.SUPER_L) + Main.wm.allowKeybinding('overlay-key', Shell.ActionMode.ALL); + + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + this.menuButtonWidget.setActiveStylePseudoClass(true); + this.add_style_pseudo_class('active'); + + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + + if(this.dtpPanel && !this.dtpNeedsRelease){ + if(this.dtpPanel.intellihide?.enabled){ + this.dtpNeedsRelease = true; + } + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + this.menuButtonWidget.hideLabel(); + if(this.dash._autohideIsEnabled || this.dash._intellihideIsEnabled){ + this.dtdNeedsHiding = true; + this.dash._autohideIsEnabled = false; + this.dash._intellihideIsEnabled = false; + } + this.menuButtonWidget.actor.add_style_pseudo_class('selected'); + this.menuButtonWidget._icon.add_style_pseudo_class('active'); + } + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + if(this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtpPanel && this.dtpNeedsRelease && !this.dtpNeedsHiding){ + this.dtpNeedsRelease = false; + this.dtpPanel.intellihide?.release(1); + } + if(this.dtpPanel && this.dtpNeedsHiding){ + this.dtpNeedsHiding = false; + this.dtpPanel.panelBox.visible = false; + } + if(this.mainPanelNeedsHiding){ + Main.layoutManager.panelBox.visible = false; + this.mainPanelNeedsHiding = false; + } + this.menuButtonWidget.setActiveStylePseudoClass(false); + this.remove_style_pseudo_class('active'); + } + } + else if(this.arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + if(!this.arcMenu.isOpen && !this.arcMenuContextMenu.isOpen){ + if(this.dtdNeedsHiding){ + let dtdSettings = Utils.getSettings('org.gnome.shell.extensions.dash-to-dock', DASH_TO_DOCK_UUID); + if(dtdSettings){ + this.dash._autohideIsEnabled = dtdSettings.get_boolean('autohide'); + this.dash._intellihideIsEnabled = dtdSettings.get_boolean('intellihide'); + } + this.dash._box.sync_hover(); + this.dash._updateDashVisibility(); + this.dtdNeedsHiding = false; + } + + this.menuButtonWidget.actor.remove_style_pseudo_class('selected'); + if(!this.menuButtonWidget.actor.hover) + this.menuButtonWidget._icon.remove_style_pseudo_class('active'); + } + } + } + } +}); + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this._menuButton.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this._menuButton.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this._menuButton.contextMenuManager.activeMenu) + this._menuButton.contextMenuManager.activeMenu.toggle(); + if(this._menuButton.subMenuManager.activeMenu) + this._menuButton.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; + +var ArcMenuContextMenu = class Arc_Menu_ArcMenuContextMenu extends PopupMenu.PopupMenu { + constructor(sourceActor, arrowAlignment, arrowSide) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this._menuButton = sourceActor; + this.extensionSettingsItem = false; + + this.actor.add_style_class_name('panel-menu'); + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + + this.addMenuItem(this.createQuickLinkItem(_("ArcMenu Settings"), Constants.PrefsVisiblePage.MAIN)); + + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + let item = new PopupMenu.PopupMenuItem(_("Settings Quick Links:"), { + activate: false, + reactive: false + }); + item.add_style_class_name("margin-box arcmenu-menu-item"); + this.addMenuItem(item); + + this.addMenuItem(this.createQuickLinkItem(_("Change Menu Layout"), Constants.PrefsVisiblePage.MENU_LAYOUT)); + this.addMenuItem(this.createQuickLinkItem(_("Layout Tweaks"), Constants.PrefsVisiblePage.LAYOUT_TWEAKS)); + this.addMenuItem(this.createQuickLinkItem(_("Customize Menu"), Constants.PrefsVisiblePage.CUSTOMIZE_MENU)); + this.addMenuItem(this.createQuickLinkItem(_("Button Appearance"), Constants.PrefsVisiblePage.BUTTON_APPEARANCE)); + + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.addMenuItem(separator); + + this.addMenuItem(this.createQuickLinkItem(_("About"), Constants.PrefsVisiblePage.ABOUT)); + } + + addExtensionSettings(arcMenuPlacement){ + if(!this.extensionSettingsItem){ + let extensionCommand, extensionName; + if(arcMenuPlacement === Constants.ArcMenuPlacement.PANEL){ + extensionName = _("Dash to Panel Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_PANEL_UUID; + } + else if(arcMenuPlacement === Constants.ArcMenuPlacement.DASH){ + let dashToDock = Main.extensionManager.lookup(DASH_TO_DOCK_UUID); + let ubuntuDash = Main.extensionManager.lookup(UBUNTU_DOCK_UUID); + if(dashToDock && dashToDock.stateObj && dashToDock.stateObj.dockManager){ + extensionName = _("Dash to Dock Settings"); + extensionCommand = 'gnome-extensions prefs ' + DASH_TO_DOCK_UUID; + } + if(ubuntuDash && ubuntuDash.stateObj && ubuntuDash.stateObj.dockManager){ + extensionName = _("Ubuntu Dock Settings"); + extensionCommand = 'gnome-control-center ubuntu'; + } + } + + let item = new PopupMenu.PopupMenuItem(_(extensionName)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + Util.spawnCommandLine(extensionCommand); + }); + this.addMenuItem(item, 1); + this.extensionSettingsItem = true; + } + } + + removeExtensionSettings(){ + let children = this._getMenuItems(); + children[1].destroy(); + this.extensionSettingsItem = false; + } + + createQuickLinkItem(title, prefsVisiblePage){ + let item = new PopupMenu.PopupMenuItem(_(title)); + item.add_style_class_name("margin-box arcmenu-menu-item"); + item.connect('activate', ()=>{ + this._settings.set_int('prefs-visible-page', prefsVisiblePage); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + }); + return item; + } +}; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js new file mode 100644 index 0000000..c38431f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menuWidgets.js @@ -0,0 +1,3693 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const {Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Shell, St} = imports.gi; +const AccountsService = imports.gi.AccountsService; +const AppFavorites = imports.ui.appFavorites; +const BoxPointer = imports.ui.boxpointer; +const Constants = Me.imports.constants; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const _SystemActions = imports.misc.systemActions; +const SystemActions = _SystemActions.getDefault(); +const Util = imports.misc.util; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; +const { loadInterfaceXML } = imports.misc.fileUtils; + +const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration'); +const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface); + +Gio._promisify(Gio._LocalFilePrototype, 'query_info_async', 'query_info_finish'); +Gio._promisify(Gio._LocalFilePrototype, 'set_attributes_async', 'set_attributes_finish'); + +const INDICATOR_ICON_SIZE = 18; +const USER_AVATAR_SIZE = 28; + +function activatePowerOption(powerType, arcMenu){ + arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + if(powerType === Constants.PowerType.POWER_OFF) + SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.RESTART) + SystemActions.activateRestart ? SystemActions.activateRestart() : SystemActions.activatePowerOff(); + else if(powerType === Constants.PowerType.LOCK) + SystemActions.activateLockScreen(); + else if(powerType === Constants.PowerType.LOGOUT) + SystemActions.activateLogout(); + else if(powerType === Constants.PowerType.SUSPEND) + SystemActions.activateSuspend(); + else if(powerType === Constants.PowerType.HYBRID_SLEEP) + Utils.activateHybridSleep(); + else if(powerType === Constants.PowerType.HIBERNATE) + Utils.activateHibernate(); +} + +var ApplicationContextItems = GObject.registerClass({ + Signals: { + 'close-context-menu': { }, + }, + +}, class Arc_Menu_ApplicationContextItems extends St.BoxLayout{ + _init(actor, app, menuLayout){ + super._init({ + vertical: true, + x_expand: true, + y_expand: true, + style_class: 'margin-box', + }); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.sourceActor = actor; + this.layout = this._settings.get_enum('menu-layout'); + + this.discreteGpuAvailable = false; + this._switcherooNotifyId = global.connect('notify::switcheroo-control', + () => this._updateDiscreteGpuAvailable()); + this._updateDiscreteGpuAvailable(); + } + + set path(path){ + this._path = path; + } + + _updateDiscreteGpuAvailable() { + this._switcherooProxy = global.get_switcheroo_control(); + if (this._switcherooProxy) { + let prop = this._switcherooProxy.get_cached_property('HasDualGpu'); + this.discreteGpuAvailable = prop?.unpack() ?? false; + } else { + this.discreteGpuAvailable = false; + } + } + + closeMenus(){ + this.close(); + this._menuLayout.arcMenu.toggle(); + } + + close(){ + this.emit('close-context-menu'); + } + + rebuildItems(){ + this.destroy_all_children(); + if(this._app instanceof Shell.App){ + this.appInfo = this._app.get_app_info(); + let actions = this.appInfo.list_actions(); + + let windows = this._app.get_windows().filter( + w => !w.skip_taskbar + ); + + if (windows.length > 0){ + let item = new PopupMenu.PopupMenuItem(_("Current Windows:"), { + reactive: false, + can_focus: false + }); + item.actor.add_style_class_name('inactive'); + this.add_child(item); + + windows.forEach(window => { + let title = window.title ? window.title + : this._app.get_name(); + let item = this._appendMenuItem(title); + item.connect('activate', () => { + this.closeMenus(); + Main.activateWindow(window); + }); + }); + this._appendSeparator(); + } + + if (!this._app.is_window_backed()) { + if (this._app.can_open_new_window() && !actions.includes('new-window')) { + let newWindowItem = this._appendMenuItem(_("New Window")); + newWindowItem.connect('activate', () => { + this.closeMenus(); + this._app.open_new_window(-1); + }); + } + if (this.discreteGpuAvailable && this._app.state == Shell.AppState.STOPPED) { + const appPrefersNonDefaultGPU = this.appInfo.get_boolean('PrefersNonDefaultGPU'); + const gpuPref = appPrefersNonDefaultGPU + ? Shell.AppLaunchGpu.DEFAULT + : Shell.AppLaunchGpu.DISCRETE; + + this._onGpuMenuItem = this._appendMenuItem(appPrefersNonDefaultGPU + ? _('Launch using Integrated Graphics Card') + : _('Launch using Discrete Graphics Card')); + + this._onGpuMenuItem.connect('activate', () => { + this.closeMenus(); + this._app.launch(0, -1, gpuPref); + }); + } + + for (let i = 0; i < actions.length; i++) { + let action = actions[i]; + let item; + if(action === "empty-trash-inactive"){ + item = new PopupMenu.PopupMenuItem(this.appInfo.get_action_name(action), {reactive:false, can_focus:false}); + item.actor.add_style_class_name('inactive'); + this._appendSeparator(); + this.add_child(item); + } + else if(action === "empty-trash"){ + this._appendSeparator(); + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + else{ + item = this._appendMenuItem(this.appInfo.get_action_name(action)); + } + + item.connect('activate', (emitter, event) => { + this.closeMenus(); + this._app.launch_action(action, event.get_time(), -1); + }); + } + + //If Trash Can, we don't want to add the rest of the entries below. + if(this.appInfo.get_string('Id') === "ArcMenu_Trash") + return false; + + let desktopIcons = Main.extensionManager.lookup("desktop-icons@csoriano"); + let desktopIconsNG = Main.extensionManager.lookup("ding@rastersoft.com"); + if((desktopIcons && desktopIcons.stateObj) || (desktopIconsNG && desktopIconsNG.stateObj)){ + this._appendSeparator(); + let fileDestination = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP); + let src = Gio.File.new_for_path(this.appInfo.get_filename()); + let dst = Gio.File.new_for_path(GLib.build_filenamev([fileDestination, src.get_basename()])); + let exists = dst.query_exists(null); + if(exists) { + let item = this._appendMenuItem(_("Delete Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + dst.delete(null); + } catch (e) { + log(`Failed to delete shortcut: ${e.message}`); + } + } + this.close(); + }); + } + else { + let item = this._appendMenuItem(_("Create Desktop Shortcut")); + item.connect('activate', () => { + if(src && dst){ + try { + // copy_async() isn't introspectable :-( + src.copy(dst, Gio.FileCopyFlags.OVERWRITE, null, null); + this._markTrusted(dst); + } catch (e) { + log(`Failed to copy to desktop: ${e.message}`); + } + } + this.close(); + }); + } + } + + let canFavorite = global.settings.is_writable('favorite-apps'); + if (canFavorite) { + this._appendSeparator(); + let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._app.get_id()); + if (isFavorite) { + let item = this._appendMenuItem(_("Remove from Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.removeFavorite(this._app.get_id()); + this.close(); + }); + } else { + let item = this._appendMenuItem(_("Add to Favorites")); + item.connect('activate', () => { + let favs = AppFavorites.getAppFavorites(); + favs.addFavorite(this._app.get_id()); + this.close(); + }); + } + } + + let pinnedApps = this._settings.get_strv('pinned-app-list'); + let pinnedAppID = []; + + //filter pinnedApps list by every 3rd entry in list. 3rd entry contains an appID or command + for(let i = 2; i < pinnedApps.length; i += 3){ + pinnedAppID.push(pinnedApps[i]); + } + let isAppPinned = pinnedAppID.find((element) => { + return element == this._app.get_id(); + }); + + //if app is pinned and menulayout has PinnedApps category, show Unpin from ArcMenu entry + if(isAppPinned && this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app.get_id()){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + else if(this._menuLayout.hasPinnedApps) { + let item = this._appendMenuItem(_("Pin to ArcMenu")); + item.connect('activate', ()=>{ + this.close(); + pinnedApps.push(this.appInfo.get_display_name()); + pinnedApps.push(''); + pinnedApps.push(this._app.get_id()); + this._settings.set_strv('pinned-app-list',pinnedApps); + }); + } + + if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { + this._appendSeparator(); + let item = this._appendMenuItem(_("Show Details")); + item.connect('activate', () => { + let id = this._app.get_id(); + let args = GLib.Variant.new('(ss)', [id, '']); + Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => { + let bus = Gio.DBus.get_finish(res); + bus.call('org.gnome.Software', + '/org/gnome/Software', + 'org.gtk.Actions', 'Activate', + GLib.Variant.new('(sava{sv})', + ['details', [args], null]), + null, 0, -1, null, null); + this.closeMenus(); + }); + }); + } + } + } + else if(this._path){ + let newWindowItem = this._appendMenuItem(_("Open Folder Location")); + newWindowItem.connect('activate', () => { + let file = Gio.File.new_for_path(this._path); + let context = global.create_app_launch_context(Clutter.get_current_event().get_time(), -1) + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + this.closeMenus(); + }); + } + else if(this._menuLayout.hasPinnedApps && this.sourceActor instanceof PinnedAppsMenuItem) { + let item = this._appendMenuItem(_("Unpin from ArcMenu")); + item.connect('activate', () => { + this.close(); + let pinnedApps = this._settings.get_strv('pinned-app-list'); + for(let i = 0; i < pinnedApps.length; i += 3){ + if(pinnedApps[i + 2] === this._app){ + pinnedApps.splice(i, 3); + this._settings.set_strv('pinned-app-list', pinnedApps); + break; + } + } + }); + } + } + + //_markTrusted function borrowed from + //https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/apps-menu + async _markTrusted(file) { + let modeAttr = Gio.FILE_ATTRIBUTE_UNIX_MODE; + let trustedAttr = 'metadata::trusted'; + let queryFlags = Gio.FileQueryInfoFlags.NONE; + let ioPriority = GLib.PRIORITY_DEFAULT; + + try { + let info = await file.query_info_async(modeAttr, queryFlags, ioPriority, null); + + let mode = info.get_attribute_uint32(modeAttr) | 0o100; + info.set_attribute_uint32(modeAttr, mode); + info.set_attribute_string(trustedAttr, 'yes'); + await file.set_attributes_async(info, queryFlags, ioPriority, null); + + // Hack: force nautilus to reload file info + info = new Gio.FileInfo(); + info.set_attribute_uint64( + Gio.FILE_ATTRIBUTE_TIME_ACCESS, GLib.get_real_time()); + try { + await file.set_attributes_async(info, queryFlags, ioPriority, null); + } catch (e) { + log(`Failed to update access time: ${e.message}`); + } + } catch (e) { + log(`Failed to mark file as trusted: ${e.message}`); + } + } + + _appendSeparator() { + let separator = new ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.add_child(separator); + } + + _appendMenuItem(labelText) { + let item = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.label = new St.Label({ + text: _(labelText), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + item.add_child(this.label); + this.add_child(item); + return item; + } +}); + +var ApplicationContextMenu = class Arc_Menu_ApplicationContextMenu extends PopupMenu.PopupMenu { + constructor(actor, app, menuLayout){ + super(actor, 0.0, St.Side.TOP); + this._menuLayout = menuLayout; + this._settings = menuLayout._settings; + this._menuButton = menuLayout.menuButton; + this._app = app; + this.layout = this._settings.get_enum('menu-layout'); + this._boxPointer.setSourceAlignment(.20); + this._boxPointer._border.queue_repaint(); + this.blockSourceEvents = true; + Main.uiGroup.add_child(this.actor); + this._menuLayout.contextMenuManager.addMenu(this); + this.contextMenuItems = new ApplicationContextItems(actor, app, menuLayout); + this.contextMenuItems.connect('close-context-menu', () => this.toggle()); + this.contextMenuItems._delegate = this.contextMenuItems; + this.box.add_child(this.contextMenuItems); + this.sourceActor = actor; + this.sourceActor.connect("destroy", ()=> { + if(this.isOpen) + this.close(); + Main.uiGroup.remove_child(this.actor); + this.contextMenuItems.destroy(); + this.destroy(); + }); + } + + centerBoxPointerPosition(){ + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + rightBoxPointerPosition(){ + this._arrowSide = St.Side.LEFT; + this._boxPointer._arrowSide = St.Side.LEFT; + this._boxPointer._userArrowSide = St.Side.LEFT; + this._boxPointer.setSourceAlignment(.50); + this._arrowAlignment = .5; + this._boxPointer._border.queue_repaint(); + } + + set path(path){ + this.contextMenuItems.path = path; + } + + open(animate){ + if(this._menuLayout.searchResults && this.sourceActor !== this._menuLayout.searchResults.getTopResult()) + this._menuLayout.searchResults.getTopResult()?.remove_style_pseudo_class('active'); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.sourceActor.tooltip){ + this.sourceActor.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + super.open(animate); + } + + close(animate){ + super.close(animate); + if(this.sourceActor instanceof ArcMenuButtonItem) + this.sourceActor.sync_hover(); + else{ + this.sourceActor.active = false; + } + + this.sourceActor.sync_hover(); + this.sourceActor.hovered = this.sourceActor.hover; + } + + rebuildItems(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(customStyle){ + this.actor.style_class = 'arc-menu-boxpointer'; + this.actor.add_style_class_name('arc-menu'); + } + else{ + this.actor.style_class = 'popup-menu-boxpointer'; + this.actor.add_style_class_name('popup-menu'); + } + + this.contextMenuItems.rebuildItems(); + } + + _onKeyPress(actor, event) { + return Clutter.EVENT_PROPAGATE; + } +}; + +var ArcMenuPopupBaseMenuItem = GObject.registerClass({ + Properties: { + 'active': GObject.ParamSpec.boolean('active', 'active', 'active', + GObject.ParamFlags.READWRITE, + false), + 'hovered': GObject.ParamSpec.boolean('hovered', 'hovered', 'hovered', + GObject.ParamFlags.READWRITE, + false), + 'sensitive': GObject.ParamSpec.boolean('sensitive', 'sensitive', 'sensitive', + GObject.ParamFlags.READWRITE, + true), + }, + Signals: { + 'activate': { param_types: [Clutter.Event.$gtype] }, + }, + +}, class Arc_Menu_PopupBaseMenuItem extends St.BoxLayout{ + _init(menuLayout, params){ + params = imports.misc.params.parse(params, { + reactive: true, + activate: true, + hover: true, + style_class: null, + can_focus: true, + }); + super._init({ style_class: 'popup-menu-item arcmenu-menu-item', + reactive: params.reactive, + track_hover: params.reactive, + can_focus: params.can_focus, + accessible_role: Atk.Role.MENU_ITEM + }); + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this.hasContextMenu = false; + this._delegate = this; + this._menuLayout = menuLayout; + this.arcMenu = this._menuLayout.arcMenu; + this.shouldShow = true; + this._parent = null; + this._active = false; + this._activatable = params.reactive && params.activate; + this._sensitive = true; + + this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' }); + this.add_child(this._ornamentLabel); + + this.x_align = Clutter.ActorAlign.FILL; + this.x_expand = true; + + if (!this._activatable) + this.add_style_class_name('popup-inactive-menu-item'); + + if (params.style_class) + this.add_style_class_name(params.style_class); + + if (params.reactive && params.hover) + this.bind_property('hover', this, 'hovered', GObject.BindingFlags.SYNC_CREATE); + + if(params.hover) + this.actor.connect('notify::hover', this._onHover.bind(this)); + + this.arcMenuOpenStateChangeID = this.arcMenu.connect('open-state-changed', (menu, open) =>{ + if(!open) + this.cancelPopupTimeout(); + }); + + let textureCache = St.TextureCache.get_default(); + let iconThemeChangedId = textureCache.connect('icon-theme-changed', this._updateIcon.bind(this)); + this.connect('destroy', () => { + textureCache.disconnect(iconThemeChangedId); + this._onDestroy(); + }); + } + + _updateIcon() { + if(!this._iconBin || !this.createIcon) + return; + + let icon = this.createIcon(); + this._iconBin.set_child(icon); + } + + get actor() { + return this; + } + + get active(){ + return this._active; + } + + set active(active) { + if(this.isDestroyed) + return; + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + if(this._menuLayout.activeMenuItem !== this) + this._menuLayout.activeMenuItem = this; + this.remove_style_class_name('selected'); + this.add_style_pseudo_class('active'); + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_pseudo_class('active'); + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + set hovered(hover) { + let hoverChanged = hover != this.hovered; + if(hoverChanged){ + let isActiveStyle = this.get_style_pseudo_class()?.includes('active') + if(hover && !isActiveStyle){ + this.add_style_class_name('selected'); + } + else{ + this.remove_style_class_name('selected'); + } + } + } + + setShouldShow(){ + //If a saved shortcut link is a desktop app, check if currently installed. + //Do NOT display if application not found. + if(this._command.endsWith(".desktop") && !Shell.AppSystem.get_default().lookup_app(this._command)){ + this.shouldShow = false; + } + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = this.description; + if(this._app) + description = this._app.get_description(); + Utils.createTooltip(this._menuLayout, this, this.label, description, this._displayType ? this._displayType : -1); + } + } + + vfunc_button_press_event(){ + let event = Clutter.get_current_event(); + this.pressed = false; + if(event.get_button() == 1){ + this._menuLayout._blockActivateEvent = false; + this.pressed = true; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + } + else if(event.get_button() == 3){ + this.pressed = true; + } + this.active = true; + return Clutter.EVENT_PROPAGATE; + } + + vfunc_button_release_event(){ + let event = Clutter.get_current_event(); + if(event.get_button() == 1 && !this._menuLayout._blockActivateEvent && this.pressed){ + this.pressed = false; + this.activate(event); + if(!(this instanceof CategoryMenuItem) && !(this instanceof ArcMenuButtonItem)) + this.active = false; + return Clutter.EVENT_STOP; + } + if(event.get_button() == 3 && this.pressed){ + this.pressed = false; + if(this.hasContextMenu) + this.popupContextMenu(); + else if(!(this instanceof CategoryMenuItem && !(this instanceof ArcMenuButtonItem))){ + this.active = false; + this.hovered = true; + } + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_key_focus_in() { + super.vfunc_key_focus_in(); + if(!this.actor.hover) + this._menuLayout._keyFocusIn(this.actor); + this.active = true; + } + + vfunc_key_focus_out() { + if(this.contextMenu && this.contextMenu.isOpen){ + return; + } + super.vfunc_key_focus_out(); + this.active = false; + } + + activate(event) { + this.emit('activate', event); + } + + vfunc_key_press_event(keyEvent) { + if (!this._activatable) + return super.vfunc_key_press_event(keyEvent); + + let state = keyEvent.modifier_state; + + // if user has a modifier down (except capslock and numlock) + // then don't handle the key press here + state &= ~Clutter.ModifierType.LOCK_MASK; + state &= ~Clutter.ModifierType.MOD2_MASK; + state &= Clutter.ModifierType.MODIFIER_MASK; + + if (state) + return Clutter.EVENT_PROPAGATE; + + let symbol = keyEvent.keyval; + if ( symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter) { + this.activate(Clutter.get_current_event()); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + } + + vfunc_touch_event(event){ + if(event.type == Clutter.EventType.TOUCH_END && !this._menuLayout._blockActivateEvent && this.pressed){ + this.remove_style_pseudo_class('active'); + this.activate(Clutter.get_current_event()); + this.pressed = false; + return Clutter.EVENT_STOP; + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && !this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = true; + this._menuLayout._blockActivateEvent = false; + if(this.hasContextMenu) + this.contextMenuTimeOut(); + this.add_style_pseudo_class('active'); + } + else if(event.type == Clutter.EventType.TOUCH_BEGIN && this._menuLayout.contextMenuManager.activeMenu){ + this.pressed = false; + this._menuLayout._blockActivateEvent = false; + this._menuLayout.contextMenuManager.activeMenu.toggle(); + } + return Clutter.EVENT_PROPAGATE; + } + + contextMenuTimeOut(){ + this._popupTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 600, () => { + this.pressed = false; + this._popupTimeoutId = null; + if(this.hasContextMenu && this._menuLayout.arcMenu.isOpen && !this._menuLayout._blockActivateEvent) { + this.popupContextMenu(); + this._menuLayout.contextMenuManager.ignoreRelease(); + } + return GLib.SOURCE_REMOVE; + }); + } + + cancelPopupTimeout(){ + if(this._popupTimeoutId){ + GLib.source_remove(this._popupTimeoutId); + this._popupTimeoutId = null; + } + } + + _onDestroy(){ + this.isDestroyed = true; + if(this.arcMenuOpenStateChangeID){ + this.arcMenu.disconnect(this.arcMenuOpenStateChangeID); + this.arcMenuOpenStateChangeID = null; + } + } +}); + +var ArcMenuSeparator = GObject.registerClass( +class Arc_Menu_Separator extends PopupMenu.PopupBaseMenuItem { + _init(separatorLength, separatorAlignment, text) { + super._init({ + style_class: 'popup-separator-menu-item', + reactive: false, + can_focus: false, + }); + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + this.remove_child(this._ornamentLabel); + this.reactive = true; + this.label = new St.Label({ + text: text || '', + style: 'font-weight: bold' + }); + this.add_child(this.label); + this.label_actor = this.label; + + this.label.add_style_pseudo_class = () => { return false; }; + + this.label.connect('notify::text', + this._syncLabelVisibility.bind(this)); + this._syncLabelVisibility(); + + this._separator = new St.Widget({ + style_class: 'popup-separator-menu-item-separator separator-color-style', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(this._separator); + if(separatorAlignment === Constants.SeparatorAlignment.HORIZONTAL){ + this.style = "padding: 0px 5px;" + if(separatorLength === Constants.SeparatorStyle.SHORT) + this._separator.style = "margin: 5px 45px;"; + else if(separatorLength === Constants.SeparatorStyle.MEDIUM) + this._separator.style = "margin: 5px 15px;"; + else if(separatorLength === Constants.SeparatorStyle.LONG) + this._separator.style = "margin: 0px 5px;"; + else if(separatorLength === Constants.SeparatorStyle.MAX) + this._separator.style = "margin: 0px; padding: 0px;"; + else if(separatorLength === Constants.SeparatorStyle.HEADER_LABEL){ + this._separator.style = "margin: 0px 20px 0px 10px;"; + this.style = "padding: 5px 15px;" + } + } + else if(separatorAlignment === Constants.SeparatorAlignment.VERTICAL){ + if(separatorLength === Constants.SeparatorStyle.ALWAYS_SHOW){ + this.style = "padding: 8px 4px;" + } + else{ + this._syncVisibility(); + this.vertSeparatorChangedID = this._settings.connect('changed::vert-separator', this._syncVisibility.bind(this)); + this.style = "padding: 0px 4px;" + } + + this._separator.style = "margin: 0px; width: 1px; height: -1px;"; + this.remove_child(this.label); + this.x_expand = this._separator.x_expand = true; + this.x_align = this._separator.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = this._separator.y_expand = true; + this.y_align = this._separator.y_align = Clutter.ActorAlign.FILL; + } + + this.connect('destroy', () => { + if(this.vertSeparatorChangedID){ + this._settings.disconnect(this.vertSeparatorChangedID); + this.vertSeparatorChangedID = null; + } + }); + } + + _syncLabelVisibility() { + this.label.visible = this.label.text != ''; + } + + _syncVisibility() { + this._separator.visible = this._settings.get_boolean('vert-separator'); + } +}); + +var ActivitiesMenuItem = GObject.registerClass(class Arc_Menu_ActivitiesMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _("Activities Overview"), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + icon_name: 'view-fullscreen-symbolic', + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + activate(event) { + this._menuLayout.arcMenu.toggle(); + Main.overview.show(); + super.activate(event); + } +}); + +var Tooltip = class Arc_Menu_Tooltip{ + constructor(menuLayout, sourceActor, title, description) { + this._menuButton = menuLayout.menuButton; + this._settings = this._menuButton._settings; + this.sourceActor = sourceActor; + if(this.sourceActor.tooltipLocation) + this.location = this.sourceActor.tooltipLocation; + else + this.location = Constants.TooltipLocation.BOTTOM; + let descriptionLabel; + this.actor = new St.BoxLayout({ + vertical: true, + style_class: 'dash-label tooltip-menu-item', + opacity: 0 + }); + + if(title){ + this.titleLabel = new St.Label({ + text: _(title), + style: description ? "font-weight: bold;" : null, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this.titleLabel); + } + + if(description){ + descriptionLabel = new St.Label({ + text: description, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(descriptionLabel); + } + + global.stage.add_child(this.actor); + + this.actor.connect('destroy',()=>{ + if(this.destroyID){ + this.sourceActor.disconnect(this.destroyID); + this.destroyID = null; + } + if(this.activeID){ + this.sourceActor.disconnect(this.activeID); + this.activeID = null; + } + + if(this.hoverID){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.toggleID){ + this._settings.disconnect(this.toggleID); + this.toggleID = null; + } + }) + this.activeID = this.sourceActor.connect('notify::active', ()=> this.setActive(this.sourceActor.active)); + this.destroyID = this.sourceActor.connect('destroy',this.destroy.bind(this)); + this.hoverID = this.sourceActor.connect('notify::hover', this._onHover.bind(this)); + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + this.toggleID = this._settings.connect('changed::disable-tooltips', this.disableTooltips.bind(this)); + } + + setActive(active){ + if(!active) + this.hide(); + } + + disableTooltips() { + this._useTooltips = ! this._settings.get_boolean('disable-tooltips'); + } + + _onHover() { + if(this._useTooltips){ + if(this.sourceActor.hover){ + if(this._menuButton.tooltipShowing){ + this.show(); + this._menuButton.activeTooltip = this.actor; + } + else{ + this._menuButton.tooltipShowingID = GLib.timeout_add(0, 750, () => { + this.show(); + this._menuButton.tooltipShowing = true; + this._menuButton.activeTooltip = this.actor; + this._menuButton.tooltipShowingID = null; + return GLib.SOURCE_REMOVE; + }); + } + if(this._menuButton.tooltipHidingID){ + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + } + else { + this.hide(); + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + this._menuButton.tooltipHidingID = GLib.timeout_add(0, 750, () => { + this._menuButton.tooltipShowing = false; + this._menuButton.activeTooltip = null; + this._menuButton.tooltipHidingID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + } + + show() { + if(this._useTooltips){ + this.actor.opacity = 0; + this.actor.show(); + + let [stageX, stageY] = this.sourceActor.get_transformed_position(); + + let itemWidth = this.sourceActor.allocation.x2 - this.sourceActor.allocation.x1; + let itemHeight = this.sourceActor.allocation.y2 - this.sourceActor.allocation.y1; + + let labelWidth = this.actor.get_width(); + let labelHeight = this.actor.get_height(); + + let x, y; + let gap = 5; + + switch (this.location) { + case Constants.TooltipLocation.BOTTOM_CENTERED: + y = stageY + itemHeight + gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.TOP_CENTERED: + y = stageY - labelHeight - gap; + x = stageX + Math.floor((itemWidth - labelWidth) / 2); + break; + case Constants.TooltipLocation.BOTTOM: + y = stageY + itemHeight + gap; + x = stageX + gap; + break; + } + + // keep the label inside the screen + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + if (x - monitor.x < gap) + x += monitor.x - x + gap; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + else if (y - monitor.y < gap) + y += monitor.y - y + gap; + else if (y + labelHeight > monitor.y + monitor.height - gap) + y -= y + labelHeight - (monitor.y + monitor.height) + gap; + + this.actor.set_position(x, y); + this.actor.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + } + + hide() { + if(this._useTooltips){ + this.actor.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.actor.hide() + }); + } + } + + destroy() { + if (this._menuButton.tooltipShowingID) { + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + } + if (this._menuButton.tooltipHidingID) { + GLib.source_remove(this._menuButton.tooltipHidingID); + this._menuButton.tooltipHidingID = null; + } + if(this.toggleID>0){ + this._settings.disconnect(this.toggleID); + this.toggleID = 0; + } + if(this.hoverID>0){ + this.sourceActor.disconnect(this.hoverID); + this.hoverID = 0; + } + if(this._menuButton.activeTooltip = this.actor) + this._menuButton.activeTooltip = null; + + global.stage.remove_child(this.actor); + this.actor.destroy(); + } +}; + +var ArcMenuButtonItem = GObject.registerClass( + class Arc_Menu_ArcMenuButtonItem extends ArcMenuPopupBaseMenuItem { + _init(menuLayout, tooltipText, iconName, gicon) { + super._init(menuLayout); + this.style_class = 'popup-menu-item arc-menu-button'; + this._settings = this._menuLayout._settings; + this._menuLayout = menuLayout; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.iconName = iconName; + this.gicon = gicon; + this.toggleMenuOnClick = true; + + if(tooltipText){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, tooltipText); + this.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + this.tooltip.hide(); + } + + if(this.iconName !== null){ + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + } + } + + createIcon(overrideIconSize){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this.gicon ? this.gicon : Gio.icon_new_for_string(this.iconName), + icon_size: overrideIconSize ? overrideIconSize : iconSize, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER + }); + } + + setIconSize(size){ + if(!this._iconBin) + return; + this._iconBin.set_child(this.createIcon(size)); + } + + activate(event){ + if(this.toggleMenuOnClick) + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +// Settings Button +var SettingsButton = GObject.registerClass(class Arc_Menu_SettingsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Settings"), 'emblem-system-symbolic'); + } + activate(event) { + super.activate(event); + Util.spawnCommandLine('gnome-control-center'); + } +}); + +// Runner Layout Tweaks Button +var RunnerTweaksButton = GObject.registerClass(class Arc_Menu_RunnerTweaksButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Configure Runner"), 'emblem-system-symbolic'); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + } + activate(event) { + super.activate(event); + this._menuLayout._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.RUNNER_TWEAKS); + Util.spawnCommandLine(Constants.ArcMenuSettingsCommand); + } +}); + +//'Insider' layout Pinned Apps hamburger button +var PinnedAppsButton = GObject.registerClass(class Arc_Menu_PinnedAppsButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Pinned Apps"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.togglePinnedAppsMenu(); + } +}); + +//'Windows' layout extras hamburger button +var ExtrasButton = GObject.registerClass(class Arc_Menu_ExtrasButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Extras"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleExtrasMenu(); + } +}); + +//"Leave" Button with popupmenu that shows lock, power off, restart, etc +var LeaveButton = GObject.registerClass(class Arc_Menu_LeaveButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Leave"), 'system-shutdown-symbolic'); + this.toggleMenuOnClick = false; + this._menuLayout = menuLayout; + this.menuButton = menuLayout.menuButton; + this._settings = menuLayout._settings; + this._createLeaveMenu(); + } + + _createLeaveMenu(){ + this.leaveMenu = new PopupMenu.PopupMenu(this, 0.5 , St.Side.BOTTOM); + this.leaveMenu.blockSourceEvents = true; + let section = new PopupMenu.PopupMenuSection(); + this.leaveMenu.addMenuItem(section); + + let box = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + box._delegate = box; + + section.actor.add_child(box); + + box.add_child(this._menuLayout.createLabelRow(_("Session"))); + + this.lockItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOCK); + box.add_child(this.lockItem); + + let logOutItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.LOGOUT); + box.add_child(logOutItem); + + box.add_child(this._menuLayout.createLabelRow(_("System"))); + + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + let sleepItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HYBRID_SLEEP); + box.insert_child_at_index(sleepItem, 4); + } + }); + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + let hibernateItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.HIBERNATE); + box.insert_child_at_index(hibernateItem, 5); + } + }); + + let suspendItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.SUSPEND); + box.add_child(suspendItem); + + let restartItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.RESTART); + box.add_child(restartItem); + + let powerOffItem = new PowerMenuItem(this._menuLayout, Constants.PowerType.POWER_OFF); + box.add_child(powerOffItem); + + this._menuLayout.subMenuManager.addMenu(this.leaveMenu); + this.leaveMenu.actor.hide(); + Main.uiGroup.add_child(this.leaveMenu.actor); + this.leaveMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.active = false; + this.sync_hover(); + this.hovered = this.hover; + } + }); + } + + _onDestroy(){ + Main.uiGroup.remove_child(this.leaveMenu.actor); + this.leaveMenu.destroy(); + } + + activate(event) { + super.activate(event); + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.leaveMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.leaveMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.leaveMenu.toggle(); + } +}); + +//'Unity' layout categories hamburger button +var CategoriesButton = GObject.registerClass(class Arc_Menu_CategoriesButton extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, _("Categories"), Me.path + Constants.HamburgerIcon.PATH); + this.toggleMenuOnClick = false; + } + activate(event) { + super.activate(event); + this._menuLayout.toggleCategoriesMenu(); + } +}); + +var PowerButton = GObject.registerClass(class Arc_Menu_PowerButton extends ArcMenuButtonItem { + _init(menuLayout, powerType) { + super._init(menuLayout, Constants.PowerOptions[powerType].TITLE, Constants.PowerOptions[powerType].IMAGE); + this.powerType = powerType; + } + activate(event) { + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PowerMenuItem = GObject.registerClass(class Arc_Menu_PowerMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, type) { + super._init(menuLayout); + this.powerType = type; + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(Constants.PowerOptions[this.powerType].TITLE), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.label); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: Gio.icon_new_for_string(Constants.PowerOptions[this.powerType].IMAGE), + style_class: 'popup-menu-icon', + icon_size: iconSize, + }); + } + + activate(){ + activatePowerOption(this.powerType, this._menuLayout.arcMenu); + } +}); + +var PlasmaMenuItem = GObject.registerClass(class Arc_Menu_PlasmaMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, title, iconPath) { + super._init(menuLayout); + this.remove_child(this._ornamentLabel); + this._menuLayout = menuLayout; + this.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.vertical = true; + this.name = "arc-menu-plasma-button"; + this.iconPath = iconPath; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(title), + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label.x_align = this.label.y_align = Clutter.ActorAlign.CENTER; + this.label.y_expand = true; + + this._iconBin.x_align = this._iconBin.y_align = Clutter.ActorAlign.CENTER; + this._iconBin.y_expand = true; + + this.label.get_clutter_text().set_line_wrap(true); + this.add_child(this.label); + this.actor.connect('notify::hover', this._onHover.bind(this)); + } + + createIcon(){ + return new St.Icon({ + gicon: Gio.icon_new_for_string(this.iconPath), + style_class: 'popup-menu-icon', + icon_size: Constants.MEDIUM_ICON_SIZE + }); + } + + _onHover(){ + if(this.tooltip === undefined && this.actor.hover && this.label){ + let description = null; + Utils.createTooltip(this._menuLayout, this, this.label, description, Constants.DisplayType.LIST); + } + let shouldHover = this._settings.get_boolean('plasma-enable-hover'); + if(shouldHover && this.actor.hover && !this.isActive){ + this.activate(Clutter.get_current_event()); + } + } + + set active(active) { + let activeChanged = active != this.active; + if(activeChanged){ + this._active = active; + if(active){ + this.add_style_class_name('selected'); + this._menuLayout.activeMenuItem = this; + if(this.can_focus) + this.grab_key_focus(); + } + else{ + this.remove_style_class_name('selected'); + } + this.notify('active'); + } + } + + setActive(active){ + if(active){ + this.isActive = true; + this.set_style_pseudo_class("active-item"); + } + else{ + this.isActive = false; + this.set_style_pseudo_class(null); + } + } + + activate(event){ + this._menuLayout.searchBox.clearWithoutSearchChangeEvent(); + this._menuLayout.clearActiveItem(); + this.setActive(true); + super.activate(event); + } +}); + +var PlasmaCategoryHeader = GObject.registerClass(class Arc_Menu_PlasmaCategoryHeader extends St.BoxLayout{ + _init(menuLayout) { + super._init({ + style_class: "popup-menu-item", + style: 'padding: 0px;', + reactive: true, + track_hover:true, + can_focus: true, + accessible_role: Atk.Role.MENU_ITEM + }); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this.backButton = new ArcMenuPopupBaseMenuItem(this._menuLayout); + this.backButton.x_expand = false; + this.backButton.x_align = Clutter.ActorAlign.CENTER; + this.label = new St.Label({ + text: _("Applications"), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + style: 'font-weight: bold' + }); + + this.backButton.add_child(this.label); + + this.add_child(this.backButton); + this.backButton.connect("activate", () => this._menuLayout.displayCategories() ); + + this.categoryLabel = new St.Label({ + text: '', + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this.categoryLabel); + } + + setActiveCategory(categoryText){ + if(categoryText){ + this.categoryLabel.text = _(categoryText); + this.categoryLabel.show(); + } + else + this.categoryLabel.hide(); + } +}); + +var AllAppsButton = GObject.registerClass(class Arc_Menu_AllAppsButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-next-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("All Apps"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.insert_child_at_index(this._label, 0); + } + + activate(event){ + super.activate(event); + this._menuLayout.displayAllApps(); + } +}); + +var BackButton = GObject.registerClass(class Arc_Menu_BackButton extends ArcMenuButtonItem{ + _init(menuLayout) { + super._init(menuLayout, null, 'go-previous-symbolic'); + this.setIconSize(Constants.EXTRA_SMALL_ICON_SIZE); + this.toggleMenuOnClick = false; + this.style = 'min-height: 28px; padding: 0px 8px;' + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + this.x_expand = true; + this.x_align = Clutter.ActorAlign.END; + this._label = new St.Label({ + text: _("Back"), + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_expand: false, + y_align: Clutter.ActorAlign.CENTER + }); + + this.add_child(this._label); + } + + activate(event){ + super.activate(event); + this._menuLayout.setDefaultMenuView(); + } +}); + +// Menu item to go back to category view +var BackMenuItem = GObject.registerClass(class Arc_Menu_BackMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._layout = this._menuLayout.layout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + let backLabel = new St.Label({ + text: _("Back"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-previous-symbolic', + icon_size: iconSize, + }); + } + + activate(event) { + if(this._layout === Constants.MenuLayout.ARCMENU){ + //If the current page is inside a category and + //previous page was the categories page, + //go back to categories page + if(this._menuLayout.previousCategoryType === Constants.CategoryType.CATEGORIES_LIST && (this._menuLayout.activeCategoryType <= 4 || this._menuLayout.activeCategoryType instanceof GMenu.TreeDirectory)) + this._menuLayout.displayCategories(); + else + this._menuLayout.setDefaultMenuView(); + } + else if(this._layout === Constants.MenuLayout.TOGNEE) + this._menuLayout.setDefaultMenuView(); + super.activate(event); + } +}); + +// Menu item to view all apps +var ViewAllPrograms = GObject.registerClass(class Arc_Menu_ViewAllPrograms extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + let backLabel = new St.Label({ + text: _("All Applications"), + x_expand: false, + x_align: Clutter.ActorAlign.START, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(backLabel); + + this._iconBin = new St.Bin({ + x_expand: false, + x_align: Clutter.ActorAlign.START, + }); + this.add_child(this._iconBin); + this._updateIcon(); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.MISC_ICON_SIZE); + + return new St.Icon({ + icon_name: 'go-next-symbolic', + icon_size: iconSize, + x_align: Clutter.ActorAlign.START + }); + } + + activate(event) { + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this._menuLayout.displayCategories(); + else + this._menuLayout.displayAllApps(); + super.activate(event); + } +}); + +var ShortcutMenuItem = GObject.registerClass(class Arc_Menu_ShortcutMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + if(this._settings.get_enum('shortcut-icon-type') === Constants.CategoryIconType.FULL_COLOR) + this.add_style_class_name('regular-icons'); + else + this.add_style_class_name('symbolic-icons'); + this._command = command; + this._displayType = displayType; + this.isContainedInCategory = isContainedInCategory; + this.iconName = icon; + + //Check for default commands-------- + if(this._command == "ArcMenu_Software"){ + let softwareManager = Utils.findSoftwareManager(); + this._command = softwareManager ? softwareManager : 'ArcMenu_unfound.desktop'; + } + else if(this._command === "ArcMenu_Trash"){ + this.trash = new Me.imports.placeDisplay.Trash(this); + this._command = "ArcMenu_Trash"; + this._app = this.trash.getApp(); + } + if(!this._app) + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + + if(this._app && icon === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this.iconName = appIcon.gicon.to_string(); + } + } + //------------------------------------- + + this.hasContextMenu = this._app ? true : false; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(name), y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this.layout = this._settings.get_enum('menu-layout'); + if(this.layout === Constants.MenuLayout.PLASMA && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + else if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.remove_child(this.label); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + this.setShouldShow(); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + iconSizeEnum = this._settings.get_enum('button-item-icon-size'); + defaultIconSize = LayoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + } + else if(this._displayType === Constants.DisplayType.GRID){ + iconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(iconSizeEnum, defaultIconStyle); + } + + return new St.Icon({ + icon_name: this.iconName, + gicon: Gio.icon_new_for_string(this.iconName), + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this._app && this.contextMenu == undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID || this.layout === Constants.MenuLayout.UNITY || this.layout === Constants.MenuLayout.AZ) + this.contextMenu.centerBoxPointerPosition(); + else if(this.layout === Constants.MenuLayout.MINT || this.layout === Constants.MenuLayout.TOGNEE) + this.contextMenu.rightBoxPointerPosition(); + if(this._path) + this.contextMenu.path = this._path; + } + if(this.contextMenu !== undefined){ + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen){ + this.contextMenu.rebuildItems(); + } + this.contextMenu.toggle(); + } + } + + activate(event) { + if(this._command === "ArcMenu_LogOut") + activatePowerOption(Constants.PowerType.LOGOUT, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Lock") + activatePowerOption(Constants.PowerType.LOCK, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_PowerOff") + activatePowerOption(Constants.PowerType.POWER_OFF, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Restart") + activatePowerOption(Constants.PowerType.RESTART, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Suspend") + activatePowerOption(Constants.PowerType.SUSPEND, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_HybridSleep") + activatePowerOption(Constants.PowerType.HYBRID_SLEEP, this._menuLayout.arcMenu); + else if(this._command === "ArcMenu_Hibernate") + activatePowerOption(Constants.PowerType.HIBERNATE, this._menuLayout.arcMenu); + + else{ + this._menuLayout.arcMenu.toggle(); + if(this._command === "ArcMenu_ActivitiesOverview") + Main.overview.show(); + else if(this._command === "ArcMenu_RunCommand") + Main.openRunDialog(); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else if(this._app) + this._app.open_new_window(-1); + else + Util.spawnCommandLine(this._command); + } + } +}); + +// Menu item which displays the current user +var UserMenuItem = GObject.registerClass(class Arc_Menu_UserMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, displayType) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._settings = this._menuLayout._settings; + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + this.iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + this.iconSize = Utils.getIconSize(IconSizeEnum, USER_AVATAR_SIZE); + } + + this.userMenuIcon = new UserMenuIcon(menuLayout, this.iconSize, false); + + this.add_child(this.userMenuIcon.actor); + this.label = this.userMenuIcon.label; + if(this._displayType !== Constants.DisplayType.BUTTON) + this.add_child(this.label); + } + + activate(event) { + Util.spawnCommandLine("gnome-control-center user-accounts"); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var UserMenuIcon = class Arc_Menu_UserMenuIcon{ + constructor(menuLayout, size, hasTooltip) { + this._menuLayout = menuLayout; + this.iconSize = size; + + let username = GLib.get_user_name(); + this._user = AccountsService.UserManager.get_default().get_user(username); + + this.actor = new St.Bin({ + style_class: 'menu-user-avatar user-icon', + track_hover: true, + reactive: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + + this.label = new St.Label({ + text: GLib.get_real_name(), + y_align: Clutter.ActorAlign.CENTER + }); + + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + + this._userLoadedId = this._user.connect('notify::is-loaded', this._onUserChanged.bind(this)); + this._userChangedId = this._user.connect('changed', this._onUserChanged.bind(this)); + this.actor.connect('destroy', this._onDestroy.bind(this)); + if(hasTooltip) + this.actor.connect('notify::hover',this._onHover.bind(this)); + + this._onUserChanged(); + } + + _onHover() { + if(this.tooltip === undefined && this.actor.hover){ + this.tooltip = new Tooltip(this._menuLayout, this.actor, GLib.get_real_name()); + this.tooltip.location = Constants.TooltipLocation.BOTTOM_CENTERED; + this.tooltip._onHover(); + } + } + + _onUserChanged() { + if (this._user.is_loaded) { + this.label.set_text(this._user.get_real_name()); + if(this.tooltip) + this.tooltip.titleLabel.text = this._user.get_real_name(); + + let iconFile = this._user.get_icon_file(); + if (iconFile && !GLib.file_test(iconFile ,GLib.FileTest.EXISTS)) + iconFile = null; + + if (iconFile) { + this.actor.child = null; + this.actor.add_style_class_name('user-avatar'); + this.actor.style = 'background-image: url("%s");'.format(iconFile) + "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + } + else { + this.actor.style = "width: " + this.iconSize + "px; height: " + this.iconSize + "px;"; + this.actor.child = new St.Icon({ + icon_name: 'avatar-default-symbolic', + icon_size: this.iconSize, + style: "padding: 5px; width: " + this.iconSize + "px; height: " + this.iconSize + "px;" + }); + } + } + } + + _onDestroy() { + if (this._userLoadedId) { + this._user.disconnect(this._userLoadedId); + this._userLoadedId = null; + } + if (this._userChangedId) { + this._user.disconnect(this._userChangedId); + this._userChangedId = null; + } + } +}; + +// Menu pinned apps item class +var PinnedAppsMenuItem = GObject.registerClass({ + Signals: { 'saveSettings': {}, }, +}, class Arc_Menu_PinnedAppsMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, name, icon, command, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._menuButton = menuLayout.menuButton; + this._settings = this._menuLayout._settings; + this._command = command; + this._iconString = this._iconPath = icon; + this._name = name; + this._displayType = displayType; + this._app = Shell.AppSystem.get_default().lookup_app(this._command); + this.hasContextMenu = true; + this.gridLocation = [-1, -1]; + this.isContainedInCategory = isContainedInCategory; + + //Modifiy the Default Pinned Apps--------------------- + if(this._name == "ArcMenu Settings"){ + this._name = _("ArcMenu Settings"); + } + else if(this._name == "Terminal"){ + this._name = _("Terminal"); + } + else if(this._name == "Files"){ + this._name = _("Files"); + } + if(this._iconPath === "ArcMenu_ArcMenuIcon" || this._iconPath === Me.path + '/media/icons/arc-menu-symbolic.svg'){ + this._iconString = this._iconPath = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + //------------------------------------------------------- + + if(this._app && this._iconPath === ''){ + let appIcon = this._app.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(appIcon instanceof St.Icon){ + this._iconString = appIcon.gicon ? appIcon.gicon.to_string() : appIcon.fallback_icon_name; + if(!this._iconString) + this._iconString = ""; + } + } + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: _(this._name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + if(this._displayType === Constants.DisplayType.LIST && this._settings.get_boolean('apps-show-extra-details') && this._app){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionLabel = new St.Label({ + text: this._app.get_description(), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + if(this._app.get_description()) + labelBox.add_child(descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this._draggable = DND.makeDraggable(this.actor); + this._draggable._animateDragEnd = (eventTime) => { + this._draggable._animationInProgress = true; + this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime); + }; + this.isDraggableApp = true; + this._draggable.connect('drag-begin', this._onDragBegin.bind(this)); + this._draggable.connect('drag-end', this._onDragEnd.bind(this)); + + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.setShouldShow(); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + icon_size: iconSize + }); + } + + popupContextMenu(){ + if(this.contextMenu == undefined){ + let app = this._app ? this._app : this._command; + this.contextMenu = new ApplicationContextMenu(this.actor, app, this._menuLayout); + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(this.tooltip !== undefined) + this.tooltip.hide(); + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + _onDragBegin() { + this.isDragging = true; + if(this._menuButton.tooltipShowingID){ + GLib.source_remove(this._menuButton.tooltipShowingID); + this._menuButton.tooltipShowingID = null; + this._menuButton.tooltipShowing = false; + } + if(this.tooltip){ + this.tooltip.hide(); + this._menuButton.tooltipShowing = false; + } + + if(this.contextMenu && this.contextMenu.isOpen) + this.contextMenu.toggle(); + + this.cancelPopupTimeout(); + + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this) + }; + DND.addDragMonitor(this._dragMonitor); + this._parentBox = this.actor.get_parent(); + let p = this._parentBox.get_transformed_position(); + this.posX = p[0]; + this.posY = p[1]; + + this.actor.opacity = 55; + this.get_allocation_box(); + this.rowHeight = this.height; + this.rowWidth = this.width; + } + + _onDragMotion(dragEvent) { + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + this.xIndex = Math.floor((this._draggable._dragX - this.posX) / (this.rowWidth + layoutManager.column_spacing)); + this.yIndex = Math.floor((this._draggable._dragY - this.posY) / (this.rowHeight + layoutManager.row_spacing)); + + if(this.xIndex === this.gridLocation[0] && this.yIndex === this.gridLocation[1]){ + return DND.DragMotionResult.CONTINUE; + } + else{ + this.gridLocation = [this.xIndex, this.yIndex]; + } + + this._parentBox.remove_child(this); + let children = this._parentBox.get_children(); + let childrenCount = children.length; + let columns = layoutManager.gridColumns; + let rows = Math.floor(childrenCount / columns); + if(this.yIndex >= rows) + this.yIndex = rows; + if(this.yIndex < 0) + this.yIndex = 0; + if(this.xIndex >= columns - 1) + this.xIndex = columns - 1; + if(this.xIndex < 0) + this.xIndex = 0; + + if(((this.xIndex + 1) + (this.yIndex * columns)) > childrenCount) + this.xIndex = Math.floor(childrenCount % columns); + + this._parentBox.remove_all_children(); + + let x = 0, y = 0; + for(let i = 0; i < children.length; i++){ + if(this.xIndex === x && this.yIndex === y) + [x, y] = this.gridLayoutIter(x, y, columns); + layoutManager.attach(children[i], x, y, 1, 1); + [x, y] = this.gridLayoutIter(x, y, columns); + } + layoutManager.attach(this, this.xIndex, this.yIndex, 1, 1); + } + return DND.DragMotionResult.CONTINUE; + } + + _onDragEnd() { + if (this._dragMonitor) { + DND.removeDragMonitor(this._dragMonitor); + this._dragMonitor = null; + } + this.actor.opacity = 255; + let layoutManager = this._parentBox.layout_manager; + if(layoutManager instanceof Clutter.GridLayout){ + let x = 0, y = 0; + let columns = layoutManager.gridColumns; + let orderedList = []; + let children = this._parentBox.get_children(); + for(let i = 0; i < children.length; i++){ + orderedList.push(this._parentBox.layout_manager.get_child_at(x, y)); + [x, y] = this.gridLayoutIter(x, y, columns); + } + this._menuLayout.pinnedAppsArray = orderedList; + } + this.emit('saveSettings'); + } + + getDragActor() { + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + let icon = new St.Icon({ + gicon: Gio.icon_new_for_string(this._iconString), + style_class: 'popup-menu-icon', + icon_size: this._iconBin.get_child().icon_size + }); + let iconColor = this._settings.get_string('menu-foreground-color'); + if(customStyle) + icon.style = `color: ${iconColor};`; + return icon; + } + + getDragActorSource() { + return this.actor; + } + + gridLayoutIter(x, y, columns){ + x++; + if(x === columns){ + y++; + x = 0; + } + return [x, y]; + } + + activate(event) { + if(this._app) + this._app.open_new_window(-1); + else if(this._command === "ArcMenu_ShowAllApplications") + Main.overview._overview._controls._toggleAppsPage(); + else + Util.spawnCommandLine(this._command); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } +}); + +var ApplicationMenuItem = GObject.registerClass(class Arc_Menu_ApplicationMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, app, displayType, metaInfo, isContainedInCategory) { + super._init(menuLayout); + this._app = app; + this._menuLayout = menuLayout; + this.metaInfo = metaInfo; + this._settings = this._menuLayout._settings; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._displayType = displayType; + this.hasContextMenu = true; + this.isSearchResult = this.metaInfo ? true : false; + this.isContainedInCategory = isContainedInCategory; + + if(this._app){ + let disableRecentAppsIndicator = this._settings.get_boolean("disable-recently-installed-apps") + if(!disableRecentAppsIndicator){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + this.isRecentlyInstalled = recentApps.some((appIter) => appIter === this._app.get_id()); + } + } + + this._iconBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._app ? this._app.get_name() : this.metaInfo['name'], + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.description = this._app ? this._app.get_description() : this.metaInfo['description']; + + let searchResultsDescriptionsSetting = this._settings.get_boolean("show-search-result-details"); + let appsShowDescriptionsSetting = this._settings.get_boolean("apps-show-extra-details"); + this.searchResultsDescriptions = searchResultsDescriptionsSetting && this.isSearchResult; + this.appsShowDescriptions = appsShowDescriptionsSetting && !this.isSearchResult; + + if(this.description && (this.searchResultsDescriptions || this.appsShowDescriptions) && this._displayType === Constants.DisplayType.LIST){ + let labelBox = new St.BoxLayout({ + vertical: true + }); + let descriptionText = this.description.split('\n')[0]; + this.descriptionLabel = new St.Label({ + text: descriptionText, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + style: "font-weight: lighter;" + }); + labelBox.add_child(this.label); + labelBox.add_child(this.descriptionLabel); + this.add_child(labelBox); + } + else{ + this.add_child(this.label); + } + + this.label_actor = this.label; + + if(this.isRecentlyInstalled){ + this._indicator = new St.Label({ + text: _('New'), + style_class: "arc-menu-menu-item-text-indicator", + style: "border-radius: 15px; margin: 0px; padding: 0px 10px;", + x_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + if(this._displayType === Constants.DisplayType.GRID) + Utils.convertToGridLayout(this); + + this.hoverID = this.connect("notify::hover", () => this.removeIndicator()); + this.keyFocusInID = this.connect("key-focus-in", () => this.removeIndicator()); + } + + createIcon(){ + let iconSize; + if(this._displayType === Constants.DisplayType.GRID){ + this._iconBin.x_align = Clutter.ActorAlign.CENTER; + + const IconSizeEnum = this._settings.get_enum('menu-item-grid-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconStyle = LayoutProps.DefaultIconGridStyle; + iconSize = Utils.getGridIconSize(IconSizeEnum, defaultIconStyle); + } + else if(this._displayType === Constants.DisplayType.LIST){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory || this.isSearchResult ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultPinnedIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + return this.metaInfo ? this.metaInfo['createIcon'](iconSize) : this._app.create_icon_texture(iconSize); + } + + removeIndicator(){ + if(this.isRecentlyInstalled){ + this.isRecentlyInstalled = false; + let recentApps = this._settings.get_strv('recently-installed-apps'); + let index = recentApps.indexOf(this._app.get_id()); + if(index > -1){ + recentApps.splice(index, 1); + } + this._settings.set_strv('recently-installed-apps', recentApps); + + this._indicator.hide(); + this._menuLayout.setRecentlyInstalledIndicator(); + } + } + + popupContextMenu(){ + this.removeIndicator(); + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activateSearchResult(provider, metaInfo, terms, event){ + this._menuLayout.arcMenu.toggle(); + if(provider.activateResult){ + provider.activateResult(metaInfo.id, terms); + if (metaInfo.clipboardText) + St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, metaInfo.clipboardText); + } + else{ + if (metaInfo.id.endsWith('.desktop')) { + let app = Shell.AppSystem.get_default().lookup_app(metaInfo.id); + if (app.can_open_new_window()) + app.open_new_window(-1); + else + app.activate(); + } + else{ + this._menuLayout.arcMenu.itemActivated(BoxPointer.PopupAnimation.NONE); + SystemActions.activateAction(metaInfo.id); + } + } + } + + activate(event) { + this.removeIndicator(); + + if(this.metaInfo){ + this.activateSearchResult(this.provider, this.metaInfo, this.resultsView.terms, event); + return Clutter.EVENT_STOP; + } + else + this._app.open_new_window(-1); + + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _onDestroy(){ + if(this.hoverID){ + this.disconnect(this.hoverID); + this.hoverID = null; + } + if(this.keyFocusInID){ + this.disconnect(this.keyFocusInID); + this.keyFocusInID = null; + } + } +}); + +// Menu Category item class +var CategoryMenuItem = GObject.registerClass(class Arc_Menu_CategoryMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, category, displayType) { + super._init(menuLayout); + this.appList = []; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._layout = this._settings.get_enum('menu-layout'); + this._category = category; + this._name = ""; + this._horizontalFlip = this._settings.get_boolean('enable-horizontal-flip'); + this._displayType = displayType; + this.layoutProps = this._menuLayout.layoutProperties; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ + text: this._name, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this.label); + + if(this.isRecentlyInstalled) + this.setRecentlyInstalledIndicator(true); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = false; + this.x_align = Clutter.ActorAlign.CENTER; + this.y_expand = false; + this.y_align = Clutter.ActorAlign.CENTER; + this.remove_child(this.label); + } + + this.label_actor = this.label; + this._menuLayout._oldX = -1; + this._menuLayout._oldY = -1; + this.connect('motion-event', this._onMotionEvent.bind(this)); + this.connect('enter-event', this._onEnterEvent.bind(this)); + this.connect('leave-event', this._onLeaveEvent.bind(this)); + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + + let defaultIconSize = this.layoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + let defaultIconSize = this.layoutProps.DefaultButtonsIconSize; + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + let icon = new St.Icon({ + style_class: 'popup-menu-icon', + icon_size: iconSize + }); + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + icon.gicon = gicon; + else if(iconName) + icon.icon_name = iconName; + else + icon.fallback_icon_name = fallbackIconName; + + return icon; + } + + setRecentlyInstalledIndicator(shouldShow){ + if(this._displayType === Constants.DisplayType.BUTTON) + return; + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.add_child(this._indicator); + } + else if(this._indicator && this.contains(this._indicator)) + this.remove_child(this._indicator); + } + + displayAppList(){ + this._menuLayout.searchBox?.clearWithoutSearchChangeEvent(); + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, null); + } + + activate(event) { + this.displayAppList(); + if(this.layoutProps.SupportsCategoryOnHover) + this._menuLayout.setActiveCategory(this, true); + super.activate(event); + } + + _onEnterEvent(actor, event) { + if(this._menuLayout.navigatingCategoryLeaveEventID){ + GLib.source_remove(this._menuLayout.navigatingCategoryLeaveEventID); + this._menuLayout.navigatingCategoryLeaveEventID = null; + } + } + + _onLeaveEvent(actor, event) { + if(!this._menuLayout.navigatingCategoryLeaveEventID){ + this._menuLayout.navigatingCategoryLeaveEventID = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { + this._menuLayout.navigatingCategory = null; + this._menuLayout.navigatingCategoryLeaveEventID = null; + return GLib.SOURCE_REMOVE; + }); + } + } + + _onMotionEvent(actor, event) { + if(this.layoutProps.SupportsCategoryOnHover && this._settings.get_boolean('activate-on-hover')){ + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategoryType !== this._category && this._menuLayout.navigatingCategory === this) + this.activate(Clutter.get_current_event()); + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } + } + + _isInTriangle([x, y]){ + let [posX, posY] = this._menuLayout.navigatingCategory.get_transformed_position(); + + //the mouse is still in the active category + if (this._menuLayout.navigatingCategory === this){ + this._menuLayout._oldX = x; + this._menuLayout._oldY = y; + return true; + } + + if(!this._menuLayout.navigatingCategory) + return false; + + let width = this._menuLayout.navigatingCategory.width; + let height = this._menuLayout.navigatingCategory.height; + + let maxX = this._horizontalFlip ? posX : posX + width; + let maxY = posY + height; + + let distance = Math.abs(maxX - this._menuLayout._oldX); + let point1 = [this._menuLayout._oldX, this._menuLayout._oldY] + let point2 = [maxX, posY - distance]; + let point3 = [maxX, maxY + distance]; + + let area = Utils.areaOfTriangle(point1, point2, point3); + let a1 = Utils.areaOfTriangle([x, y], point2, point3); + let a2 = Utils.areaOfTriangle(point1, [x, y], point3); + let a3 = Utils.areaOfTriangle(point1, point2, [x, y]); + return area === a1 + a2 + a3; + } +}); + +var SimpleMenuItem = GObject.registerClass(class Arc_Menu_SimpleMenuItem extends CategoryMenuItem{ + _init(menuLayout, category) { + super._init(menuLayout, category); + this.subMenu = new PopupMenu.PopupMenu(this.actor,.5,St.Side.LEFT); + this.subMenu.connect("open-state-changed", (menu, open) => { + if(!open){ + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + }); + + Main.uiGroup.add_child(this.subMenu.actor); + this.section = new PopupMenu.PopupMenuSection(); + this.subMenu.addMenuItem(this.section); + + this.applicationsScrollBox = this._menuLayout._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this._menuLayout.subMenuManager.addMenu(this.subMenu); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.applicationsScrollBox.style = 'max-height: 25em;'; + this.applicationsBox._delegate = this.applicationsBox; + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.section.actor.add_child(this.applicationsScrollBox); + + if(this.subMenu._keyPressId) + this.actor.disconnect(this.subMenu._keyPressId); + this.applicationsScrollBox.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Right: + case Clutter.KEY_Left: + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + } + return Clutter.EVENT_STOP; + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.actor.connect("key-press-event",(actor, event)=>{ + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Escape: + if(this.subMenu.isOpen){ + this.subMenu.toggle(); + } + return Clutter.EVENT_STOP; + case Clutter.KEY_Left: + case Clutter.KEY_Right: + case Clutter.KEY_Return: + if(!this.subMenu.isOpen){ + let navigateFocus = true; + this.activate(event, navigateFocus); + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + return Clutter.EVENT_STOP; + } + else{ + return Clutter.EVENT_PROPAGATE; + } + default: + return Clutter.EVENT_PROPAGATE; + } + }); + this.updateStyle(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.subMenu.actor.hide(); + if(customStyle){ + this.subMenu.actor.style_class = 'arc-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('arc-menu'); + } + else + { + this.subMenu.actor.style_class = 'popup-menu-boxpointer'; + this.subMenu.actor.add_style_class_name('popup-menu'); + } + } + + displayAppList(){ + this._menuLayout.activeCategory = this._name; + } + + activate(event, navigateFocus = true) { + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + this.subMenu.toggle(); + if(navigateFocus) + this.subMenu.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); + this._menuLayout.setActiveCategory(this, true); + } + + _onMotionEvent(actor, event) { + if (!this._menuLayout.navigatingCategory) { + this._menuLayout.navigatingCategory = this; + } + + if (this._isInTriangle(event.get_coords())){ + if(this._menuLayout.activeCategory !== this._name && this._menuLayout.navigatingCategory === this){ + let navigateFocus = false; + this.activate(event, navigateFocus); + } + return true; + } + this._menuLayout.navigatingCategory = this; + return true; + } +}); +// SubMenu Category item class +var CategorySubMenuItem = GObject.registerClass(class Arc_Menu_CategorySubMenuItem extends PopupMenu.PopupSubMenuMenuItem{ + _init(menuLayout, category) { + super._init('', true); + this.add_style_class_name("arcmenu-menu-item"); + this.add_style_class_name('margin-box'); + this._category = category; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + this._name = ""; + this.isSimpleMenuItem = false; + this._active = false; + this.applicationsMap = new Map(); + this.appList = []; + + let categoryIconType = this._settings.get_enum('category-icon-type'); + let [name, gicon, iconName, fallbackIconName] = Utils.getCategoryDetails(this._category, categoryIconType); + this._name = _(name); + if(gicon) + this.icon.gicon = gicon; + else if(iconName) + this.icon.icon_name = iconName; + else + this.icon.fallback_icon_name = fallbackIconName; + + this.label.text = this._name; + + const IconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = LayoutProps.DefaultCategoryIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + this.icon.icon_size = iconSize; + + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._menuLayout._blockActivateEvent = true; + this._menuLayout.onPan(action, this.menu.actor); + }); + panAction.connect('gesture-cancel',(action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + panAction.connect('gesture-end', (action) => this._menuLayout.onPanEnd(action, this.menu.actor)); + this.menu.actor.add_action(panAction); + + this.menu.actor.style = 'max-height: 250px;'; + this.menu.actor.overlay_scrollbars = true; + this.menu.actor.style_class = 'popup-sub-menu ' + (this._menuLayout.disableFadeEffect ? '' : 'small-vfade'); + this.menu._needsScrollbar = () => this._needsScrollbar(); + + this.menu.connect('open-state-changed', () => { + if(!this.menu.isOpen){ + let scrollbar= this.menu.actor.get_vscroll_bar().get_adjustment(); + scrollbar.set_value(0); + } + }); + this.menu.box.style_class = 'margin-box'; + } + + setRecentlyInstalledIndicator(shouldShow){ + this.isRecentlyInstalled = shouldShow; + if(shouldShow){ + this._indicator = new St.Icon({ + icon_name: 'message-indicator-symbolic', + style_class: 'arc-menu-menu-item-indicator', + icon_size: INDICATOR_ICON_SIZE, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this.actor.add_child(this._indicator); + } + else if(this._indicator && this.actor.contains(this._indicator)) + this.actor.remove_child(this._indicator); + } + + _needsScrollbar() { + let topMenu = this.menu; + let [, topNaturalHeight] = topMenu.actor.get_preferred_height(-1); + let topThemeNode = topMenu.actor.get_theme_node(); + + let topMaxHeight = topThemeNode.get_max_height(); + let needsScrollbar = topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight; + if(needsScrollbar) + this.menu.actor.style = 'min-height:150px; max-height: 250px;'; + else + this.menu.actor.style = 'max-height: 250px;'; + + this.menu.actor.vscrollbar_policy = St.PolicyType.AUTOMATIC; + + if (needsScrollbar) + this.menu.actor.add_style_pseudo_class('scrolled'); + else + this.menu.actor.remove_style_pseudo_class('scrolled'); + + return needsScrollbar; + } + + loadMenu(){ + let children = this.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let item = children[i]; + this.menu.box.remove_child(item); + } + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + for (let i = 0; i < appList.length; i++) { + let app = appList[i]; + let item = this.applicationsMap.get(app); + if(item.actor.get_parent()){ + item.actor.get_parent().remove_child(item.actor); + } + if (!item.actor.get_parent()) { + this.menu.box.add_child(item.actor); + } + } + } + + _setOpenState(open){ + if(this.isSimpleMenuItem && open){ + this._menuLayout.activeCategory = this._name; + Utils.activateCategory(this._category, this._menuLayout, this, true); + } + else if(open) + this.loadMenu(); + + this.setSubmenuShown(open); + } +}); + +// Place Info class +var PlaceInfo = class Arc_Menu_PlaceInfo { + constructor(file, name, icon) { + this.file = file; + this.name = name ? name : this._getFileName(); + this.icon = icon ? icon : null; + this.gicon = icon ? null : this.getIcon(); + } + + launch(timestamp) { + let context = global.create_app_launch_context(timestamp, -1); + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(this._getFileName()), e.message); + reject(e); + } + }); + }); + } + + getIcon() { + try { + let info = this.file.query_info('standard::symbolic-icon', 0, null); + return info.get_symbolic_icon(); + + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!this.file.is_native()) { + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + return this.file.get_basename(); + } + } + } + + destroy(){ + } +}; +Signals.addSignalMethods(PlaceInfo.prototype); + +// Menu Place Shortcut item class +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem extends ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info, displayType, isContainedInCategory) { + super._init(menuLayout); + this._menuLayout = menuLayout; + this._displayType = displayType; + this._info = info; + this._settings = menuLayout._settings; + this.isContainedInCategory = isContainedInCategory; + this.hasContextMenu = true; + + this.label = new St.Label({ + text: _(info.name), + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + if(this._displayType === Constants.DisplayType.BUTTON){ + this.style_class = 'popup-menu-item arc-menu-button'; + this.remove_child(this._ornamentLabel); + this.x_expand = this.y_expand = false; + this.x_align = this.y_align = Clutter.ActorAlign.CENTER; + } + else{ + this.add_child(this.label); + } + + this._changedId = this._info.connect('changed', this._propertiesChanged.bind(this)); + } + + createIcon(){ + let iconSizeEnum; + if(this.isContainedInCategory) + iconSizeEnum = this._settings.get_enum('menu-item-icon-size'); + else + iconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + + const LayoutProps = this._menuLayout.layoutProperties; + let defaultIconSize = this.isContainedInCategory ? LayoutProps.DefaultApplicationIconSize : LayoutProps.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(iconSizeEnum, defaultIconSize); + + if(this._displayType === Constants.DisplayType.BUTTON){ + let defaultIconSize = LayoutProps.DefaultButtonsIconSize; + const IconSizeEnum = this._settings.get_enum('button-item-icon-size'); + iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + } + + return new St.Icon({ + gicon: this._info.gicon ? this._info.gicon : this._info.icon, + icon_size: iconSize, + }); + } + + _onDestroy() { + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = null; + } + if(this._info) + this._info.destroy(); + super._onDestroy(); + } + + popupContextMenu(){ + if(this.tooltip) + this.tooltip.hide(); + if(!this._app && !this._path) + return; + + if(this.contextMenu === undefined){ + this.contextMenu = new ApplicationContextMenu(this.actor, this._app, this._menuLayout); + if(this._path) + this.contextMenu.path = this._path; + if(this._displayType === Constants.DisplayType.GRID) + this.contextMenu.centerBoxPointerPosition(); + } + if(!this.contextMenu.isOpen) + this.contextMenu.rebuildItems(); + this.contextMenu.toggle(); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this.createIcon(); + if(this.label) + this.label.text = info.name; + } +}); + +var SearchBox = GObject.registerClass({ +Signals: { + 'search-changed': { param_types: [GObject.TYPE_STRING] }, + 'entry-key-focus-in': { }, + 'entry-key-press': { param_types: [Clutter.Event.$gtype] }, +},}, +class Arc_Menu_SearchBox extends St.Entry { + _init(menuLayout) { + super._init({ + hint_text: _("Search…"), + track_hover: true, + can_focus: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + name: "ArcSearchEntry" + }); + this.searchResults = menuLayout.searchResults; + this._settings = menuLayout._settings; + this.triggerSearchChangeEvent = true; + + const IconSizeEnum = this._settings.get_enum('misc-item-icon-size'); + let iconSize = Utils.getIconSize(IconSizeEnum, Constants.EXTRA_SMALL_ICON_SIZE); + + this._findIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-find-symbolic', + icon_size: iconSize + }); + + this._clearIcon = new St.Icon({ + style_class: 'search-entry-icon', + icon_name: 'edit-clear-symbolic', + icon_size: iconSize + }); + + this.set_primary_icon(this._findIcon); + + this._text = this.get_clutter_text(); + this._textChangedId = this._text.connect('text-changed', this._onTextChanged.bind(this)); + this._keyPressId = this._text.connect('key-press-event', this._onKeyPress.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-in', this._onKeyFocusIn.bind(this)); + this._keyFocusInId = this._text.connect('key-focus-out', this._onKeyFocusOut.bind(this)); + this._searchIconClickedId = this.connect('secondary-icon-clicked', () => this.clear()); + this.connect('destroy', this._onDestroy.bind(this)); + } + + updateStyle(removeBorder){ + let style = this.style; + this.style = style.replace("border-width: 0;", ""); + if(removeBorder) + this.style += 'border-width: 0;'; + } + + get entryBox(){ + return this; + } + + get actor(){ + return this; + } + + getText() { + return this.get_text(); + } + + setText(text) { + this.set_text(text); + } + + clearWithoutSearchChangeEvent(){ + this.triggerSearchChangeEvent = false; + this.set_text(''); + this.triggerSearchChangeEvent = true; + } + + hasKeyFocus() { + return this.contains(global.stage.get_key_focus()); + } + + clear() { + this.set_text(''); + } + + isEmpty() { + return this.get_text() == ''; + } + + _onKeyFocusOut(){ + if(!this.isEmpty()){ + this.add_style_pseudo_class('focus'); + return Clutter.EVENT_STOP; + } + } + + _onTextChanged() { + let searchString = this.get_text(); + if(!this.isEmpty()){ + if(!this.hasKeyFocus()) + this.grab_key_focus(); + if (!this.searchResults.getTopResult()?.has_style_pseudo_class("active")) + this.searchResults.getTopResult()?.add_style_pseudo_class("active") + this.add_style_pseudo_class('focus'); + this.set_secondary_icon(this._clearIcon); + } + else{ + if(!this.hasKeyFocus()) + this.remove_style_pseudo_class('focus'); + this.set_secondary_icon(null); + } + + if(this.triggerSearchChangeEvent) + this.emit('search-changed', searchString); + } + + _onKeyPress(actor, event) { + let symbol = event.get_key_symbol(); + if (symbol == Clutter.KEY_Return || + symbol == Clutter.KEY_KP_Enter) { + if (!this.isEmpty()) { + if (this.searchResults.getTopResult()) { + this.searchResults.getTopResult().activate(event); + } + } + return Clutter.EVENT_STOP; + } + this.emit('entry-key-press', event); + return Clutter.EVENT_PROPAGATE; + } + + _onKeyFocusIn() { + this.add_style_pseudo_class('focus'); + this.emit('entry-key-focus-in'); + return Clutter.EVENT_PROPAGATE; + } + + _onDestroy() { + if (this._textChangedId) { + this._text.disconnect(this._textChangedId); + this._textChangedId = null; + } + if (this._keyPressId) { + this._text.disconnect(this._keyPressId); + this._keyPressId = null; + } + if (this._keyFocusInId) { + this._text.disconnect(this._keyFocusInId); + this._keyFocusInId = null; + } + if(this._searchIconClickedId){ + this.disconnect(this._searchIconClickedId); + this._searchIconClickedId = null; + } + } +}); + +/** + * This class is responsible for the appearance of the menu button. + */ +var MenuButtonWidget = class Arc_Menu_MenuButtonWidget{ + constructor() { + this.actor = new St.BoxLayout({ + style_class: 'panel-status-menu-box', + pack_start: false + }); + this._arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + this._arrowIcon.add_style_class_name('arc-menu-arrow'); + + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + reactive: true, + }); + this._label = new St.Label({ + text: _("Applications"), + y_expand: true, + style_class: 'arc-menu-text', + y_align: Clutter.ActorAlign.CENTER, + }); + + this.actor.add_child(this._icon); + this.actor.add_child(this._label); + this.actor.add_child(this._arrowIcon); + } + + setActiveStylePseudoClass(enable){ + if(enable){ + this._arrowIcon.add_style_pseudo_class('active'); + this._icon.add_style_pseudo_class('active'); + this._label.add_style_pseudo_class('active'); + } + else{ + this._arrowIcon.remove_style_pseudo_class('active'); + this._icon.remove_style_pseudo_class('active'); + this._label.remove_style_pseudo_class('active'); + } + } + + updateArrowIconSide(side){ + let iconName; + switch (side) { + case St.Side.TOP: + iconName = 'pan-down-symbolic'; + break; + case St.Side.RIGHT: + iconName = 'pan-start-symbolic'; + break; + case St.Side.BOTTOM: + iconName = 'pan-up-symbolic'; + break; + case St.Side.LEFT: + iconName = 'pan-end-symbolic'; + break; + } + this._arrowIcon.icon_name = iconName; + } + + getPanelLabel() { + return this._label; + } + + getPanelIcon() { + return this._icon; + } + + showArrowIcon() { + if (!this.actor.contains(this._arrowIcon)) { + this.actor.add_child(this._arrowIcon); + } + } + + hideArrowIcon() { + if (this.actor.contains(this._arrowIcon)) { + this.actor.remove_child(this._arrowIcon); + } + } + + showPanelIcon() { + if (!this.actor.contains(this._icon)) { + this.actor.add_child(this._icon); + } + } + + hidePanelIcon() { + if (this.actor.contains(this._icon)) { + this.actor.remove_child(this._icon); + } + } + + showPanelText() { + if (!this.actor.contains(this._label)) { + this.actor.add_child(this._label); + } + } + + hidePanelText() { + this._label.style = ''; + if (this.actor.contains(this._label)) { + this.actor.remove_child(this._label); + } + } + + setPanelTextStyle(style){ + this._label.style = style; + } +}; + +var DashMenuButtonWidget = class Arc_Menu_DashMenuButtonWidget{ + constructor(menuButton, settings) { + this._menuButton = menuButton; + this._settings = settings; + this.actor = new St.Button({ + style_class: 'show-apps', + track_hover: true, + can_focus: true, + toggle_mode: false, + reactive: false + }); + this.actor._delegate = this; + this.icon = new imports.ui.iconGrid.BaseIcon(_("ArcMenu"), + { setSizeManually: true, + showLabel: false, + createIcon: this._createIcon.bind(this) }); + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + icon_size: 15, + track_hover:true, + reactive: true + }); + this.icon._delegate = this.actor; + this._labelText = _("ArcMenu"); + this.label = new St.Label({ style_class: 'dash-label' }); + this.label.hide(); + Main.layoutManager.addChrome(this.label); + this.label_actor = this.label; + this.actor.set_child(this.icon); + + this.child = this.actor; + } + showLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.actor.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1; + let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let x, y, xOffset, yOffset; + + let position = this._menuButton._panel._settings.get_enum('dock-position'); + this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); + let labelOffset = node.get_length('-x-offset'); + switch (position) { + case St.Side.LEFT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = stageX + this.actor.get_width() + xOffset; + break; + case St.Side.RIGHT: + yOffset = Math.floor((itemHeight - labelHeight) / 2); + y = stageY + yOffset; + xOffset = labelOffset; + x = Math.round(stageX) - labelWidth - xOffset; + break; + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + case St.Side.BOTTOM: + yOffset = labelOffset; + y = stageY - labelHeight - yOffset; + xOffset = Math.floor((itemWidth - labelWidth) / 2); + x = stageX + xOffset; + break; + } + + // keep the label inside the screen border + // Only needed fot the x coordinate. + + // Leave a few pixel gap + let gap = 5; + let monitor = Main.layoutManager.findMonitorForActor(this.actor); + if (x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if (x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth - (monitor.x + monitor.width) + gap; + + this.label.remove_all_transitions(); + this.label.set_position(x, y); + this.label.ease({ + opacity: 255, + duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD + }); + } + hideLabel() { + this.label.ease({ + opacity: 0, + duration: Dash.DASH_ITEM_LABEL_HIDE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => this.label.hide() + }); + } + _createIcon(size) { + this._icon = new St.Icon({ + icon_name: 'start-here-symbolic', + style_class: 'arc-menu-icon', + track_hover:true, + icon_size: size, + reactive: true + }); + let path = this._settings.get_string('custom-menu-button-icon'); + let iconString = Utils.getMenuButtonIcon(this._settings, path); + this._icon.set_gicon(Gio.icon_new_for_string(iconString)); + + return this._icon; + } + getPanelIcon() { + return this._icon; + } +}; + +var WorldClocksSection = GObject.registerClass(class Arc_Menu_WorldClocksSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this._clock = new imports.gi.GnomeDesktop.WallClock(); + this._clockNotifyId = 0; + + this._locations = []; + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._grid = new St.Widget({ style_class: 'world-clocks-grid', + x_expand: true, + layout_manager: layout }); + layout.hookup_style(this._grid); + + this.add_child(this._grid); + + this._clocksApp = null; + this._clocksProxy = new ClocksProxy( + Gio.DBus.session, + 'org.gnome.clocks', + '/org/gnome/clocks', + this._onProxyReady.bind(this), + null /* cancellable */, + Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES); + + this._clockSettings = new Gio.Settings({ + schema_id: 'org.gnome.shell.world-clocks', + }); + this.clocksChangedID = this._clockSettings.connect('changed', this._clocksChanged.bind(this)); + this._clocksChanged(); + + this._appSystem = Shell.AppSystem.get_default(); + this.syncID = this._appSystem.connect('installed-changed', + this._sync.bind(this)); + this._sync(); + } + + _onDestroy(){ + if(this.syncID){ + this._appSystem.disconnect(this.syncID); + this.syncID = null; + } + if(this.clocksChangedID){ + this._clockSettings.disconnect(this.clocksChangedID); + this.clocksChangedID = null; + } + if(this.clocksProxyID){ + this._clocksProxy.disconnect(this.clocksProxyID); + this.clocksProxyID = null; + } + if (this._clockNotifyId){ + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = null; + } + } + + activate(event) { + super.activate(event); + if (this._clocksApp){ + this._clocksApp.activate(); + } + } + + _sync() { + this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); + this.visible = this._clocksApp != null; + } + + _clocksChanged() { + this._grid.destroy_all_children(); + this._locations = []; + + let world = imports.gi.GWeather.Location.get_world(); + let clocks = this._clockSettings.get_value('locations').deep_unpack(); + for (let i = 0; i < clocks.length; i++) { + let l = world.deserialize(clocks[i]); + if (l && l.get_timezone() != null) + this._locations.push({ location: l }); + } + + this._locations.sort((a, b) => { + return a.location.get_timezone().get_offset() - + b.location.get_timezone().get_offset(); + }); + + let layout = this._grid.layout_manager; + let title = this._locations.length == 0 + ? _("Add world clocks…") + : _("World Clocks"); + let header = new St.Label({ x_align: Clutter.ActorAlign.START, + text: title }); + header.style = "font-weight: bold;"; + layout.attach(header, 0, 0, 2, 1); + this.label_actor = header; + + let localOffset = GLib.DateTime.new_now_local().get_utc_offset(); + + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i].location; + + let name = l.get_city_name() || l.get_name(); + let label = new St.Label({ text: name, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true }); + label.style = "font-weight: normal; font-size: 0.9em;"; + let time = new St.Label(); + time.style = "font-feature-settings: \"tnum\"; font-size: 1.2em;"; + let otherOffset = this._getTimeAtLocation(l).get_utc_offset(); + let offset = (otherOffset - localOffset) / GLib.TIME_SPAN_HOUR; + let fmt = Math.trunc(offset) == offset ? '%s%.0f' : '%s%.1f'; + let prefix = offset >= 0 ? '+' : '-'; + let tz = new St.Label({ text: fmt.format(prefix, Math.abs(offset)), + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER }); + tz.style = "font-feature-settings: \"tnum\"; font-size: 0.9em;"; + if (this._grid.text_direction == Clutter.TextDirection.RTL) { + layout.attach(tz, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(label, 2, i + 1, 1, 1); + } else { + layout.attach(label, 0, i + 1, 1, 1); + layout.attach(time, 1, i + 1, 1, 1); + layout.attach(tz, 2, i + 1, 1, 1); + } + + this._locations[i].actor = time; + } + + if (this._grid.get_n_children() > 1) { + if (!this._clockNotifyId) { + this._clockNotifyId = + this._clock.connect('notify::clock', this._updateLabels.bind(this)); + } + this._updateLabels(); + } else { + if (this._clockNotifyId) + this._clock.disconnect(this._clockNotifyId); + this._clockNotifyId = 0; + } + } + + _getTimeAtLocation(location) { + let tz = GLib.TimeZone.new(location.get_timezone().get_tzid()); + return GLib.DateTime.new_now(tz); + } + + _updateLabels() { + for (let i = 0; i < this._locations.length; i++) { + let l = this._locations[i]; + let now = this._getTimeAtLocation(l.location); + l.actor.text = Util.formatTime(now, { timeOnly: true }); + } + } + + _onProxyReady(proxy, error) { + if (error) { + log(`Failed to create GNOME Clocks proxy: ${error}`); + return; + } + + this.clocksProxyID = this._clocksProxy.connect('g-properties-changed', + this._onClocksPropertiesChanged.bind(this)); + this._onClocksPropertiesChanged(); + } + + _onClocksPropertiesChanged() { + if (this._clocksProxy.g_name_owner == null) + return; + + this._clockSettings.set_value('locations', + new GLib.Variant('av', this._clocksProxy.Locations)); + } +}); + +var WeatherSection = GObject.registerClass(class Arc_Menu_WeatherSection extends ArcMenuButtonItem { + _init(menuLayout) { + super._init(menuLayout, null, null); + + this.x_expand = true; + this.x_align = Clutter.ActorAlign.FILL; + this._weatherClient = new imports.misc.weather.WeatherClient(); + + let box = new St.BoxLayout({ + vertical: true, + x_expand: true, + }); + + this.add_child(box); + + let titleBox = new St.BoxLayout({ }); + let label = new St.Label({ + x_align: Clutter.ActorAlign.START, + x_expand: true, + y_align: Clutter.ActorAlign.END, + text: _('Weather'), + }) + label.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(label); + box.add_child(titleBox); + + this._titleLocation = new St.Label({ + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.END, + }); + this._titleLocation.style = "font-weight: bold; padding-bottom: 5px;"; + titleBox.add_child(this._titleLocation); + + let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); + this._forecastGrid = new St.Widget({ + style_class: 'weather-grid', + layout_manager: layout, + }); + layout.hookup_style(this._forecastGrid); + box.add_child(this._forecastGrid); + + this.syncID = this._weatherClient.connect('changed', this._sync.bind(this)); + this._sync(); + + } + _onDestroy(){ + if(this.syncID){ + this._weatherClient.disconnect(this.syncID); + this.syncID = null; + } + this._weatherClient = null; + } + vfunc_map() { + this._weatherClient.update(); + super.vfunc_map(); + } + + activate(event) { + super.activate(event); + this._weatherClient.activateApp(); + } + + _getInfos() { + let forecasts = this._weatherClient.info.get_forecast_list(); + + let now = GLib.DateTime.new_now_local(); + let current = GLib.DateTime.new_from_unix_local(0); + let infos = []; + for (let i = 0; i < forecasts.length; i++) { + const [valid, timestamp] = forecasts[i].get_value_update(); + if (!valid || timestamp === 0) + continue; // 0 means 'never updated' + + const datetime = GLib.DateTime.new_from_unix_local(timestamp); + if (now.difference(datetime) > 0) + continue; // Ignore earlier forecasts + + if (datetime.difference(current) < GLib.TIME_SPAN_HOUR) + continue; // Enforce a minimum interval of 1h + + if (infos.push(forecasts[i]) == 5) + break; // Use a maximum of five forecasts + + current = datetime; + } + return infos; + } + + _addForecasts() { + let layout = this._forecastGrid.layout_manager; + + let infos = this._getInfos(); + if (this._forecastGrid.text_direction == Clutter.TextDirection.RTL) + infos.reverse(); + + let col = 0; + infos.forEach(fc => { + const [valid_, timestamp] = fc.get_value_update(); + let timeStr = Util.formatTime(new Date(timestamp * 1000), { + timeOnly: true + }); + const [, tempValue] = fc.get_value_temp(imports.gi.GWeather.TemperatureUnit.DEFAULT); + const tempPrefix = tempValue >= 0 ? ' ' : ''; + + let time = new St.Label({ + text: timeStr, + x_align: Clutter.ActorAlign.CENTER, + }); + time.style = "font-size: 0.8em;" + let icon = new St.Icon({ + style_class: 'weather-forecast-icon', + icon_name: fc.get_symbolic_icon_name(), + x_align: Clutter.ActorAlign.CENTER, + x_expand: true, + }); + let temp = new St.Label({ + text: '%s%.0f°'.format(tempPrefix, tempValue), + x_align: Clutter.ActorAlign.CENTER, + }); + + temp.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + time.clutter_text.ellipsize = imports.gi.Pango.EllipsizeMode.NONE; + + layout.attach(time, col, 0, 1, 1); + layout.attach(icon, col, 1, 1, 1); + layout.attach(temp, col, 2, 1, 1); + col++; + }); + } + + _setStatusLabel(text) { + let layout = this._forecastGrid.layout_manager; + let label = new St.Label({ text }); + layout.attach(label, 0, 0, 1, 1); + } + + _updateForecasts() { + this._forecastGrid.destroy_all_children(); + + if (!this._weatherClient.hasLocation) { + this._setStatusLabel(_("Select a location…")); + return; + } + + let info = this._weatherClient.info; + let loc = info.get_location(); + if (loc.get_level() !== imports.gi.GWeather.LocationLevel.CITY && loc.has_coords()) { + let world = imports.gi.GWeather.Location.get_world(); + loc = world.find_nearest_city(...loc.get_coords()); + } + this._titleLocation.text = loc.get_name(); + + if (this._weatherClient.loading) { + this._setStatusLabel(_("Loading…")); + return; + } + + if (info.is_valid()) { + this._addForecasts(); + return; + } + + if (info.network_error()) + this._setStatusLabel(_("Go online for weather information")); + else + this._setStatusLabel(_("Weather information is currently unavailable")); + } + + _sync() { + this.visible = this._weatherClient.available; + + if (!this.visible) + return; + + this._titleLocation.visible = this._weatherClient.hasLocation; + + this._updateForecasts(); + } +}); + +function _isToday(date) { + let now = new Date(); + return now.getYear() == date.getYear() && + now.getMonth() == date.getMonth() && + now.getDate() == date.getDate(); +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js new file mode 100644 index 0000000..a0c1d16 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/arcmenu.js @@ -0,0 +1,456 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.buttonPressEventID = global.stage.connect("button-press-event", () => { + if(this.arcMenu.isOpen && this.backButton.visible){ + let event = Clutter.get_current_event(); + if(event.get_button() === 8){ + this.backButton.activate(event); + } + } + }); + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'left-panel' + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + this.leftBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBox.add_child(separator); + + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(this.backButton.actor); + + this.viewProgramsButton = new MW.ViewAllPrograms(this); + this.navigateBox.add_child(this.viewProgramsButton.actor); + this.leftBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 5px 10px 0px 10px;"; + this.leftBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length > 0){ + this.placesShortcuts = true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length > 0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw = true; + if(shouldDraw){ + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px; padding: 0px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + this.extraCategoriesLinksBox = new St.BoxLayout({ + vertical: true + }); + this.extraCategoriesLinksBox.hide(); + this.extraCategoriesSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + + let extraCategoriesLinksLocation = this._settings.get_enum('arcmenu-extra-categories-links-location'); + if(extraCategoriesLinksLocation === Constants.MenuItemLocation.TOP) + this.leftBox.insert_child_below(this.extraCategoriesLinksBox, this.applicationsScrollBox); + else + this.navigateBox.insert_child_above(this.extraCategoriesLinksBox, this.navigateBox.get_child_at_index(0)); + this.extraCategoriesLinksBox.add_child(this.extraCategoriesSeparator); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + _createExtraCategoriesLinks(){ + this.showExtraCategoriesLinksBox = false; + let extraCategories = this._settings.get_value("arcmenu-extra-categories-links").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + //Don't create extra categories quick links if + //the default menu view is the categories list + if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + return; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.ALL_PROGRAMS && shouldShow && defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + shouldShow = false; + if(shouldShow){ + let extraCategoryItem = this.categoryDirectories.get(categoryEnum); + if(!extraCategoryItem) + continue; + + this.showExtraCategoriesLinksBox = true; + if(extraCategoryItem.get_parent()) + extraCategoryItem.get_parent().remove_child(extraCategoryItem); + + this.extraCategoriesLinksBox.insert_child_below(extraCategoryItem, this.extraCategoriesSeparator); + } + } + if(this.showExtraCategoriesLinksBox) + this.extraCategoriesLinksBox.show(); + else + this.extraCategoriesLinksBox.hide(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.hasPinnedApps = true; + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + //If ArcMenu layout set to "Pinned Apps" default view and Extra Categories "Pinned Apps" is enabled, + //do not display "Pinned Apps" as an extra category -- Same for "Frequent Apps" + if(categoryEnum == Constants.CategoryType.PINNED_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + shouldShow = false; + if(categoryEnum == Constants.CategoryType.FREQUENT_APPS && shouldShow && defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + this._createExtraCategoriesLinks(); + } + + displayPinnedApps(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS){ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayAllApps(showBackButton = true){ + super.displayAllApps(); + this.viewProgramsButton.actor.hide(); + + if(showBackButton){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + } + else{ + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.backButton.actor.hide(); + } + } + + displayCategories(){ + let defaultMenuView = this._settings.get_enum('default-menu-view'); + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS || defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS){ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.hide(); + this.backButton.actor.show(); + } + else{ + this.extraCategoriesLinksBox.hide(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + } + + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view'); + + if(defaultMenuView === Constants.DefaultMenuView.PINNED_APPS) + this.displayPinnedApps(); + else if(defaultMenuView === Constants.DefaultMenuView.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuView.FREQUENT_APPS) + this.displayFrequentApps(); + else if(defaultMenuView === Constants.DefaultMenuView.ALL_PROGRAMS) + this.displayAllApps(false); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + if (this.showExtraCategoriesLinksBox) this.extraCategoriesLinksBox.show(); + this.viewProgramsButton.actor.show(); + this.backButton.actor.hide(); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let isContainedInCategory = false; + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST, null, isContainedInCategory); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + displayRecentFiles(){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + super.displayRecentFiles(); + } + + _clearActorsFromBox(box){ + //keep track of the previous category for the back button. + this.previousCategoryType = this.activeCategoryType; + super._clearActorsFromBox(box); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.extraCategoriesLinksBox.hide(); + this.backButton.actor.show(); + this.viewProgramsButton.actor.hide(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.buttonPressEventID){ + global.stage.disconnect(this.buttonPressEventID); + this.buttonPressEventID = null; + } + super.destroy() + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js new file mode 100644 index 0000000..dce09de --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/az.js @@ -0,0 +1,285 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 4, + RowSpacing: 4, + VerticalMainBox: true, + DefaultMenuWidth: 460, + DefaultIconGridStyle: 'LargeRectIconGrid', + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBoxStyle = "margin: 0px 0px 10px 0px; spacing: 0px; background-color: rgba(186, 196,201, 0.1); padding: 11px 5px;"+ + "border-color:rgba(186, 196,201, 0.2); border-bottom-width: 1px;"; + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.topBoxStyle + }); + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 5px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.subMainBox.add_child(this.topBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 12px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "margin: 0px 15px; spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.x_expand = true; + this.user.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + + let filesButton = new MW.ShortcutMenuItem(this, _("Files"), "system-file-manager", "org.gnome.Nautilus.desktop", Constants.DisplayType.BUTTON); + if(filesButton.shouldShow) + this.actionsBox.add_child(filesButton.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton) + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton) + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.IconGridSize = 42; + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + setDefaultMenuView(){ + this.setGridLayout(Constants.DisplayType.GRID, 4, 4); + this.layoutProperties.IconGridSize = 42; + super.setDefaultMenuView(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 3); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 4, 4, false); + } + + updateStyle(){ + super.updateStyle(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + const RoundBottomBorder = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + const RoundTopBorder = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + RoundBottomBorder; + this.topBox.style = this.topBoxStyle + RoundTopBorder; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.layoutProperties.IconGridSize = 26; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.subMainBox.insert_child_at_index(this.allAppsButton, 1); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.subMainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.subMainBox.contains(this.backButton)) + this.subMainBox.remove_child(this.backButton); + if(this.subMainBox.contains(this.allAppsButton)) + this.subMainBox.remove_child(this.allAppsButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.style = 'padding: 0px 15px 10px 15px;' + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.leaveButton.destroy(); + this.backButton.destroy(); + this.allAppsButton.destroy(); + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js new file mode 100644 index 0000000..af9d2c4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/baseMenuLayout.js @@ -0,0 +1,1128 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, GMenu, Gtk, Shell, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const appSys = Shell.AppSystem.get_default(); +const ArcSearch = Me.imports.search; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MenuLayouts = Me.imports.menulayouts; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const Utils = Me.imports.utils; + +//This class handles the core functionality of all the menu layouts. +//Each menu layout extends this class. +var BaseLayout = class { + constructor(menuButton, layoutProperties){ + this.menuButton = menuButton; + this._settings = menuButton._settings; + this.mainBox = menuButton.mainBox; + this.contextMenuManager = menuButton.contextMenuManager; + this.subMenuManager = menuButton.subMenuManager; + this.arcMenu = menuButton.arcMenu; + this.section = menuButton.section; + this.layout = this._settings.get_enum('menu-layout'); + this.layoutProperties = layoutProperties; + this._focusChild = null; + this.shouldLoadPinnedApps = true; + this.hasPinnedApps = false; + + if(this.layoutProperties.Search){ + this.searchResults = new ArcSearch.SearchResults(this); + this.searchBox = new MW.SearchBox(this); + this._searchBoxChangedId = this.searchBox.connect('search-changed', this._onSearchBoxChanged.bind(this)); + this._searchBoxKeyPressId = this.searchBox.connect('entry-key-press', this._onSearchBoxKeyPress.bind(this)); + } + + this._mainBoxKeyPressId = this.mainBox.connect('key-press-event', this._onMainBoxKeyPress.bind(this)); + + this._tree = new GMenu.Tree({ menu_basename: 'applications.menu' }); + this._treeChangedId = this._tree.connect('changed', () => this.reloadApplications()); + + this._gnomeFavoritesReloadID = AppFavorites.getAppFavorites().connect('changed', () => { + if(this.categoryDirectories){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem) + this._loadGnomeFavorites(categoryMenuItem); + } + }); + + this.mainBox.vertical = this.layoutProperties.VerticalMainBox; + + this.createLayout(); + this.updateStyle(); + } + + createLayout(){ + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.activeCategoryType = -1; + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.applicationsGrid = new St.Widget({ + x_expand: true, + x_align: this.layoutProperties.DisplayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.applicationsGrid); + } + + setDefaultMenuView(){ + if(this.layoutProperties.Search){ + this.searchBox.clearWithoutSearchChangeEvent(); + this.searchResults.setTerms([]); + } + + this._clearActorsFromBox(); + this.resetScrollBarPosition(); + } + + getColumnsFromActor(actor){ + let gridIconWidth = this.getActorWidthFromStyleClass(actor.name); + return this.getBestFitColumns(gridIconWidth); + } + + getColumnsFromGridIconSizeSetting(){ + let gridIconWidth; + let iconSizeEnum = this._settings.get_enum("menu-item-grid-icon-size"); + + if(iconSizeEnum === Constants.GridIconSize.DEFAULT) + gridIconWidth = this.getActorWidthFromStyleClass(this.layoutProperties.DefaultIconGridStyle); + else{ + Constants.GridIconInfo.forEach((info) => { + if(iconSizeEnum === info.ENUM){ + gridIconWidth = info.SIZE; + return; + } + }); + } + return this.getBestFitColumns(gridIconWidth); + } + + getBestFitColumns(gridIconWidth){ + let width = this.layoutProperties.MenuWidth; + let spacing = this.layoutProperties.ColumnSpacing; + let columns = Math.floor(width / (gridIconWidth + spacing)); + return columns; + } + + getActorWidthFromStyleClass(name){ + let size; + + Constants.GridIconInfo.forEach((info) => { + if(name === info.NAME){ + size = info.SIZE; + return; + } + }); + return size; + } + + resetScrollBarPosition(){ + let appsScrollBoxAdj; + + if(this.applicationsScrollBox){ + appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.categoriesScrollBox){ + appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.shortcutsScrollBox){ + appsScrollBoxAdj = this.shortcutsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + if(this.actionsScrollBox){ + appsScrollBoxAdj = this.actionsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + } + + reloadApplications(){ + //Don't reload applications if the menu is open. + //Instead, reload on menu-closed event. + //Prevents the menu from jumping to its default view + //when reloadApplications() is called. + if(this.arcMenu.isOpen){ + if(!this._menuClosedID){ + this._menuClosedID = this.arcMenu.connect('menu-closed', () => { + this.reloadApplications(); + if(this._menuClosedID){ + this.arcMenu.disconnect(this._menuClosedID); + this._menuClosedID = null; + } + }); + } + return; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + if(this.layoutProperties.Search){ + this.searchBox.updateStyle(this._settings.get_boolean('disable-searchbox-border')) + customStyle ? this.searchResults.setStyle('arc-menu-status-text') : this.searchResults.setStyle(''); + if(customStyle){ + this.searchBox.remove_style_class_name('default-search-entry'); + this.searchBox.add_style_class_name('arc-search-entry'); + } + else{ + this.searchBox.remove_style_class_name('arc-search-entry'); + this.searchBox.add_style_class_name('default-search-entry'); + } + } + } + + loadCategories(displayType = Constants.DisplayType.LIST){ + this.applicationsMap = new Map(); + this._tree.load_sync(); + let root = this._tree.get_root_directory(); + let iter = root.iter(); + let nextType; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.DIRECTORY) { + let dir = iter.get_directory(); + if (!dir.get_is_nodisplay()) { + let categoryId = dir.get_menu_id(); + let categoryMenuItem; + if(displayType === Constants.DisplayType.SIMPLE_CATEGORY) + categoryMenuItem = new MW.SimpleMenuItem(this, dir); + else if(displayType === Constants.DisplayType.SUBMENU_CATEGORY) + categoryMenuItem = new MW.CategorySubMenuItem(this, dir); + else + categoryMenuItem = new MW.CategoryMenuItem(this, dir, displayType); + this.categoryDirectories.set(categoryId, categoryMenuItem); + let foundRecentlyInstallApp = this._loadCategory(categoryId, dir); + categoryMenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + //Sort the App List Alphabetically + categoryMenuItem.appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + } + } + } + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.ALL_PROGRAMS); + if(categoryMenuItem){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + //Show Recently Installed Indicator on All Programs category + if(value.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + categoryMenuItem.appList = appList; + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FAVORITES); + if(categoryMenuItem){ + this._loadGnomeFavorites(categoryMenuItem); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + if(categoryMenuItem){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this.hasPinnedApps = true; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + if(categoryMenuItem){ + this._loadRecentFiles(categoryMenuItem); + } + + } + + _loadCategory(categoryId, dir, submenuItem) { + let iter = dir.iter(); + let nextType; + let foundRecentlyInstallApp = false; + let isLayoutSimple2 = this.layout === Constants.MenuLayout.SIMPLE_2; + while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { + if (nextType == GMenu.TreeItemType.ENTRY) { + let entry = iter.get_entry(); + let id; + try { + id = entry.get_desktop_file_id(); + } catch (e) { + continue; + } + let app = appSys.lookup_app(id); + if (!app) + app = new Shell.App({ app_info: entry.get_app_info() }); + if (app.get_app_info().should_show()){ + let item = this.applicationsMap.get(app); + if (!item) { + let isContainedInCategory = true; + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType, null, isContainedInCategory); + } + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled && item.isRecentlyInstalled) + foundRecentlyInstallApp = true; + if(!submenuItem){ + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(app); + this.applicationsMap.set(app, item); + } + else{ + submenuItem.applicationsMap.set(app, item); + } + } + } + else if (nextType == GMenu.TreeItemType.DIRECTORY) { + let subdir = iter.get_directory(); + if (!subdir.get_is_nodisplay()){ + if(this._settings.get_boolean('enable-sub-menus') && this.layoutProperties.DisplayType === Constants.DisplayType.LIST && !isLayoutSimple2){ + let submenuItem = this.applicationsMap.get(subdir); + if (!submenuItem) { + submenuItem = new MW.CategorySubMenuItem(this, subdir); + submenuItem._setParent(this.arcMenu); + let categoryMenuItem = this.categoryDirectories.get(categoryId); + categoryMenuItem.appList.push(subdir); + this.applicationsMap.set(subdir, submenuItem); + } + let recentlyInstallApp = this._loadCategory(categoryId, subdir, submenuItem); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + submenuItem.setRecentlyInstalledIndicator(foundRecentlyInstallApp); + } + else{ + let recentlyInstallApp = this._loadCategory(categoryId, subdir); + if(recentlyInstallApp) + foundRecentlyInstallApp = true; + } + } + } + } + return foundRecentlyInstallApp; + } + + setRecentlyInstalledIndicator(){ + let disabled = this._settings.get_boolean("disable-recently-installed-apps") + if(!disabled){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.setRecentlyInstalledIndicator(false); + for(let i = 0; i < categoryMenuItem.appList.length; i++){ + let item = this.applicationsMap.get(categoryMenuItem.appList[i]); + if(!item) + continue; + if(item instanceof MW.CategorySubMenuItem){ + item.setRecentlyInstalledIndicator(false); + for(let menuItem of item.applicationsMap.values()){ + if(menuItem.isRecentlyInstalled){ + item.setRecentlyInstalledIndicator(true); + break; + } + } + } + if(item.isRecentlyInstalled){ + categoryMenuItem.setRecentlyInstalledIndicator(true); + break; + } + } + } + } + } + + displayCategories(categoriesBox){ + if(!categoriesBox){ + categoriesBox = this.applicationsBox; + } + this._clearActorsFromBox(categoriesBox); + + this._futureActiveItem = false; + + for(let categoryMenuItem of this.categoryDirectories.values()){ + if(categoryMenuItem.get_parent()) + continue; + categoriesBox.add_child(categoryMenuItem.actor); + if(!this._futureActiveItem){ + this._futureActiveItem = categoryMenuItem; + } + } + + this.activeMenuItem = this._futureActiveItem; + } + + _loadGnomeFavorites(categoryMenuItem){ + let appList = AppFavorites.getAppFavorites().getFavorites(); + + //Show Recently Installed Indicator on GNOME favorites category + for(let i = 0; i < appList.length; i++){ + let item = this.applicationsMap.get(appList[i]); + if(item && item.isRecentlyInstalled && !categoryMenuItem.isRecentlyInstalled) + categoryMenuItem.setRecentlyInstalledIndicator(true); + } + + categoryMenuItem.appList = appList; + if(this.activeCategoryType === Constants.CategoryType.FAVORITES) + categoryMenuItem.displayAppList(); + } + + _loadRecentFiles(){ + if(!this.recentFilesManager) + this.recentFilesManager = new RecentFilesManager(); + } + + displayRecentFiles(box = this.applicationsBox, callback){ + const homeRegExp = new RegExp('^(' + GLib.get_home_dir() + ')'); + this._clearActorsFromBox(box); + this._futureActiveItem = false; + + this.recentFilesManager.filterRecentFiles(recentFile => { + let file = Gio.File.new_for_uri(recentFile.get_uri()); + let filePath = file.get_path(); + let name = recentFile.get_display_name(); + let icon = Gio.content_type_get_symbolic_icon(recentFile.get_mime_type()).to_string(); + let isContainedInCategory = true; + + let placeMenuItem = this.createMenuItem([name, icon, filePath], Constants.DisplayType.LIST, isContainedInCategory); + placeMenuItem._path = file.get_parent()?.get_path() // can be null + placeMenuItem.style = "padding-right: 15px;"; + placeMenuItem.description = recentFile.get_uri_display().replace(homeRegExp, '~'); + placeMenuItem.fileUri = recentFile.get_uri(); + + placeMenuItem._removeBtn = new MW.ArcMenuButtonItem(this, null, 'edit-delete-symbolic'); + placeMenuItem._removeBtn.toggleMenuOnClick = false; + placeMenuItem._removeBtn.x_align = Clutter.ActorAlign.END; + placeMenuItem._removeBtn.x_expand = true; + placeMenuItem._removeBtn.add_style_class_name("arcmenu-small-button"); + placeMenuItem._removeBtn.setIconSize(14); + placeMenuItem._removeBtn.connect('activate', () => { + try { + let recentManager = this.recentFilesManager.getRecentManager(); + recentManager.remove_item(placeMenuItem.fileUri); + } catch(err) { + log(err); + } + + placeMenuItem.cancelPopupTimeout(); + placeMenuItem.contextMenu?.close(); + box.remove_child(placeMenuItem); + placeMenuItem.destroy(); + }); + + placeMenuItem.add_child(placeMenuItem._removeBtn); + box.add_child(placeMenuItem); + + if(!this._futureActiveItem){ + this._futureActiveItem = placeMenuItem; + this.activeMenuItem = this._futureActiveItem; + } + + if(callback) + callback(); + }); + } + + _displayPlaces() { + var SHORTCUT_TRANSLATIONS = [_("Home"), _("Documents"), _("Downloads"), _("Music"), _("Pictures"), _("Videos"), _("Computer"), _("Network")]; + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem) + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadExtraPinnedApps(pinnedAppsArray, separatorIndex){ + let pinnedApps = pinnedAppsArray; + //if the extraPinnedApps array is empty, create a default list of apps. + if(!pinnedApps.length || !Array.isArray(pinnedApps)){ + pinnedApps = this._createExtraPinnedAppsList(); + } + + for(let i = 0;i < pinnedApps.length; i += 3){ + if(i === separatorIndex * 3 && i !== 0) + this._addSeparator(); + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2]], Constants.DisplayType.BUTTON, isContainedInCategory); + placeMenuItem.actor.x_expand = false; + placeMenuItem.actor.y_expand = false; + placeMenuItem.actor.y_align = Clutter.ActorAlign.CENTER; + placeMenuItem.actor.x_align = Clutter.ActorAlign.CENTER; + this.actionsBox.add_child(placeMenuItem.actor); + } + } + + createMenuItem(menuItemArray, displayType, isContainedInCategory){ + let placeInfo, placeMenuItem; + let command = menuItemArray[2]; + let app = Shell.AppSystem.get_default().lookup_app(command); + + if(command === "ArcMenu_Home"){ + let homePath = GLib.get_home_dir(); + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(homePath), _("Home")); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Computer"){ + placeInfo = new PlaceDisplay.RootInfo(); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Network"){ + placeInfo = new PlaceDisplay.PlaceInfo('network', Gio.File.new_for_uri('network:///'), _('Network'),'network-workgroup-symbolic'); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Software"){ + let software = Utils.findSoftwareManager(); + if(software) + placeMenuItem = new MW.ShortcutMenuItem(this, _("Software"), 'system-software-install-symbolic', software, displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Trash"){ + placeMenuItem = new MW.ShortcutMenuItem(this, _("Trash"), '', "ArcMenu_Trash", displayType, isContainedInCategory); + } + else if(command === Constants.ArcMenuSettingsCommand || command === "ArcMenu_Suspend" || command === "ArcMenu_LogOut" || command === "ArcMenu_PowerOff" + || command === "ArcMenu_Lock" || command === "ArcMenu_Restart" || command === "ArcMenu_HybridSleep" || command === "ArcMenu_Hibernate" || app){ + + placeMenuItem = new MW.ShortcutMenuItem(this, menuItemArray[0], menuItemArray[1], menuItemArray[2], displayType, isContainedInCategory); + } + else if(command === "ArcMenu_Recent"){ + let uri = "recent:///"; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_uri(uri), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + else if(command.startsWith("ArcMenu_")){ + let path = command.replace("ArcMenu_",''); + + if(path === "Documents") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS; + else if(path === "Downloads") + path = imports.gi.GLib.UserDirectory.DIRECTORY_DOWNLOAD; + else if(path === "Music") + path = imports.gi.GLib.UserDirectory.DIRECTORY_MUSIC; + else if(path === "Pictures") + path = imports.gi.GLib.UserDirectory.DIRECTORY_PICTURES; + else if(path === "Videos") + path = imports.gi.GLib.UserDirectory.DIRECTORY_VIDEOS; + + path = GLib.get_user_special_dir(path); + if (path !== null){ + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0])); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + } + else{ + let path = command; + placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _(menuItemArray[0]), (menuItemArray[1] !== "ArcMenu_Folder") ? Gio.icon_new_for_string(menuItemArray[1]) : null); + placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, displayType, isContainedInCategory); + } + return placeMenuItem; + } + + loadPinnedApps(){ + let pinnedApps = this._settings.get_strv('pinned-app-list'); + + this.pinnedAppsArray = null; + this.pinnedAppsArray = []; + + let categoryMenuItem = this.categoryDirectories ? this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS) : null; + let isContainedInCategory = categoryMenuItem ? true : false; + + for(let i = 0; i < pinnedApps.length; i += 3){ + if(i === 0 && pinnedApps[0] === "ArcMenu_WebBrowser") + this._updatePinnedAppsWebBrowser(pinnedApps); + + let pinnedAppsMenuItem = new MW.PinnedAppsMenuItem(this, pinnedApps[i], pinnedApps[i + 1], pinnedApps[i + 2], this.layoutProperties.DisplayType, isContainedInCategory); + pinnedAppsMenuItem.connect('saveSettings', ()=> { + let array = []; + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + array.push(this.pinnedAppsArray[i]._name); + array.push(this.pinnedAppsArray[i]._iconPath); + array.push(this.pinnedAppsArray[i]._command); + } + this._settings.set_strv('pinned-app-list',array); + }); + this.pinnedAppsArray.push(pinnedAppsMenuItem); + } + + if(categoryMenuItem){ + categoryMenuItem.appList = null; + categoryMenuItem.appList = []; + categoryMenuItem.appList = categoryMenuItem.appList.concat(this.pinnedAppsArray); + } + } + + _updatePinnedAppsWebBrowser(pinnedApps){ + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + if(pinnedApps[0] === "ArcMenu_WebBrowser"){ + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + + this._app = appSys.lookup_app(browserName); + if(this._app){ + pinnedApps[0] = this._app.get_name(); + pinnedApps[1] = ''; + pinnedApps[2] = this._app.get_id(); + } + else{ + pinnedApps.splice(0,3); + } + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + } + } + + displayPinnedApps(){ + this._clearActorsFromBox(); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + placesAddSeparator(id){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this._sections[id].add_child(separator); + } + + _redisplayPlaces(id) { + if(this._sections[id].get_n_children() > 0){ + this.bookmarksShorctus = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this._sections[id].destroy_all_children(); + } + this._createPlaces(id); + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + if(this.placesManager.get('network').length > 0) + this.networkDevicesShorctus = true; + if(this.placesManager.get('devices').length > 0) + this.externalDevicesShorctus=true; + if(this.placesManager.get('bookmarks').length > 0) + this.bookmarksShorctus = true; + + if(this._settings.get_boolean('show-bookmarks')){ + if(id === 'bookmarks' && places.length > 0){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + //create a separator if bookmark and software shortcut are both shown + if(this.bookmarksShorctus && this.softwareShortcuts){ + this.placesAddSeparator(id); + } + } + } + if(this._settings.get_boolean('show-external-devices')){ + if(id === 'devices'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if((this.externalDevicesShorctus && !this.networkDevicesShorctus) && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + if(id === 'network'){ + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i]); + this._sections[id].add_child(item); + } + if(this.networkDevicesShorctus && (this.bookmarksShorctus || this.softwareShortcuts)) + this.placesAddSeparator(id); + } + } + } + + setActiveCategory(category, setActive = true){ + this._futureActiveItem = category; + this.activeMenuItem = category; + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()) + categoryMenuItem.appList.push(mostUsed[i]); + } + } + + _clearActorsFromBox(box){ + this.recentFilesManager?.cancelCurrentQueries(); + if(!box){ + box = this.applicationsBox; + this.activeCategoryType = -1; + } + let parent = box.get_parent(); + if(parent instanceof St.ScrollView){ + let scrollBoxAdj = parent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = box.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + box.remove_child(actor); + } + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _displayAppList(apps, category, grid){ + this.activeCategoryType = category; + grid.remove_all_children(); + let count = 0; + let top = -1; + let left = 0; + this._futureActiveItem = false; + let currentCharacter; + let alphabetizeAllPrograms = this._settings.get_boolean("alphabetize-all-programs") && this.layoutProperties.DisplayType === Constants.DisplayType.LIST; + let rtl = this.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + let columns = -1; + + for (let i = 0; i < apps.length; i++) { + let app = apps[i]; + let item; + let shouldShow = true; + + if(category === Constants.CategoryType.PINNED_APPS || category === Constants.CategoryType.HOME_SCREEN){ + item = app; + if(!item.shouldShow) + shouldShow = false; + } + else{ + item = this.applicationsMap.get(app); + if (!item) { + item = new MW.ApplicationMenuItem(this, app, this.layoutProperties.DisplayType); + this.applicationsMap.set(app, item); + } + } + + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + + if(shouldShow){ + if(columns === -1){ + if(grid.layout_manager.forceGridColumns) + columns = grid.layout_manager.forceGridColumns; + else if(this.layoutProperties.DisplayType === Constants.DisplayType.GRID) + columns = this.getColumnsFromActor(item); + else + columns = 1; + grid.layout_manager.gridColumns = columns; + } + + if(!rtl && (count % columns === 0)){ + top++; + left = 0; + } + else if(rtl && (left === 0)){ + top++; + left = columns; + } + + if(alphabetizeAllPrograms && category === Constants.CategoryType.ALL_PROGRAMS){ + if(currentCharacter !== app.get_name().charAt(0).toLowerCase()){ + currentCharacter = app.get_name().charAt(0).toLowerCase(); + + let label = this._createLabelWithSeparator(currentCharacter.toUpperCase()); + grid.layout_manager.attach(label, left, top, 1, 1); + top++; + } + } + + grid.layout_manager.attach(item, left, top, 1, 1); + item.gridLocation = [left, top]; + + if(item instanceof MW.CategorySubMenuItem){ + top++; + grid.layout_manager.attach(item.menu.actor, left, top, 1, 1); + } + + if(!rtl) + left++; + else if(rtl) + left--; + count++; + + if(!this._futureActiveItem && grid === this.applicationsGrid){ + this._futureActiveItem = item; + } + } + } + if(this.applicationsBox && !this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + if(this._futureActiveItem) + this.activeMenuItem = this._futureActiveItem; + } + + displayAllApps(){ + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + } + + get activeMenuItem() { + return this._activeMenuItem; + } + + set activeMenuItem(item) { + let itemChanged = item !== this._activeMenuItem; + if(itemChanged){ + this._activeMenuItem = item; + if(this.arcMenu.isOpen && item && this.layoutProperties.SupportsCategoryOnHover) + item.grab_key_focus(); + else if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + if(this.layout === Constants.MenuLayout.LAUNCHER && !this.layoutProperties.StandaloneRunner && item) + this.createActiveSearchItemPanel(item); + } + } + + _onSearchBoxChanged(searchBox, searchString) { + if(searchBox.isEmpty()){ + this.searchResults.hide(); + this.setDefaultMenuView(); + } + else{ + this._clearActorsFromBox(); + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.show(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms(searchString.split(/\s+/)); + } + } + + _onSearchBoxKeyPress(searchBox, event) { + let symbol = event.get_key_symbol(); + switch (symbol) { + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_Up) + return Clutter.EVENT_PROPAGATE; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + let cursorPosition = this.searchBox.clutter_text.get_cursor_position(); + + if(cursorPosition === Constants.CaretPosition.END && symbol === Clutter.KEY_Right) + cursorPosition = Constants.CaretPosition.END; + else if(cursorPosition === Constants.CaretPosition.START && symbol === Clutter.KEY_Left) + cursorPosition = Constants.CaretPosition.START; + else + cursorPosition = Constants.CaretPosition.MIDDLE; + + if(cursorPosition === Constants.CaretPosition.END || cursorPosition === Constants.CaretPosition.START){ + let navigateActor = this.activeMenuItem; + if(this.searchResults.hasActiveResult()){ + navigateActor = this.searchResults.getTopResult(); + if(navigateActor.has_style_pseudo_class("active")){ + navigateActor.grab_key_focus(); + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + navigateActor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + if(!navigateActor) + return Clutter.EVENT_PROPAGATE; + return this.mainBox.navigate_focus(navigateActor, direction, false); + } + return Clutter.EVENT_PROPAGATE; + default: + return Clutter.EVENT_PROPAGATE; + } + } + + _onMainBoxKeyPress(actor, event) { + if (event.has_control_modifier()) { + if(this.searchBox) + this.searchBox.grab_key_focus(); + return Clutter.EVENT_PROPAGATE; + } + + let symbol = event.get_key_symbol(); + let unicode = Clutter.keysym_to_unicode(symbol); + + switch (symbol) { + case Clutter.KEY_BackSpace: + if(this.searchBox && !this.searchBox.hasKeyFocus() && !this.searchBox.isEmpty()){ + this.searchBox.grab_key_focus(); + let newText = this.searchBox.getText().slice(0, -1); + this.searchBox.setText(newText); + } + return Clutter.EVENT_PROPAGATE; + case Clutter.KEY_Up: + case Clutter.KEY_Down: + case Clutter.KEY_Left: + case Clutter.KEY_Right: + let direction; + if (symbol === Clutter.KEY_Down) + direction = St.DirectionType.DOWN; + if (symbol === Clutter.KEY_Right) + direction = St.DirectionType.RIGHT + if (symbol === Clutter.KEY_Up) + direction = St.DirectionType.UP; + if (symbol === Clutter.KEY_Left) + direction = St.DirectionType.LEFT; + + if(this.layoutProperties.Search && this.searchBox.hasKeyFocus() && this.searchResults.hasActiveResult() && this.searchResults.get_parent()){ + if(this.searchResults.getTopResult().has_style_pseudo_class("active")){ + this.searchResults.getTopResult().actor.grab_key_focus(); + return actor.navigate_focus(global.stage.key_focus, direction, false); + } + this.searchResults.getTopResult().actor.grab_key_focus(); + return Clutter.EVENT_STOP; + } + else if(global.stage.key_focus === this.mainBox && symbol === Clutter.KEY_Up){ + return actor.navigate_focus(global.stage.key_focus, direction, true); + } + else if(global.stage.key_focus === this.mainBox){ + this.activeMenuItem.grab_key_focus(); + return Clutter.EVENT_STOP; + } + + return actor.navigate_focus(global.stage.key_focus, direction, false); + case Clutter.KEY_Tab: + case Clutter.KEY_KP_Tab: + case Clutter.KEY_KP_Enter: + case Clutter.KEY_Return: + case Clutter.KEY_Escape: + return Clutter.EVENT_PROPAGATE; + default: + if (unicode !== 0 && this.searchBox) { + global.stage.set_key_focus(this.searchBox.clutter_text); + let synthEvent = event.copy(); + synthEvent.set_source(this.searchBox.clutter_text); + this.searchBox.clutter_text.event(synthEvent, false); + } + } + return Clutter.EVENT_PROPAGATE; + } + + destroy(){ + if(this.recentFilesManager){ + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + } + + if(this._treeChangedId){ + this._tree.disconnect(this._treeChangedId); + this._treeChangedId = null; + this._tree = null; + } + + if(this.applicationsBox){ + if(this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.remove_child(this.applicationsGrid); + } + + if(this.network){ + this.network.destroy(); + this.networkMenuItem.destroy(); + } + + if(this.computer){ + this.computer.destroy(); + this.computerMenuItem.destroy(); + } + + if(this.placesManager){ + for(let id in this._sections){ + this._sections[id].get_children().forEach((child) =>{ + child.destroy(); + }); + }; + if(this.placeManagerUpdatedID){ + this.placesManager.disconnect(this.placeManagerUpdatedID); + this.placeManagerUpdatedID = null; + } + this.placesManager.destroy(); + this.placesManager = null + } + + if(this._searchBoxChangedId){ + this.searchBox?.disconnect(this._searchBoxChangedId); + this._searchBoxChangedId = null;; + } + if(this._searchBoxKeyPressId){ + this.searchBox?.disconnect(this._searchBoxKeyPressId); + this._searchBoxKeyPressId = null; + } + if(this._searchBoxKeyFocusInId){ + this.searchBox?.disconnect(this._searchBoxKeyFocusInId); + this._searchBoxKeyFocusInId = null; + } + + if(this.searchBox) + this.searchBox.destroy(); + + if(this.searchResults){ + this.searchResults.setTerms([]); + this.searchResults.destroy(); + this.searchResults = null; + } + + if (this._mainBoxKeyPressId) { + this.mainBox.disconnect(this._mainBoxKeyPressId); + this._mainBoxKeyPressId = null; + } + + if(this._gnomeFavoritesReloadID){ + AppFavorites.getAppFavorites().disconnect(this._gnomeFavoritesReloadID); + this._gnomeFavoritesReloadID = null; + } + + if(this.pinnedAppsArray){ + for(let i = 0; i < this.pinnedAppsArray.length; i++){ + this.pinnedAppsArray[i].destroy(); + } + this.pinnedAppsArray = null; + } + + if(this.applicationsMap){ + this.applicationsMap.forEach((value,key,map)=>{ + value.destroy(); + }); + this.applicationsMap = null; + } + + if(this.categoryDirectories){ + this.categoryDirectories.forEach((value,key,map)=>{ + value.destroy(); + }); + this.categoryDirectories = null; + } + + this.mainBox.destroy_all_children(); + } + + _createScrollBox(params){ + let scrollBox = new St.ScrollView(params); + let panAction = new Clutter.PanAction({ interpolate: false }); + panAction.connect('pan', (action) => { + this._blockActivateEvent = true; + this.onPan(action, scrollBox); + }); + panAction.connect('gesture-cancel',(action) => this.onPanEnd(action, scrollBox)); + panAction.connect('gesture-end', (action) => this.onPanEnd(action, scrollBox)); + scrollBox.add_action(panAction); + + scrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); + scrollBox.clip_to_allocation = true; + + return scrollBox; + } + + _createLabelWithSeparator(headerLabel){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.HEADER_LABEL, Constants.SeparatorAlignment.HORIZONTAL, headerLabel); + return separator; + } + + createLabelRow(title){ + let labelRow = new PopupMenu.PopupMenuItem(_(title), { + hover: false, + can_focus: false + }); + labelRow.actor.add_style_pseudo_class = () => { return false;}; + labelRow.label.style = 'font-weight: bold;'; + return labelRow; + } + + _keyFocusIn(actor) { + if (this._focusChild == actor) + return; + this._focusChild = actor; + Utils.ensureActorVisibleInScrollView(actor); + } + + onPan(action, scrollbox) { + let [dist_, dx_, dy] = action.get_motion_delta(0); + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + adjustment.value -= dy; + return false; + } + + onPanEnd(action, scrollbox) { + let velocity = -action.get_velocity(0)[2]; + let adjustment = scrollbox.get_vscroll_bar().get_adjustment(); + let endPanValue = adjustment.value + velocity * 2; + adjustment.value = endPanValue; + } +}; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js new file mode 100644 index 0000000..fefdcd6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/brisk.js @@ -0,0 +1,206 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus70' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.actionsBox.style = "padding: 5px 0px 0px 0px;" + this.leftBox.add_child(this.actionsBox); + + //create new section for Power, Lock, Logout, Suspend Buttons + this.sessionBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.sessionBox.style = "spacing: 6px;"; + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.sessionBox.add_child(powerButton); + } + } + this.leftBox.add_child(this.sessionBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + let pinnedApps = this._settings.get_strv('brisk-shortcuts-list'); + + for(let i = 0;i < pinnedApps.length; i += 3){ + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem([pinnedApps[i],pinnedApps[i+1], pinnedApps[i+2]], Constants.DisplayType.LIST, isContainedInCategory); + if(placeMenuItem){ + this.actionsBox.add_child(placeMenuItem.actor); + } + } + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js new file mode 100644 index 0000000..46107c5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/budgie.js @@ -0,0 +1,184 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * Budgie.js Layout Created By: MagneFire https://gitlab.com/MagneFire + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-bottom: 6px;"; + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + vertical: true, + style_class: 'right-panel-plus70', + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus70 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + // Disable horizontal scrolling, hide vertical scrollbar, but allow vertical scrolling. + this.applicationsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel-small ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + this.leftBox.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + if(this._settings.get_boolean('enable-activities-shortcut')){ + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(this.activities.actor); + this.leftBox.add_child(this.activitiesBox); + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MAX, Constants.SeparatorAlignment.HORIZONTAL); + separator.style += "margin-top: 6px;"; + this.mainBox.add_child(separator); + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px; margin: 0; spacing: 0;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js new file mode 100644 index 0000000..e0d862c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/chromebook.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive: true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js new file mode 100644 index 0000000..79de6aa --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/elementary.js @@ -0,0 +1,118 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + + this.subMainBox= new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START + }); + this.mainBox.add_child(this.subMainBox); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + reactive:true + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;" + this.mainBox.add_child(this.searchBox.actor); + } + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js new file mode 100644 index 0000000..1b3f548 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/eleven.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultMenuWidth: 650, + DefaultIconGridStyle: "MediumRectIconGrid", + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.style = "margin: 5px 15px 10px 15px;"; + + this.topBox.add_child(this.searchBox.actor); + this.mainBox.insert_child_at_index(this.topBox, 0); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + style: "padding-bottom: 10px;" + }); + this.applicationsScrollBox = this._createScrollBox({ + clip_to_allocation: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px; background-color:rgba(186, 196,201, 0.1); padding: 12px 25px;"+ + "border-color: rgba(186, 196,201, 0.2); border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true, + style: 'padding: 0px 25px;' + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 5, + column_homogeneous: true + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + layout.forceGridColumns = 2; + this.shortcutsBox.add_child(this.shortcutsGrid); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.actionsBox.add_child(this.user.actor); + + this.quickLinksBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER, + vertical: false, + style: 'spacing: 10px;' + }); + let path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Downloads")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path !== null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.quickLinksBox.add_child(placeMenuItem.actor); + } + + let settingsButton = new MW.SettingsButton(this); + this.quickLinksBox.add_child(settingsButton.actor); + + this.leaveButton = new MW.LeaveButton(this); + this.quickLinksBox.add_child(this.leaveButton.actor); + + this.actionsBox.add_child(this.quickLinksBox); + + this.backButton = this._createNavigationButtons(_("All Apps"), MW.BackButton); + this.allAppsButton = this._createNavigationButtons(_("Pinned"), MW.AllAppsButton); + this.frequentAppsHeader = this._createNavigationButtons(_("Frequent"), null); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + + this.disableFrequentAppsID = this._settings.connect("changed::eleven-disable-frequent-apps", () => this.setDefaultMenuView()); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + } + + loadFrequentApps(){ + this.frequentAppsList = []; + + if(this._settings.get_boolean("eleven-disable-frequent-apps")) + return; + + let labelRow = this.createLabelRow(_("Frequent")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + + if(mostUsed.length < 1) + return; + + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + + const MaxItems = 8; + if(this.frequentAppsList.length > MaxItems) + this.frequentAppsList.splice(MaxItems); + } + + setDefaultMenuView(){ + this.layoutProperties.IconGridSize = 34; + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + super.setDefaultMenuView(); + this.loadFrequentApps(); + this.activeCategory = _("Pinned"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayAllApps(){ + this.activeCategory = _("All Apps"); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + + this.setGridLayout(Constants.DisplayType.LIST, 1, 5); + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this._clearActorsFromBox(); + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0, false); + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + setGridLayout(displayType, columns, spacing, setStyle = true){ + if(setStyle){ + this.applicationsGrid.x_align = displayType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER; + displayType === Constants.DisplayType.LIST ? this.applicationsBox.add_style_class_name('margin-box') : this.applicationsBox.remove_style_class_name('margin-box'); + } + this.applicationsGrid.layout_manager.column_spacing = spacing; + this.applicationsGrid.layout_manager.row_spacing = spacing; + this.layoutProperties.DisplayType = displayType; + } + + loadCategories() { + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + displayPinnedApps() { + this._clearActorsFromBox(this.applicationsBox); + this.activeCategory = _("Pinned"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + + if(this.frequentAppsList.length > 0 && !this._settings.get_boolean("eleven-disable-frequent-apps")){ + this.activeCategory = _("Frequent"); + this.setGridLayout(Constants.DisplayType.GRID, 2, 0); + this._displayAppList(this.frequentAppsList, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + this.setGridLayout(Constants.DisplayType.GRID, 6, 0); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + } + else if(this.applicationsBox.contains(this.shortcutsBox)){ + this.applicationsBox.remove_child(this.shortcutsBox); + } + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + this._hideNavigationButtons(); + + if(category === Constants.CategoryType.PINNED_APPS){ + this.applicationsBox.insert_child_at_index(this.allAppsButton, 0); + } + else if(category === Constants.CategoryType.HOME_SCREEN){ + this.applicationsBox.insert_child_at_index(this.frequentAppsHeader, 2); + } + else if(category === Constants.CategoryType.ALL_PROGRAMS){ + this.mainBox.insert_child_at_index(this.backButton, 1); + } + } + + _hideNavigationButtons(){ + if(this.mainBox.contains(this.backButton)) + this.mainBox.remove_child(this.backButton); + } + + _createNavigationButtons(buttonTitle, ButtonClass){ + let navButton = this.createLabelRow(buttonTitle); + navButton.remove_child(navButton._ornamentLabel); + navButton.label.y_align = Clutter.ActorAlign.CENTER; + navButton.label.style = 'padding: 15px 0px;'; + navButton.style = 'padding: 0px 25px;' + if(ButtonClass) + navButton.add_child(new ButtonClass(this)); + return navButton; + } + + _onSearchBoxChanged(searchBox, searchString){ + this.applicationsBox.remove_style_class_name('margin-box'); + if(!searchBox.isEmpty()) + this._hideNavigationButtons(); + super._onSearchBoxChanged(searchBox, searchString); + } + + destroy(){ + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + this.backButton.destroy(); + this.allAppsButton.destroy(); + if(this.disableFrequentAppsID){ + this._settings.disconnect(this.disableFrequentAppsID); + this.disableFrequentAppsID = null; + } + + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js new file mode 100644 index 0000000..8b66793 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/gnomemenu.js @@ -0,0 +1,161 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + + this.activitiesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + let activities = new MW.ActivitiesMenuItem(this); + this.activitiesBox.add_child(activities.actor); + this.leftBox.add_child(this.activitiesBox); + + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.actor.style = "padding-top: 8px; padding-bottom: 8px;"; + categoryMenuItem._iconBin.visible = false; + } + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js new file mode 100644 index 0000000..e298283 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/insider.js @@ -0,0 +1,337 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + PinnedAppsColumns: 1, + DefaultMenuWidth: 525, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.pinnedAppsButton = new MW.PinnedAppsButton(this); + this.pinnedAppsButton.actor.y_expand = true; + this.pinnedAppsButton.actor.y_align= Clutter.ActorAlign.START; + this.pinnedAppsButton.actor.margin = 5; + this.actionsBox.add_child(this.pinnedAppsButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + settingsButton.actor.expand = false; + settingsButton.actor.margin = 5; + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.leaveButton.actor.expand = false; + this.leaveButton.actor.margin = 5; + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + let userMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + vertical: false, + }) + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.user.label.x_align = Clutter.ActorAlign.CENTER; + this.user.label.style = "margin-left: 10px;" + userMenuBox.add_child(this.user.actor); + userMenuBox.add_child(this.user.label); + this.subMainBox.add_child(userMenuBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 10px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor( this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createPinnedAppsMenu(); + this.setDefaultMenuView(); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + super.loadPinnedApps(); + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + } + + _createPinnedAppsMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.pinnedAppsMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.pinnedAppsMenu.blockSourceEvents = true; + this.section = new PopupMenu.PopupMenuSection(); + this.pinnedAppsMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.togglePinnedAppsMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + headerBox.add_child(this.createLabelRow(_("Pinned Apps"))); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + + this.leftPanelPopup.add_child(this.pinnedAppsScrollBox); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 0, + row_spacing: 0 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + layout_manager: layout + }); + layout.forceGridColumns = 1; + layout.hookup_style(this.pinnedAppsGrid); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.displayPinnedApps(); + this.subMenuManager.addMenu(this.pinnedAppsMenu); + this.pinnedAppsMenu.actor.hide(); + Main.uiGroup.add_child(this.pinnedAppsMenu.actor); + this.pinnedAppsMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.pinnedAppsButton.tooltip){ + this.pinnedAppsButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.pinnedAppsButton.active = false; + this.pinnedAppsButton.sync_hover(); + this.pinnedAppsButton.hovered = this.pinnedAppsButton.hover; + } + }); + } + + togglePinnedAppsMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.pinnedAppsMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.pinnedAppsMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.pinnedAppsButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.pinnedAppsMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base: 0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.pinnedAppsMenu.toggle(); + if(this.pinnedAppsMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + this.activeMenuItem = this.applicationsGrid.layout_manager.get_child_at(0, 0); + if(!this.applicationsBox.contains(this.applicationsGrid)) + this.applicationsBox.add_child(this.applicationsGrid); + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + this._clearActorsFromBox(this.pinnedAppsBox); + this.layoutProperties.GridColumns = 1; + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + this.updateStyle(); + this.layoutProperties.GridColumns = 5; + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js new file mode 100644 index 0000000..7dbeccc --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/launcher.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const MORE_PROVIDERS_POP_UP = -1; +const MAX_VISIBLE_PROVIDERS = 4; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + MenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.activeResult = null; + this.searchProvidersBoxStyle = "padding: 0px 15px; margin-bottom: 10px; height: 50px; background-color: rgba(186, 196, 201, 0.1); border-color:rgba(186, 196, 201, 0.2); border-bottom-width: 1px;" + this.themeNodeBorderRadius = ""; + this.searchProvidersBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: this.searchProvidersBoxStyle + this.themeNodeBorderRadius + }); + this.searchProvidersBox.clip_to_allocation = true; + this.mainBox.add_child(this.searchProvidersBox); + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px;"; + this.searchTermsChangedID = this.searchResults.connect('have-results', () => { + this.searchResultsChangedEvent(); + }); + this.searchNoResultsID = this.searchResults.connect('no-results', () => { + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + }) + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.subMainBox.style = "width:750px; spacing: 8px;"; + + this.searchResultDetailsBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL, + style: 'width: 415px; spacing: 20px;' + }); + + this.searchResultDetailsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.searchResultDetailsScrollBox.add_actor(this.searchResultDetailsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.mainBox.add_child(this.searchBox); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.arcMenu.box.style = "padding-top: 0px;"; + this.hasPinnedApps = true; + this.loadPinnedApps(); + this.loadCategories(); + + this.moreItem = this.createProviderMenuItem(_("More"), MORE_PROVIDERS_POP_UP); + let arrowIcon = PopupMenu.arrowIcon(St.Side.BOTTOM); + arrowIcon.y_expand = false; + this.moreItem.add_child(arrowIcon); + this._createMoreProvidersMenu(); + + this.setDefaultMenuView(); + } + + loadPinnedApps(){ + super.loadPinnedApps(); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.FREQUENT_APPS, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.FREQUENT_APPS, categoryMenuItem); + + super.loadCategories(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.moveProvidersMenuItems = []; + this.moreProvidersBox.remove_all_children(); + this.searchResults.setProvider(Constants.CategoryType.SEARCH_RESULTS); + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + this.displayPinnedApps(); + this.searchProvidersBox.remove_all_children(); + let allProvidersItem = this.createProviderMenuItem(_("All"), Constants.CategoryType.SEARCH_RESULTS); + this.searchProvidersBox.add_child(allProvidersItem); + let searchProviders = this.searchResults.getProviders(); + + let currentItems = 1; + for(let provider of searchProviders){ + provider = provider.appInfo ? provider : _("Applications"); + let item = this.createProviderMenuItem(provider, provider.appInfo ? null : Constants.CategoryType.ALL_PROGRAMS); + + if(currentItems < MAX_VISIBLE_PROVIDERS) + this.searchProvidersBox.add_child(item); + else{ + this.moveProvidersMenuItems.push(item); + item.moreIndex = currentItems - MAX_VISIBLE_PROVIDERS; + item.x_expand = true; + item.x_align = Clutter.ActorAlign.FILL; + this.moreProvidersBox.add_child(item); + } + + currentItems++; + } + + this.searchProvidersBox.add_child(this.moreItem); + + this.activeProvider = allProvidersItem; + this.activeProvider.add_style_class_name("active-item"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + createProviderMenuItem(provider, providerEnum){ + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + + let providerMenuItem = new MW.ArcMenuPopupBaseMenuItem(this); + providerMenuItem.name = "arc-menu-launcher-button"; + providerMenuItem.x_expand = false; + providerMenuItem.remove_child(providerMenuItem._ornamentLabel); + providerMenuItem.x_align = Clutter.ActorAlign.START; + providerMenuItem.style = 'padding: 10px 14px; margin: 0px;'; + providerMenuItem.provider = provider; + let label = new St.Label({ + text: _(providerName), + y_expand: false, + y_align: Clutter.ActorAlign.CENTER, + }); + providerMenuItem.label = label; + providerMenuItem.add_child(label); + + providerMenuItem.connect("activate", () => this.activateProviderMenuItem(providerMenuItem, providerEnum)); + return providerMenuItem; + } + + activateProviderMenuItem(providerMenuItem, providerEnum){ + if(providerEnum && providerEnum === MORE_PROVIDERS_POP_UP){ + this.moreItem.add_style_class_name("active-item"); + this.toggleMoreProvidersMenu(); + } + else{ + if(this.activeProvider) + this.activeProvider.remove_style_class_name("active-item"); + + if(this.moreProvidersMenu.isOpen) + this.moreProvidersMenu.toggle(); + + this.moreItem.remove_style_class_name("active-item"); + this.moreItem.active = false; + + let potentialMovedItem = this.searchProvidersBox.get_child_at_index(MAX_VISIBLE_PROVIDERS); + + if(potentialMovedItem.wasMoved) + this.moveProviderMenuItem(potentialMovedItem, this.searchProvidersBox, this.moreProvidersBox, true); + + if(providerMenuItem.get_parent() === this.moreProvidersBox) + this.moveProviderMenuItem(providerMenuItem, this.moreProvidersBox, this.searchProvidersBox, false); + + this.activeProvider = providerMenuItem; + providerMenuItem.add_style_class_name("active-item"); + + this.displayProviderPage(providerMenuItem.provider, providerEnum); + this.searchResults.setProvider(providerMenuItem.provider.appInfo ? providerMenuItem.provider.appInfo.get_id() : providerEnum); + + if(!this.searchBox.isEmpty()){ + this._clearActorsFromBox(); + let searchString = this.searchBox.get_text(); + searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, ''); + this.searchResults.setTerms([]); + + let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + this.applicationsBox.add_child(this.searchResults); + this.searchResults.setTerms(searchString.split(/\s+/)); + this.searchResults.highlightDefault(true); + this.activeProvider.grab_key_focus(); + } + } + } + + moveProviderMenuItem(menuItem, currentBox, newBox, wasMoved){ + let expand = wasMoved ? true : false; + let align = wasMoved ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.START; + let index = wasMoved ? menuItem.moreIndex : MAX_VISIBLE_PROVIDERS; + + currentBox.remove_child(menuItem); + newBox.insert_child_at_index(menuItem, index); + menuItem.x_expand = expand; + menuItem.x_align = align; + menuItem.wasMoved = !wasMoved; + } + + displayProviderPage(provider, providerEnum){ + if(this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.remove_child(this.searchResultDetailsScrollBox); + if(providerEnum){ + if(providerEnum === Constants.CategoryType.SEARCH_RESULTS) + this.displayPinnedApps(); + if(providerEnum === Constants.CategoryType.ALL_PROGRAMS) + this.displayFrequentApps(); + return; + } + this._clearActorsFromBox(); + let providerName = provider.appInfo ? provider.appInfo.get_name() : provider; + let providerIcon = provider.appInfo ? provider.appInfo.get_icon() : Gio.icon_new_for_string(''); + + this.setSearchHintText(providerName); + + let providerBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let icon = new St.Icon({ + icon_size: 76, + gicon: providerIcon, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + }); + let label = new St.Label({ + text: _("Search") + " " + _(providerName), + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: false, + y_align: Clutter.ActorAlign.START, + }); + providerBox.add_child(icon); + providerBox.add_child(label); + this.applicationsBox.add_child(providerBox); + } + + _createMoreProvidersMenu(){ + this.moreProvidersMenu = new PopupMenu.PopupMenu(this.moreItem, 0.5, St.Side.TOP); + this.moreProvidersMenu.connect('open-state-changed', (menu, open) => { + if(!open) + this.moreItem.remove_style_class_name("active-item"); + }); + + this.section = new PopupMenu.PopupMenuSection(); + this.moreProvidersMenu.addMenuItem(this.section); + + this.moreProvidersBox = new St.BoxLayout({ + vertical: true + }); + + this.moreProvidersScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'vfade', + overlay_scrollbars: true, + reactive: true + }); + this.moreProvidersScrollBox._delegate = this.moreProvidersBoxScrollBox; + this.moreProvidersScrollBox.add_actor(this.moreProvidersBox); + this.moreProvidersScrollBox.clip_to_allocation = true; + + this.moreProvidersScrollBox.style = "max-height: 350px;"; + this.section.actor.add_child(this.moreProvidersScrollBox); + this.subMenuManager.addMenu(this.moreProvidersMenu); + this.moreProvidersMenu.actor.hide(); + Main.uiGroup.add_child(this.moreProvidersMenu.actor); + } + + toggleMoreProvidersMenu(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.moreProvidersMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.moreProvidersMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + + this.moreProvidersMenu.toggle(); + } + + displayFrequentApps(){ + this._clearActorsFromBox(); + this.setSearchHintText(_("Applications")); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.FREQUENT_APPS); + let label = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(categoryMenuItem.appList, Constants.CategoryType.FREQUENT_APPS, this.applicationsGrid); + } + + setSearchHintText(providerName){ + this.searchBox.hint_text = _("Search") + " " + _(providerName) + "…"; + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: " + borderRadius + "px " + borderRadius + "px 0px 0px;"; + this.searchProvidersBox.style = this.searchProvidersBoxStyle + this.themeNodeBorderRadius; + if(removeMenuArrow) + this.arcMenu.box.style = "padding-top: 0px; margin: 0px;"; + else + this.arcMenu.box.style = "padding-top: 0px;"; + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + } + + displayPinnedApps() { + super._clearActorsFromBox(); + let label = this.createLabelRow(_("Pinned Apps")); + this.searchBox.hint_text = _("Search…"); + this.applicationsBox.add_child(label); + this.layoutProperties.GridColumns = 5; + super._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + } + + searchResultsChangedEvent(){ + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + this.subMainBox.add_child(this.searchResultDetailsScrollBox); + if(this.activeResult === this.searchResults.getTopResult()) + return; + + this.activeResult = this.searchResults.getTopResult(); + if(!this.activeResult || this.activeResult === null){ + return; + } + + this.createActiveSearchItemPanel(this.searchResults.getTopResult()); + } + + createActiveSearchItemPanel(activeResult){ + if(!activeResult) + return; + if(!this.subMainBox.contains(this.searchResultDetailsScrollBox)) + return; + if(!activeResult.provider || activeResult === this.activeResultMenuItem) + return; + this.activeCategoryType = -1; + this.searchResultDetailsBox.destroy_all_children(); + + if(!activeResult.metaInfo) + return; + + let app = activeResult.app ? activeResult.app : null; + let path = activeResult._path ? activeResult._path : null; + + this.activeResultMenuItem = new MW.ApplicationMenuItem(this, app, Constants.DisplayType.GRID, activeResult.metaInfo); + this.activeResultMenuItem.name = "ExtraLargeIconGrid"; + this.activeResultMenuItem.provider = activeResult.provider; + this.activeResultMenuItem.resultsView = activeResult.resultsView; + this.activeResultMenuItem._path = path; + this.activeResultMenuItem.x_expand = false; + this.activeResultMenuItem.x_align = Clutter.ActorAlign.CENTER; + let iconSize = 76; + let icon = activeResult.metaInfo ?activeResult.metaInfo['createIcon'](iconSize) : app.create_icon_texture(iconSize); + this.activeResultMenuItem._iconBin.set_child(icon); + if(!this.activeResultMenuItem._iconBin.get_child()){ + let icon = new St.Icon({ + icon_size: iconSize, + gicon: activeResult.provider.appInfo.get_icon() + }); + this.activeResultMenuItem._iconBin.set_child(icon); + } + this.searchResultDetailsBox.add_child(this.activeResultMenuItem); + this.searchResultContextItems = new MW.ApplicationContextItems(this.activeResultMenuItem, app, this); + this.searchResultContextItems.path = path; + this.searchResultContextItems.rebuildItems(); + this.searchResultDetailsBox.add_child(this.searchResultContextItems); + } + + destroy(){ + this.arcMenu.box.style = null; + + if(this.searchTermsChangedID){ + this.searchResults.disconnect(this.searchTermsChangedID); + this.searchTermsChangedID = null; + } + + if(this.searchNoResultsID){ + this.searchResults.disconnect(this.searchNoResultsID); + this.searchNoResultsID = null; + } + + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js new file mode 100644 index 0000000..3185f2d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/mint.js @@ -0,0 +1,250 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + //Stores the Pinned Icons on the left side + this.actionsScrollBox = new St.ScrollView({ + x_expand: false, + y_expand: false, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'small-vfade' + }); + this.actionsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + this.actionsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsScrollBox.add_actor(this.actionsBox); + this.actionsScrollBox.clip_to_allocation = true; + + this.actionsScrollBox.style = "padding: 21px 0px; width: 62px; margin: 0px 10px 10px 20px; background-color:rgba(186, 196,201, 0.1); border-color:rgba(186, 196,201, 0.2); border-width: 1px; border-radius: 5px;"; + this.actionsBox.style = "spacing: 10px;"; + //check if custom ArcMenu is enabled + if( this._settings.get_boolean('enable-custom-arc-menu')) + this.actionsBox.add_style_class_name('arc-menu'); + + this.mainBox.add_child(this.actionsScrollBox); + this.rightMenuBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.rightMenuBox); + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + else + this.rightMenuBox.style = "margin-top: 10px;"; + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.rightMenuBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + + this.categoriesScrollBox.add_actor( this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 20px 10px 8px;"; + this.rightMenuBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + _addSeparator(){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.add_child(separator); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + loadExtraPinnedApps(){ + this.actionsBox.destroy_all_children(); + super.loadExtraPinnedApps(this._settings.get_strv('mint-pinned-app-list'), this._settings.get_int('mint-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + //Find the Default Web Browser, if found add to pinned apps list, if not found delete the placeholder. + //Will only run if placeholder is found. Placeholder only found with default settings set. + let browserName = ''; + try{ + //user may not have xdg-utils package installed which will throw error + let [res, stdout, stderr, status] = GLib.spawn_command_line_sync("xdg-settings get default-web-browser"); + let webBrowser = String.fromCharCode(...stdout); + browserName = webBrowser.split(".desktop")[0]; + browserName += ".desktop"; + } + catch(error){ + global.log("ArcMenu Error - Failed to find default web browser. Removing placeholder pinned app.") + } + this._app = appSys.lookup_app(browserName); + if(this._app){ + let appIcon = this._app.create_icon_texture(25); + let iconName = ''; + if(appIcon.icon_name) + iconName = appIcon.icon_name; + else if(appIcon.gicon) + iconName = appIcon.gicon.to_string(); + pinnedApps.push(this._app.get_name(), iconName, this._app.get_id()); + } + else{ + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + } + pinnedApps.push(_("Terminal"), "utilities-terminal", "org.gnome.Terminal.desktop"); + pinnedApps.push(_("Settings"), "emblem-system-symbolic", "gnome-control-center.desktop"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('mint-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js new file mode 100644 index 0000000..2135cc5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/plasma.js @@ -0,0 +1,453 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gio, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 450, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.leftTopBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + vertical: false, + y_align: Clutter.ActorAlign.CENTER, + style: "padding-left: 10px; margin-left: 0.4em" + }); + this.rightTopBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + style_class: 'popup-menu-item', + style: "padding: 0px; margin: 0px; spacing: 0px;" + }); + + this.user = new MW.UserMenuIcon(this, 55, true); + this.user.actor.x_expand = false; + this.user.actor.y_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.CENTER; + this.user.actor.y_align = Clutter.ActorAlign.CENTER; + this.leftTopBox.add_child(this.user.actor); + this.rightTopBox.add_child(this.user.label); + this.user.label.style = "padding-left: 0.4em; margin: 0px 10px 0px 15px; font-weight: bold;"; + this.user.label.y_expand = false; + this.user.label.x_expand = true; + this.user.label.x_align = Clutter.ActorAlign.START; + this.rightTopBox.add_child(this.searchBox.actor); + + this.topBox.add_child(this.leftTopBox); + this.topBox.add_child(this.rightTopBox); + + this.searchBarLocation = this._settings.get_enum('searchbar-default-top-location'); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? 'margin-box' : 'margin-box small-vfade', + overlay_scrollbars: true, + reactive:true, + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBoxContainer = new St.BoxLayout({ + x_expand: true, + y_expand: false, + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START + }); + this.navigateBox = new St.BoxLayout({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 6px;", + }); + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_homogeneous: true, + column_spacing: 10, + row_spacing: 10 + }); + this.grid = new St.Widget({ + layout_manager: layout + }); + layout.hookup_style(this.grid); + this.navigateBox.add_child(this.grid); + + this.pinnedAppsButton = new MW.PlasmaMenuItem(this, _("Pinned Apps"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'); + this.pinnedAppsButton.connect("activate", () => this.displayPinnedApps() ); + this.grid.layout_manager.attach(this.pinnedAppsButton, 0, 0, 1, 1); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + + this.applicationsButton = new MW.PlasmaMenuItem(this, _("Applications"), 'preferences-desktop-apps-symbolic'); + this.applicationsButton.connect("activate", () => this.displayCategories() ); + this.grid.layout_manager.attach(this.applicationsButton, 1, 0, 1, 1); + + this.computerButton = new MW.PlasmaMenuItem(this, _("Computer"), 'computer-symbolic'); + this.computerButton.connect("activate", () => this.displayComputerCategory() ); + this.grid.layout_manager.attach(this.computerButton, 2, 0, 1, 1); + + this.leaveButton = new MW.PlasmaMenuItem(this, _("Leave"), 'system-shutdown-symbolic'); + this.leaveButton.connect("activate", () => this.displayPowerItems() ); + this.grid.layout_manager.attach(this.leaveButton, 3, 0, 1, 1); + + this.categoryHeader = new MW.PlasmaCategoryHeader(this); + this.categoryHeader.add_style_class_name('margin-box'); + + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 3px 10px 5px 10px;"; + this.topBox.style = 'padding-top: 0.5em;' + + this.navigateBoxContainer.add_child(this.navigateBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.y_expand = false; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.START; + this.mainBox.add_child(this.navigateBoxContainer); + this.mainBox.add_child(this.applicationsScrollBox); + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + + this.mainBox.add_child(this.topBox); + } + else if(this.searchBarLocation === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 3px 10px 10px 10px;"; + + this.mainBox.add_child(this.topBox); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + this.mainBox.add_child(this.applicationsScrollBox); + this.navigateBoxContainer.y_expand = true; + this.navigateBoxContainer.y_align = Clutter.ActorAlign.END; + separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.navigateBoxContainer.add_child(separator); + this.navigateBoxContainer.add_child(this.navigateBox); + this.mainBox.add_child(this.navigateBoxContainer); + } + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + this.updateWidth(); + this._createPowerItems(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setFrequentAppsList(categoryMenuItem){ + categoryMenuItem.appList = []; + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + categoryMenuItem.appList.push(mostUsed[i]); + let item = this.applicationsMap.get(mostUsed[i]); + if (!item) { + item = new MW.ApplicationMenuItem(this, mostUsed[i], this.layoutProperties.DisplayType); + this.applicationsMap.set(mostUsed[i], item); + } + } + } + } + + _clearActorsFromBox(box){ + this.categoryHeader.setActiveCategory(null); + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + super._clearActorsFromBox(box); + } + + clearActiveItem(){ + this.pinnedAppsButton.setActive(false); + this.computerButton.setActive(false); + this.applicationsButton.setActive(false); + this.leaveButton.setActive(false); + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum === Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayComputerCategory(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.applicationsBox.add_child(this.applicationShortcuts[i]); + } + this.applicationsBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.applicationsBox.add_child(this.directoryShortcuts[i]); + } + this.applicationsBox.add_child(this.externalDevicesBox); + this.activeMenuItem = this.applicationShortcuts[0]; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + displayPinnedApps(){ + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + super.displayPinnedApps(); + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let isContainedInCategory = false; + let directory = directoryShortcutsList[i]; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createPowerItems(){ + this.lock = new MW.PowerMenuItem(this, Constants.PowerType.LOCK); + this.logOut = new MW.PowerMenuItem(this, Constants.PowerType.LOGOUT); + Utils.canHybridSleep((canHybridSleep, needsAuth) => { + if(canHybridSleep){ + this.sleep = new MW.PowerMenuItem(this, Constants.PowerType.HYBRID_SLEEP); + } + }); + + + Utils.canHibernate((canHibernate, needsAuth) => { + if(canHibernate){ + this.hibernate = new MW.PowerMenuItem(this, Constants.PowerType.HIBERNATE); + } + }); + this.suspend = new MW.PowerMenuItem(this, Constants.PowerType.SUSPEND); + this.restart = new MW.PowerMenuItem(this, Constants.PowerType.RESTART); + this.powerOff = new MW.PowerMenuItem(this, Constants.PowerType.POWER_OFF); + } + + displayPowerItems(){ + this._clearActorsFromBox(this.applicationsBox); + this.applicationsBox.add_child(this.createLabelRow(_("Session"))); + this.applicationsBox.add_child(this.lock); + this.applicationsBox.add_child(this.logOut); + this.applicationsBox.add_child(this.createLabelRow(_("System"))); + this.applicationsBox.add_child(this.suspend); + if(this.sleep) + this.applicationsBox.insert_child_at_index(this.sleep, 4); + + if(this.hibernate) + this.applicationsBox.insert_child_at_index(this.hibernate, 5); + this.applicationsBox.add_child(this.restart); + this.applicationsBox.add_child(this.powerOff); + this.activeMenuItem = this.lock; + } + + displayCategories(){ + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this._clearActorsFromBox(this.applicationsBox); + + this.categoryHeader.setActiveCategory(null); + this._insertCategoryHeader(); + + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.applicationsBox.add_child(categoryMenuItem.actor); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.clearActiveItem(); + this.pinnedAppsButton.set_style_pseudo_class("active-item"); + this.displayPinnedApps(); + } + + _insertCategoryHeader(){ + if(this.mainBox.contains(this.categoryHeader)) + this.mainBox.remove_child(this.categoryHeader); + if(this.searchBarLocation === Constants.SearchbarLocation.BOTTOM) + this.mainBox.insert_child_at_index(this.categoryHeader, 1); + else + this.mainBox.insert_child_at_index(this.categoryHeader, 2); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._insertCategoryHeader(); + this.categoryHeader.setActiveCategory(this.activeCategory); + this._displayAppList(appList, category, this.applicationsGrid); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this._insertCategoryHeader(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.categoryHeader.setActiveCategory(this.activeCategory); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(!searchBox.isEmpty()){ + this.clearActiveItem(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } + + destroy(){ + if(this.sleep) + this.sleep.destroy(); + if(this.hibernate) + this.hibernate.destroy(); + + this.lock.destroy(); + this.logOut.destroy(); + this.suspend.destroy(); + this.restart.destroy(); + this.powerOff.destroy(); + + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js new file mode 100644 index 0000000..2630ef5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/raven.js @@ -0,0 +1,395 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 410, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + SupportsCategoryOnHover: true, + DefaultCategoryIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.ravenPositionChangedID = this._settings.connect('changed::raven-position', () => this._updatePosition()); + + this.dummyCursor = new St.Widget({ width: 1, height: 0, opacity: 0}); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.actionsBoxContainer = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + + this.actionsBox = new St.BoxLayout({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + this.actionsBoxContainer.add_child(this.actionsBox); + this.actionsBox.style = "spacing: 5px;"; + this.actionsBoxContainerStyle = "margin: 0px 0px 0px 0px; spacing: 10px; background-color: rgba(186, 196,201, 0.1); padding: 5px 5px;"+ + "border-color: rgba(186, 196,201, 0.2);"; + + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + //Sub Main Box -- stores left and right box + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.subMainBox.add_child(this.topBox); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 25px 10px 10px 10px;"; + this.topBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + x_align: Clutter.ActorAlign.FILL, + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.weatherBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: true + }); + + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.x_expand = true; + this._clocksItem.x_align = Clutter.ActorAlign.FILL; + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px 25px 25px 25px;"; + + this.weatherBox.add_child(this._clocksItem); + this.weatherBox.add_child(this._weatherItem); + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this._updatePosition(); + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.weatherBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _updatePosition(){ + let ravenPosition = this._settings.get_enum('raven-position'); + if(this.mainBox.contains(this.actionsBoxContainer)){ + this.mainBox.remove_child(this.actionsBoxContainer); + } + if(ravenPosition === Constants.RavenPosition.LEFT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 0); + this.actionsBoxContainer.style = "border-right-width: 1px;" + this.actionsBoxContainerStyle; + } + else if(ravenPosition === Constants.RavenPosition.RIGHT){ + this.mainBox.insert_child_at_index(this.actionsBoxContainer, 1); + this.actionsBoxContainer.style = "border-left-width: 1px;" + this.actionsBoxContainerStyle; + } + } + + updateLocation(){ + let ravenPosition = this._settings.get_enum('raven-position'); + + let alignment = ravenPosition === Constants.RavenPosition.LEFT ? 0 : 1; + this.arcMenu._boxPointer.setSourceAlignment(alignment); + this.arcMenu._arrowAlignment = alignment; + + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let monitorWorkArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); + + let positionX = ravenPosition === Constants.RavenPosition.LEFT ? monitorWorkArea.x : monitorWorkArea.x + monitorWorkArea.width - 1; + let positionY = this.arcMenu._arrowSide === St.Side.BOTTOM ? monitorWorkArea.y + monitorWorkArea.height : monitorWorkArea.y; + + this.dummyCursor.set_position(positionX, positionY); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + let screenHeight = monitorWorkArea.height; + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderWidth = themeNode.get_length('-arrow-border-width'); + + let height = Math.round((screenHeight - borderWidth * 2) / scaleFactor); + this.mainBox.style = `height: ${height}px;`; + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + updateStyle(){ + super.updateStyle(); + + this.arcMenu.actor.style = "-arrow-base: 0px; -arrow-rise: 0px; -boxpointer-gap: 0px; -arrow-border-radius: 0px;"; + this.arcMenu.box.style = "padding-bottom: 0px; padding-top: 0px; margin: 0px;"; + this.updateLocation(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.BUTTON); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.BUTTON); + this.displayCategories(); + } + + displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.actionsBox.add_child(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + let actors = this.weatherBox.get_children(); + for (let i = 0; i < actors.length; i++) { + this.weatherBox.remove_child(actors[i]); + } + if(this._settings.get_boolean('enable-clock-widget-raven')){ + this.weatherBox.add_child(this._clocksItem); + } + if(this._settings.get_boolean('enable-weather-widget-raven')){ + this.weatherBox.add_child(this._weatherItem); + } + if(!this.subMainBox.contains(this.weatherBox)) + this.subMainBox.add_child(this.weatherBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.subMainBox.contains(this.weatherBox)){ + this.subMainBox.remove_child(this.weatherBox); + } + + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + let label = this._createLabelWithSeparator(this.activeCategory); + + if(grid === this.applicationsGrid){ + label.actor.style += "padding-left: 10px;"; + this.applicationsBox.insert_child_at_index(label.actor, 0); + } + else{ + label.actor.style += "padding-left: 10px; padding-top: 20px;"; + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + if(this.ravenPositionChangedID){ + this._settings.disconnect(this.ravenPositionChangedID); + this.ravenPositionChangedID = null; + } + + this.arcMenu.actor.style = null; + this.arcMenu.box.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + this.arcMenu.close(); + this.arcMenu._boxPointer.hide(); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js new file mode 100644 index 0000000..d0cb17d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/redmond.js @@ -0,0 +1,229 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 10, + RowSpacing: 10, + DefaultMenuWidth: 450, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 10px 5px 10px;"; + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP) + this.subMainBox.add_child(this.searchBox.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.subMainBox.add_child(this.applicationsScrollBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.subMainBox.add_child(this.searchBox.actor); + } + + this.rightBox = new St.BoxLayout({ + y_align: Clutter.ActorAlign.FILL, + y_expand: true, + vertical: true, + style_class: 'right-panel margin-box' + }); + + this.placesShortcuts = false; + this.externalDevicesShorctus = false; + this.networkDevicesShorctus = false; + this.bookmarksShorctus = false; + this.softwareShortcuts = false; + + if(!this._settings.get_boolean('disable-user-avatar')){ + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.rightBox.add_child(this.user.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.rightBox.add_child(separator); + } + + this.shortcutsBox = new St.BoxLayout({ + vertical: true + }); + + this.shortcutsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.rightBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //draw bottom right horizontal separator + logic to determine if should show + let shouldDraw = false; + if(this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0){ + this.placesShortcuts=true; + } + if(this._settings.get_value('application-shortcuts-list').deep_unpack().length>0){ + this.softwareShortcuts = true; + } + + //check to see if should draw separator + if(this.placesShortcuts && (this._settings.get_boolean('show-external-devices') || this.softwareShortcuts || this._settings.get_boolean('show-bookmarks')) ) + shouldDraw=true; + if(shouldDraw){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.SHORT, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //External Devices and Bookmarks Shortcuts + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this.shortcutsBox.add_child(this.externalDevicesBox); + + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + //create new section for Power, Lock, Logout, Suspend Buttons + this.actionsBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_expand: true, + y_align: Clutter.ActorAlign.END, + style: "spacing: 6px;" + }); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + this.rightBox.add_child(this.actionsBox); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.mainBox.add_child(horizonalFlip ? this.rightBox : this.subMainBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.mainBox.add_child(verticalSeparator); + this.mainBox.add_child(horizonalFlip ? this.subMainBox: this.rightBox); + horizonalFlip ? this.rightBox.style += "margin-right: 0px" : this.rightBox.style += "margin-left: 0px" + + this.updateWidth(); + this.loadCategories(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayAllApps(); + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + super.loadCategories(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js new file mode 100644 index 0000000..7386301 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/runner.js @@ -0,0 +1,208 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PanelMenu = imports.ui.panelMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton, isStandalone) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + StandaloneRunner: isStandalone + }); + } + + createLayout(){ + super.createLayout(); + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.updateLocation(); + + //store old ArcMenu variables + this.oldSourceActor = this.arcMenu.sourceActor; + this.oldFocusActor = this.arcMenu.focusActor; + this.oldArrowAlignment = this.arcMenu.actor._arrowAlignment; + + this.arcMenu.sourceActor = this.dummyCursor; + this.arcMenu.focusActor = this.dummyCursor; + this.arcMenu._boxPointer.setPosition(this.dummyCursor, 0.5); + + this.topBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: false, + style: "margin: 5px 0px 0px 0px;" + }); + + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + this.runnerTweaksButton = new MW.RunnerTweaksButton(this); + this.runnerTweaksButton.actor.x_expand = false; + this.runnerTweaksButton.actor.y_expand = true; + this.runnerTweaksButton.actor.y_align = this.searchBox.y_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.x_align = Clutter.ActorAlign.CENTER; + this.runnerTweaksButton.actor.style = "margin: 0px 6px;"; + + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.runnerTweaksButton); + this.mainBox.add_child(this.topBox); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + x_align: Clutter.ActorAlign.START, + overlay_scrollbars: false, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + reactive:true + }); + + this.mainBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "margin: 5px 6px 0px 16px;" + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.activeMenuItem = null; + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + this.activeMenuItem = null; + super.setDefaultMenuView(); + if(this._settings.get_boolean("runner-show-frequent-apps")) + this.displayFrequentApps(); + } + + displayFrequentApps(){ + let labelRow = this.createLabelRow(_("Frequent Apps")); + this.applicationsBox.add_child(labelRow); + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + let appList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + appList.push(item); + } + } + let activeMenuItemSet = false; + for (let i = 0; i < appList.length; i++) { + let item = appList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_actor(item.actor); + if(!activeMenuItemSet){ + activeMenuItemSet = true; + this.activeMenuItem = item; + } + } + } + + /** + * if button is hidden, menu should appear on current monitor, unless preference is to always show on primary monitor + * @returns index of monitor where menu should appear + */ + _getMonitorIndexForPlacement() { + if (this.layoutProperties.StandaloneRunner) { + return this._settings.get_boolean('runner-hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + } + else if (this._settings.get_enum('menu-button-appearance') === Constants.MenuButtonAppearance.NONE) + return this._settings.get_boolean('hotkey-open-primary-monitor') ? Main.layoutManager.primaryMonitor.index : Main.layoutManager.currentMonitor.index; + else + return Main.layoutManager.findIndexForActor(this.menuButton); + } + + updateLocation(){ + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + this.arcMenu._boxPointer.setSourceAlignment(0.5); + this.arcMenu._arrowAlignment = 0.5; + + let rect = Main.layoutManager.getWorkAreaForMonitor(this._getMonitorIndexForPlacement()); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + (this._settings.get_boolean('runner-use-theme-gap') ? this.rise : 0); + if(this._settings.get_enum('runner-position') == 1) + positionY = Math.round(rect.y + (rect.height / 2) - 125); + this.dummyCursor.set_position(positionX, positionY); + + if(!this.topBox) + return; + + this._runnerWidth = this._settings.get_int("runner-menu-width"); + this._runnerHeight = this._settings.get_int("runner-menu-height"); + this._runnerFontSize = this._settings.get_int("runner-font-size"); + this.mainBox.style = `max-height: ${this._runnerHeight}px;`; + if(this._runnerFontSize > 0){ + this.mainBox.style += `font-size: ${this._runnerFontSize}pt;` + this.searchBox.style += `font-size: ${this._runnerFontSize}pt;` + } + else{ + this.searchBox.style = "margin: 0px 0px 0px 16px;"; + } + this.topBox.style = `width: ${this._runnerWidth}px; margin: 5px 0px 0px 0px;`; + this.applicationsScrollBox.style = `width: ${this._runnerWidth}px;`; + } + + updateStyle(){ + super.updateStyle(); + this.arcMenu.actor.style = "-arrow-base:0px; -arrow-rise:0px;"; + } + + loadCategories(){ + } + + destroy(){ + this.arcMenu.actor.style = null; + this.arcMenu.sourceActor = this.oldSourceActor; + this.arcMenu.focusActor = this.oldFocusActor; + this.arcMenu._boxPointer.setPosition(this.oldSourceActor, this.oldArrowAlignment); + Main.uiGroup.remove_child(this.dummyCursor); + this.dummyCursor.destroy(); + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js new file mode 100644 index 0000000..0e971e4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple.js @@ -0,0 +1,159 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GMenu, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.section = this.menuButton.section; + let actors = this.section.actor.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + this.section.actor.remove_child(actor); + } + this.section.actor.add_child(this.mainBox); + + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + updateStyle(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem.updateStyle(); + } + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.SimpleMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SIMPLE_CATEGORY); + } + + displayCategories(){ + super.displayCategories(this.mainBox); + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + let children = categoryMenuItem.applicationsBox.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.applicationsBox.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.applicationsBox); + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + if(!categoryMenuItem.applicationsBox.contains(this.applicationsGrid)) + categoryMenuItem.applicationsBox.add_child(this.applicationsGrid); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js new file mode 100644 index 0000000..ec5b2cf --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/simple2.js @@ -0,0 +1,179 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, St} = imports.gi; +const AppFavorites = imports.ui.appFavorites; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: false, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + this.mainBox.style = null; + this.mainBox.style_class = 'margin-box'; + this.loadPinnedApps(); + this.loadCategories(); + this._display(); + this.arcMenu.actor.style = 'max-height: ' + (this.arcMenu.actor.height + 250) + 'px;'; + } + + setDefaultMenuView(){ + this.activeMenuItem = this.categoryDirectories.values().next().value; + let actors = this.mainBox.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + } + } + + _display() { + this.displayCategories(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategorySubMenuItem(this, categoryEnum); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(Constants.DisplayType.SUBMENU_CATEGORY); + + for(let categoryMenuItem of this.categoryDirectories.values()){ + categoryMenuItem._setParent(this.arcMenu); + categoryMenuItem.isSimpleMenuItem = true; + } + } + + displayCategories(){ + this._clearActorsFromBox(); + let isActiveMenuItemSet = false; + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.arcMenu.addMenuItem(categoryMenuItem); + if(!isActiveMenuItemSet){ + isActiveMenuItemSet = true; + this.activeMenuItem = categoryMenuItem; + } + } + } + + _clearActorsFromBox(box) { + let parent = this.applicationsGrid.get_parent(); + if(!parent) + return; + let scrollViewParent = parent.get_parent(); + + if(scrollViewParent && scrollViewParent instanceof St.ScrollView){ + let scrollBoxAdj = scrollViewParent.get_vscroll_bar().get_adjustment(); + scrollBoxAdj.set_value(0); + } + let actors = parent.get_children(); + for (let i = 0; i < actors.length; i++) { + let actor = actors[i]; + if(actor instanceof St.Widget && actor.layout_manager instanceof Clutter.GridLayout){ + actor.get_children().forEach(gridChild => { + if(gridChild instanceof MW.CategorySubMenuItem) + gridChild.menu.close(); + }); + } + parent.remove_child(actor); + } + super._clearActorsFromBox(this.mainBox); + } + + displayCategoryAppList(appList, category, categoryMenuItem){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, categoryMenuItem); + } + + displayRecentFiles(){ + this._clearActorsFromBox(); + this.applicationsGrid.remove_all_children(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.RECENT_FILES); + + let children = categoryMenuItem.menu.box.get_children(); + for (let i = 0; i < children.length; i++) { + let actor = children[i]; + if(actor._delegate instanceof MW.CategorySubMenuItem) + actor._delegate.menu.close(); + categoryMenuItem.menu.box.remove_child(actor); + } + super.displayRecentFiles(categoryMenuItem.menu.box, () => categoryMenuItem._needsScrollbar()); + if(!categoryMenuItem.menu.box.contains(this.applicationsGrid)) + categoryMenuItem.menu.box.add_child(this.applicationsGrid); + + } + + displayPinnedApps() { + this._clearActorsFromBox(); + let categoryMenuItem = this.categoryDirectories.get(Constants.CategoryType.PINNED_APPS); + if(categoryMenuItem){ + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, categoryMenuItem); + } + } + + _displayAppList(apps, category, categoryMenuItem) { + super._displayAppList(apps, category, this.applicationsGrid); + let box = categoryMenuItem.menu.box; + if(!box.contains(this.applicationsGrid)) + box.add_child(this.applicationsGrid); + } + + destroy(){ + this.arcMenu.actor.style = null; + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js new file mode 100644 index 0000000..9d279ee --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tognee.js @@ -0,0 +1,290 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * tognee Layout Created By: tognee https://gitlab.com/tognee + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 290, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + + this.searchBox.name = "ArcSearchEntryRound"; + + //subMainBox stores left and right box + this.subMainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + // The "Left Box" + // Contains the app list and the searchbar + this.appBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + vertical: true, + y_align: Clutter.ActorAlign.FILL, + }); + + //Applications Box - Contains Favorites, Categories or programs + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true, + reactive:true + }); + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 0px 10px 10px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + this.appBox.add_child(this.applicationsScrollBox); + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + + this.navigateBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); + this.backButton = new MW.BackMenuItem(this); + this.navigateBox.add_child(new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL)); + this.navigateBox.add_child(this.backButton.actor); + this.appBox.add_child(this.navigateBox); + if(this._settings.get_enum('searchbar-default-bottom-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.appBox.add_child(this.searchBox.actor); + } + + // The "Right Box" + // Contains some useful shortcuts + this.quickBox = new St.BoxLayout({ + vertical: true, + style: "margin: 0px 1px;", + y_expand: true, + y_align: Clutter.ActorAlign.FILL + }); + + this.subMainBox.add_child(horizonalFlip ? this.appBox : this.quickBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.quickBox : this.appBox); + + this.placesShortcuts= this._settings.get_value('directory-shortcuts-list').deep_unpack().length>0; + this.softwareShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack().length>0; + + this.shortcutsBox = new St.BoxLayout({ + vertical: true, + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + style: "spacing: 5px; padding-bottom: 5px;" + }); + + this.shortcutsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + this.shortcutsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.shortcutsScrollBox.add_actor(this.shortcutsBox); + this.quickBox.add_child(this.shortcutsScrollBox); + + // Add place shortcuts to menu (Home,Documents,Downloads,Music,Pictures,Videos) + this._displayPlaces(); + + //check to see if should draw separator + if(this.placesShortcuts && this.softwareShortcuts){ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.shortcutsBox.add_child(separator); + } + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.BUTTON, isContainedInCategory); + if(shortcutMenuItem.shouldShow) + this.shortcutsBox.add_child(shortcutMenuItem.actor); + } + + // Bottom Section for Power etc... + this.actionsScrollBox = new St.ScrollView({ + x_expand: true, + y_expand: false, + y_align: Clutter.ActorAlign.END, + x_align: Clutter.ActorAlign.CENTER + }); + this.actionsScrollBox.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.EXTERNAL); + this.actionsScrollBox.clip_to_allocation = true; + + //create new section for Leave Button + this.actionsBox = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.CENTER, + style: "spacing: 3px;" + }); + this.actionsScrollBox.add_actor(this.actionsBox); + + let leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(leaveButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.LONG, Constants.SeparatorAlignment.HORIZONTAL); + this.actionsBox.insert_child_at_index(separator, 0); + this.quickBox.add_child(this.actionsScrollBox); + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 175px minimum limit for the menu width + menuWidth = Math.max(175, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _displayPlaces() { + let directoryShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + for (let i = 0; i < directoryShortcuts.length; i++) { + let directory = directoryShortcuts[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.BUTTON, isContainedInCategory); + this.shortcutsBox.add_child(placeMenuItem.actor); + } + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayPinnedApps(){ + super.displayPinnedApps(); + this.activeCategoryType = Constants.CategoryType.PINNED_APPS; + this.navigateBox.show(); + } + + displayAllApps(){ + this.navigateBox.hide(); + super.displayAllApps() + } + + displayCategories(){ + super.displayCategories(); + this.activeCategoryType = Constants.CategoryType.CATEGORIES_LIST; + this.navigateBox.hide(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let defaultMenuView = this._settings.get_enum('default-menu-view-tognee'); + + if(defaultMenuView === Constants.DefaultMenuViewTognee.CATEGORIES_LIST) + this.displayCategories(); + else if(defaultMenuView === Constants.DefaultMenuViewTognee.ALL_PROGRAMS) + this.displayAllApps(); + } + + displayCategoryAppList(appList, category){ + super.displayCategoryAppList(appList, category); + this.navigateBox.show(); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.navigateBox.show(); + } + + _onSearchBoxChanged(searchBox, searchString){ + super._onSearchBoxChanged(searchBox, searchString); + if(searchBox.isEmpty()){ + this.navigateBox.hide(); + } + else if(!searchBox.isEmpty()){ + this.navigateBox.show(); + this.activeCategoryType = Constants.CategoryType.SEARCH_RESULTS; + } + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js new file mode 100644 index 0000000..290a169 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/tweaks/tweaks.js @@ -0,0 +1,1286 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Prefs = Me.imports.prefs; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var TweaksPage = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_TweaksPage extends Gtk.Box { + _init(settings, layoutName) { + this._settings = settings; + this.addResponse = false; + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.layoutNameLabel = new Gtk.Label({ + label: "" + _(layoutName) + "", + use_markup: true, + xalign: 0, + hexpand: true, + halign: Gtk.Align.CENTER + }) + + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + }); + backButton.halign = Gtk.Align.START; + backButton.connect('clicked', ()=> { + this.emit('response', -20); + }); + this.headerBox = new Gtk.Grid({ + hexpand: true, + halign: Gtk.Align.FILL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + }); + + this.headerBox.attach(backButton, 0, 0, 1, 1); + this.headerBox.attach(this.layoutNameLabel, 0, 0, 1, 1); + this.mainScrollWindow = new Gtk.ScrolledWindow(); + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.append(this.headerBox); + this.mainScrollWindow.set_child(this.mainBox); + this.mainScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.append(this.mainScrollWindow); + this._createLayout(); + } + + setActiveLayout(menuLayout, layoutName){ + if(layoutName) + this.layoutNameLabel.label = "" + _(layoutName) + ""; + let children = [...this.mainBox]; + for(let child of children){ + this.mainBox.remove(child); + } + this._createLayout(menuLayout); + } + + _createLayout(menuLayout) { + if(!menuLayout) + menuLayout = this._settings.get_enum('menu-layout'); + + if(menuLayout == Constants.MenuLayout.ARCMENU) + this._loadArcMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.BRISK) + this._loadBriskMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WHISKER) + this._loadWhiskerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_MENU) + this._loadGnomeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.MINT) + this._loadMintMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEMENTARY) + this._loadElementaryTweaks(); + else if(menuLayout == Constants.MenuLayout.GNOME_OVERVIEW) + this._loadGnomeOverviewTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.SIMPLE_2) + this._loadPlaceHolderTweaks(); + else if(menuLayout == Constants.MenuLayout.REDMOND) + this._loadRedmondMenuTweaks() + else if(menuLayout == Constants.MenuLayout.UNITY) + this._loadUnityTweaks(); + else if(menuLayout == Constants.MenuLayout.RAVEN) + this._loadRavenTweaks(); + else if(menuLayout == Constants.MenuLayout.BUDGIE) + this._loadBudgieMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.INSIDER) + this._loadInsiderMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.RUNNER) + this._loadRunnerMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.CHROMEBOOK) + this._loadChromebookTweaks(); + else if(menuLayout == Constants.MenuLayout.TOGNEE) + this._loadTogneeMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.PLASMA) + this._loadPlasmaMenuTweaks(); + else if(menuLayout == Constants.MenuLayout.WINDOWS) + this._loadWindowsTweaks(); + else if(menuLayout == Constants.MenuLayout.ELEVEN) + this._loadElevenTweaks(); + else + this._loadPlaceHolderTweaks(); + } + + _createActivateOnHoverRow(){ + let activateOnHoverRow = new PW.FrameBoxRow(); + let activateOnHoverLabel = new Gtk.Label({ + label: _("Category Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let activateOnHoverCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + activateOnHoverCombo.append_text(_("Mouse Click")); + activateOnHoverCombo.append_text(_("Mouse Hover")); + if(this._settings.get_boolean('activate-on-hover')) + activateOnHoverCombo.set_active(1); + else + activateOnHoverCombo.set_active(0); + activateOnHoverCombo.connect('changed', (widget) => { + if(widget.get_active()==0) + this._settings.set_boolean('activate-on-hover',false); + if(widget.get_active()==1) + this._settings.set_boolean('activate-on-hover',true); + }); + + activateOnHoverRow.add(activateOnHoverLabel); + activateOnHoverRow.add(activateOnHoverCombo); + return activateOnHoverRow; + } + _createAvatarShapeRow(){ + let avatarStyleRow = new PW.FrameBoxRow(); + let avatarStyleLabel = new Gtk.Label({ + label: _('Avatar Icon Shape'), + xalign:0, + hexpand: true, + }); + let avatarStyleCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + avatarStyleCombo.append_text(_("Circular")); + avatarStyleCombo.append_text(_("Square")); + avatarStyleCombo.set_active(this._settings.get_enum('avatar-style')); + avatarStyleCombo.connect('changed', (widget) => { + this._settings.set_enum('avatar-style', widget.get_active()); + this._settings.set_boolean('reload-theme', true); + }); + avatarStyleRow.add(avatarStyleLabel); + avatarStyleRow.add(avatarStyleCombo); + return avatarStyleRow; + } + _createSearchBarLocationRow(bottomDefault){ + let searchBarLocationSetting = bottomDefault ? 'searchbar-default-bottom-location' : 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting )); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + return searchbarLocationRow; + } + _createFlipHorizontalRow(){ + let horizontalFlipRow = new PW.FrameBoxRow(); + let horizontalFlipLabel = new Gtk.Label({ + label: _("Flip Layout Horizontally"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let horizontalFlipSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + horizontalFlipSwitch.set_active(this._settings.get_boolean('enable-horizontal-flip')); + horizontalFlipSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-horizontal-flip', widget.get_active()); + }); + horizontalFlipRow.add(horizontalFlipLabel); + horizontalFlipRow.add(horizontalFlipSwitch); + return horizontalFlipRow; + } + _disableAvatarRow(){ + let disableAvatarRow = new PW.FrameBoxRow(); + let disableAvatarLabel = new Gtk.Label({ + label: _('Disable User Avatar'), + xalign:0, + hexpand: true, + }); + let disableAvatarSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableAvatarSwitch.set_active(this._settings.get_boolean('disable-user-avatar')); + disableAvatarSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('disable-user-avatar', widget.get_active()); + }); + disableAvatarRow.add(disableAvatarLabel); + disableAvatarRow.add(disableAvatarSwitch); + return disableAvatarRow; + } + + _loadElevenTweaks(){ + let elevenTweaksFrame = new PW.FrameBox(); + let disableFrequentAppsRow = new PW.FrameBoxRow(); + let disableFrequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let disableFrequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + disableFrequentAppsSwitch.set_active(this._settings.get_boolean('eleven-disable-frequent-apps')); + disableFrequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('eleven-disable-frequent-apps', widget.get_active()); + }); + disableFrequentAppsRow.add(disableFrequentAppsLabel); + disableFrequentAppsRow.add(disableFrequentAppsSwitch); + elevenTweaksFrame.add(disableFrequentAppsRow); + this.mainBox.append(elevenTweaksFrame); + } + + _loadGnomeOverviewTweaks(){ + let gnomeOverviewTweaksFrame = new PW.FrameBox(); + let appsGridRow = new PW.FrameBoxRow(); + let appsGridLabel = new Gtk.Label({ + label: _("Show Applications Grid"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appsGridSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appsGridSwitch.set_active(this._settings.get_boolean('gnome-dash-show-applications')); + appsGridSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('gnome-dash-show-applications', widget.get_active()); + }); + appsGridRow.add(appsGridLabel); + appsGridRow.add(appsGridSwitch); + gnomeOverviewTweaksFrame.add(appsGridRow); + this.mainBox.append(gnomeOverviewTweaksFrame); + } + + _loadWindowsTweaks(){ + let windowsTweaksFrame = new PW.FrameBox(); + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Disable Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let frequentAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + frequentAppsSwitch.set_active(this._settings.get_boolean('windows-disable-frequent-apps')); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + windowsTweaksFrame.add(frequentAppsRow); + + let pinnedAppsRow = new PW.FrameBoxRow(); + let pinnedAppsLabel = new Gtk.Label({ + label: _("Disable Pinned Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let pinnedAppsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + pinnedAppsSwitch.set_active(this._settings.get_boolean('windows-disable-pinned-apps')); + pinnedAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('windows-disable-pinned-apps', widget.get_active()); + }); + pinnedAppsRow.add(pinnedAppsLabel); + pinnedAppsRow.add(pinnedAppsSwitch); + windowsTweaksFrame.add(pinnedAppsRow); + + this.mainBox.append(windowsTweaksFrame); + } + + _loadPlasmaMenuTweaks(){ + let plasmaMenuTweaksFrame = new PW.FrameBox(); + + let searchBarLocationSetting = 'searchbar-default-top-location'; + + let searchbarLocationRow = new PW.FrameBoxRow(); + let searchbarLocationLabel = new Gtk.Label({ + label: _("Searchbar Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let searchbarLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + searchbarLocationCombo.append_text(_("Bottom")); + searchbarLocationCombo.append_text(_("Top")); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + searchbarLocationCombo.connect('changed', (widget) => { + this._settings.set_enum(searchBarLocationSetting , widget.get_active()); + }); + + searchbarLocationRow.add(searchbarLocationLabel); + searchbarLocationRow.add(searchbarLocationCombo); + plasmaMenuTweaksFrame.add(searchbarLocationRow); + + let hoverRow = new PW.FrameBoxRow(); + let hoverLabel = new Gtk.Label({ + label: _("Activate on Hover"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hoverSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + hoverSwitch.set_active(this._settings.get_boolean('plasma-enable-hover')); + hoverSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('plasma-enable-hover', widget.get_active()); + }); + hoverRow.add(hoverLabel); + hoverRow.add(hoverSwitch); + plasmaMenuTweaksFrame.add(hoverRow); + + let foregroundColorRow = new PW.FrameBoxRow(); + let foregroundColorLabel = new Gtk.Label({ + label: _('Selected Button Border Color'), + xalign:0, + hexpand: true, + }); + let foregroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-color')); + foregroundColorChooser.set_rgba(color); + foregroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-color', foregroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + foregroundColorRow.add(foregroundColorLabel); + foregroundColorRow.add(foregroundColorChooser); + plasmaMenuTweaksFrame.add(foregroundColorRow); + + let backgroundColorRow = new PW.FrameBoxRow(); + let backgroundColorLabel = new Gtk.Label({ + label: _('Selected Button Background Color'), + xalign:0, + hexpand: true, + }); + let backgroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this._settings.get_string('plasma-selected-background-color')); + backgroundColorChooser.set_rgba(color); + backgroundColorChooser.connect('color-set', ()=>{ + this._settings.set_string('plasma-selected-background-color',backgroundColorChooser.get_rgba().to_string()); + this._settings.set_boolean('reload-theme', true); + }); + backgroundColorRow.add(backgroundColorLabel); + backgroundColorRow.add(backgroundColorChooser); + plasmaMenuTweaksFrame.add(backgroundColorRow); + + this.mainBox.append(plasmaMenuTweaksFrame); + + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true + }); + resetButton.set_sensitive(true); + resetButton.connect('clicked', ()=> { + let foregroundColor = this._settings.get_default_value('plasma-selected-color').unpack(); + let backgroundColor = this._settings.get_default_value('plasma-selected-background-color').unpack(); + let hoverEnabled = this._settings.get_default_value('plasma-enable-hover').unpack(); + let showDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this._settings.reset('searchbar-default-top-location'); + searchbarLocationCombo.set_active(this._settings.get_enum(searchBarLocationSetting)); + hoverSwitch.set_active(hoverEnabled); + color.parse(foregroundColor); + foregroundColorChooser.set_rgba(color); + color.parse(backgroundColor); + backgroundColorChooser.set_rgba(color); + descriptionsSwitch.set_active(showDescriptions); + this._settings.reset('plasma-selected-color'); + this._settings.reset('plasma-selected-background-color'); + this._settings.reset('plasma-enable-hover'); + this._settings.reset('apps-show-extra-details'); + this._settings.set_boolean('reload-theme', true); + }); + this.mainBox.append(resetButton); + } + _loadBriskMenuTweaks(){ + let briskMenuTweaksFrame = new PW.FrameBox(); + briskMenuTweaksFrame.add(this._createActivateOnHoverRow()); + briskMenuTweaksFrame.add(this._createSearchBarLocationRow()); + briskMenuTweaksFrame.add(this._createFlipHorizontalRow()); + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_max_content_height(100); + pinnedAppsScrollWindow.set_min_content_height(100); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('brisk-shortcuts-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('brisk-shortcuts-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Brisk Menu Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + + this.mainBox.append(briskMenuTweaksFrame); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + } + _loadChromebookTweaks(){ + let chromeBookTweaksFrame = new PW.FrameBox(); + chromeBookTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(chromeBookTweaksFrame); + } + _loadElementaryTweaks(){ + let elementaryTweaksFrame = new PW.FrameBox(); + elementaryTweaksFrame.add(this._createSearchBarLocationRow()); + this.mainBox.append(elementaryTweaksFrame); + } + _loadBudgieMenuTweaks(){ + let budgieMenuTweaksFrame = new PW.FrameBox(); + budgieMenuTweaksFrame.add(this._createActivateOnHoverRow()); + budgieMenuTweaksFrame.add(this._createSearchBarLocationRow()); + budgieMenuTweaksFrame.add(this._createFlipHorizontalRow()); + + let enableActivitiesRow = new PW.FrameBoxRow(); + let enableActivitiesLabel = new Gtk.Label({ + label: _('Enable Activities Overview Shortcut'), + xalign:0, + hexpand: true, + }); + let enableActivitiesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableActivitiesSwitch.set_active(this._settings.get_boolean('enable-activities-shortcut')); + enableActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-activities-shortcut', widget.get_active()); + }); + enableActivitiesRow.add(enableActivitiesLabel); + enableActivitiesRow.add(enableActivitiesSwitch); + budgieMenuTweaksFrame.add(enableActivitiesRow); + + this.mainBox.append(budgieMenuTweaksFrame); + } + _loadRunnerMenuTweaks(){ + let runnerMenuTweaksFrame = new PW.FrameBox(); + let runnerPositionRow = new PW.FrameBoxRow(); + let runnerPositionLabel = new Gtk.Label({ + label: _('Position'), + xalign:0, + hexpand: true, + }); + let runnerPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + runnerPositionCombo.append_text(_("Top")); + runnerPositionCombo.append_text(_("Centered")); + runnerPositionCombo.set_active(this._settings.get_enum('runner-position')); + runnerPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('runner-position', widget.get_active()); + }); + runnerPositionRow.add(runnerPositionLabel); + runnerPositionRow.add(runnerPositionCombo); + runnerMenuTweaksFrame.add(runnerPositionRow); + + let runnerWidthRow = new PW.FrameBoxRow(); + let runnerWidthLabel = new Gtk.Label({ + label: _("Width"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerWidthScale.add_mark(500, Gtk.PositionType.TOP, _("Default")); + runnerWidthScale.set_value(this._settings.get_int('runner-menu-width')); + runnerWidthScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-width', widget.get_value()); + }); + runnerWidthRow.add(runnerWidthLabel); + runnerWidthRow.add(runnerWidthScale); + runnerMenuTweaksFrame.add(runnerWidthRow); + + let runnerHeightRow = new PW.FrameBoxRow(); + let runnerHeightLabel = new Gtk.Label({ + label: _("Height"), + use_markup: true, + hexpand: true, + xalign: 0 + }); + let runnerHeightScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: 1000, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + runnerHeightScale.add_mark(400, Gtk.PositionType.TOP, _("Default")); + runnerHeightScale.set_value(this._settings.get_int('runner-menu-height')); + runnerHeightScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-menu-height', widget.get_value()); + }); + + runnerHeightRow.add(runnerHeightLabel); + runnerHeightRow.add(runnerHeightScale); + runnerMenuTweaksFrame.add(runnerHeightRow); + + let runnerFontSizeRow = new PW.FrameBoxRow(); + let runnerFontSizeLabel = new Gtk.Label({ + label: _("Font Size"), + hexpand: true, + use_markup: true, + xalign: 0 + }); + let runnerFontSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 30, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + + runnerFontSizeScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); + runnerFontSizeScale.set_value(this._settings.get_int('runner-font-size')); + runnerFontSizeScale.connect('value-changed', (widget) => { + this._settings.set_int('runner-font-size', widget.get_value()); + }); + runnerFontSizeRow.add(runnerFontSizeLabel); + runnerFontSizeRow.add(runnerFontSizeScale); + runnerMenuTweaksFrame.add(runnerFontSizeRow); + + let frequentAppsRow = new PW.FrameBoxRow(); + let frequentAppsLabel = new Gtk.Label({ + label: _("Show Frequent Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let frequentAppsSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-show-frequent-apps')) + frequentAppsSwitch.set_active(true); + frequentAppsSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-show-frequent-apps', widget.get_active()); + }); + frequentAppsRow.add(frequentAppsLabel); + frequentAppsRow.add(frequentAppsSwitch); + runnerMenuTweaksFrame.add(frequentAppsRow); + + let inheritThemeGapRow = new PW.FrameBoxRow(); + let inheritThemeGapLabel = new Gtk.Label({ + label: _("Inherit Shell Theme Popup Gap"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let inheritThemeGapSwitch = new Gtk.Switch(); + if(this._settings.get_boolean('runner-use-theme-gap')) + inheritThemeGapSwitch.set_active(true); + inheritThemeGapSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('runner-use-theme-gap', widget.get_active()); + }); + inheritThemeGapRow.add(inheritThemeGapLabel); + inheritThemeGapRow.add(inheritThemeGapSwitch); + runnerMenuTweaksFrame.add(inheritThemeGapRow); + + this.mainBox.append(runnerMenuTweaksFrame); + } + _loadUnityTweaks(){ + let pinnedAppsFrame = new PW.FrameBox(); + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.UNITY); + this.mainBox.append(widgetFrame); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('unity-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('unity-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Unity Layout Buttons") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + this.mainBox.append(pinnedAppsScrollWindow); + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Button Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('unity-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('unity-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadRavenTweaks(){ + let generalTweaksFrame = new PW.FrameBox(); + let homeScreenRow = new PW.FrameBoxRow(); + let homeScreenLabel = new Gtk.Label({ + label: _('Default View'), + xalign:0, + hexpand: true, + }); + let homeScreenCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + homeScreenCombo.append_text(_("Home Screen")); + homeScreenCombo.append_text(_("All Programs")); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + homeScreenCombo.set_active(homeScreen ? 0 : 1); + homeScreenCombo.connect('changed', (widget) => { + let enable = widget.get_active() ==0 ? true : false; + this._settings.set_boolean('enable-unity-homescreen', enable); + }); + homeScreenRow.add(homeScreenLabel); + homeScreenRow.add(homeScreenCombo); + generalTweaksFrame.add(homeScreenRow); + this.mainBox.append(generalTweaksFrame); + + let ravenPositionRow = new PW.FrameBoxRow(); + let ravenPositionLabel = new Gtk.Label({ + label: _('Position on Monitor'), + xalign:0, + hexpand: true, + }); + let ravenPositionCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + ravenPositionCombo.append_text(_("Left")); + ravenPositionCombo.append_text(_("Right")); + let ravenPosition = this._settings.get_enum('raven-position'); + ravenPositionCombo.set_active(ravenPosition); + ravenPositionCombo.connect('changed', (widget) => { + this._settings.set_enum('raven-position', widget.get_active()); + }); + ravenPositionRow.add(ravenPositionLabel); + ravenPositionRow.add(ravenPositionCombo); + generalTweaksFrame.add(ravenPositionRow); + generalTweaksFrame.add(this._createActivateOnHoverRow()); + let widgetFrame = this._createWidgetsRows(Constants.MenuLayout.RAVEN); + this.mainBox.append(widgetFrame); + } + _loadMintMenuTweaks(){ + let mintMenuTweaksFrame = new PW.FrameBox(); + mintMenuTweaksFrame.add(this._createActivateOnHoverRow()); + mintMenuTweaksFrame.add(this._createSearchBarLocationRow()); + mintMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(mintMenuTweaksFrame); + + let pinnedAppsHeaderLabel = new Gtk.Label({ + label: "" + _("Mint Layout Shortcuts") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsHeaderLabel); + + let pinnedAppsFrame = new PW.FrameBox(); + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow(); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + let savePinnedAppsButton = new Gtk.Button({ + label: _("Save"), + }); + savePinnedAppsButton.connect('clicked', ()=> { + let array = []; + for(let x = 0;x < pinnedAppsFrame.count; x++) { + array.push(pinnedAppsFrame.get_index(x)._name); + array.push(pinnedAppsFrame.get_index(x)._icon); + array.push(pinnedAppsFrame.get_index(x)._cmd); + } + this._settings.set_strv('mint-pinned-app-list',array); + savePinnedAppsButton.set_sensitive(false); + }); + savePinnedAppsButton.set_halign(Gtk.Align.END); + savePinnedAppsButton.set_sensitive(false); + + this._loadPinnedApps(this._settings.get_strv('mint-pinned-app-list'), pinnedAppsFrame, savePinnedAppsButton, pinnedAppsScrollWindow); + pinnedAppsScrollWindow.set_child(pinnedAppsFrame); + this.mainBox.append(pinnedAppsScrollWindow); + + this.mainBox.append(savePinnedAppsButton); + + let pinnedAppsSeparatorHeaderLabel = new Gtk.Label({ + label: "" + _("Shortcut Separator Position") + "", + use_markup: true, + xalign: 0 + }); + this.mainBox.append(pinnedAppsSeparatorHeaderLabel); + + let pinnedAppsSeparatorFrame = new PW.FrameBox(); + let pinnedAppsSeparatorRow = new PW.FrameBoxRow(); + let pinnedAppsSeparatorLabel = new Gtk.Label({ + label: _("Separator Position"), + use_markup: true, + xalign: 0 + }); + let pinnedAppsSeparatorScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 7, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + }); + pinnedAppsSeparatorScale.add_mark(0, Gtk.PositionType.BOTTOM, _("None")); + pinnedAppsSeparatorScale.set_value(this._settings.get_int('mint-separator-index')); + pinnedAppsSeparatorScale.connect('value-changed', (widget) => { + this._settings.set_int('mint-separator-index', widget.get_value()); + }); + + let infoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + infoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _('Adjust the position of the separator in the button panel'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorLabel); + pinnedAppsSeparatorRow.add(pinnedAppsSeparatorScale); + pinnedAppsSeparatorRow.add(infoButton); + pinnedAppsSeparatorFrame.add(pinnedAppsSeparatorRow); + this.mainBox.append(pinnedAppsSeparatorFrame); + } + _loadPinnedApps(array,frame, savePinnedAppsButton, scrollWindow) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(scrollWindow); + frameRow._name = array[i]; + frameRow._icon = Prefs.getIconPath([array[i], array[i+1], array[i+2]]); + frameRow._cmd = array[i+2]; + frameRow.saveButton = savePinnedAppsButton; + frameRow.hasEditButton = true; + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + frameRow.add(frameLabel); + + Prefs.checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: frame, + buttons: [savePinnedAppsButton], + modifyButton: true, + changeButton: true + }); + + buttonBox.connect('change', ()=> { + let dialog = new Prefs.AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.OTHER); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + let icon = Prefs.getIconPath(newPinnedApps); + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new Prefs.AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.OTHER, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + arcMenuImage.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + frame.show(); + savePinnedAppsButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(buttonBox); + frame.add(frameRow); + } + } + _loadWhiskerMenuTweaks(){ + let whiskerMenuTweaksFrame = new PW.FrameBox(); + whiskerMenuTweaksFrame.add(this._createActivateOnHoverRow()); + whiskerMenuTweaksFrame.add(this._createAvatarShapeRow()); + whiskerMenuTweaksFrame.add(this._createSearchBarLocationRow()); + whiskerMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(whiskerMenuTweaksFrame); + } + _loadRedmondMenuTweaks(){ + let redmondMenuTweaksFrame = new PW.FrameBox(); + redmondMenuTweaksFrame.add(this._createSearchBarLocationRow()); + + redmondMenuTweaksFrame.add(this._createFlipHorizontalRow()); + redmondMenuTweaksFrame.add(this._createAvatarShapeRow()); + redmondMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(redmondMenuTweaksFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + + } + _loadInsiderMenuTweaks(){ + let insiderMenuTweaksFrame = new PW.FrameBox(); + insiderMenuTweaksFrame.add(this._createAvatarShapeRow()); + this.mainBox.append(insiderMenuTweaksFrame); + } + _loadGnomeMenuTweaks(){ + let gnomeMenuTweaksFrame = new PW.FrameBox(); + gnomeMenuTweaksFrame.add(this._createActivateOnHoverRow()); + gnomeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(gnomeMenuTweaksFrame); + } + _loadPlaceHolderTweaks(){ + let placeHolderFrame = new PW.FrameBox(); + let placeHolderRow = new PW.FrameBoxRow(); + let placeHolderLabel = new Gtk.Label({ + label: _("Nothing Yet!"), + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + placeHolderRow.add(placeHolderLabel); + placeHolderFrame.add(placeHolderRow); + this.mainBox.append(placeHolderFrame); + } + _loadTogneeMenuTweaks(){ + let togneeMenuTweaksFrame = new PW.FrameBox(); + let searchBarBottomDefault = true; + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END + }); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view-tognee')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view-tognee', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + togneeMenuTweaksFrame.add(defaultLeftBoxRow); + togneeMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + togneeMenuTweaksFrame.add(this._createFlipHorizontalRow()); + this.mainBox.append(togneeMenuTweaksFrame); + } + _loadArcMenuTweaks(){ + let arcMenuTweaksFrame = new PW.FrameBox(); + let defaultLeftBoxRow = new PW.FrameBoxRow(); + let defaultLeftBoxLabel = new Gtk.Label({ + label: _("Default View"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let defaultLeftBoxCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + defaultLeftBoxCombo.append_text(_("Pinned Apps")); + defaultLeftBoxCombo.append_text(_("Categories List")); + defaultLeftBoxCombo.append_text(_("Frequent Apps")); + defaultLeftBoxCombo.append_text(_("All Programs")); + defaultLeftBoxCombo.set_active(this._settings.get_enum('default-menu-view')); + defaultLeftBoxCombo.connect('changed', (widget) => { + this._settings.set_enum('default-menu-view', widget.get_active()); + }); + + defaultLeftBoxRow.add(defaultLeftBoxLabel); + defaultLeftBoxRow.add(defaultLeftBoxCombo); + arcMenuTweaksFrame.add(defaultLeftBoxRow); + + let searchBarBottomDefault = true; + arcMenuTweaksFrame.add(this._createSearchBarLocationRow(searchBarBottomDefault)); + arcMenuTweaksFrame.add(this._createFlipHorizontalRow()); + arcMenuTweaksFrame.add(this._createAvatarShapeRow()); + arcMenuTweaksFrame.add(this._disableAvatarRow()); + + let placesFrame = new PW.FrameBox(); + let externalDeviceRow = new PW.FrameBoxRow(); + let externalDeviceLabel = new Gtk.Label({ + label: _("External Devices"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let externalDeviceButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-external-devices')) + externalDeviceButton.set_active(true); + externalDeviceButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-external-devices', widget.get_active()); + }); + externalDeviceRow.add(externalDeviceLabel); + externalDeviceRow.add(externalDeviceButton); + + placesFrame.add(externalDeviceRow); + + let bookmarksRow = new PW.FrameBoxRow(); + let bookmarksLabel = new Gtk.Label({ + label: _("Bookmarks"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let bookmarksButton = new Gtk.Switch(); + if(this._settings.get_boolean('show-bookmarks')) + bookmarksButton.set_active(true); + bookmarksButton.connect('notify::active', (widget) => { + this._settings.set_boolean('show-bookmarks', widget.get_active()); + }); + bookmarksRow.add(bookmarksLabel); + bookmarksRow.add(bookmarksButton); + + placesFrame.add(bookmarksRow); + this.mainBox.append(arcMenuTweaksFrame); + + let extraCategoriesFrame = new PW.FrameBox(); + let extraCategoriesRow = new PW.FrameBoxRow(); + let extraCategoriesButtonRow = new PW.FrameBoxRow(); + let extraCategoriesLocationRow = new PW.FrameBoxRow(); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Shortcuts") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + this.mainBox.append(placesFrame); + this.mainBox.append(new Gtk.Label({ + label: "" + _("Extra Categories Quick Links") + "" + + "\n" + '' + _("Display quick links of extra categories on the home page") + "" + + "\n" + '' + _("See Customize Menu -> Extra Categories") + "", + use_markup: true, + xalign: 0, + hexpand: true + })); + let extraCategoriesLinksBox = new Prefs.MenuSettingsCategoriesPage(this._settings, "arcmenu-extra-categories-links"); + extraCategoriesLinksBox.categoriesFrame.unparent(); + extraCategoriesLinksBox.buttonRow.unparent(); + extraCategoriesRow.add(extraCategoriesLinksBox.categoriesFrame); + extraCategoriesLinksBox.categoriesFrame.hexpand = true; + extraCategoriesLinksBox.categoriesFrame.halign = Gtk.Align.FILL; + extraCategoriesButtonRow.add(extraCategoriesLinksBox.buttonRow); + extraCategoriesFrame.add(extraCategoriesRow); + extraCategoriesFrame.add(extraCategoriesButtonRow); + + this.mainBox.append(extraCategoriesFrame); + + let extraCategoriesLocationFrame = new PW.FrameBox(); + let extraCategoriesLocationLabel = new Gtk.Label({ + label: _("Quick Links Location"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let extraCategoriesLocationCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + extraCategoriesLocationCombo.append_text(_("Bottom")); + extraCategoriesLocationCombo.append_text(_("Top")); + extraCategoriesLocationCombo.set_active(this._settings.get_enum('arcmenu-extra-categories-links-location')); + extraCategoriesLocationCombo.connect('changed', (widget) => { + this._settings.set_enum('arcmenu-extra-categories-links-location' , widget.get_active()); + }); + + extraCategoriesLocationRow.add(extraCategoriesLocationLabel); + extraCategoriesLocationRow.add(extraCategoriesLocationCombo); + extraCategoriesLocationFrame.add(extraCategoriesLocationRow); + this.mainBox.append(extraCategoriesLocationFrame); + } + _createWidgetsRows(layout){ + let weatherWidgetSetting = 'enable-weather-widget-raven'; + let clockWidgetSetting = 'enable-clock-widget-raven'; + if(layout == Constants.MenuLayout.RAVEN){ + weatherWidgetSetting = 'enable-weather-widget-raven'; + clockWidgetSetting = 'enable-clock-widget-raven'; + } + else{ + weatherWidgetSetting = 'enable-weather-widget-unity'; + clockWidgetSetting = 'enable-clock-widget-unity'; + } + + let widgetFrame = new PW.FrameBox(); + let weatherWidgetRow = new PW.FrameBoxRow(); + let weatherWidgetLabel = new Gtk.Label({ + label: _("Enable Weather Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let weatherWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + weatherWidgetSwitch.set_active(this._settings.get_boolean(weatherWidgetSetting)); + weatherWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(weatherWidgetSetting, widget.get_active()); + }); + + weatherWidgetRow.add(weatherWidgetLabel); + weatherWidgetRow.add(weatherWidgetSwitch); + widgetFrame.add(weatherWidgetRow); + + let clockWidgetRow = new PW.FrameBoxRow(); + let clockWidgetLabel = new Gtk.Label({ + label: _("Enable Clock Widget"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clockWidgetSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + clockWidgetSwitch.set_active(this._settings.get_boolean(clockWidgetSetting)); + clockWidgetSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(clockWidgetSetting, widget.get_active()); + }); + + clockWidgetRow.add(clockWidgetLabel); + clockWidgetRow.add(clockWidgetSwitch); + widgetFrame.add(clockWidgetRow); + + return widgetFrame; + } +}); diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js new file mode 100644 index 0000000..b29a5bb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/unity.js @@ -0,0 +1,445 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.GRID, + SearchDisplayType: Constants.DisplayType.GRID, + ColumnSpacing: 15, + RowSpacing: 15, + VerticalMainBox: true, + DefaultMenuWidth: 750, + DefaultIconGridStyle: "LargeIconGrid", + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + + createLayout(){ + super.createLayout(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen) + this.activeCategory = _("Pinned Apps"); + else + this.activeCategory = _("All Programs"); + + this.topBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false, + style: 'padding-bottom: 10px; padding-right: 15px;' + }); + + this.mainBox.add_child(this.topBox); + this.categoriesButton = new MW.CategoriesButton(this); + + this.subMainBox= new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.mainBox.add_child(this.subMainBox); + + this.searchBox.actor.y_align = Clutter.ActorAlign.CENTER; + this.searchBox.actor.y_expand = true; + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 0px 15px 0px 15px;"; + this.topBox.add_child(this.searchBox.actor); + this.topBox.add_child(this.categoriesButton.actor); + + this.applicationsBox = new St.BoxLayout({ + vertical: true, + style: "padding-bottom: 10px;" + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade', + }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + + this.arcMenu.box.style = "padding-bottom:0px;"; + + this.actionsContainerBoxStyle = "margin: 0px; spacing: 0px;background-color:rgba(186, 196,201, 0.1) ; padding: 5px 5px;"+ + "border-color:rgba(186, 196,201, 0.2) ; border-top-width: 1px;"; + this.themeNodeBorderRadius = ""; + this.actionsContainerBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.END, + vertical: false, + style: this.actionsContainerBoxStyle + this.themeNodeBorderRadius + }); + + this.subMainBox.add_child(this.actionsContainerBox); + + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px;"; + this.appsBox = new St.BoxLayout({ + vertical: true + }); + this.actionsContainerBox.add_child(this.actionsBox); + + this.widgetBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + vertical: false, + style_class: 'datemenu-displays-box' + }); + + this.widgetBox.style = "margin: 0px; spacing: 10px; padding: 10px 50px;"; + this._weatherItem = new MW.WeatherSection(this); + this._weatherItem.style = "border-radius:4px; width: 350px; padding: 10px; margin: 0px"; + this._clocksItem = new MW.WorldClocksSection(this); + this._clocksItem.style = "border-radius:4px; padding: 10px; margin: 0px"; + + this.appShortcuts = []; + this.shortcutsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER, + vertical: true + }); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.layoutProperties.ColumnSpacing, + row_spacing: this.layoutProperties.RowSpacing + }); + this.shortcutsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.shortcutsGrid); + + this.shortcutsBox.add_child(this.shortcutsGrid); + + //Add Application Shortcuts to menu (Software, Settings, Tweaks, Terminal) + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + let isContainedInCategory = false; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcuts[i][1], applicationShortcuts[i][2], Constants.DisplayType.GRID, isContainedInCategory); + this.appShortcuts.push(shortcutMenuItem); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + this._createCategoriesMenu(); + this.loadExtraPinnedApps(); + + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.applicationsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView) + this.setDefaultMenuView(); + } + + _addSeparator(){ + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.ALWAYS_SHOW, Constants.SeparatorAlignment.VERTICAL); + this.actionsBox.add_child(verticalSeparator); + } + + loadExtraPinnedApps(){ + this.actionsContainerBox.remove_child(this.actionsBox); + this.actionsBox.destroy_all_children(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + vertical: false + }); + this.actionsBox.style = "spacing: 10px; padding: 5px 0px;"; + this.actionsContainerBox.add_child(this.actionsBox); + + super.loadExtraPinnedApps(this._settings.get_strv('unity-pinned-app-list'), this._settings.get_int('unity-separator-index')); + } + + _createExtraPinnedAppsList(){ + let pinnedApps = []; + pinnedApps.push(_("Home"), "ArcMenu_Home", "ArcMenu_Home"); + pinnedApps.push(_("Documents"), "ArcMenu_Documents", "ArcMenu_Documents"); + pinnedApps.push(_("Downloads"), "ArcMenu_Downloads", "ArcMenu_Downloads"); + + let software = Utils.findSoftwareManager(); + if(software) + pinnedApps.push(_("Software"), 'system-software-install-symbolic', software); + else + pinnedApps.push(_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"); + + pinnedApps.push(_("Files"), "system-file-manager", "org.gnome.Nautilus.desktop"); + pinnedApps.push(_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"); + pinnedApps.push(_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"); + pinnedApps.push(_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"); + + this.shouldLoadPinnedApps = false; // We don't want to trigger a setting changed event + this._settings.set_strv('unity-pinned-app-list', pinnedApps); + this.shouldLoadPinnedApps = true; + return pinnedApps; + } + + _createCategoriesMenu(){ + this.categoriesMenu = new PopupMenu.PopupMenu(this.categoriesButton.actor, 0.5, St.Side.TOP); + this.categoriesMenu.blockSourceEvents = true; + this.categoriesMenu.connect('open-state-changed', (menu, open) => { + if(open){ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.categoriesButton.tooltip){ + this.categoriesButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + else{ + this.categoriesButton.active = false; + this.categoriesButton.sync_hover(); + this.categoriesButton.hovered = this.categoriesButton.hover; + } + }); + this.section = new PopupMenu.PopupMenuSection(); + this.categoriesMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + overlay_scrollbars: true, + reactive:true + }); + this.leftPanelPopup.add_child(this.categoriesScrollBox); + + this.categoriesBox = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + this.categoriesScrollBox.clip_to_allocation = true; + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(350 / scaleFactor); + this.leftPanelPopup.style = `max-height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this._displayCategories(); + this.subMenuManager.addMenu(this.categoriesMenu); + this.categoriesMenu.actor.hide(); + Main.uiGroup.add_child(this.categoriesMenu.actor); + } + + toggleCategoriesMenu(){ + let appsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.categoriesMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.categoriesMenu.actor.add_style_class_name( customStyle ? 'arc-menu' : 'popup-menu'); + this.categoriesButton.tooltip.hide(); + + this.categoriesMenu.toggle(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + let homeScreen = this._settings.get_boolean('enable-unity-homescreen'); + if(homeScreen){ + this.activeCategory = _("Pinned Apps"); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + this.displayPinnedApps(); + } + else{ + this.activeCategory = _("All Programs"); + let isGridLayout = true; + this.displayAllApps(isGridLayout); + this.activeCategoryType = Constants.CategoryType.ALL_PROGRAMS; + } + } + + updateStyle(){ + super.updateStyle(); + let removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + this.themeNodeBorderRadius = "border-radius: 0px 0px " + borderRadius + "px " + borderRadius + "px;"; + this.actionsContainerBox.style = this.actionsContainerBoxStyle + this.themeNodeBorderRadius; + + if(removeMenuArrow) + this.arcMenu.box.style = "padding-bottom:0px; margin:0px;"; + else + this.arcMenu.box.style = "padding-bottom:0px;"; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + let categoryMenuItem = new MW.CategoryMenuItem(this, Constants.CategoryType.HOME_SCREEN, Constants.DisplayType.LIST); + this.categoryDirectories.set(Constants.CategoryType.HOME_SCREEN, categoryMenuItem); + this.hasPinnedApps = true; + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(categoryEnum == Constants.CategoryType.PINNED_APPS) + shouldShow = false; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + _displayCategories(){ + for(let categoryMenuItem of this.categoryDirectories.values()){ + this.categoriesBox.add_actor(categoryMenuItem.actor); + } + } + + displayPinnedApps() { + if(this.activeCategoryType === Constants.CategoryType.HOME_SCREEN) + this._clearActorsFromBox(this.applicationsBox); + else + this._clearActorsFromBox(); + this.subMainBox.remove_child(this.actionsContainerBox); + this.activeCategory = _("Pinned Apps"); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.PINNED_APPS, this.applicationsGrid); + this.activeCategory = _("Shortcuts"); + this._displayAppList(this.appShortcuts, Constants.CategoryType.HOME_SCREEN, this.shortcutsGrid); + if(!this.applicationsBox.contains(this.shortcutsBox)) + this.applicationsBox.add_child(this.shortcutsBox); + this.widgetBox.remove_all_children(); + if(this._settings.get_boolean('enable-clock-widget-unity')) + this.widgetBox.add_child(this._clocksItem); + if(this._settings.get_boolean('enable-weather-widget-unity')) + this.widgetBox.add_child(this._weatherItem); + if(!this.subMainBox.contains(this.widgetBox)) + this.subMainBox.add_child(this.widgetBox); + this.subMainBox.add_child(this.actionsContainerBox); + } + + displayRecentFiles(){ + super.displayRecentFiles(); + let label = this._createLabelWithSeparator(_("Recent Files")); + this.applicationsBox.insert_child_at_index(label, 0); + this.activeCategoryType = Constants.CategoryType.RECENT_FILES; + this.applicationsBox.add_style_class_name('margin-box'); + } + + displayCategoryAppList(appList, category){ + this._clearActorsFromBox(); + this._displayAppList(appList, category, this.applicationsGrid); + } + + _clearActorsFromBox(box) { + if(this.categoriesMenu.isOpen) + this.categoriesMenu.toggle(); + if(this.subMainBox.contains(this.widgetBox)){ + this.subMainBox.remove_child(this.widgetBox); + } + this.applicationsBox.remove_style_class_name('margin-box'); + super._clearActorsFromBox(box); + } + + _displayAppList(apps, category, grid){ + super._displayAppList(apps, category, grid); + + let label = this._createLabelWithSeparator(this.activeCategory); + if(grid === this.applicationsGrid) + this.applicationsBox.insert_child_at_index(label.actor, 0); + else + this.applicationsBox.insert_child_at_index(label.actor, 2); + } + + destroy(){ + if(this._clocksItem) + this._clocksItem.destroy(); + if(this._weatherItem) + this._weatherItem.destroy(); + + this.arcMenu.box.style = null; + this.arcMenu.actor.style = null; + + super.destroy(); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js new file mode 100644 index 0000000..ab4958e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/whisker.js @@ -0,0 +1,187 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, Gtk, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + DisplayType: Constants.DisplayType.LIST, + SearchDisplayType: Constants.DisplayType.LIST, + GridColumns: 1, + ColumnSpacing: 0, + RowSpacing: 0, + SupportsCategoryOnHover: true, + VerticalMainBox: true, + DefaultCategoryIconSize: Constants.MEDIUM_ICON_SIZE, + DefaultApplicationIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.MEDIUM_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: false + }); + + this.actionsBox.style = "spacing: 6px; margin: 0px 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.user = new MW.UserMenuItem(this, Constants.DisplayType.LIST); + this.user.actor.x_expand = true; + this.user.actor.x_align = Clutter.ActorAlign.FILL; + this.actionsBox.add_child(this.user.actor); + + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + + let powerOptions = this._settings.get_value("power-options").deep_unpack(); + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let shouldShow = powerOptions[i][1]; + if(shouldShow){ + let powerButton = new MW.PowerButton(this, powerType); + this.actionsBox.add_child(powerButton); + } + } + + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.TOP){ + this.searchBox.style = "margin: 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + else{ + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + this.mainBox.add_child(separator); + } + + //Sub Main Box -- stores left and right box + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: false, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.rightBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'right-panel-plus45' + }); + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + this.applicationsScrollBox = this._createScrollBox({ + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'right-panel-plus45 ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.rightBox.add_child(this.applicationsScrollBox); + + this.leftBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'left-panel' + }); + + let horizonalFlip = this._settings.get_boolean("enable-horizontal-flip"); + this.subMainBox.add_child(horizonalFlip ? this.rightBox : this.leftBox); + let verticalSeparator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.VERTICAL); + this.subMainBox.add_child(verticalSeparator); + this.subMainBox.add_child(horizonalFlip ? this.leftBox : this.rightBox); + + this.categoriesScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + overlay_scrollbars: true + }); + + this.leftBox.add_child(this.categoriesScrollBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); + this.categoriesScrollBox.add_actor(this.categoriesBox); + if(this._settings.get_enum('searchbar-default-top-location') === Constants.SearchbarLocation.BOTTOM){ + this.searchBox.style = "margin: 10px 10px 0px 10px;"; + this.mainBox.add_child(this.searchBox.actor); + } + this.loadCategories(); + this.loadPinnedApps(); + + this.setDefaultMenuView(); + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + this.displayCategories(); + this.categoryDirectories.values().next().value.displayAppList(); + this.activeMenuItem = this.categoryDirectories.values().next().value; + if(this.arcMenu.isOpen) + this.activeMenuItem.active = true; + } + + loadCategories(){ + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + + let extraCategories = this._settings.get_value("extra-categories").deep_unpack(); + + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let shouldShow = extraCategories[i][1]; + if(shouldShow){ + let categoryMenuItem = new MW.CategoryMenuItem(this, categoryEnum, Constants.DisplayType.LIST); + this.categoryDirectories.set(categoryEnum, categoryMenuItem); + } + } + + super.loadCategories(); + } + + displayCategories(){ + super.displayCategories(this.categoriesBox); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js new file mode 100644 index 0000000..047bd63 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/menulayouts/windows.js @@ -0,0 +1,465 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Gio, Gtk, Shell, St} = imports.gi; +const BaseMenuLayout = Me.imports.menulayouts.baseMenuLayout; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PlaceDisplay = Me.imports.placeDisplay; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var createMenu = class extends BaseMenuLayout.BaseLayout{ + constructor(menuButton) { + super(menuButton, { + Search: true, + SearchDisplayType: Constants.DisplayType.LIST, + DisplayType: Constants.DisplayType.LIST, + ColumnSpacing: 0, + RowSpacing: 0, + DefaultMenuWidth: 300, + DefaultIconGridStyle: "SmallIconGrid", + VerticalMainBox: false, + DefaultCategoryIconSize: Constants.LARGE_ICON_SIZE, + DefaultApplicationIconSize: Constants.LARGE_ICON_SIZE, + DefaultQuickLinksIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultButtonsIconSize: Constants.EXTRA_SMALL_ICON_SIZE, + DefaultPinnedIconSize: Constants.LARGE_ICON_SIZE, + }); + } + createLayout(){ + super.createLayout(); + this.actionsBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.FILL, + vertical: true + }); + this.actionsBox.style = "margin: 0px 5px 0px 10px; spacing: 10px;"; + this.mainBox.add_child(this.actionsBox); + + this.extrasButton = new MW.ExtrasButton(this); + this.extrasButton.actor.y_expand = true; + this.extrasButton.actor.y_align= Clutter.ActorAlign.START; + this.actionsBox.add_child(this.extrasButton.actor); + let userButton = new MW.UserMenuItem(this, Constants.DisplayType.BUTTON); + this.actionsBox.add_child(userButton.actor); + let path = GLib.get_user_special_dir(imports.gi.GLib.UserDirectory.DIRECTORY_DOCUMENTS); + if (path != null){ + let placeInfo = new MW.PlaceInfo(Gio.File.new_for_path(path), _("Documents")); + let isContainedInCategory = false; + let placeMenuItem = new MW.PlaceMenuItem(this, placeInfo, Constants.DisplayType.BUTTON, isContainedInCategory); + this.actionsBox.add_child(placeMenuItem.actor); + } + let settingsButton = new MW.SettingsButton(this); + this.actionsBox.add_child(settingsButton.actor); + this.leaveButton = new MW.LeaveButton(this); + this.actionsBox.add_child(this.leaveButton.actor); + + this.subMainBox = new St.BoxLayout({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.FILL, + vertical: true, + style_class: 'margin-box' + }); + this.mainBox.add_child(this.subMainBox); + + this.pinnedAppsScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: this.disableFadeEffect ? '' : 'vfade' + }); + + this.pinnedAppsBox = new St.BoxLayout({ + vertical: true, + x_expand: true + }); + this.pinnedAppsScrollBox.add_actor(this.pinnedAppsBox); + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: 10, + row_spacing: 10 + }); + this.pinnedAppsGrid = new St.Widget({ + x_expand: true, + x_align: Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this.pinnedAppsGrid); + + this.searchBox.name = "ArcSearchEntryRound"; + this.searchBox.style = "margin: 15px 10px 0px 10px;"; + + this.applicationsBox = new St.BoxLayout({ + vertical: true + }); + + this.applicationsScrollBox = this._createScrollBox({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + style_class: 'left-panel ' + (this.disableFadeEffect ? '' : 'small-vfade'), + }); + + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.subMainBox.add_child(this.applicationsScrollBox); + this.subMainBox.add_child(this.searchBox.actor); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + + let SOFTWARE_TRANSLATIONS = [_("Software"), _("Settings"), _("Tweaks"), _("Terminal"), _("Activities Overview"), _("ArcMenu Settings")]; + let applicationShortcutsList = this._settings.get_value('application-shortcuts-list').deep_unpack(); + this.applicationShortcuts = []; + for(let i = 0; i < applicationShortcutsList.length; i++){ + let applicationName = applicationShortcutsList[i][0]; + let shortcutMenuItem = new MW.ShortcutMenuItem(this, _(applicationName), applicationShortcutsList[i][1], applicationShortcutsList[i][2], Constants.DisplayType.LIST); + if(shortcutMenuItem.shouldShow) + this.applicationShortcuts.push(shortcutMenuItem.actor); + } + + let directoryShortcutsList = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + this._loadPlaces(directoryShortcutsList); + + this.externalDevicesBox = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true + }); + this._sections = { }; + this.placesManager = new PlaceDisplay.PlacesManager(); + for (let i = 0; i < Constants.SECTIONS.length; i++) { + let id = Constants.SECTIONS[i]; + this._sections[id] = new St.BoxLayout({ + vertical: true + }); + this.placeManagerUpdatedID = this.placesManager.connect(`${id}-updated`, () => { + this._redisplayPlaces(id); + }); + + this._createPlaces(id); + this.externalDevicesBox.add_child(this._sections[id]); + } + + this.updateWidth(); + this.loadCategories(); + this.loadPinnedApps(); + + this._createExtrasMenu(); + this.setDefaultMenuView(); + } + + updateWidth(setDefaultMenuView){ + const widthAdjustment = this._settings.get_int("menu-width-adjustment"); + let menuWidth = this.layoutProperties.DefaultMenuWidth + widthAdjustment; + //Set a 300px minimum limit for the menu width + menuWidth = Math.max(300, menuWidth); + this.pinnedAppsScrollBox.style = `width: ${menuWidth}px;`; + this.layoutProperties.MenuWidth = menuWidth; + if(setDefaultMenuView){ + this.loadPinnedApps(); + this.setDefaultMenuView(); + } + + } + + loadPinnedApps(){ + this.layoutProperties.DisplayType = Constants.DisplayType.GRID; + super.loadPinnedApps(); + this.pinnedAppsGrid.layout_manager.forceGridColumns = this.getColumnsFromGridIconSizeSetting(); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + } + + _createPlaces(id) { + let places = this.placesManager.get(id); + + if(id === 'bookmarks' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Bookmarks"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'devices' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Devices"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + + if(id === 'network' && places.length > 0){ + this._sections[id].add_child(this.createLabelRow(_("Network"))); + for (let i = 0; i < places.length; i++){ + let item = new PlaceDisplay.PlaceMenuItem(this, places[i], Constants.DisplayType.LIST); + this._sections[id].add_child(item); + } + } + } + + _loadPlaces(directoryShortcutsList) { + this.directoryShortcuts = []; + for (let i = 0; i < directoryShortcutsList.length; i++) { + let directory = directoryShortcutsList[i]; + let isContainedInCategory = false; + let placeMenuItem = this.createMenuItem(directory, Constants.DisplayType.LIST, isContainedInCategory); + this.directoryShortcuts.push(placeMenuItem); + } + } + + _createExtrasMenu(){ + this.dummyCursor = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyCursor); + this.extrasMenu = new PopupMenu.PopupMenu(this.dummyCursor, 0, St.Side.TOP); + this.section = new PopupMenu.PopupMenuSection(); + this.extrasMenu.addMenuItem(this.section); + + this.leftPanelPopup = new St.BoxLayout({ + vertical: true, + style_class: 'margin-box' + }); + this.leftPanelPopup._delegate = this.leftPanelPopup; + let headerBox = new St.BoxLayout({ + x_expand: false, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.START, + vertical: true + }); + this.leftPanelPopup.add_child(headerBox); + + this.backButton = new MW.BackMenuItem(this); + this.backButton.connect("activate", () => this.toggleExtrasMenu()); + headerBox.add_child(this.backButton.actor); + let separator = new MW.ArcMenuSeparator(Constants.SeparatorStyle.MEDIUM, Constants.SeparatorAlignment.HORIZONTAL); + headerBox.add_child(separator); + + this.computerScrollBox = this._createScrollBox({ + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + overlay_scrollbars: true, + reactive:true, + style_class: this.disableFadeEffect ? '' : 'small-vfade', + }); + + this.leftPanelPopup.add_child(this.computerScrollBox); + + this.computerBox = new St.BoxLayout({ + vertical: true + }); + this.computerScrollBox.add_actor(this.computerBox); + + this.computerBox.add_child(this.createLabelRow(_("Application Shortcuts"))); + for(let i = 0; i < this.applicationShortcuts.length; i++){ + this.computerBox.add_child(this.applicationShortcuts[i]); + } + this.computerBox.add_child(this.createLabelRow(_("Places"))); + for(let i = 0; i < this.directoryShortcuts.length; i++){ + this.computerBox.add_child(this.directoryShortcuts[i]); + } + this.computerBox.add_child(this.externalDevicesBox); + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + let scaleFactor = themeContext.scale_factor; + let height = Math.round(this._settings.get_int('menu-height') / scaleFactor) - 1; + this.leftPanelPopup.style = `height: ${height}px`; + this.section.actor.add_child(this.leftPanelPopup); + this.subMenuManager.addMenu(this.extrasMenu); + this.extrasMenu.actor.hide(); + Main.uiGroup.add_child(this.extrasMenu.actor); + this.extrasMenu.connect('open-state-changed', (menu, open) => { + if(!open){ + this.extrasButton.active = false; + this.extrasButton.sync_hover(); + this.extrasButton.hovered = this.extrasButton.hover; + } + else{ + if(this.menuButton.tooltipShowingID){ + GLib.source_remove(this.menuButton.tooltipShowingID); + this.menuButton.tooltipShowingID = null; + this.menuButton.tooltipShowing = false; + } + if(this.extrasButton.tooltip){ + this.extrasButton.tooltip.hide(); + this.menuButton.tooltipShowing = false; + } + } + }); + } + + toggleExtrasMenu(){ + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + this.extrasMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.extrasMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + this.extrasButton.tooltip.hide(); + + let themeNode = this.arcMenu.actor.get_theme_node(); + let backgroundColor = themeNode.get_color('-arrow-background-color'); + let borderWidth = themeNode.get_length('-arrow-border-width'); + let borderRadius = themeNode.get_length('-arrow-border-radius'); + let monitorIndex = Main.layoutManager.findIndexForActor(this.menuButton); + let scaleFactor = Main.layoutManager.monitors[monitorIndex].geometry_scale; + borderRadius = borderRadius / scaleFactor; + + let drawBoxShadow = true; + if(backgroundColor?.alpha === 0){ + backgroundColor = themeNode.get_color('background-color'); + if(backgroundColor?.alpha === 0){ + drawBoxShadow = false; + } + } + + let styleProperties, shadowColor; + if(drawBoxShadow){ + shadowColor = backgroundColor.shade(.35); + backgroundColor = Utils.clutterColorToRGBA(backgroundColor); + shadowColor = Utils.clutterColorToRGBA(shadowColor); + styleProperties = "box-shadow: 3px 0px 2px " + shadowColor + "; background-color: " + backgroundColor + ";"; + } + + this.extrasMenu.actor.style = "-boxpointer-gap: 0px; -arrow-border-color: transparent; -arrow-border-width: 0px; width: 250px;" + +"-arrow-base:0px; -arrow-rise: 0px; -arrow-background-color: transparent;" + +"border-radius: " + borderRadius + "px;" + styleProperties; + + this.arcMenu.actor.get_allocation_box(); + let [x, y] = this.arcMenu.actor.get_transformed_position(); + let rise = themeNode.get_length('-arrow-rise'); + + if(this.arcMenu._arrowSide === St.Side.TOP) + y += rise + 1; + else + y += 1; + + if(this.arcMenu._arrowSide === St.Side.LEFT) + x = x + (borderRadius * 2) + rise + 1; + else + x = x + (borderRadius * 2); + + this.dummyCursor.set_position(Math.round(x + borderWidth), Math.round(y + borderWidth)); + this.extrasMenu.toggle(); + if(this.extrasMenu.isOpen){ + this.activeMenuItem = this.backButton; + this.backButton.grab_key_focus(); + } + } + + setDefaultMenuView(){ + super.setDefaultMenuView(); + + this.displayAllApps(); + if(!this._settings.get_boolean('windows-disable-pinned-apps')){ + if(!this.mainBox.contains(this.pinnedAppsScrollBox)) + this.mainBox.add_child(this.pinnedAppsScrollBox); + this.displayPinnedApps(); + } + + let appsScrollBoxAdj = this.pinnedAppsScrollBox.get_vscroll_bar().get_adjustment(); + appsScrollBoxAdj.set_value(0); + } + + displayAllApps(){ + this._clearActorsFromBox(); + let label = this._createLabelWithSeparator(_("Frequent")); + this.activeMenuItemSet = false; + + if(!this._settings.get_boolean('windows-disable-frequent-apps')){ + let mostUsed = Shell.AppUsage.get_default().get_most_used(); + this.frequentAppsList = []; + for (let i = 0; i < mostUsed.length; i++) { + if (mostUsed[i] && mostUsed[i].get_app_info().should_show()){ + let item = new MW.ApplicationMenuItem(this, mostUsed[i], Constants.DisplayType.LIST); + this.frequentAppsList.push(item); + } + } + const MaxItems = 8; + if(this.frequentAppsList.length > 0){ + this.applicationsBox.add_child(label.actor); + for (let i = 0; i < this.frequentAppsList.length && i < MaxItems; i++) { + let item = this.frequentAppsList[i]; + if(item.actor.get_parent()) + item.actor.get_parent().remove_child(item.actor); + if (!item.actor.get_parent()) + this.applicationsBox.add_child(item.actor); + if(!this.activeMenuItemSet){ + this._frequentActiveItem = item; + this.activeMenuItemSet = true; + } + } + } + } + + let appList = []; + this.applicationsMap.forEach((value,key,map) => { + appList.push(key); + }); + appList.sort((a, b) => { + return a.get_name().toLowerCase() > b.get_name().toLowerCase(); + }); + this.layoutProperties.DisplayType = Constants.DisplayType.LIST; + this._displayAppList(appList, Constants.CategoryType.ALL_PROGRAMS, this.applicationsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } + + loadCategories() { + this.categoryDirectories = null; + this.categoryDirectories = new Map(); + this.hasPinnedApps = true; + super.loadCategories(); + } + + _clearActorsFromBox(box){ + super._clearActorsFromBox(box); + this.activeCategoryType = Constants.CategoryType.HOME_SCREEN; + } + + displayPinnedApps() { + super._clearActorsFromBox(this.pinnedAppsBox); + this.pinnedAppsGrid.remove_all_children(); + let label = this.createLabelRow(_("Pinned Apps")); + label.remove_child(label._ornamentLabel); + this.pinnedAppsBox.add_child(label); + this._displayAppList(this.pinnedAppsArray, Constants.CategoryType.HOME_SCREEN, this.pinnedAppsGrid); + if(!this.pinnedAppsBox.contains(this.pinnedAppsGrid)) + this.pinnedAppsBox.add_child(this.pinnedAppsGrid); + + if(this.activeMenuItemSet) + this.activeMenuItem = this._frequentActiveItem; + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/metadata.json b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/metadata.json new file mode 100644 index 0000000..f6d4800 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/metadata.json @@ -0,0 +1,15 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Application menu for GNOME Shell\n\nFeatures include: various menu layouts, built in GNOME search, quick access to system shortcuts, and much more!\n\nCommon solutions for ERROR message:\n - Restart your GNOME session after updating ArcMenu.\n - Install one of the following packages: 'gir1.2-gmenu-3.0' or 'gnome-menus'\n\nGeneral Help:\n - Visit https://gitlab.com/arcmenu/ArcMenu/-/wikis/home\n\nPlease report all bugs or issues at https://gitlab.com/arcmenu/ArcMenu", + "extension-id": "arcmenu", + "gettext-domain": "arcmenu", + "name": "ArcMenu", + "settings-schema": "org.gnome.shell.extensions.arcmenu", + "shell-version": [ + "40", + "41" + ], + "url": "https://gitlab.com/arcmenu/ArcMenu", + "uuid": "arcmenu@arcmenu.com", + "version": 27 +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js new file mode 100644 index 0000000..4e58333 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/placeDisplay.js @@ -0,0 +1,764 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from places-menu extension + * (https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/tree/master/extensions/places-menu) + * and Dash to Dock extension 'location.js' file to implement a trash shortcut + * (https://github.com/micheleg/dash-to-dock/blob/master/locations.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {St, Gio, GLib, Shell } = imports.gi; +const Clutter = imports.gi.Clutter; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const GObject = imports.gi.GObject; +const Main = imports.ui.main; +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const ShellMountOperation = imports.ui.shellMountOperation; +const Signals = imports.signals; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const BACKGROUND_SCHEMA = 'org.gnome.desktop.background'; +const Hostname1Iface = ' \ + \ + \ + \ +'; +const Hostname1 = Gio.DBusProxy.makeProxyWrapper(Hostname1Iface); + +var PlaceMenuItem = GObject.registerClass(class Arc_Menu_PlaceMenuItem2 extends MW.ArcMenuPopupBaseMenuItem{ + _init(menuLayout, info) { + super._init(menuLayout); + this._info = info; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this._iconBin = new St.Bin(); + this.add_child(this._iconBin); + + this._updateIcon(); + + this.label = new St.Label({ text: info.name, + x_expand: true, + y_expand: false, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.CENTER }); + + this.add_child(this.label); + + if (info.isRemovable()) { + this.style = "padding-right: 15px;"; + this._ejectButton = new MW.ArcMenuButtonItem(this._menuLayout, null, 'media-eject-symbolic'); + this._ejectButton.add_style_class_name("arcmenu-small-button") + this._ejectButton.setIconSize(14); + this._ejectButton.x_align = Clutter.ActorAlign.END; + this._ejectButton.x_expand = true; + this._ejectButton.connect('activate', info.eject.bind(info)); + this.add_child(this._ejectButton); + } + + this._changedId = info.connect('changed', + this._propertiesChanged.bind(this)); + this.actor.connect('destroy',()=>{ + if (this._changedId) { + this._info.disconnect(this._changedId); + this._changedId = 0; + } + }); + + } + + createIcon(){ + const IconSizeEnum = this._settings.get_enum('quicklinks-item-icon-size'); + let defaultIconSize = this._menuLayout.layoutProperties.DefaultQuickLinksIconSize; + let iconSize = Utils.getIconSize(IconSizeEnum, defaultIconSize); + + return new St.Icon({ + gicon: this._info.icon, + icon_size: iconSize + }); + } + + activate(event) { + this._info.launch(event.get_time()); + this._menuLayout.arcMenu.toggle(); + super.activate(event); + } + + _propertiesChanged(info) { + this._info = info; + this._iconBin.set_child(this.createIcon()); + this.label.text = info.name; + } +}); + +var PlaceInfo = class Arc_Menu_PlaceInfo2 { + constructor() { + this._init.apply(this, arguments); + } + + _init(kind, file, name, icon) { + this.kind = kind; + this.file = file; + this.name = name || this._getFileName(); + this.icon = icon ? new Gio.ThemedIcon({ name: icon }) : this.getIcon(); + } + + destroy() { + } + + isRemovable() { + return false; + } + + async _ensureMountAndLaunch(context, tryMount) { + try { + await this._launchDefaultForUri(this.file.get_uri(), context, null); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_MOUNTED)) { + Main.notifyError(_('Failed to launch “%s”').format(this.name), e.message); + return; + } + + let source = { + get_icon: () => this.icon + }; + let op = new ShellMountOperation.ShellMountOperation(source); + try { + await this._mountEnclosingVolume(0, op.mountOp, null); + + if (tryMount) + this._ensureMountAndLaunch(context, false); + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED)) + Main.notifyError(_('Failed to mount volume for “%s”').format(this.name), e.message); + } finally { + op.close(); + } + } + } + + launch(timestamp) { + let launchContext = global.create_app_launch_context(timestamp, -1); + this._ensureMountAndLaunch(launchContext, true); + } + + getIcon() { + this.file.query_info_async('standard::symbolic-icon', 0, 0, null, + (file, result) => { + try { + let info = file.query_info_finish(result); + this.icon = info.get_symbolic_icon(); + this.emit('changed'); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return; + throw e; + } + }); + + // return a generic icon for this kind for now, until we have the + // icon from the query info above + switch (this.kind) { + case 'network': + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + case 'devices': + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + case 'special': + case 'bookmarks': + default: + if (!this.file.is_native()) + return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + else + return new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + + _getFileName() { + try { + let info = this.file.query_info('standard::display-name', 0, null); + return info.get_display_name(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) + return this.file.get_basename(); + throw e; + } + } + + _launchDefaultForUri(uri, context, cancel) { + return new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(uri, context, cancel, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } + + _mountEnclosingVolume(flags, mountOp, cancel) { + return new Promise((resolve, reject) => { + this.file.mount_enclosing_volume(flags, mountOp, cancel, (o, res) => { + try { + this.file.mount_enclosing_volume_finish(res); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + } +} +Signals.addSignalMethods(PlaceInfo.prototype); + +var RootInfo = class Arc_Menu_RootInfo extends PlaceInfo { + _init() { + super._init('devices', Gio.File.new_for_path('/'), _('Computer')); + + let busName = 'org.freedesktop.hostname1'; + let objPath = '/org/freedesktop/hostname1'; + new Hostname1(Gio.DBus.system, busName, objPath, (obj, error) => { + if (error) + return; + + this._proxy = obj; + this._proxyID = this._proxy.connect('g-properties-changed', + this._propertiesChanged.bind(this)); + this._propertiesChanged(obj); + }); + + } + + getIcon() { + return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' }); + } + + _propertiesChanged(proxy) { + // GDBusProxy will emit a g-properties-changed when hostname1 goes down + // ignore it + if (proxy.g_name_owner) { + this.name = proxy.PrettyHostname || _('Computer'); + this.emit('changed'); + } + } + + destroy() { + if (this._proxyID) { + this._proxy.disconnect(this._proxyID); + this._proxy = 0; + } + if (this._proxy) { + this._proxy.run_dispose(); + this._proxy = null; + } + super.destroy(); + } +}; + + +var PlaceDeviceInfo = class Arc_Menu_PlaceDeviceInfo extends PlaceInfo { + _init(kind, mount) { + this._mount = mount; + super._init(kind, mount.get_root(), mount.get_name()); + } + + getIcon() { + return this._mount.get_symbolic_icon(); + } + + isRemovable() { + return this._mount.can_eject(); + } + + eject() { + let unmountArgs = [ + Gio.MountUnmountFlags.NONE, + (new ShellMountOperation.ShellMountOperation(this._mount)).mountOp, + null // Gio.Cancellable + ]; + + if (this._mount.can_eject()) + this._mount.eject_with_operation(...unmountArgs, + this._ejectFinish.bind(this)); + else + this._mount.unmount_with_operation(...unmountArgs, + this._unmountFinish.bind(this)); + } + + _ejectFinish(mount, result) { + try { + mount.eject_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _unmountFinish(mount, result) { + try { + mount.unmount_with_operation_finish(result); + } catch (e) { + this._reportFailure(e); + } + } + + _reportFailure(exception) { + let msg = _('Ejecting drive “%s” failed:').format(this._mount.get_name()); + Main.notifyError(msg, exception.message); + } +}; + +var PlaceVolumeInfo = class Arc_Menu_PlaceVolumeInfo extends PlaceInfo { + _init(kind, volume) { + this._volume = volume; + super._init(kind, volume.get_activation_root(), volume.get_name()); + } + + launch(timestamp) { + if (this.file) { + super.launch(timestamp); + return; + } + + this._volume.mount(0, null, null, (volume, result) => { + volume.mount_finish(result); + + let mount = volume.get_mount(); + this.file = mount.get_root(); + super.launch(timestamp); + }); + } + + getIcon() { + return this._volume.get_symbolic_icon(); + } +}; + +const DefaultDirectories = [ + GLib.UserDirectory.DIRECTORY_DOCUMENTS, + GLib.UserDirectory.DIRECTORY_PICTURES, + GLib.UserDirectory.DIRECTORY_MUSIC, + GLib.UserDirectory.DIRECTORY_DOWNLOAD, + GLib.UserDirectory.DIRECTORY_VIDEOS, +]; + +var PlacesManager = class Arc_Menu_PlacesManager { + constructor() { + this._places = { + special: [], + devices: [], + bookmarks: [], + network: [], + }; + + this._settings = new Gio.Settings({ schema_id: BACKGROUND_SCHEMA }); + this._showDesktopIconsChangedId = + this._settings.connect('changed::show-desktop-icons', + this._updateSpecials.bind(this)); + this._updateSpecials(); + + /* + * Show devices, code more or less ported from nautilus-places-sidebar.c + */ + this._volumeMonitor = Gio.VolumeMonitor.get(); + this._connectVolumeMonitorSignals(); + this._updateMounts(); + + this._bookmarksFile = this._findBookmarksFile(); + this._bookmarkTimeoutId = 0; + this._monitor = null; + + if (this._bookmarksFile) { + this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null); + this._monitor.connect('changed', () => { + if (this._bookmarkTimeoutId > 0) + return; + /* Defensive event compression */ + this._bookmarkTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 100, () => { + this._bookmarkTimeoutId = 0; + this._reloadBookmarks(); + return false; + }); + }); + + this._reloadBookmarks(); + } + } + + _connectVolumeMonitorSignals() { + const signals = [ + 'volume-added', + 'volume-removed', + 'volume-changed', + 'mount-added', + 'mount-removed', + 'mount-changed', + 'drive-connected', + 'drive-disconnected', + 'drive-changed' + ]; + + this._volumeMonitorSignals = []; + let func = this._updateMounts.bind(this); + for (let i = 0; i < signals.length; i++) { + let id = this._volumeMonitor.connect(signals[i], func); + this._volumeMonitorSignals.push(id); + } + } + + destroy() { + if (this._settings) + this._settings.disconnect(this._showDesktopIconsChangedId); + this._settings = null; + + for (let i = 0; i < this._volumeMonitorSignals.length; i++) + this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]); + + if (this._monitor) + this._monitor.cancel(); + if (this._bookmarkTimeoutId) + GLib.source_remove(this._bookmarkTimeoutId); + } + + _updateSpecials() { + this._places.special.forEach(p => p.destroy()); + this._places.special = []; + + let homePath = GLib.get_home_dir(); + + this._places.special.push(new PlaceInfo('special', + Gio.File.new_for_path(homePath), + _('Home'))); + + let specials = []; + let dirs = DefaultDirectories.slice(); + + if (this._settings.get_boolean('show-desktop-icons')) + dirs.push(GLib.UserDirectory.DIRECTORY_DESKTOP); + + for (let i = 0; i < dirs.length; i++) { + let specialPath = GLib.get_user_special_dir(dirs[i]); + if (specialPath == null || specialPath == homePath) + continue; + + let file = Gio.File.new_for_path(specialPath), info; + try { + info = new PlaceInfo('special', file); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + continue; + throw e; + } + + specials.push(info); + } + + specials.sort((a, b) => GLib.utf8_collate(a.name, b.name)); + this._places.special = this._places.special.concat(specials); + + this.emit('special-updated'); + } + + _updateMounts() { + let networkMounts = []; + let networkVolumes = []; + + this._places.devices.forEach(p => p.destroy()); + this._places.devices = []; + this._places.network.forEach(p => p.destroy()); + this._places.network = []; + + /* Add standard places */ + // this._places.devices.push(new RootInfo()); + /* this._places.network.push(new PlaceInfo('network', + Gio.File.new_for_uri('network:///'), + _('Network'), + 'network-workgroup-symbolic'));*/ + + /* first go through all connected drives */ + let drives = this._volumeMonitor.get_connected_drives(); + for (let i = 0; i < drives.length; i++) { + let volumes = drives[i].get_volumes(); + + for (let j = 0; j < volumes.length; j++) { + let identifier = volumes[j].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[j]); + } else { + let mount = volumes[j].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + } + + /* add all volumes that is not associated with a drive */ + let volumes = this._volumeMonitor.get_volumes(); + for (let i = 0; i < volumes.length; i++) { + if (volumes[i].get_drive() != null) + continue; + + let identifier = volumes[i].get_identifier('class'); + if (identifier && identifier.includes('network')) { + networkVolumes.push(volumes[i]); + } else { + let mount = volumes[i].get_mount(); + if (mount != null) + this._addMount('devices', mount); + } + } + + /* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */ + let mounts = this._volumeMonitor.get_mounts(); + for (let i = 0; i < mounts.length; i++) { + if (mounts[i].is_shadowed()) + continue; + + if (mounts[i].get_volume()) + continue; + + let root = mounts[i].get_default_location(); + if (!root.is_native()) { + networkMounts.push(mounts[i]); + continue; + } + this._addMount('devices', mounts[i]); + } + + for (let i = 0; i < networkVolumes.length; i++) { + let mount = networkVolumes[i].get_mount(); + if (mount) { + networkMounts.push(mount); + continue; + } + this._addVolume('network', networkVolumes[i]); + } + + for (let i = 0; i < networkMounts.length; i++) { + this._addMount('network', networkMounts[i]); + } + + this.emit('devices-updated'); + this.emit('network-updated'); + } + + _findBookmarksFile() { + let paths = [ + GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']), + GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']), + ]; + + for (let i = 0; i < paths.length; i++) { + if (GLib.file_test(paths[i], GLib.FileTest.EXISTS)) + return Gio.File.new_for_path(paths[i]); + } + + return null; + } + + _reloadBookmarks() { + + this._bookmarks = []; + + let content = Shell.get_file_contents_utf8_sync(this._bookmarksFile.get_path()); + let lines = content.split('\n'); + + let bookmarks = []; + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let components = line.split(' '); + let bookmark = components[0]; + + if (!bookmark) + continue; + + let file = Gio.File.new_for_uri(bookmark); + if (file.is_native() && !file.query_exists(null)) + continue; + + let duplicate = false; + for (let i = 0; i < this._places.special.length; i++) { + if (file.equal(this._places.special[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + for (let i = 0; i < bookmarks.length; i++) { + if (file.equal(bookmarks[i].file)) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + let label = null; + if (components.length > 1) + label = components.slice(1).join(' '); + + bookmarks.push(new PlaceInfo('bookmarks', file, label)); + } + + this._places.bookmarks = bookmarks; + + this.emit('bookmarks-updated'); + } + + _addMount(kind, mount) { + let devItem; + + try { + devItem = new PlaceDeviceInfo(kind, mount); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(devItem); + } + + _addVolume(kind, volume) { + let volItem; + + try { + volItem = new PlaceVolumeInfo(kind, volume); + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) + return; + throw e; + } + + this._places[kind].push(volItem); + } + + get(kind) { + return this._places[kind]; + } +}; +Signals.addSignalMethods(PlacesManager.prototype); + +//Trash can class implemented from Dash to Dock https://github.com/micheleg/dash-to-dock/blob/master/locations.js +var Trash = class Arc_Menu_Trash { + constructor(menuItem) { + this._menuItem = menuItem; + let trashPath = GLib.get_home_dir() + '/.local/share/Trash/files/'; + this._file = Gio.file_new_for_path(trashPath); + try { + this._monitor = this._file.monitor_directory(0, null); + this._signalId = this._monitor.connect( + 'changed', + this._onTrashChange.bind(this) + ); + } catch (e) { + log(`Impossible to monitor trash: ${e}`); + } + this._lastEmpty = true; + this._empty = true; + this._schedUpdateId = 0; + this._updateTrash(); + } + + destroy() { + if (this._monitor) { + this._monitor.disconnect(this._signalId); + this._monitor.run_dispose(); + } + this._file.run_dispose(); + } + + _onTrashChange() { + if (this._schedUpdateId) { + GLib.source_remove(this._schedUpdateId); + } + this._schedUpdateId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, 500, () => { + this._schedUpdateId = 0; + this._updateTrash(); + return GLib.SOURCE_REMOVE; + }); + } + + _updateTrash() { + try { + let children = this._file.enumerate_children('*', 0, null); + this._empty = children.next_file(null) == null; + children.close(null); + } catch (e) { + log(`Impossible to enumerate trash children: ${e}`) + return; + } + + this._ensureApp(); + } + + _ensureApp() { + if (this._trashApp == null || + this._lastEmpty != this._empty) { + let trashKeys = new GLib.KeyFile(); + trashKeys.set_string('Desktop Entry', 'Name', _('Trash')); + trashKeys.set_string('Desktop Entry', 'Id', 'ArcMenu_Trash'); + trashKeys.set_string('Desktop Entry', 'Icon', + this._empty ? 'user-trash-symbolic' : 'user-trash-full-symbolic'); + trashKeys.set_string('Desktop Entry', 'Type', 'Application'); + trashKeys.set_string('Desktop Entry', 'Exec', 'gio open trash:///'); + trashKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); + trashKeys.set_string('Desktop Entry', 'XdtdUri', 'trash:///'); + if (!this._empty) { + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash;'); + trashKeys.set_string('Desktop Action empty-trash', 'Name', _('Empty Trash')); + trashKeys.set_string('Desktop Action empty-trash', 'Exec', + 'dbus-send --print-reply --dest=org.gnome.Nautilus /org/gnome/Nautilus org.gnome.Nautilus.FileOperations.EmptyTrash'); + } + else{ + trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash-inactive;'); + trashKeys.set_string('Desktop Action empty-trash-inactive', 'Name', _('Empty Trash')); + } + + let trashAppInfo = Gio.DesktopAppInfo.new_from_keyfile(trashKeys); + this._trashApp = new Shell.App({appInfo: trashAppInfo}); + this._lastEmpty = this._empty; + + this._menuItem._app = this._trashApp; + if(this._menuItem.contextMenu) + this._menuItem.contextMenu._app = this._trashApp; + let trashIcon = this._trashApp.create_icon_texture(Constants.MEDIUM_ICON_SIZE); + if(this._menuItem._iconBin && trashIcon) + this._menuItem.iconName = trashIcon.gicon.to_string(); + this._menuItem._updateIcon(); + this.emit('changed'); + } + } + + getApp() { + this._ensureApp(); + return this._trashApp; + } +} +Signals.addSignalMethods(Trash.prototype); diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefs.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefs.js new file mode 100644 index 0000000..916491b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefs.js @@ -0,0 +1,6786 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const ByteArray = imports.byteArray; +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const LayoutTweaks = Me.imports.menulayouts.tweaks; +const PW = Me.imports.prefsWidgets; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/arcmenu/'; +const GSET = 'gnome-shell-extension-tool'; + +var MenuSettingsPinnedAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPinnedAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + + this.pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.pinnedAppsScrollWindow.set_min_content_height(300); + this.pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.frame = new PW.FrameBox(); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END, + vexpand: false, + valign: Gtk.Align.END + }); + this._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + this.pinnedAppsScrollWindow.set_child(this.frame); + this.mainBox.append(this.pinnedAppsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array = []; + for(let i = 0; i < newPinnedApps.length; i++){ + array.push(newPinnedApps[i]._name); + array.push(newPinnedApps[i]._icon); + array.push(newPinnedApps[i]._cmd); + } + this._loadPinnedApps(array); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addPinnedAppsFrameRow.add(addPinnedAppsFrameLabel); + addPinnedAppsFrameRow.add(addPinnedAppsButton); + addPinnedAppsFrame.add(addPinnedAppsFrameRow); + this.mainBox.append(addPinnedAppsFrame); + + let addCustomAppFrame = new PW.FrameBox(); + let addCustomAppFrameRow = new PW.FrameBoxRow(); + let addCustomAppFrameLabel = new Gtk.Label({ + label: _("Add Custom Shortcut"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addCustomAppButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addCustomAppButton.connect('clicked', ()=> { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps(newPinnedApps); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let x = 0; x < this.frame.count; x++) { + array.push(this.frame.get_index(x)._name); + array.push(this.frame.get_index(x)._icon); + array.push(this.frame.get_index(x)._cmd); + } + this._settings.set_strv('pinned-app-list',array); + this.saveButton.set_sensitive(false); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + _loadPinnedApps(array) { + for(let i = 0; i < array.length; i += 3) { + let frameRow = new PW.FrameBoxDragRow(this.pinnedAppsScrollWindow); + let iconString; + frameRow._name = array[i]; + frameRow._icon = array[i + 1]; + frameRow._cmd = array[i + 2]; + frameRow.saveButton = this.saveButton; + if(frameRow._icon === "ArcMenu_ArcMenuIcon"){ + frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + } + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let arcMenuImage = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + let arcMenuImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + arcMenuImageBox.append(dragImage); + arcMenuImageBox.append(arcMenuImage); + frameRow.add(arcMenuImageBox); + + let frameLabel = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true + }); + + frameLabel.label = _(frameRow._name); + + checkIfValidShortcut(frameRow, frameLabel, arcMenuImage); + + frameRow.add(frameLabel); + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.frame, + buttons: [this.saveButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DEFAULT, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + frameRow._name = newPinnedApps[0]; + frameRow._icon = newPinnedApps[1]; + frameRow._cmd = newPinnedApps[2]; + frameLabel.label = _(frameRow._name); + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)) + arcMenuImage.gicon = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon(); + else + arcMenuImage.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + this.frame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + frameRow.add(buttonBox); + this.frame.add(frameRow); + } + } +}); + +var AddAppsToPinnedListWindow = GObject.registerClass( + class Arc_Menu_AddAppsToPinnedListWindow extends PW.DialogWindow { + _init(settings, parent, dialogType) { + this._settings = settings; + this._dialogType = dialogType; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(_('Add to your Pinned Apps'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(_('Change Selected Pinned App'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(_('Select Application Shortcuts'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(_('Select Directory Shortcuts'), parent); + this.newPinnedAppsArray=[]; + this.addResponse = false; + } + + _createLayout(vbox) { + let searchBar = new Gtk.SearchEntry({ + placeholder_text: _("Search…") + }); + searchBar.connect('search-changed', ()=> { + this._loadCategories(); + let applist = Gio.app_info_get_all(); + + let pattern = searchBar.text; + let searchResults = []; + let res = []; + for (let i in applist) { + let app = applist[i]; + let match; + + match = app.get_name().toLowerCase() + " "; + let info = Gio.DesktopAppInfo.new(app.get_id()); + + if (info.get_display_name()) + match += info.get_display_name().toLowerCase() + " "; + if (info.get_executable()) + match += info.get_executable().toLowerCase() + " "; + if (info.get_keywords()) + match += info.get_keywords().toString().toLowerCase() + " "; + if (app.get_description()) + match += app.get_description().toLowerCase(); + + + let index = match.indexOf(pattern); + if (index != -1) { + searchResults.push([index, app]); + } + } + let arcMenuSettings = _("ArcMenu Settings").toLowerCase(); + let index = arcMenuSettings.indexOf(pattern); + let showArcMenuSettings = false; + if (index != -1) { + showArcMenuSettings = true; + } + + searchResults.sort(function(a,b) { + return a[0] > b[0]; + }); + res = searchResults.map(function(value,index) { return value[1]; }); + this.appsFrame.remove_all_children(); + this._loadCategories(res, showArcMenuSettings); + this.appsFrame.show(); + + }); + + let pinnedAppsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + pinnedAppsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + pinnedAppsScrollWindow.set_min_content_height(400); + pinnedAppsScrollWindow.set_min_content_width(650); + this.appsFrame = new PW.FrameBox(); + let addAppsButton; + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS + || this._dialogType == Constants.DiaglogType.DIRECTORIES){ + addAppsButton = new Gtk.Button({ + label: _("Add") + }); + + addAppsButton.connect('clicked', ()=> { + this.addResponse = true; + this.response(-10); + }); + addAppsButton.set_halign(Gtk.Align.END); + } + + pinnedAppsScrollWindow.set_child(this.appsFrame); + vbox.append(pinnedAppsScrollWindow); + if(this._dialogType == Constants.DiaglogType.DEFAULT){ + this._loadCategories(); + vbox.append(addAppsButton); + vbox.prepend(searchBar); + } + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Recent"), "document-open-recent-symbolic", "ArcMenu_Recent"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + this.appsFrame.add(frameRow); + } + vbox.append(addAppsButton); + } + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS){ + this._loadCategories(); + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + let defaultApplicationShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("ArcMenu Settings"), Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg', Constants.ArcMenuSettingsCommand]); + defaultApplicationShortcuts.push([_("Run Command..."), "system-run-symbolic", "ArcMenu_RunCommand"]); + defaultApplicationShortcuts.push([_("Show All Applications"), "view-fullscreen-symbolic", "ArcMenu_ShowAllApplications"]); + + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(frameRow._icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) { + this.newPinnedAppsArray.push(frameRow); + } + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Default Apps")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultApplicationShortcutsFrame); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + vbox.append(addAppsButton); + } + else{ + this._loadCategories(); + let defaultAppsWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + defaultAppsWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + defaultAppsWindow.set_min_content_width(500); + defaultAppsWindow.set_min_content_width(500); + + let defaultApplicationShortcutsFrame = new PW.FrameBox(); + defaultAppsWindow.set_child(defaultApplicationShortcutsFrame); + let defaultApplicationShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + defaultApplicationShortcuts.push([_("Computer"), "ArcMenu_Computer", "ArcMenu_Computer"]); + defaultApplicationShortcuts.push([_("Network"), "ArcMenu_Network", "ArcMenu_Network"]); + defaultApplicationShortcuts.push([_("Trash"), "user-trash-symbolic", "ArcMenu_Trash"]); + defaultApplicationShortcuts.push([_("Lock"), "changes-prevent-symbolic", "ArcMenu_Lock"]); + defaultApplicationShortcuts.push([_("Log Out"), "application-exit-symbolic", "ArcMenu_LogOut"]); + defaultApplicationShortcuts.push([_("Power Off"), "system-shutdown-symbolic", "ArcMenu_PowerOff"]); + defaultApplicationShortcuts.push([_("Restart"), 'system-reboot-symbolic', "ArcMenu_Restart"]); + defaultApplicationShortcuts.push([_("Suspend"), "media-playback-pause-symbolic", "ArcMenu_Suspend"]); + defaultApplicationShortcuts.push([_("Hybrid Sleep"), Me.path + Constants.SleepIcon.PATH, "ArcMenu_HybridSleep"]); + defaultApplicationShortcuts.push([_("Hibernate"), "document-save-symbolic", "ArcMenu_Hibernate"]); + for(let i = 0;i < defaultApplicationShortcuts.length; i++) { + let frameRow = new PW.FrameBoxRow(); + + frameRow._name = _(defaultApplicationShortcuts[i][0]); + frameRow._icon = defaultApplicationShortcuts[i][1]; + frameRow._cmd = defaultApplicationShortcuts[i][2]; + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(getIconPath(defaultApplicationShortcuts[i])), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + + + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + + defaultApplicationShortcutsFrame.add(frameRow); + + } + let notebook = new PW.Notebook(); + + let defaultAppsPage = new PW.NotebookPage(_("Presets")); + notebook.append_page(defaultAppsPage); + defaultAppsPage.append(defaultAppsWindow); + vbox.remove(pinnedAppsScrollWindow); + let systemAppsPage = new PW.NotebookPage(_("System Apps")); + notebook.append_page(systemAppsPage); + systemAppsPage.append(pinnedAppsScrollWindow); + systemAppsPage.prepend(searchBar); + + vbox.append(notebook); + } + } + + get_newPinnedAppsArray() { + return this.newPinnedAppsArray; + } + + get_response() { + return this.addResponse; + } + + _loadCategories(searchResults, showArcMenuSettings) { + let allApps = searchResults ? searchResults : Gio.app_info_get_all(); + allApps.sort((a, b) => { + let _a = a.get_display_name(); + let _b = b.get_display_name(); + return GLib.strcmp0(_a, _b); + }); + + let iter = -1; + if(searchResults) + iter = 0; + if(showArcMenuSettings) + iter = -1; + for(let i = iter; i < allApps.length; i++) { + if(i == -1 ? true : allApps[i].should_show()) { + let frameRow = new PW.FrameBoxRow(); + let icon; + if(i == -1){ + frameRow._name = _("ArcMenu Settings"); + icon = frameRow._icon = Me.path + '/media/icons/menu_icons/arc-menu-symbolic.svg'; + frameRow._cmd = Constants.ArcMenuSettingsCommand; + } + else{ + frameRow._app = allApps[i]; + frameRow._name = allApps[i].get_display_name(); + frameRow._icon = ''; + if(allApps[i].get_icon()) + icon = allApps[i].get_icon().to_string(); + else + icon = "dialog-information"; + + frameRow._cmd = allApps[i].get_id(); + } + + let iconImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string(icon), + pixel_size: 22 + }); + + let iconImageBox = new Gtk.Box( { + margin_start: 5, + hexpand: false, + vexpand: false + }); + iconImageBox.append(iconImage); + frameRow.add(iconImageBox); + + let frameLabel = new Gtk.Label( { + use_markup: false, + xalign: 0, + hexpand: true + }); + frameLabel.label = frameRow._name; + frameRow.add(frameLabel); + if(this._dialogType == Constants.DiaglogType.DEFAULT || this._dialogType == Constants.DiaglogType.APPLICATIONS|| + this._dialogType == Constants.DiaglogType.DIRECTORIES){ + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', ()=> { + if(checkButton.get_active()) + this.newPinnedAppsArray.push(frameRow); + else { + let index= this.newPinnedAppsArray.indexOf(frameRow); + this.newPinnedAppsArray.splice(index,1); + } + }); + frameRow.add(checkButton); + } + else{ + let checkButton = new PW.Button({ + icon_name: 'list-add-symbolic' + }); + checkButton.margin_end = 20; + checkButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(frameRow._name, frameRow._icon, frameRow._cmd); + this.addResponse = true; + this.response(-10); + }); + frameRow.add(checkButton); + } + + this.appsFrame.add(frameRow); + } + } + } +}); + +var AddCustomLinkDialogWindow = GObject.registerClass( + class Arc_Menu_AddCustomLinkDialogWindow extends PW.DialogWindow { + _init(settings, parent, dialogType, isAppEdit=false, appArray=null) { + this._settings = settings; + this.newPinnedAppsArray=[]; + this.addResponse = false; + this.isAppEdit = isAppEdit; + this._dialogType = dialogType; + this.appArray = appArray; + if(this._dialogType == Constants.DiaglogType.DEFAULT) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.OTHER) + super._init(isAppEdit?_('Edit Pinned App'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.APPLICATIONS) + super._init(isAppEdit?_('Edit Shortcut'):_('Add a Custom Shortcut'), parent); + else if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + super._init(isAppEdit?_('Edit Custom Shortcut'):_('Add a Custom Shortcut'), parent); + } + + _createLayout(vbox) { + let mainFrame = new PW.FrameBox(); + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Shortcut Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let nameEntry = new Gtk.Entry(); + nameEntry.set_width_chars(35); + nameFrameRow.add(nameFrameLabel); + nameFrameRow.add(nameEntry); + nameEntry.grab_focus(); + mainFrame.add(nameFrameRow); + + let iconFrameRow = new PW.FrameBoxRow(); + let iconFrameLabel = new Gtk.Label({ + label: _("Icon:"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconEntry = new Gtk.Entry(); + iconEntry.set_width_chars(35); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Browse...') + }); + + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.set_filter(fileFilter); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + let iconFilepath = dialog.get_file().get_path(); + iconEntry.set_text(iconFilepath); + dialog.destroy(); + } + else if(response === Gtk.ResponseType.CANCEL) + dialog.destroy(); + }) + + dialog.show(); + }); + + iconFrameRow.add(iconFrameLabel); + iconFrameRow.add(fileChooserButton); + iconFrameRow.add(iconEntry); + mainFrame.add(iconFrameRow); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + iconEntry.set_text("ArcMenu_Folder"); + + let cmdFrameRow = new PW.FrameBoxRow(); + let cmdFrameLabel = new Gtk.Label({ + label: _('Terminal Command:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + if(this._dialogType == Constants.DiaglogType.DIRECTORIES) + cmdFrameLabel.label = _("Shortcut Path:"); + let cmdEntry = new Gtk.Entry(); + cmdEntry.set_width_chars(35); + cmdFrameRow.add(cmdFrameLabel); + cmdFrameRow.add(cmdEntry); + mainFrame.add(cmdFrameRow); + + let addButton = new Gtk.Button({ + label: this.isAppEdit ?_("Apply") :_("Add") + }); + + if(this.appArray!=null) { + nameEntry.text=this.appArray[0]; + iconEntry.text=this.appArray[1]; + cmdEntry.text=this.appArray[2]; + } + addButton.connect('clicked', ()=> { + this.newPinnedAppsArray.push(nameEntry.get_text()); + this.newPinnedAppsArray.push(iconEntry.get_text()); + this.newPinnedAppsArray.push(cmdEntry.get_text()); + this.addResponse = true; + this.response(-10); + }); + addButton.set_halign(Gtk.Align.END); + + vbox.append(mainFrame); + vbox.append(addButton); + } + + get_newPinnedAppsArray(){ + return this.newPinnedAppsArray; + } + + get_response(){ + return this.addResponse; + } +}); + +var GeneralPage = GObject.registerClass( + class Arc_Menu_GeneralPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let arcMenuPlacementHeader = new Gtk.Label({ + label: "" + _("Display Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(arcMenuPlacementHeader); + let menuPlacementFrame = new PW.FrameBox(); + this._createDisplayOnFrame(menuPlacementFrame, true); + this._settings.connect('changed::available-placement', ()=>{ + menuPlacementFrame.remove_all_children(); + this._createDisplayOnFrame(menuPlacementFrame, false); + menuPlacementFrame.show(); + }) + + this.mainBox.append(menuPlacementFrame); + + let hotCornerHeader = new Gtk.Label({ + label: "" + _("Hot Corner Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(hotCornerHeader); + + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Modify Hot Corner"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let modifyHotCornerButton = new PW.Button({ + icon_name: 'emblem-system-symbolic', + }); + modifyHotCornerButton.connect('clicked', ()=> { + let dialog = new ModifyHotCornerDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + dialog.destroy(); + }); + }); + let modifyHotCornerSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + modifyHotCornerSwitch.set_active(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerButton.set_sensitive(this._settings.get_boolean('override-hot-corners')); + modifyHotCornerSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('override-hot-corners',widget.get_active()); + modifyHotCornerButton.set_sensitive(widget.get_active()); + if(!widget.get_active()){ + this._settings.set_enum('hot-corners',Constants.HotCornerAction.DEFAULT); + } + }); + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(modifyHotCornerButton); + modifyHotCornerRow.add(modifyHotCornerSwitch); + modifyHotCornerFrame.add(modifyHotCornerRow); + this.mainBox.append(modifyHotCornerFrame); + + let menuHotkeyHeader = new Gtk.Label({ + label: "" + _("Hotkey Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuHotkeyHeader); + + let menuHotKeyFrame = this._createHotkeyFrame(true); + this.mainBox.append(menuHotKeyFrame); + + let runnerHeaderLabel = new Gtk.Label({ + label: "" + _("Standalone Runner Menu") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(runnerHeaderLabel); + + let runnerHotkeyFrame = this._createHotkeyFrame(false); + this.mainBox.append(runnerHotkeyFrame); + } + + _createHotkeyFrame(isMenuHotkey){ + let hotkeyFrame = new PW.FrameBox(); + let enableRunnerMenuSwitch, hotkeyEnumSetting, customHotkeySetting, primaryMonitorSetting; + if(isMenuHotkey){ + hotkeyEnumSetting = 'menu-hotkey'; + customHotkeySetting = 'toggle-arcmenu'; + primaryMonitorSetting = 'hotkey-open-primary-monitor'; + } + else{ + hotkeyEnumSetting = 'runner-menu-hotkey'; + customHotkeySetting = 'toggle-runner-menu'; + primaryMonitorSetting = 'runner-hotkey-open-primary-monitor'; + let enableRunnerMenuRow = new PW.FrameBoxRow(); + let enableRunnerMenuLabel = new Gtk.Label({ + label: _("Enable a standalone Runner menu"), + use_markup: true, + xalign: 0, + hexpand: true + }); + enableRunnerMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + enableRunnerMenuSwitch.set_active(this._settings.get_boolean('enable-standlone-runner-menu')); + enableRunnerMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-standlone-runner-menu', widget.get_active()); + if(!widget.get_active()){ + hotkeyFrame.removeChildrenAfterIndex(0); + } + else{ + hotkeyFrame.add(hotkeyRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 0) + hotkeyFrame.add(primaryMonitorRow); + if(this._settings.get_enum(hotkeyEnumSetting) === 1){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + } + }); + enableRunnerMenuRow.add(enableRunnerMenuLabel); + enableRunnerMenuRow.add(enableRunnerMenuSwitch); + hotkeyFrame.add(enableRunnerMenuRow); + } + + let hotkeyActivationRow = new PW.FrameBoxRow(); + let hotkeyActivationLabel = new Gtk.Label({ + label: _("Hotkey Activation"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotkeyActivationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotkeyActivationCombo.append_text(_("Key Release")); + hotkeyActivationCombo.append_text(_("Key Press")); + if(this._settings.get_boolean('disable-hotkey-onkeyrelease')) + hotkeyActivationCombo.set_active(1); + else + hotkeyActivationCombo.set_active(0); + hotkeyActivationCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + this._settings.set_boolean('disable-hotkey-onkeyrelease',false); + if(widget.get_active() === 1) + this._settings.set_boolean('disable-hotkey-onkeyrelease',true); + }); + + hotkeyActivationRow.add(hotkeyActivationLabel); + hotkeyActivationRow.add(hotkeyActivationCombo); + + let primaryMonitorRow = new PW.FrameBoxRow(); + let primaryMonitorLabel = new Gtk.Label({ + label: _("Open on Primary Monitor"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let primaryMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + primaryMonitorSwitch.set_active(this._settings.get_boolean(primaryMonitorSetting)); + primaryMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean(primaryMonitorSetting, widget.get_active()); + }); + primaryMonitorRow.add(primaryMonitorLabel); + primaryMonitorRow.add(primaryMonitorSwitch); + + + let hotkeyRow = new PW.FrameBoxRow(); + let hotkeyLabel = new Gtk.Label({ + label: isMenuHotkey ? _("Menu Hotkey") : _("Runner Hotkey"), + use_markup: true, + xalign: 0, + hexpand: true + }); + hotkeyRow.add(hotkeyLabel); + + let hotkeyCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + if(isMenuHotkey) + hotkeyCombo.append("NONE", _("None")); + hotkeyCombo.append("SUPER_L", _("Left Super Key")); + hotkeyCombo.append("CUSTOM", _("Custom Hotkey")); + hotkeyCombo.set_active(this._settings.get_enum(hotkeyEnumSetting)); + hotkeyCombo.connect('changed', (widget) => { + let removeIndex = isMenuHotkey ? 0 : 1; + if(widget.get_active_id() === "NONE"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + } + else if(widget.get_active_id() === "SUPER_L"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(primaryMonitorRow); + } + else if(widget.get_active_id() === "CUSTOM"){ + if(hotkeyFrame.count > removeIndex + 1) + hotkeyFrame.removeChildrenAfterIndex(removeIndex); + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + hotkeyFrame.show(); + } + this._settings.set_enum(hotkeyEnumSetting, widget.get_active()); + }); + hotkeyRow.add(hotkeyCombo); + + hotkeyFrame.add(hotkeyRow); + + let customHotkeyRow = new PW.FrameBoxRow(); + let currentHotkeyLabel = new Gtk.Label( { + label: _("Current Hotkey"), + use_markup: true, + xalign: 0, + hexpand: false + }); + + let shortcutCell = new Gtk.ShortcutsShortcut({ + halign: Gtk.Align.START, + hexpand: true, + }); + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + + let modifyHotkeyButton = new Gtk.Button({ + label: _("Modify Hotkey"), + halign: Gtk.Align.END, + hexpand: false, + }); + customHotkeyRow.add(currentHotkeyLabel); + customHotkeyRow.add(shortcutCell); + customHotkeyRow.add(modifyHotkeyButton); + modifyHotkeyButton.connect('clicked', () => { + let dialog = new CustomHotkeyDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', () => { + let customHotKeyEnum = isMenuHotkey ? 2 : 1; + if(dialog.addResponse) { + this._settings.set_enum(hotkeyEnumSetting, 0); + this._settings.set_strv(customHotkeySetting, [dialog.resultsText]); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + shortcutCell.accelerator = dialog.resultsText; + dialog.destroy(); + } + else { + shortcutCell.accelerator = this._settings.get_strv(customHotkeySetting).toString(); + this._settings.set_enum(hotkeyEnumSetting, customHotKeyEnum); + dialog.destroy(); + } + }); + }); + + if(hotkeyCombo.get_active_id() === "SUPER_L"){ + hotkeyFrame.add(primaryMonitorRow); + } + else if(hotkeyCombo.get_active_id() === "CUSTOM"){ + hotkeyFrame.add(customHotkeyRow); + hotkeyFrame.add(hotkeyActivationRow); + hotkeyFrame.add(primaryMonitorRow); + } + + if(!isMenuHotkey && !enableRunnerMenuSwitch.get_active()) + hotkeyFrame.removeChildrenAfterIndex(0); + return hotkeyFrame; + } + + _createDisplayOnFrame(menuPlacementFrame, setComboBox){ + let menuPlacementRow = new PW.FrameBoxRow(); + let menuPlacementLabel = new Gtk.Label({ + label: _("Display ArcMenu On"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuPlacementCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + let avaliablePlacement = this._settings.get_value('available-placement').deep_unpack(); + let dashExtensionName = _("Dash to Dock"); + let gnomeSettings = Gio.Settings.new("org.gnome.shell"); + let enabledExtensions = gnomeSettings.get_strv('enabled-extensions'); + if (enabledExtensions.includes('ubuntu-dock@ubuntu.com')) { + dashExtensionName = _("Ubuntu Dock"); + } + + menuPlacementCombo.append_text(_("Main Panel")); + menuPlacementCombo.append_text(_("Dash to Panel")); + menuPlacementCombo.append_text(dashExtensionName); + + menuPlacementRow.add(menuPlacementLabel); + menuPlacementRow.add(menuPlacementCombo); + menuPlacementFrame.add(menuPlacementRow); + + let dashToDockWarningRow = new PW.FrameBoxRow(); + let dashToDockWarningLabel = new Gtk.Label({ + label: _("Dash to Dock extension not running!") + "\n" + _("Enable Dash to Dock for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesRow = new PW.FrameBoxRow(); + let showActivitiesLabel = new Gtk.Label({ + label: _("Show Activities Button"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let showActivitiesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + showActivitiesSwitch.set_active(this._settings.get_boolean('show-activities-button')); + showActivitiesSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('show-activities-button', widget.get_active()); + }); + showActivitiesRow.add(showActivitiesLabel); + showActivitiesRow.add(showActivitiesSwitch); + + let warningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let warningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + warningImageBox.append(warningImage); + + if(!avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + dashToDockWarningRow.add(warningImageBox); + } + dashToDockWarningRow.add(dashToDockWarningLabel); + + let panelWarningRow = new PW.FrameBoxRow(); + let panelWarningLabel = new Gtk.Label({ + label: avaliablePlacement[Constants.ArcMenuPlacement.DTP] ? _("Main Panel not found!") : + _("Dash to Panel extension not running!") + "\n" + _("Enable Dash to Panel for this feature to work."), + use_markup: true, + xalign: 0, + hexpand: true + }); + let panelWarningImage = new Gtk.Image({ + icon_name: 'warning-symbolic', + pixel_size: 24 + }); + let panelWarningImageBox = new Gtk.Box({ + margin_top: 0, + margin_bottom: 0, + margin_start: 10 + }); + panelWarningImageBox.append(panelWarningImage); + panelWarningRow.add(panelWarningImageBox); + panelWarningRow.add(panelWarningLabel); + + let menuPositionRow = new PW.FrameBoxRow(); + let menuPositionBoxLabel = new Gtk.Label({ + label: _("Position in Panel"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuPositionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + + menuPositionCombo.append_text(_('Left')); + menuPositionCombo.append_text(_('Center')); + menuPositionCombo.append_text(_('Right')); + menuPositionCombo.set_active(this._settings.get_enum('position-in-panel')); + menuPositionCombo.connect('changed', (widget) => { + if(widget.get_active() === Constants.MenuPosition.LEFT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + else if(widget.get_active() === Constants.MenuPosition.CENTER){ + if(menuPlacementFrame.get_index(2) != menuPositionAdjustmentRow){ + menuPlacementFrame.insert(menuPositionAdjustmentRow, 2); + menuPlacementFrame.show(); + } + } + else if(widget.get_active() === Constants.MenuPosition.RIGHT){ + if(menuPlacementFrame.get_index(2) === menuPositionAdjustmentRow) + menuPlacementFrame.remove(menuPositionAdjustmentRow); + } + this._settings.set_enum('position-in-panel', widget.get_active()); + }); + + menuPositionRow.add(menuPositionBoxLabel); + menuPositionRow.add(menuPositionCombo); + + let menuPositionAdjustmentRow = new PW.FrameBoxRow(); + let menuPositionAdjustmentLabel = new Gtk.Label({ + label: _("Menu Alignment"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alignmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 100, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + }); + alignmentScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Left")); + alignmentScale.add_mark(50, Gtk.PositionType.BOTTOM, _("Center")); + alignmentScale.add_mark(100, Gtk.PositionType.BOTTOM, _("Right")); + + alignmentScale.set_value(this._settings.get_int('menu-position-alignment')); + alignmentScale.connect('value-changed', (widget) => { + this._settings.set_int('menu-position-alignment', widget.get_value()); + }); + menuPositionAdjustmentRow.add(menuPositionAdjustmentLabel); + menuPositionAdjustmentRow.add(alignmentScale); + + let multiMonitorRow = new PW.FrameBoxRow(); + let multiMonitorLabel = new Gtk.Label({ + label: _("Display ArcMenu on all monitors"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let multiMonitorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + multiMonitorSwitch.set_active(this._settings.get_boolean('multi-monitor')); + multiMonitorSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('multi-monitor', widget.get_active()); + }); + + multiMonitorRow.add(multiMonitorLabel); + multiMonitorRow.add(multiMonitorSwitch); + + menuPlacementCombo.connect('changed', (widget) => { + let placement = widget.get_active(); + this._settings.set_enum('arc-menu-placement', placement); + menuPlacementFrame.remove_all_children(); + menuPlacementFrame.add(menuPlacementRow); + if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.PANEL){ + if(avaliablePlacement[Constants.ArcMenuPlacement.PANEL] === false){ + menuPlacementFrame.add(panelWarningRow); + } + else{ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + menuPlacementFrame.show(); + } + else if(menuPlacementCombo.get_active() == Constants.ArcMenuPlacement.DTP){ + if(avaliablePlacement[Constants.ArcMenuPlacement.DTP]){ + menuPlacementFrame.add(menuPositionRow); + if(this._settings.get_enum('position-in-panel') == Constants.MenuPosition.CENTER) + menuPlacementFrame.add(menuPositionAdjustmentRow); + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(panelWarningRow); + + menuPlacementFrame.show(); + } + else{ + if(avaliablePlacement[Constants.ArcMenuPlacement.DASH]){ + menuPlacementFrame.add(multiMonitorRow); + menuPlacementFrame.add(showActivitiesRow); + } + else + menuPlacementFrame.add(dashToDockWarningRow); + + menuPlacementFrame.show(); + } + }); + let placement = this._settings.get_enum('arc-menu-placement'); + if(setComboBox){ + if(placement == Constants.ArcMenuPlacement.PANEL && !avaliablePlacement[Constants.ArcMenuPlacement.PANEL]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.DTP); + else if(placement == Constants.ArcMenuPlacement.DTP && !avaliablePlacement[Constants.ArcMenuPlacement.DTP]) + menuPlacementCombo.set_active(Constants.ArcMenuPlacement.PANEL); + else + menuPlacementCombo.set_active(placement); + } + else + menuPlacementCombo.set_active(placement); + } +}); + +var ModifyHotCornerDialogWindow = GObject.registerClass( + class Arc_Menu_ModifyHotCornerDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + super._init(_('Modify Hot Corner'), parent); + this.set_default_size(600,250); + } + + _createLayout(vbox) { + let modifyHotCornerFrame = new PW.FrameBox(); + let modifyHotCornerRow = new PW.FrameBoxRow(); + let modifyHotCornerLabel = new Gtk.Label({ + label: _("Hot Corner Action"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerActionCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + hotCornerActionCombo.append_text(_("GNOME Default")); + hotCornerActionCombo.append_text(_("Disabled")); + hotCornerActionCombo.append_text(_("Open ArcMenu")); + hotCornerActionCombo.append_text(_("Custom")); + + let customHotCornerFrame = new PW.FrameBox(); + let customHeaderHotCornerRow = new PW.FrameBoxRow(); + + let customHeaderHotCornerLabel = new Gtk.Label({ + label: ""+_("Custom Hot Corner Action") + "\n" + _("Choose from a list of preset commands or use your own terminal command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + customHeaderHotCornerRow.add(customHeaderHotCornerLabel); + + let presetCustomHotCornerRow = new PW.FrameBoxRow(); + let presetCustomHotCornerLabel = new Gtk.Label({ + label: _("Preset commands"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let hotCornerPresetsCombo = new Gtk.ComboBoxText({ + hexpand: true + }); + + hotCornerPresetsCombo.append_text(_("Show all Applications")); + hotCornerPresetsCombo.append_text(_("GNOME Terminal")); + hotCornerPresetsCombo.append_text(_("GNOME System Monitor")); + hotCornerPresetsCombo.append_text(_("GNOME Calculator")); + hotCornerPresetsCombo.append_text(_("GNOME gedit")); + hotCornerPresetsCombo.append_text(_("GNOME Screenshot")); + hotCornerPresetsCombo.append_text(_("GNOME Weather")); + hotCornerPresetsCombo.append_text(_("Run Command...")); + hotCornerPresetsCombo.connect('changed', (widget) => { + if(widget.get_active() === 0) + customHotCornerEntry.set_text("ArcMenu_ShowAllApplications"); + else if(widget.get_active() === 1) + customHotCornerEntry.set_text("gnome-terminal"); + else if(widget.get_active() === 2) + customHotCornerEntry.set_text("gnome-system-monitor"); + else if(widget.get_active() === 3) + customHotCornerEntry.set_text("gnome-calculator"); + else if(widget.get_active() === 4) + customHotCornerEntry.set_text("gedit"); + else if(widget.get_active() === 5) + customHotCornerEntry.set_text("gnome-screenshot"); + else if(widget.get_active() === 6) + customHotCornerEntry.set_text("gnome-weather"); + else if(widget.get_active() === 7) + customHotCornerEntry.set_text("ArcMenu_RunCommand"); + }); + presetCustomHotCornerRow.add(presetCustomHotCornerLabel); + presetCustomHotCornerRow.add(hotCornerPresetsCombo); + + let customHotCornerRow = new PW.FrameBoxRow(); + let customHotCornerLabel = new Gtk.Label({ + label: _("Terminal Command"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let customHotCornerEntry = new Gtk.Entry({ + }); + customHotCornerEntry.set_text(this._settings.get_string('custom-hot-corner-cmd')); + customHotCornerEntry.connect('changed', (widget) => { + applyButton.set_sensitive(true); + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + }); + customHotCornerEntry.set_width_chars(40); + + let index = this.checkIfMatch(customHotCornerEntry.get_text()); + hotCornerPresetsCombo.set_active(index) + customHotCornerRow.add(customHotCornerLabel); + customHotCornerRow.add(customHotCornerEntry); + + customHotCornerFrame.add(customHeaderHotCornerRow); + customHotCornerFrame.add(presetCustomHotCornerRow); + customHotCornerFrame.add(customHotCornerRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + }); + applyButton.connect('clicked', () => { + this._settings.set_string('custom-hot-corner-cmd',customHotCornerEntry.get_text()); + this._settings.set_enum('hot-corners',hotCornerActionCombo.get_active()); + applyButton.set_sensitive(false); + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + applyButton.set_sensitive(false); + + + let hotCornerAction = this._settings.get_enum('hot-corners'); + hotCornerActionCombo.set_active(hotCornerAction); + hotCornerActionCombo.connect('changed', (widget) => { + applyButton.set_sensitive(true); + if(widget.get_active()==Constants.HotCornerAction.CUSTOM){ + customHotCornerFrame.set_sensitive(true); + } + else{ + customHotCornerFrame.set_sensitive(false); + } + }); + + modifyHotCornerRow.add(modifyHotCornerLabel); + modifyHotCornerRow.add(hotCornerActionCombo); + modifyHotCornerFrame.add(modifyHotCornerRow); + if(hotCornerActionCombo.get_active() == Constants.HotCornerAction.CUSTOM) + customHotCornerFrame.set_sensitive(true); + else + customHotCornerFrame.set_sensitive(false); + vbox.append(modifyHotCornerFrame); + vbox.append(customHotCornerFrame); + vbox.append(applyButton); + } + checkIfMatch(text){ + if(text === "ArcMenu_ShowAllApplications") + return 0; + else if(text === "gnome-terminal") + return 1; + else if(text === "gnome-system-monitor") + return 2; + else if(text === "gnome-calculator") + return 3; + else if(text === "gedit") + return 4; + else if(text === "gnome-screenshot") + return 5; + else if(text === "gnome-weather") + return 6; + else if(text === "ArcMenu_RunCommand") + return 7; + else + return -1; + } +}); + +var CustomHotkeyDialogWindow = GObject.registerClass({ + Signals: { + 'response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_CustomHotkeyDialogWindow extends Gtk.Window { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.keyEventController = new Gtk.EventControllerKey(); + + super._init({ + modal: true, + title: _("Set Custom Hotkey"), + transient_for: parent.get_root() + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + this.set_child(vbox); + this._createLayout(vbox); + this.add_controller(this.keyEventController); + this.set_size_request(500, 250); + } + + _createLayout(vbox) { + let hotkeyKey = ''; + + let modLabel = new Gtk.Label({ + label:_("Choose Modifiers"), + use_markup: true, + hexpand: true, + halign: Gtk.Align.START + }); + let modFrame = new PW.FrameBox(); + let modRow = new PW.FrameBoxRow(); + modRow.add(modLabel); + + let buttonBox = new Gtk.Box({ + hexpand: true, + halign: Gtk.Align.END, + spacing: 5 + }); + modRow.add(buttonBox); + let ctrlButton = new Gtk.ToggleButton({ + label: _("Ctrl") + }); + let superButton = new Gtk.ToggleButton({ + label: _("Super") + }); + let shiftButton = new Gtk.ToggleButton({ + label: _("Shift") + }); + let altButton = new Gtk.ToggleButton({ + label: _("Alt") + }); + ctrlButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + superButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + shiftButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + altButton.connect('toggled', () => { + this.resultsText=""; + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += hotkeyKey; + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + buttonBox.append(ctrlButton); + buttonBox.append(superButton); + buttonBox.append(shiftButton); + buttonBox.append(altButton); + modFrame.add(modRow); + vbox.append(modFrame); + + let keyFrame = new PW.FrameBox(); + let keyLabel = new Gtk.Label({ + label: _("Press any key"), + use_markup: true, + xalign: .5, + hexpand: true, + halign: Gtk.Align.CENTER + }); + vbox.append(keyLabel); + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/keyboard-symbolic.svg', 256, 72); + let keyboardImage = Gtk.Picture.new_for_pixbuf(pixbuf); + keyboardImage.hexpand = true; + keyboardImage.vexpand = true; + keyboardImage.halign = Gtk.Align.CENTER; + keyboardImage.valign = Gtk.Align.CENTER; + vbox.append(keyboardImage) + + let resultsRow = new PW.FrameBoxRow(); + let resultsLabel = new Gtk.Label({ + label: _("New Hotkey"), + use_markup: true, + xalign: .5, + hexpand: false, + halign: Gtk.Align.START + }); + let resultsWidget = new Gtk.ShortcutsShortcut({ + hexpand: true, + halign: Gtk.Align.END + }); + resultsRow.add(resultsLabel); + resultsRow.add(resultsWidget); + keyFrame.add(resultsRow); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + halign: Gtk.Align.END + }); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.emit("response", -10); + }); + applyButton.set_sensitive(false); + + this.keyEventController.connect('key-released', (controller, keyval, keycode, state) => { + this.resultsText = ""; + let key = keyval; + hotkeyKey = Gtk.accelerator_name(key, 0); + if(ctrlButton.get_active()) this.resultsText += ""; + if(superButton.get_active()) this.resultsText += ""; + if(shiftButton.get_active()) this.resultsText += ""; + if(altButton.get_active()) this.resultsText += ""; + this.resultsText += Gtk.accelerator_name(key,0); + resultsWidget.accelerator = this.resultsText; + applyButton.set_sensitive(true); + }); + + vbox.append(keyFrame); + vbox.append(applyButton); + } +}); + +function getIconPixbuf(filePath){ + if (GLib.file_test(filePath, GLib.FileTest.EXISTS)) + return GdkPixbuf.Pixbuf.new_from_file_at_size(filePath, 25, 25); + else + return null; +} + +var ButtonAppearancePage = GObject.registerClass( + class Arc_Menu_ButtonAppearancePage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + this.menuButtonColor = this._settings.get_string('menu-button-color'); + this.menuButtonHoverColor = this._settings.get_string('menu-button-hover-color'); + this.menuButtonActiveColor = this._settings.get_string('menu-button-active-color'); + this.menuButtonHoverBackgroundcolor = this._settings.get_string('menu-button-hover-backgroundcolor'); + this.menuButtonActiveBackgroundcolor = this._settings.get_string('menu-button-active-backgroundcolor'); + this._createLayout(this.mainBox); + } + + _createLayout(vbox) { + this.arcMenuPlacement = this._settings.get_enum('arc-menu-placement'); + let menuButtonAppearanceHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonAppearanceHeaderLabel); + + let menuButtonAppearanceFrame = new PW.FrameBox(); + let menuButtonAppearanceRow = new PW.FrameBoxRow(); + let menuButtonAppearanceLabel = new Gtk.Label({ + label: _('Appearance'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonAppearanceCombo = new Gtk.ComboBoxText({ halign: Gtk.Align.END }); + menuButtonAppearanceCombo.append_text(_("Icon")); + menuButtonAppearanceCombo.append_text(_("Text")); + menuButtonAppearanceCombo.append_text(_("Icon and Text")); + menuButtonAppearanceCombo.append_text(_("Text and Icon")); + menuButtonAppearanceCombo.append_text(_("Hidden")); + menuButtonAppearanceCombo.set_active(this._settings.get_enum('menu-button-appearance')); + menuButtonAppearanceCombo.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + menuButtonAppearanceFrame.removeChildrenAfterIndex(0); + if(widget.get_active() === Constants.MenuButtonAppearance.NONE){ + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.show(); + } + else if(widget.get_active() === Constants.MenuButtonAppearance.ICON_TEXT || widget.get_active() === Constants.MenuButtonAppearance.TEXT_ICON || + widget.get_active() === Constants.MenuButtonAppearance.TEXT){ + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + if (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + menuButtonAppearanceFrame.show(); + } + this._settings.set_enum('menu-button-appearance', widget.get_active()); + }); + + menuButtonAppearanceRow.add(menuButtonAppearanceLabel); + menuButtonAppearanceRow.add(menuButtonAppearanceCombo); + menuButtonAppearanceFrame.add(menuButtonAppearanceRow); + + let menuButtonArrowIconBoxRow = new PW.FrameBoxRow(); + let menuButtonArrowIconLabel = new Gtk.Label({ + label: _('Show Arrow'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let enableArrowIconSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + enableArrowIconSwitch.set_active(this._settings.get_boolean('enable-menu-button-arrow')); + enableArrowIconSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-menu-button-arrow', widget.get_active()); + this.resetButton.set_sensitive(true); + }); + + menuButtonArrowIconBoxRow.add(menuButtonArrowIconLabel); + menuButtonArrowIconBoxRow.add(enableArrowIconSwitch); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonArrowIconBoxRow); + + let menuButtonPaddingRow = new PW.FrameBoxRow(); + let menuButtonPadding = this._settings.get_int('button-padding'); + let menuButtonPaddingLabel = new Gtk.Label({ + label: _('Menu Button Padding'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let paddingScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, + upper: 25, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + paddingScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + paddingScale.add_mark(-1, Gtk.PositionType.TOP, _("Default")); + paddingScale.set_value(menuButtonPadding); + paddingScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('button-padding', paddingScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonPaddingRow.add(menuButtonPaddingLabel); + menuButtonPaddingRow.add(paddingScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonPaddingRow); + + ///// Row for menu button offset ///// + let menuButtonOffsetRow = new PW.FrameBoxRow(); + let menuButtonOffset = this._settings.get_int('menu-button-position-offset'); + let menuButtonOffsetLabel = new Gtk.Label({ + label: _('Menu Button Position'), + use_markup: true, + xalign: 0, + hexpand: true, + }); + let offsetScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 10, // arbitrary value + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + offsetScale.add_mark(0, Gtk.PositionType.TOP, _("Default")); // offset 0 is default + offsetScale.add_mark(1, Gtk.PositionType.TOP, null); + offsetScale.add_mark(2, Gtk.PositionType.TOP, null); + offsetScale.set_value(menuButtonOffset); + offsetScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-position-offset', offsetScale.get_value()); + }); + menuButtonOffsetRow.add(menuButtonOffsetLabel); + menuButtonOffsetRow.add(offsetScale); + if(menuButtonAppearanceCombo.get_active() !== Constants.MenuButtonAppearance.NONE && + (this.arcMenuPlacement === Constants.ArcMenuPlacement.PANEL || this.arcMenuPlacement === Constants.ArcMenuPlacement.DTP)) + menuButtonAppearanceFrame.add(menuButtonOffsetRow); + //////////////////// + + let menuButtonCustomTextBoxRow = new PW.FrameBoxRow(); + let menuButtonCustomTextLabel = new Gtk.Label({ + label: _('Text'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonCustomTextEntry = new Gtk.Entry({ halign: Gtk.Align.END }); + menuButtonCustomTextEntry.set_width_chars(30); + menuButtonCustomTextEntry.set_text(this._settings.get_string('custom-menu-button-text')); + menuButtonCustomTextEntry.connect('changed', (widget) => { + this.resetButton.set_sensitive(true); + let customMenuButtonText = widget.get_text(); + this._settings.set_string('custom-menu-button-text', customMenuButtonText); + }); + + menuButtonCustomTextBoxRow.add(menuButtonCustomTextLabel); + menuButtonCustomTextBoxRow.add(menuButtonCustomTextEntry); + if(this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.ICON && this._settings.get_enum('menu-button-appearance') != Constants.MenuButtonAppearance.NONE) + menuButtonAppearanceFrame.add(menuButtonCustomTextBoxRow); + vbox.append(menuButtonAppearanceFrame); + + let menuButtonIconHeaderLabel = new Gtk.Label({ + label: "" + _('Icon Appearance') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonIconHeaderLabel); + + let menuButtonIconFrame = new PW.FrameBox(); + let menuButtonIconRow = new PW.FrameBoxRow(); + let menuButtonIconLabel = new Gtk.Label({ + label: _('Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let menuButtonIconButton = new PW.Button({ + title: _("Browse Icons") + " ", + icon_name: 'icon-preview-symbolic', + hexpand: false, + }); + menuButtonIconButton.connect('clicked', () => { + let dialog = new ArcMenuIconsDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', ()=> { + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + dialog.destroy(); + }); + }); + + menuButtonIconRow.add(menuButtonIconLabel); + menuButtonIconRow.add(menuButtonIconButton); + menuButtonIconFrame.add(menuButtonIconRow); + + let menuButtonIconSizeRow = new PW.FrameBoxRow(); + let iconSize = this._settings.get_double('custom-menu-button-icon-size'); + let menuButtonIconSizeLabel = new Gtk.Label({ + label: _('Icon Size'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonIconSizeScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 14, + upper: 64, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonIconSizeScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonIconSizeScale.set_value(iconSize); + menuButtonIconSizeScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_double('custom-menu-button-icon-size', menuButtonIconSizeScale.get_value()); + }); + + menuButtonIconSizeRow.add(menuButtonIconSizeLabel); + menuButtonIconSizeRow.add(menuButtonIconSizeScale); + menuButtonIconFrame.add(menuButtonIconSizeRow); + + vbox.append(menuButtonIconFrame); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + halign: Gtk.Align.START, + hexpand: true, + valign: Gtk.Align.END, + vexpand: true + }); + + let menuButtonColorHeaderLabel = new Gtk.Label({ + label: "" + _('Menu Button Styling') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(menuButtonColorHeaderLabel); + + this.menuButtonIconColorFrame = new PW.FrameBox(); + + let[menuButtonColorSwitch, menuButtonColorChooser] = this.newColorChooserRow({ + color: this.menuButtonColor, + label: _("Color"), + settingColorName: 'menu-button-color', + settingOverrideName: 'override-menu-button-color', + }); + + let[menuButtonHoverColorSwitch, menuButtonHoverColorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverColor, + label: _("Hover Color"), + settingColorName: 'menu-button-hover-color', + settingOverrideName: 'override-menu-button-hover-color', + }); + + let[menuButtonActiveColorSwitch, menuButtonActiveColorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveColor, + label: _("Active Color"), + settingColorName: 'menu-button-active-color', + settingOverrideName: 'override-menu-button-active-color', + }); + + let[menuButtonHoverBackgroundcolorSwitch, menuButtonHoverBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonHoverBackgroundcolor, + label: _("Hover Background Color"), + settingColorName: 'menu-button-hover-backgroundcolor', + settingOverrideName: 'override-menu-button-hover-background-color', + }); + + let[menuButtonActiveBackgroundcolorSwitch, menuButtonActiveBackgroundcolorChooser] = this.newColorChooserRow({ + color: this.menuButtonActiveBackgroundcolor, + label: _("Active Background Color"), + settingColorName: 'menu-button-active-backgroundcolor', + settingOverrideName: 'override-menu-button-active-background-color', + }); + + let roundedCornersRow = new PW.FrameBoxRow(); + + let roundedCornersLabel = new Gtk.Label({ + label: _("Override Border Radius"), + xalign:0, + hexpand: true, + }); + let roundedCornersSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean('menu-button-override-border-radius') + }); + roundedCornersSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean('menu-button-override-border-radius', widget.get_active()) + this._settings.set_boolean('reload-theme', true); + menuButtonBorderRadiusRow.set_sensitive(widget.get_active()); + }); + + roundedCornersRow.add(roundedCornersLabel); + roundedCornersRow.add(roundedCornersSwitch); + + this.menuButtonIconColorFrame.add(roundedCornersRow); + + let menuButtonBorderRadiusRow = new PW.FrameBoxRow(); + let borderRadius = this._settings.get_int('menu-button-border-radius'); + let menuButtonBorderRadiusLabel = new Gtk.Label({ + label: _('Border Radius'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let menuButtonBorderRadiusScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 0, + upper: 20, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuButtonBorderRadiusScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + menuButtonBorderRadiusScale.set_value(borderRadius); + menuButtonBorderRadiusScale.connect('value-changed', () => { + this.resetButton.set_sensitive(true); + this._settings.set_int('menu-button-border-radius', menuButtonBorderRadiusScale.get_value()); + this._settings.set_boolean('reload-theme', true); + }); + + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusLabel); + menuButtonBorderRadiusRow.add(menuButtonBorderRadiusScale); + menuButtonBorderRadiusRow.set_sensitive(this._settings.get_boolean('menu-button-override-border-radius')); + this.menuButtonIconColorFrame.add(menuButtonBorderRadiusRow); + + vbox.append(this.menuButtonIconColorFrame); + + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + menuButtonAppearanceCombo.set_active(0); + menuButtonCustomTextEntry.set_text('Applications'); + paddingScale.set_value(-1); + menuButtonIconSizeScale.set_value(20); + let colorParse = new Gdk.RGBA(); + colorParse.parse('rgb(240,240,240)'); + menuButtonActiveColorChooser.set_rgba(colorParse); + menuButtonColorChooser.set_rgba(colorParse); + colorParse.parse('rgb(214,214,214)'); + menuButtonHoverColorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.1)'); + menuButtonHoverBackgroundcolorChooser.set_rgba(colorParse); + colorParse.parse('rgba(238,238,236,0.18)'); + menuButtonActiveBackgroundcolorChooser.set_rgba(colorParse); + enableArrowIconSwitch.set_active(false); + menuButtonColorSwitch.set_active(false); + menuButtonHoverColorSwitch.set_active(false); + menuButtonActiveColorSwitch.set_active(false); + menuButtonHoverBackgroundcolorSwitch.set_active(false); + menuButtonActiveBackgroundcolorSwitch.set_active(false); + roundedCornersSwitch.set_active(false); + menuButtonBorderRadiusScale.set_value(0); + offsetScale.set_value(0); + this._settings.reset('menu-button-icon'); + this._settings.reset('arc-menu-icon'); + this._settings.reset('distro-icon'); + this._settings.reset('custom-menu-button-icon'); + this._settings.reset('menu-button-hover-color'); + this._settings.reset('menu-button-active-color'); + this._settings.reset('menu-button-hover-backgroundcolor'); + this._settings.reset('menu-button-active-backgroundcolor'); + this._settings.reset('menu-button-color'); + this._settings.reset('override-menu-button-hover-color'); + this._settings.reset('override-menu-button-active-color'); + this._settings.reset('override-menu-button-hover-background-color'); + this._settings.reset('override-menu-button-active-background-color'); + this._settings.reset('override-menu-button-color'); + this._settings.reset('menu-button-override-border-radius'); + this._settings.reset('menu-button-border-radius'); + this._settings.reset('menu-button-position-offset'); + this._settings.set_boolean('reload-theme', true); + + this.resetButton.set_sensitive(false); + }); + vbox.append(this.resetButton); + } + + newColorChooserRow(params){ + let colorParse = new Gdk.RGBA(); + let colorRow = new PW.FrameBoxRow(); + let buttonsGrid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + + let colorLabel = new Gtk.Label({ + label: params.label, + xalign:0, + hexpand: true, + }); + let colorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + active: this._settings.get_boolean(params.settingOverrideName) + }); + colorSwitch.connect("notify::active", (widget)=> { + this.resetButton.set_sensitive(true); + this._settings.set_boolean(params.settingOverrideName, widget.get_active()) + colorChooser.sensitive = widget.get_active(); + this._settings.set_boolean('reload-theme', true); + }); + + let colorChooser = new Gtk.ColorButton({ + use_alpha: true, + sensitive: colorSwitch.get_active() + }); + + colorParse.parse(params.color); + colorChooser.set_rgba(colorParse); + + colorChooser.connect('color-set', ()=>{ + this.resetButton.set_sensitive(true); + params.color = colorChooser.get_rgba().to_string(); + this._settings.set_string(params.settingColorName, params.color); + this._settings.set_boolean('reload-theme', true); + }); + + colorRow.add(colorLabel); + buttonsGrid.attach(colorSwitch, 0, 0, 1, 1); + buttonsGrid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 1, 0, 1, 1); + buttonsGrid.attach(colorChooser, 2, 0, 1, 1); + colorRow.add(buttonsGrid); + this.menuButtonIconColorFrame.add(colorRow); + return [colorSwitch, colorChooser]; + } + + checkIfResetButtonSensitive(){ + if( this._settings.get_string('menu-button-hover-backgroundcolor') != 'rgba(238,238,236,0.1)' || + this._settings.get_string('menu-button-active-backgroundcolor') != 'rgba(238,238,236,0.18)' || + this._settings.get_string('menu-button-active-color') != 'rgb(240,240,240)' || + this._settings.get_string('menu-button-hover-color') != 'rgb(214,214,214)' || + this._settings.get_string('menu-button-color') != 'rgb(240,240,240)' || + this._settings.get_double('custom-menu-button-icon-size') != 20 || + this._settings.get_int('button-padding') != -1 || + this._settings.get_enum('menu-button-icon') != 0 || + this._settings.get_int('arc-menu-icon') != 0 || + this._settings.get_string('custom-menu-button-text') != 'Applications' || + this._settings.get_enum('menu-button-appearance') != 0 || + this._settings.get_boolean('enable-menu-button-arrow') || + this._settings.get_boolean('override-menu-button-color') || + this._settings.get_boolean('override-menu-button-hover-color') || + this._settings.get_boolean('override-menu-button-active-color') || + this._settings.get_boolean('override-menu-button-hover-background-color') || + this._settings.get_boolean('override-menu-button-active-background-color') || + this._settings.get_boolean('menu-button-override-border-radius') || + this._settings.get_int('menu-button-border-radius') != 0 || + this._settings.get_int('menu-button-position-offset') != 0 ) + return true; + else + return false; + } +}); + +var ArcMenuIconsDialogWindow = GObject.registerClass( + class Arc_Menu_ArcMenuIconsDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + super._init(_('ArcMenu Icons'), parent); + this.set_default_size(550, 400); + } + + _createLayout(vbox){ + this.stack = new Gtk.Stack({ + halign: Gtk.Align.FILL, + hexpand: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let arcMenuIconsBox = new Gtk.ScrolledWindow(); + + let arcMenuIconsFlowBox = new PW.IconGrid(); + arcMenuIconsFlowBox.connect('child-activated', ()=> { + distroIconsBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = arcMenuIconsFlowBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.ARC_MENU); + this._settings.set_int('arc-menu-icon', selectedChildIndex); + }); + arcMenuIconsBox.set_child(arcMenuIconsFlowBox); + Constants.MenuIcons.forEach((icon)=>{ + let iconName = icon.PATH.replace("/media/icons/menu_button_icons/icons/", ''); + iconName = iconName.replace(".svg", ''); + let iconImage = new Gtk.Image({ + icon_name: iconName, + pixel_size: 36 + }); + arcMenuIconsFlowBox.add(iconImage); + }); + + let distroIconsBox = new PW.IconGrid(); + distroIconsBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + customIconFlowBox.unselect_all(); + let selectedChild = distroIconsBox.get_selected_children(); + let selectedChildIndex = selectedChild[0].get_index(); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.DISTRO_ICON); + this._settings.set_int('distro-icon', selectedChildIndex); + }); + Constants.DistroIcons.forEach((icon)=>{ + let iconImage; + if(icon.PATH === 'start-here-symbolic'){ + iconImage = new Gtk.Image({ + icon_name: 'start-here-symbolic', + pixel_size: 36 + }); + } + else{ + let iconName1 = icon.PATH.replace("/media/icons/menu_button_icons/distro_icons/", ''); + iconName1 = iconName1.replace(".svg", ''); + iconImage = new Gtk.Image({ + icon_name: iconName1, + pixel_size: 36 + }); + } + distroIconsBox.add(iconImage); + }); + + let customIconBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + let customIconFlowBox = new PW.IconGrid(); + customIconFlowBox.vexpand = false; + customIconFlowBox.homogeneous = false; + customIconFlowBox.connect('child-activated', ()=> { + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + let customIconPath = this._settings.get_string('custom-menu-button-icon'); + this._settings.set_string('custom-menu-button-icon', customIconPath) + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + }); + customIconBox.append(customIconFlowBox); + let customIconImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(this._settings.get_string('custom-menu-button-icon')), + pixel_size: 36 + }); + customIconFlowBox.add(customIconImage); + + let fileChooserFrame = new PW.FrameBox(); + fileChooserFrame.margin_top = 20; + fileChooserFrame.margin_bottom = 20; + fileChooserFrame.margin_start = 20; + fileChooserFrame.margin_end = 20; + let fileChooserRow = new PW.FrameBoxRow(); + let fileChooserLabel = new Gtk.Label({ + label: _('Browse for a Custom Icon'), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + let fileChooserButton = new Gtk.Button({ + label: _('Select an Icon') + }); + fileChooserButton.connect('clicked', (widget) => { + let dialog = new Gtk.FileChooserDialog({ + title: _('Select an Icon'), + transient_for: this.get_root(), + modal: true, + action: Gtk.FileChooserAction.OPEN, + }); + + if(dialog.get_parent()) + dialog.unparent(); + dialog.set_filter(fileFilter); + + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button("_Open", Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + arcMenuIconsFlowBox.unselect_all(); + distroIconsBox.unselect_all(); + customIconImage.gicon = Gio.icon_new_for_string(dialog.get_file().get_path()); + this._settings.set_string('custom-menu-button-icon', dialog.get_file().get_path()); + this._settings.set_enum('menu-button-icon', Constants.MenuIcon.CUSTOM); + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + dialog.destroy(); + } + else + dialog.destroy(); + }) + + dialog.show(); + }); + + fileChooserRow.add(fileChooserLabel); + fileChooserRow.add(fileChooserButton); + fileChooserFrame.add(fileChooserRow); + customIconBox.append(fileChooserFrame); + + this.stack.add_titled(arcMenuIconsBox, 'ArcMenu Icons', _('ArcMenu Icons')); + this.stack.add_titled(distroIconsBox, 'Distro Icons', _('Distro Icons')); + this.stack.add_titled(customIconBox, 'Custom Icon', _('Custom Icon')); + + let stackSwitcher = new Gtk.StackSwitcher({ + stack: this.stack, + halign: Gtk.Align.CENTER + }); + + vbox.append(stackSwitcher); + vbox.append(this.stack); + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU){ + let children = arcMenuIconsFlowBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('arc-menu-icon')){ + arcMenuIconsFlowBox.select_child(arcMenuIconsFlowBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON){ + let children = distroIconsBox.childrenCount; + for(let i = 0; i < children; i++){ + if(i === this._settings.get_int('distro-icon')){ + distroIconsBox.select_child(distroIconsBox.get_child_at_index(i)); + break; + } + } + } + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM){ + customIconFlowBox.select_child(customIconFlowBox.get_child_at_index(0)); + } + + let distroInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + distroInfoButton.halign = Gtk.Align.START; + distroInfoButton.connect('clicked', ()=> { + let dialog = new DistroIconsDisclaimerWindow(this._settings, this); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + vbox.append(distroInfoButton); + } + + setVisibleChild(){ + if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.ARC_MENU) + this.stack.set_visible_child_name('ArcMenu Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.DISTRO_ICON) + this.stack.set_visible_child_name('Distro Icons'); + else if(this._settings.get_enum('menu-button-icon') === Constants.MenuIcon.CUSTOM) + this.stack.set_visible_child_name('Custom Icon'); + } +}); + +var DistroIconsDisclaimerWindow = GObject.registerClass( + class Arc_Menu_DistroIconsDisclaimerWindow extends Gtk.MessageDialog { + _init(settings, parent) { + this._settings = settings; + super._init({ + text: "" + _("Legal disclaimer for Distro Icons...") + "", + use_markup: true, + message_type: Gtk.MessageType.OTHER, + transient_for: parent.get_root(), + modal: true, + buttons: Gtk.ButtonsType.OK + }); + + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + }); + this.get_content_area().append(vbox); + this._createLayout(vbox); + } + + _createLayout(vbox) { + let scrollWindow = new Gtk.ScrolledWindow({ + min_content_width: 500, + max_content_width: 500, + min_content_height: 400, + max_content_height: 400, + hexpand: false, + halign: Gtk.Align.START, + }); + scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + let frame = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + halign: Gtk.Align.START + }); + + let bodyLabel = new Gtk.Label({ + label: Constants.DistroIconsDisclaimer, + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true + }); + bodyLabel.set_size_request(500,-1); + + frame.append(bodyLabel); + scrollWindow.set_child(frame); + vbox.append(scrollWindow); + } +}); + +var MenuLayoutPage = GObject.registerClass( + class Arc_Menu_MenuLayoutPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + this._settings = settings; + + this.scrollBox = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.scrollBox.set_child(this.mainBox); + + let currentLayoutLabel = new Gtk.Label({ + label: "" + _("Current Menu Layout") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("Available Menu Layouts") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(currentLayoutLabel); + + let currentLayoutFrame = new PW.FrameBox(); + + let currentLayoutBoxLabel = new Gtk.Label({ + label: "" + this.getMenuLayoutName(this._settings.get_enum('menu-layout')) + "", + use_markup: true, + hexpand: true, + vexpand: true, + halign: Gtk.Align.CENTER, + valign: Gtk.Align.CENTER + }); + let currentLayoutBoxRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + currentLayoutBoxRow.activatable = true; + currentLayoutBoxRow._grid.row_spacing = 0; + currentLayoutBoxRow._grid.column_spacing = 0; + + let goNextImage = new Gtk.Image({ + icon_name: 'go-next-symbolic', + halign: Gtk.Align.END + }); + + currentLayoutFrame._listBox.connect('row-activated', () => { + this.displayLayoutTweaksPage(); + }); + + this.layoutsTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout'))); + this.layoutsTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + + let currentLayoutImagePath = this.getMenuLayoutImagePath(this._settings.get_enum('menu-layout')); + + let currentLayoutImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string(currentLayoutImagePath), + pixel_size: 155, + hexpand: false, + halign: Gtk.Align.START, + valign: Gtk.Align.CENTER, + }); + let tweaksLabel = new Gtk.Label({ + label: this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')), + use_markup: true, + halign: Gtk.Align.END, + vexpand: true, + hexpand: true + }); + currentLayoutBoxRow._grid.attach(currentLayoutImage, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(currentLayoutBoxLabel, 0, 0, 1, 1); + currentLayoutBoxRow._grid.attach(goNextImage, 0, 0, 1, 1); + currentLayoutFrame.add(currentLayoutBoxRow); + + this.mainBox.append(currentLayoutFrame); + this.mainBox.append(chooseNewLayoutLabel); + + this.stack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + this.layoutTilesBox = new Gtk.Grid({ + column_homogeneous: true, + column_spacing: 14, + row_spacing: 6, + hexpand: true, + halign: Gtk.Align.FILL, + vexpand: true, + valign: Gtk.Align.FILL + }); + this.mainBox.append(this.layoutTilesBox); + this.stack.add_named(this.scrollBox, "LayoutsBox"); + this.stack.add_named(this.layoutsTweaksPage, "LayoutsTweaks") + let gridY = 0; + Constants.MenuStyles.STYLES.forEach((style) => { + let tile = new PW.LayoutTile(style.TITLE, style.IMAGE, style); + this.layoutTilesBox.attach(tile, 0, gridY, 1, 1); + let menuLayoutsBox = new MenuLayoutCategoryPage(this._settings, this, tile, style.TITLE); + gridY++; + menuLayoutsBox.connect('menu-layout-response', (dialog, response) => { + if(response === -10) { + this._settings.set_enum('menu-layout', dialog.index); + this._settings.set_boolean('reload-theme', true); + currentLayoutBoxLabel.label = "" + this.getMenuLayoutName(dialog.index) + ""; + tweaksLabel.label = this.getMenuLayoutTweaksName(dialog.index); + currentLayoutImage.gicon = Gio.icon_new_for_string(this.getMenuLayoutImagePath(dialog.index)); + this.stack.set_visible_child_name("LayoutsBox"); + this.scrollBox.vadjustment.set_value(this.scrollBox.vadjustment.get_lower()); + } + if(response === -20){ + this.stack.set_visible_child_name("LayoutsBox"); + } + }); + this.stack.add_named(menuLayoutsBox, "Layout_" + style.TITLE); + tile._listBox.connect('row-activated', ()=> { + this.stack.set_visible_child_name("Layout_" + style.TITLE); + menuLayoutsBox.enableSelectionMode(); + }); + }); + + this.append(this.stack); + } + + displayLayoutTweaksPage(){ + let layoutName = this.getMenuLayoutTweaksName(this._settings.get_enum('menu-layout')); + this.layoutsTweaksPage.setActiveLayout(this._settings.get_enum('menu-layout'), layoutName); + this.stack.set_visible_child_name("LayoutsTweaks"); + } + + displayRunnerTweaksPage(){ + if(!this.runnerTweaksPage){ + let activeLayoutName = this.getMenuLayoutTweaksName(Constants.MenuLayout.RUNNER); + this.runnerTweaksPage = new LayoutTweaks.tweaks.TweaksPage(this._settings, activeLayoutName); + this.stack.add_named(this.runnerTweaksPage, "RunnerTweaks") + this.runnerTweaksPage.connect("response", (page, response) => { + if(response === -20) + this.stack.set_visible_child_name("LayoutsBox"); + }); + this.runnerTweaksPage.setActiveLayout(Constants.MenuLayout.RUNNER); + } + this.stack.set_visible_child_name("RunnerTweaks"); + } + + getMenuLayoutName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _(style.TITLE); + } + } + } + } + + getMenuLayoutTweaksName(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return _("%s Layout Tweaks", style.TITLE).format(style.TITLE); + } + } + } + } + + getMenuLayoutImagePath(index){ + for(let styles of Constants.MenuStyles.STYLES){ + for(let style of styles.MENU_TYPE){ + if(style.LAYOUT == index){ + return style.IMAGE; + } + } + } + } + +}); + +var MenuThemePage = GObject.registerClass( + class Arc_Menu_MenuThemePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.checkIfPresetMatch(); + + let overrideArcMenuHeaderLabel = new Gtk.Label({ + label: "" + _('Enable Custom Menu Theme') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(overrideArcMenuHeaderLabel); + + let overrideArcMenuFrame = new PW.FrameBox(); + let overrideArcMenuRow = new PW.FrameBoxRow(); + let overrideArcMenuLabel = new Gtk.Label({ + label: _("Override Menu Theme"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let overrideArcMenuSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + }); + overrideArcMenuSwitch.set_active(this._settings.get_boolean('enable-custom-arc-menu')); + overrideArcMenuSwitch.connect('notify::active', (widget) => { + this._settings.set_boolean('enable-custom-arc-menu',widget.get_active()); + this._settings.set_boolean('reload-theme', true); + if(widget.get_active()){ + this.mainBox.append(this.menuThemeCustomizationBox); + this.menuThemeCustomizationBox.show(); + this.append(this.buttonRow); + this.buttonRow.show(); + } + else{ + this.mainBox.remove(this.menuThemeCustomizationBox); + this.remove(this.buttonRow); + } + this.mainBox.show(); + }); + + this.menuThemeCustomizationBox = new OverrideArcMenuThemeWindow(this._settings, this.mainBox, this); + this.menuThemeCustomizationBox.connect('menu-theme-response', (dialog, response) => { + if(response === -10) { + this._settings.set_string('separator-color', dialog.separatorColor); + this._settings.set_boolean('vert-separator', dialog.verticalSeparator); + this._settings.set_string('menu-color', dialog.menuColor); + this._settings.set_string('menu-foreground-color', dialog.menuForegroundColor); + this._settings.set_string('border-color', dialog.borderColor); + this._settings.set_string('highlight-color', dialog.highlightColor ); + this._settings.set_string('highlight-foreground-color', dialog.highlightForegroundColor); + this._settings.set_int('menu-font-size', dialog.fontSize); + this._settings.set_int('menu-border-size', dialog.borderSize); + this._settings.set_int('menu-corner-radius', dialog.cornerRadius); + this._settings.set_int('menu-margin', dialog.menuMargin); + this._settings.set_int('menu-arrow-size', dialog.menuArrowSize); + this._settings.set_boolean('reload-theme', true); + this.presetName = dialog.presetName; + } + else{ + this.checkIfPresetMatch(); + } + }); + + overrideArcMenuRow.add(overrideArcMenuLabel); + overrideArcMenuRow.add(overrideArcMenuSwitch); + overrideArcMenuFrame.add(overrideArcMenuRow); + + this.mainBox.append(overrideArcMenuFrame); + if(overrideArcMenuSwitch.get_active()) + this.mainBox.append(this.menuThemeCustomizationBox); + else + this.remove(this.buttonRow); + } + + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < all_color_themes.length; i++){ + this.isEqual = true; + for(let l = 0; l < this.currentSettingsArray.length; l++){ + if(this.currentSettingsArray[l] !== all_color_themes[i][l + 1]){ + this.isEqual=false; + break; + } + } + if(this.isEqual){ + this.presetName = all_color_themes[i][0]; + break; + } + } + } +}); + +var MenuLayoutCategoryPage = GObject.registerClass({ + Signals: { + 'menu-layout-response': { param_types: [GObject.TYPE_INT] }, + }, +}, class Arc_Menu_MenuLayoutCategoryPage extends Gtk.ScrolledWindow { + _init(settings, parent, tile, title) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this.title = title; + this._parent = parent; + this._settings = settings; + this.index = this._settings.get_enum('menu-layout'); + this.layoutStyle = tile.layout; + + this._params = { + maxColumns: tile.layout.length > 3 ? 3 : tile.layout.length, + imageHeight: 155, + imageWidth: 155, + styles: tile.layout + }; + let layoutsFrame = new PW.FrameBox(); + let layoutsRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false, + }) + layoutsRow._grid.orientation = Gtk.Orientation.VERTICAL; + layoutsFrame.add(layoutsRow); + let buttonBox = new Gtk.Box({ + spacing: 10 + }); + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: false, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + let selectedBox = this._tileGrid.get_selected_children(); + this.index = selectedBox[0].get_child().layout; + this._tileGrid.unselect_all(); + applyButton.set_sensitive(false); + this.emit('menu-layout-response', -10); + }); + let backButton = new PW.Button({ + icon_name: 'go-previous-symbolic', + title: _("Back"), + icon_first: true, + halign: Gtk.Align.START + }); + backButton.connect('clicked', ()=> { + this.emit('menu-layout-response', -20); + }); + buttonBox.append(backButton); + let chooseNewLayoutLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", this.title).format(this.title) + "", + use_markup: true, + halign: Gtk.Align.CENTER, + hexpand: true + }); + buttonBox.append(chooseNewLayoutLabel); + buttonBox.append(applyButton); + applyButton.set_sensitive(false); + + this.mainBox.append(buttonBox); + this.mainBox.append(layoutsFrame); + this._tileGrid = new PW.TileGrid(this._params.maxColumns); + + this._params.styles.forEach((style) => { + this._addTile(style.TITLE, style.IMAGE, style.LAYOUT); + }); + + layoutsRow.add(this._tileGrid); + + this._tileGrid.connect('selected-children-changed', () => { + applyButton.set_sensitive(true); + }); + + this._tileGrid.set_selection_mode(Gtk.SelectionMode.NONE); + } + + + enableSelectionMode(){ + this._tileGrid.set_selection_mode(Gtk.SelectionMode.SINGLE); + } + + _addTile(name, image, layout) { + let tile = new PW.Tile(name, image, this._params.imageWidth, this._params.imageHeight, layout); + this._tileGrid.insert(tile, -1); + } +}); + +var MenuSettingsGeneralPage = GObject.registerClass( + class Arc_Menu_MenuSettingsGeneralPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.heightValue = this._settings.get_int('menu-height'); + this.widthValue = this._settings.get_int('menu-width-adjustment'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.menuWidth = this._settings.get_int('menu-width'); + this.forcedMenuLocation = this._settings.get_enum('force-menu-location'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.appDescriptions = this._settings.get_boolean('apps-show-extra-details'); + this.categoryIconType = this._settings.get_enum('category-icon-type'); + this.shortcutsIconType = this._settings.get_enum('shortcut-icon-type'); + + let menuSizeFrame = new PW.FrameBox(); + //find the greatest screen height of all monitors + //use that value to set Menu Height cap + let display = Gdk.Display.get_default(); + let monitors = display.get_monitors(); + let nMonitors = monitors.get_n_items(); + let greatestHeight = 0; + let scaleFactor = 1; + for (let i = 0; i < nMonitors; i++) { + let monitor = monitors.get_item(i); + let monitorHeight = monitor.get_geometry().height; + if(monitorHeight > greatestHeight){ + scaleFactor = monitor.get_scale_factor(); + greatestHeight = monitorHeight; + } + } + let monitorHeight = greatestHeight * scaleFactor; + monitorHeight = Math.round((monitorHeight * 8) / 10); + + let menuSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuSizeHeaderLabel); + + this.mainBox.append(menuSizeFrame); + let heightRow = new PW.FrameBoxRow(); + let heightLabel = new Gtk.Label({ + label: _('Height'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let hscale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 300, + upper: monitorHeight, + step_increment: 10, + page_increment: 10, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + hscale.set_value(this.heightValue); + hscale.connect('value-changed', () => { + this.heightValue = hscale.get_value(); + if(hSpinButton.value !== this.heightValue) + hSpinButton.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let hSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: monitorHeight, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + hSpinButton.set_value(this.heightValue); + hSpinButton.connect('value-changed', () => { + this.heightValue = hSpinButton.get_value(); + if(hscale.value !== this.heightValue) + hscale.set_value(this.heightValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + heightRow.add(heightLabel); + heightRow.add(hscale); + heightRow.add(hSpinButton); + menuSizeFrame.add(heightRow); + + let menuWidthTwoPanelsHeaderRow = new PW.FrameBoxRow(); + let menuWidthTwoPanelsHeaderLabel = new Gtk.Label({ + label: _("Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + menuWidthTwoPanelsHeaderRow.add(menuWidthTwoPanelsHeaderLabel) + menuSizeFrame.add(menuWidthTwoPanelsHeaderRow); + + let menuWidthRow = new PW.FrameBoxRow(); + menuWidthRow._grid.margin_start = 25; + let menuWidthLabel = new Gtk.Label({ + label: _('Left-Panel'), + xalign:0, + hexpand: false, + }); + let menuWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + menuWidthScale.set_value(this.menuWidth); + menuWidthScale.connect('value-changed', () => { + this.menuWidth = menuWidthScale.get_value(); + if(menuWidthSpinButton.value !== this.menuWidth) + menuWidthSpinButton.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let menuWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 175, upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + menuWidthSpinButton.set_value(this.menuWidth); + menuWidthSpinButton.connect('value-changed', () => { + this.menuWidth = menuWidthSpinButton.get_value(); + if(menuWidthScale.value !== this.menuWidth) + menuWidthScale.set_value(this.menuWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + menuWidthRow.add(menuWidthLabel); + menuWidthRow.add(menuWidthScale); + menuWidthRow.add( menuWidthSpinButton); + menuSizeFrame.add(menuWidthRow); + + let rightPanelWidthRow = new PW.FrameBoxRow(); + rightPanelWidthRow._grid.margin_start = 25; + let rightPanelWidthLabel = new Gtk.Label({ + label: _('Right-Panel'), + xalign:0, + hexpand: false, + }); + let rightPanelWidthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + rightPanelWidthScale.set_value(this.rightPanelWidth); + rightPanelWidthScale.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthScale.get_value(); + if(rightPanelWidthSpinButton.value !== this.rightPanelWidth) + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let rightPanelWidthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 200,upper: 500, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + }); + rightPanelWidthSpinButton.set_value(this.rightPanelWidth); + rightPanelWidthSpinButton.connect('value-changed', () => { + this.rightPanelWidth = rightPanelWidthSpinButton.get_value(); + if(rightPanelWidthScale.value !== this.rightPanelWidth) + rightPanelWidthScale.set_value(this.rightPanelWidth); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + rightPanelWidthRow.add(rightPanelWidthLabel); + rightPanelWidthRow.add(rightPanelWidthScale); + rightPanelWidthRow.add(rightPanelWidthSpinButton); + menuSizeFrame.add(rightPanelWidthRow); + + let otherWidthHeaderRow = new PW.FrameBoxRow(); + let otherWidthHeaderLabel = new Gtk.Label({ + label: _("Non-Traditional Layouts Width"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false, + sensitive: false + }); + otherWidthHeaderRow.add(otherWidthHeaderLabel) + menuSizeFrame.add(otherWidthHeaderRow); + + let widthRow = new PW.FrameBoxRow(); + widthRow._grid.margin_start = 25; + let widthLabel = new Gtk.Label({ + label: _('Width Offset'), + use_markup: true, + xalign: 0, + hexpand: false, + selectable: false + }); + let widthScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -350, + upper: 600, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + value_pos: Gtk.PositionType.RIGHT + }); + widthScale.add_mark(0, Gtk.PositionType.BOTTOM, _("Default")); + widthScale.set_value(this.widthValue); + widthScale.connect('value-changed', (widget) => { + this.widthValue = widget.get_value(); + if(widthSpinButton.value !== this.widthValue) + widthSpinButton.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let widthSpinButton = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: -350, upper: 600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + valign: Gtk.Align.START + }); + widthSpinButton.set_value(this.widthValue); + widthSpinButton.connect('value-changed', () => { + this.widthValue = widthSpinButton.get_value(); + if(widthScale.value !== this.widthValue) + widthScale.set_value(this.widthValue); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + widthRow.add(widthLabel); + widthRow.add(widthScale); + widthRow.add(widthSpinButton); + menuSizeFrame.add(widthRow); + + let iconsSizeFrame = new PW.FrameBox(); + let menuItemSizeHeaderLabel = new Gtk.Label({ + label: "" + _("Menu Items Icon Size") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(menuItemSizeHeaderLabel); + + let gridIconsSizeRow = new PW.FrameBoxRow(); + let gridIconsSizeLabel = new Gtk.Label({ + label: _("Grid Icons"), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.gridIconsSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + this.gridIconsSizeCombo.append("Default", _("Default")); + this.gridIconsSizeCombo.append("Small", _("Small") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Medium", _("Medium") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Large", _("Large") + " - " + _("Square")); + this.gridIconsSizeCombo.append("Small Rect", _("Small") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Medium Rect", _("Medium") + " - " + _("Wide")); + this.gridIconsSizeCombo.append("Large Rect", _("Large") + " - " + _("Wide")); + this.gridIconsSizeCombo.set_active(this._settings.get_enum('menu-item-grid-icon-size')); + this.gridIconsSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + gridIconsSizeRow.add(gridIconsSizeLabel); + gridIconsSizeRow.add(this.gridIconsSizeCombo); + iconsSizeFrame.add(gridIconsSizeRow); + + [this.menuItemIconSizeCombo, this.menuItemIconSizeRow] = this.createIconSizeRow(_("Categories & Applications"), this._settings.get_enum('menu-item-icon-size')); + iconsSizeFrame.add(this.menuItemIconSizeRow); + [this.buttonIconSizeCombo, this.buttonIconSizeRow] = this.createIconSizeRow(_("Buttons"), this._settings.get_enum('button-item-icon-size')); + iconsSizeFrame.add(this.buttonIconSizeRow); + [this.quicklinksIconSizeCombo, this.quicklinksIconSizeRow] = this.createIconSizeRow(_("Quick Links"), this._settings.get_enum('quicklinks-item-icon-size')); + iconsSizeFrame.add(this.quicklinksIconSizeRow); + [this.miscIconSizeCombo, this.miscIconSizeRow] = this.createIconSizeRow(_("Misc"), this._settings.get_enum('misc-item-icon-size')); + iconsSizeFrame.add(this.miscIconSizeRow); + + this.mainBox.append(iconsSizeFrame); + + let generalHeaderLabel = new Gtk.Label({ + label: "" + _("General Settings") + "", + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + this.mainBox.append(generalHeaderLabel); + + let generalSettingsFrame = new PW.FrameBox(); + let menuLocationRow = new PW.FrameBoxRow(); + let menuLocationLabel = new Gtk.Label({ + label: _('Override Menu Location'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let menuLocationCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + menuLocationCombo.append_text(_("Off")); + menuLocationCombo.append_text(_("Top Centered")); + menuLocationCombo.append_text(_("Bottom Centered")); + menuLocationCombo.set_active(this._settings.get_enum('force-menu-location')); + menuLocationCombo.connect('changed', (widget) => { + this.forcedMenuLocation = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + menuLocationRow.add(menuLocationLabel); + menuLocationRow.add(menuLocationCombo); + generalSettingsFrame.add(menuLocationRow); + this.mainBox.append(generalSettingsFrame); + + let appDescriptionsRow = new PW.FrameBoxRow(); + let appDescriptionsLabel = new Gtk.Label({ + label: _("Show Application Descriptions"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let appDescriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + appDescriptionsSwitch.set_active(this.appDescriptions); + appDescriptionsSwitch.connect('notify::active', (widget) => { + this.appDescriptions = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appDescriptionsRow.add(appDescriptionsLabel); + appDescriptionsRow.add(appDescriptionsSwitch); + generalSettingsFrame.add(appDescriptionsRow); + + let categoryIconTypeRow = new PW.FrameBoxRow(); + let categoryIconTypeLabel = new Gtk.Label({ + label: _('Category Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let categoryIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + categoryIconTypeCombo.append_text(_("Full Color")); + categoryIconTypeCombo.append_text(_("Symbolic")); + categoryIconTypeCombo.set_active(this.categoryIconType); + categoryIconTypeCombo.connect('changed', (widget) => { + this.categoryIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + categoryIconTypeRow.add(categoryIconTypeLabel); + categoryIconTypeRow.add(categoryIconTypeCombo); + generalSettingsFrame.add(categoryIconTypeRow); + + let shortcutsIconTypeRow = new PW.FrameBoxRow(); + let shortcutsIconTypeLabel = new Gtk.Label({ + label: _('Shortcuts Icon Type'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let shortcutsIconTypeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + shortcutsIconTypeCombo.append_text(_("Full Color")); + shortcutsIconTypeCombo.append_text(_("Symbolic")); + shortcutsIconTypeCombo.set_active(this.shortcutsIconType); + shortcutsIconTypeCombo.connect('changed', (widget) => { + this.shortcutsIconType = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + shortcutsIconTypeRow.add(shortcutsIconTypeLabel); + shortcutsIconTypeRow.add(shortcutsIconTypeCombo); + generalSettingsFrame.add(shortcutsIconTypeRow); + + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + generalSettingsFrame.add(vertSeparatorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.heightValue = this._settings.get_default_value('menu-height').unpack(); + this.widthValue = this._settings.get_default_value('menu-width-adjustment').unpack(); + this.rightPanelWidth = this._settings.get_default_value('right-panel-width').unpack(); + this.menuWidth = this._settings.get_default_value('menu-width').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.appDescriptions = this._settings.get_default_value('apps-show-extra-details').unpack(); + this.categoryIconType = 0; + this.shortcutsIconType = 1; + this.forcedMenuLocation = 0; + hscale.set_value(this.heightValue); + widthScale.set_value(this.widthValue); + menuWidthScale.set_value(this.menuWidth); + rightPanelWidthScale.set_value(this.rightPanelWidth); + vertSeparatorSwitch.set_active(this.verticalSeparator); + this.gridIconsSizeCombo.set_active(0); + this.menuItemIconSizeCombo.set_active(0); + this.buttonIconSizeCombo.set_active(0); + this.quicklinksIconSizeCombo.set_active(0); + this.miscIconSizeCombo.set_active(0); + appDescriptionsSwitch.set_active(this.appDescriptions); + menuLocationCombo.set_active(this.forcedMenuLocation); + categoryIconTypeCombo.set_active(0); + shortcutsIconTypeCombo.set_active(1); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('menu-height', this.heightValue); + this._settings.set_int('menu-width-adjustment', this.widthValue); + this._settings.set_int('right-panel-width', this.rightPanelWidth); + this._settings.set_int('menu-width', this.menuWidth); + this._settings.set_enum('force-menu-location', this.forcedMenuLocation); + this._settings.set_boolean('vert-separator', this.verticalSeparator); + this._settings.set_enum('menu-item-icon-size', this.menuItemIconSizeCombo.get_active()); + this._settings.set_enum('menu-item-grid-icon-size', this.gridIconsSizeCombo.get_active()); + this._settings.set_enum('button-item-icon-size', this.buttonIconSizeCombo.get_active()); + this._settings.set_enum('quicklinks-item-icon-size', this.quicklinksIconSizeCombo.get_active()); + this._settings.set_enum('misc-item-icon-size', this.miscIconSizeCombo.get_active()); + this._settings.set_boolean('reload-theme', true); + this._settings.set_boolean('apps-show-extra-details', this.appDescriptions); + this._settings.set_enum('category-icon-type', this.categoryIconType); + this._settings.set_enum('shortcut-icon-type', this.shortcutsIconType); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + createIconSizeRow(title, iconSizeEnum){ + let iconsSizeRow = new PW.FrameBoxRow(); + let iconsSizeLabel = new Gtk.Label({ + label: _(title), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let iconSizeCombo = new Gtk.ComboBoxText({ + halign: Gtk.Align.END, + }); + iconSizeCombo.append("Default", _("Default")); + iconSizeCombo.append("ExtraSmall", _("Extra Small")); + iconSizeCombo.append("Small", _("Small")); + iconSizeCombo.append("Medium", _("Medium")); + iconSizeCombo.append("Large", _("Large")); + iconSizeCombo.append("ExtraLarge", _("Extra Large")); + iconSizeCombo.set_active(iconSizeEnum); + iconSizeCombo.connect('changed', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + iconsSizeRow.add(iconsSizeLabel); + iconsSizeRow.add(iconSizeCombo); + return [iconSizeCombo, iconsSizeRow]; + } + + checkIfResetButtonSensitive(){ + return ( + this.heightValue !== this._settings.get_default_value('menu-height').unpack() || + this.widthValue !== this._settings.get_default_value('menu-width-adjustment').unpack() || + this.rightPanelWidth !== this._settings.get_default_value('right-panel-width').unpack() || + this.menuWidth !== this._settings.get_default_value('menu-width').unpack() || + this.forcedMenuLocation !== 0 || + this.verticalSeparator !== this._settings.get_default_value('vert-separator').unpack() || + this.gridIconsSizeCombo.get_active() !== 0 || + this.menuItemIconSizeCombo.get_active() !== 0 || + this.buttonIconSizeCombo.get_active() !== 0 || + this.quicklinksIconSizeCombo.get_active() !== 0 || + this.miscIconSizeCombo.get_active() !== 0 || + this.appDescriptions !== this._settings.get_default_value('apps-show-extra-details').unpack() || + this.categoryIconType !== 0 || + this.shortcutsIconType !== 1 ) ? true : false + } +}); + +var MenuSettingsFineTunePage = GObject.registerClass( + class Arc_Menu_MenuSettingsFineTunePage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableFadeEffect = this._settings.get_boolean('disable-scrollview-fade-effect'); + this.gapAdjustment = this._settings.get_int('gap-adjustment'); + this.removeMenuArrow = this._settings.get_boolean('remove-menu-arrow'); + this.disableSearchStyle = this._settings.get_boolean('disable-searchbox-border'); + this.alphabetizeAllPrograms = this._settings.get_boolean('alphabetize-all-programs') + this.multiLinedLabels = this._settings.get_boolean('multi-lined-labels'); + this.disableTooltips = this._settings.get_boolean('disable-tooltips'); + this.subMenus = this._settings.get_boolean('enable-sub-menus'); + this.showHiddenRecentFiles = this._settings.get_boolean('show-hidden-recent-files'); + + let searchStyleFrame = new PW.FrameBox(); + let searchStyleRow = new PW.FrameBoxRow(); + let searchStyleLabel = new Gtk.Label({ + label: _("Disable Searchbox Border"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let searchStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + searchStyleSwitch.set_active(this._settings.get_boolean('disable-searchbox-border')); + searchStyleSwitch.connect('notify::active', (widget) => { + this.disableSearchStyle = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + searchStyleRow.add(searchStyleLabel); + searchStyleRow.add(searchStyleSwitch); + searchStyleFrame.add(searchStyleRow); + this.mainBox.append(searchStyleFrame); + + let tweakStyleFrame = new PW.FrameBox(); + let tweakStyleRow = new PW.FrameBoxRow(); + let tweakStyleLabel = new Gtk.Label({ + label: _("Disable Menu Arrow"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let tweakStyleSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tweakStyleSwitch.set_active(this._settings.get_boolean('remove-menu-arrow')); + tweakStyleSwitch.connect('notify::active', (widget) => { + this.removeMenuArrow = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tweakStyleRow.add(tweakStyleLabel); + tweakStyleRow.add(tweakStyleSwitch); + tweakStyleFrame.add(tweakStyleRow); + this.mainBox.append(tweakStyleFrame); + + let fadeEffectFrame = new PW.FrameBox(); + let fadeEffectRow = new PW.FrameBoxRow(); + let fadeEffectLabel = new Gtk.Label({ + label: _("Disable ScrollView Fade Effects"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let fadeEffectSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + fadeEffectSwitch.set_active(this._settings.get_boolean('disable-scrollview-fade-effect')); + fadeEffectSwitch.connect('notify::active', (widget) => { + this.disableFadeEffect = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + fadeEffectRow.add(fadeEffectLabel); + fadeEffectRow.add(fadeEffectSwitch); + fadeEffectFrame.add(fadeEffectRow); + this.mainBox.append(fadeEffectFrame); + + let tooltipFrame = new PW.FrameBox(); + let tooltipRow = new PW.FrameBoxRow(); + let tooltipLabel = new Gtk.Label({ + label: _("Disable Tooltips"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let tooltipSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + tooltipSwitch.set_active(this.disableTooltips); + tooltipSwitch.connect('notify::active', (widget) => { + this.disableTooltips = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + tooltipRow.add(tooltipLabel); + tooltipRow.add(tooltipSwitch); + tooltipFrame.add(tooltipRow); + this.mainBox.append(tooltipFrame); + + let alphabetizeAllProgramsFrame = new PW.FrameBox(); + let alphabetizeAllProgramsRow = new PW.FrameBoxRow(); + let alphabetizeAllProgramsLabel = new Gtk.Label({ + label: _("Alphabetize 'All Programs' Category"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let alphabetizeAllProgramsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + alphabetizeAllProgramsSwitch.set_active(this._settings.get_boolean('alphabetize-all-programs')); + alphabetizeAllProgramsSwitch.connect('notify::active', (widget) => { + this.alphabetizeAllPrograms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsLabel); + alphabetizeAllProgramsRow.add(alphabetizeAllProgramsSwitch); + alphabetizeAllProgramsFrame.add(alphabetizeAllProgramsRow); + this.mainBox.append(alphabetizeAllProgramsFrame); + + let subMenusFrame = new PW.FrameBox(); + let subMenusRow = new PW.FrameBoxRow(); + let subMenusLabel = new Gtk.Label({ + label: _('Category Sub Menus'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let subMenusSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + subMenusSwitch.set_active(this.subMenus); + subMenusSwitch.connect('notify::active', (widget) => { + this.subMenus = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + subMenusRow.add(subMenusLabel); + subMenusRow.add(subMenusSwitch); + subMenusFrame.add(subMenusRow); + this.mainBox.append(subMenusFrame); + + let hiddenFilesFrame = new PW.FrameBox(); + let hiddenFilesRow = new PW.FrameBoxRow(); + let hiddenFilesLabel = new Gtk.Label({ + label: _('Show Hidden Recent Files'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let hiddenFilesSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + hiddenFilesSwitch.connect('notify::active', (widget) => { + this.showHiddenRecentFiles = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + hiddenFilesRow.add(hiddenFilesLabel); + hiddenFilesRow.add(hiddenFilesSwitch); + hiddenFilesFrame.add(hiddenFilesRow); + this.mainBox.append(hiddenFilesFrame); + + let multiLinedLabelFrame = new PW.FrameBox(); + let multiLinedLabelRow = new PW.FrameBoxRow(); + let multiLinedLabelLabel = new Gtk.Label({ + label: _("Multi-Lined Labels"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let multiLinedLabelSwitch = new Gtk.Switch({ halign: Gtk.Align.END, vexpand: false, valign: Gtk.Align.CENTER }); + multiLinedLabelSwitch.set_active(this._settings.get_boolean('multi-lined-labels')); + multiLinedLabelSwitch.connect('notify::active', (widget) => { + this.multiLinedLabels = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + let multiLinedLabelInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + multiLinedLabelInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Multi-Lined Labels"), + secondaryText: _('Enable/Disable multi-lined labels on large application icon layouts.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + multiLinedLabelRow.add(multiLinedLabelLabel); + multiLinedLabelRow.add(multiLinedLabelSwitch); + multiLinedLabelRow.add(multiLinedLabelInfoButton); + multiLinedLabelFrame.add(multiLinedLabelRow); + this.mainBox.append(multiLinedLabelFrame); + + let gapAdjustmentFrame = new PW.FrameBox(); + let gapAdjustmentRow = new PW.FrameBoxRow(); + let gapAdjustmentLabel = new Gtk.Label({ + label: _('Gap Adjustment'), + xalign:0, + hexpand: false, + }); + let gapAdjustmentScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: -1, upper: 20, step_increment: 1, page_increment: 1, page_size: 0 + }), + digits: 0,round_digits: 0,hexpand: true, + value_pos: Gtk.PositionType.RIGHT, + draw_value: true, + }); + gapAdjustmentScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + gapAdjustmentScale.set_value(this.gapAdjustment); + gapAdjustmentScale.connect('value-changed', () => { + this.gapAdjustment = gapAdjustmentScale.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + let gapAdjustmentInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + gapAdjustmentInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Adjust the gap between the ArcMenu button and the menu."), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + gapAdjustmentRow.add(gapAdjustmentLabel); + gapAdjustmentRow.add(gapAdjustmentScale); + gapAdjustmentRow.add(gapAdjustmentInfoButton); + gapAdjustmentFrame.add(gapAdjustmentRow); + this.mainBox.append(gapAdjustmentFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.gapAdjustment = this._settings.get_default_value('gap-adjustment').unpack(); + this.removeMenuArrow = this._settings.get_default_value('remove-menu-arrow').unpack(); + this.disableSearchStyle = this._settings.get_default_value('disable-searchbox-border').unpack(); + this.alphabetizeAllPrograms = this._settings.get_default_value('alphabetize-all-programs').unpack(); + this.multiLinedLabels = this._settings.get_default_value('multi-lined-labels').unpack(); + this.subMenus = this._settings.get_default_value('enable-sub-menus').unpack(); + this.showHiddenRecentFiles = this._settings.get_default_value('show-hidden-recent-files').unpack(); + this.disableTooltips = this._settings.get_default_value('disable-tooltips').unpack(); + this.disableFadeEffect = this._settings.get_default_value('disable-scrollview-fade-effect').unpack(); + alphabetizeAllProgramsSwitch.set_active(this.alphabetizeAllPrograms); + gapAdjustmentScale.set_value(this.gapAdjustment); + searchStyleSwitch.set_active(this.disableSearchStyle); + tweakStyleSwitch.set_active(this.removeMenuArrow); + multiLinedLabelSwitch.set_active(this.multiLinedLabels); + tooltipSwitch.set_active(this.disableTooltips); + subMenusSwitch.set_active(this.subMenus); + hiddenFilesSwitch.set_active(this.showHiddenRecentFiles); + fadeEffectSwitch.set_active(this.disableFadeEffect); + + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_int('gap-adjustment', this.gapAdjustment); + this._settings.set_boolean('remove-menu-arrow', this.removeMenuArrow); + this._settings.set_boolean('disable-searchbox-border', this.disableSearchStyle); + this._settings.set_boolean('alphabetize-all-programs', this.alphabetizeAllPrograms); + this._settings.set_boolean('multi-lined-labels', this.multiLinedLabels); + this._settings.set_boolean('disable-scrollview-fade-effect', this.disableFadeEffect); + this._settings.set_boolean('disable-tooltips', this.disableTooltips); + this._settings.set_boolean('enable-sub-menus', this.subMenus); + this._settings.set_boolean('show-hidden-recent-files', this.showHiddenRecentFiles); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.subMenus !== this._settings.get_default_value('enable-sub-menus').unpack() || + this.disableTooltips !== this._settings.get_default_value('disable-tooltips').unpack() || + this.gapAdjustment !== this._settings.get_default_value('gap-adjustment').unpack() || + this.removeMenuArrow !== this._settings.get_default_value('remove-menu-arrow').unpack() || + this.disableSearchStyle !== this._settings.get_default_value('disable-searchbox-border').unpack()|| + this.alphabetizeAllPrograms !== this._settings.get_default_value('alphabetize-all-programs').unpack()|| + this.multiLinedLabels !== this._settings.get_default_value('multi-lined-labels').unpack() || + this.disableFadeEffect !== this._settings.get_default_value('disable-scrollview-fade-effect').unpack() || + this.showHiddenRecentFiles !== this._settings.get_default_value('show-hidden-recent-files').unpack()) ? true : false; + } +}); + +var MenuSettingsNewAppsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsNewAppsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.disableRecentApps = this._settings.get_boolean('disable-recently-installed-apps'); + this.indicatorColor = this._settings.get_string('indicator-color'); + this.indicatorTextColor = this._settings.get_string('indicator-text-color'); + + let recentAppsFrame = new PW.FrameBox(); + let recentAppsRow = new PW.FrameBoxRow(); + let recentAppsLabel = new Gtk.Label({ + label: _("Disable New Apps Tracker"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentAppsSwitch = new Gtk.Switch({ + halign: Gtk.Align.END, + }); + + recentAppsSwitch.connect('notify::active', (widget) => { + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + this.disableRecentApps = widget.get_active(); + + if(widget.get_active()){ + appIndicatorColorFrame.hide(); + recentlyInstalledInfoLabel.hide(); + clearRecentAppsFrame.hide(); + } + else{ + appIndicatorColorFrame.show(); + recentlyInstalledInfoLabel.show(); + clearRecentAppsFrame.show(); + this.mainBox.show(); + } + this._settings.set_boolean('disable-recently-installed-apps', widget.get_active()); + }); + + recentAppsSwitch.set_active(this._settings.get_boolean('disable-recently-installed-apps')); + + recentAppsRow.add(recentAppsLabel); + recentAppsRow.add(recentAppsSwitch); + recentAppsFrame.add(recentAppsRow); + this.mainBox.append(recentAppsFrame); + + let appIndicatorColorFrame = new PW.FrameBox(); + let recentlyInstalledInfoLabel = new Gtk.Label({ + label: "" + _("Customize New Apps Indicator") + "", + use_markup: true, + xalign: 0, + hexpand: true, + }); + this.mainBox.append(recentlyInstalledInfoLabel); + let appIndicatorColorRow = new PW.FrameBoxRow(); + let appIndicatorColorLabel = new Gtk.Label({ + label: _('Category Indicator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + appIndicatorColorChooser.connect('color-set', ()=>{ + this.indicatorColor = appIndicatorColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorColorRow.add(appIndicatorColorLabel); + appIndicatorColorRow.add(appIndicatorColorChooser); + appIndicatorColorFrame.add(appIndicatorColorRow); + + let appIndicatorTextColorRow = new PW.FrameBoxRow(); + let appIndicatorTextColorLabel = new Gtk.Label({ + label: _('App Indicator Label Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let appIndicatorTextColorChooser = new Gtk.ColorButton({ + use_alpha: true, + }); + color = new Gdk.RGBA(); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + appIndicatorTextColorChooser.connect('color-set', ()=>{ + this.indicatorTextColor = appIndicatorTextColorChooser.get_rgba().to_string(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + appIndicatorTextColorRow.add(appIndicatorTextColorLabel); + appIndicatorTextColorRow.add(appIndicatorTextColorChooser); + appIndicatorColorFrame.add(appIndicatorTextColorRow); + this.mainBox.append(appIndicatorColorFrame); + + let clearRecentAppsFrame = new PW.FrameBox(); + let clearRecentAppsRow = new PW.FrameBoxRow(); + let clearRecentAppsLabel = new Gtk.Label({ + label: _("Clear Apps Marked 'New'"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let clearRecentAppsButton = new Gtk.Button({ + halign: Gtk.Align.END, + label: _("Clear All"), + }); + let sensitive = this._settings.get_strv('recently-installed-apps').length > 0; + clearRecentAppsButton.set_sensitive(sensitive); + clearRecentAppsButton.connect('clicked', (widget) => { + clearRecentAppsButton.set_sensitive(false); + this._settings.reset('recently-installed-apps'); + }); + clearRecentAppsRow.add(clearRecentAppsLabel); + clearRecentAppsRow.add(clearRecentAppsButton); + clearRecentAppsFrame.add(clearRecentAppsRow); + this.mainBox.append(clearRecentAppsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.disableRecentApps = this._settings.get_default_value('disable-recently-installed-apps').unpack(); + this.indicatorColor = this._settings.get_default_value('indicator-color').unpack(); + this.indicatorTextColor = this._settings.get_default_value('indicator-text-color').unpack(); + recentAppsSwitch.set_active(this.disableRecentApps); + let color = new Gdk.RGBA(); + color.parse(this.indicatorColor); + appIndicatorColorChooser.set_rgba(color); + color.parse(this.indicatorTextColor); + appIndicatorTextColorChooser.set_rgba(color); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('disable-recently-installed-apps', this.disableRecentApps); + this._settings.set_string('indicator-color', this.indicatorColor); + this._settings.set_string('indicator-text-color', this.indicatorTextColor); + this._settings.set_boolean('reload-theme', true); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.disableRecentApps !== this._settings.get_default_value('disable-recently-installed-apps').unpack() || + this.indicatorColor !== this._settings.get_default_value('indicator-color').unpack() || + this.indicatorTextColor !== this._settings.get_default_value('indicator-text-color').unpack() + ) ? true : false; + } +}); + +var MenuSettingsSearchOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsSearchOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.searchResultsDetails = this._settings.get_boolean('show-search-result-details'); + this.openWindowsSearchProvider = this._settings.get_boolean('search-provider-open-windows'); + this.recentFilesSearchProvider = this._settings.get_boolean('search-provider-recent-files'); + this.highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + this.maxSearchResults = this._settings.get_int('max-search-results'); + + let searchProvidersFrame = new PW.FrameBox(); + let searchProvidersLabel = new Gtk.Label({ + label: "" + _("Search Providers") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchProvidersLabel); + let openWindowsRow = new PW.FrameBoxRow(); + let openWindowsLabel = new Gtk.Label({ + label: _("Search for open windows across all workspaces"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let openWindowsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + openWindowsSwitch.connect('notify::active', (widget) => { + this.openWindowsSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + openWindowsRow.add(openWindowsLabel); + openWindowsRow.add(openWindowsSwitch); + searchProvidersFrame.add(openWindowsRow); + + let recentFilesRow = new PW.FrameBoxRow(); + let recentFilesLabel = new Gtk.Label({ + label: _("Search for recent files"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let recentFilesSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + recentFilesSwitch.connect('notify::active', (widget) => { + this.recentFilesSearchProvider = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + recentFilesRow.add(recentFilesLabel); + recentFilesRow.add(recentFilesSwitch); + searchProvidersFrame.add(recentFilesRow); + this.mainBox.append(searchProvidersFrame); + + let searchOptionsFrame = new PW.FrameBox(); + let searchOptionsLabel = new Gtk.Label({ + label: "" + _("Search Options") + "", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(searchOptionsLabel); + let descriptionsRow = new PW.FrameBoxRow(); + let descriptionsLabel = new Gtk.Label({ + label: _("Show descriptions of search results"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let descriptionsSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + descriptionsSwitch.set_active(this.searchResultsDetails); + descriptionsSwitch.connect('notify::active', (widget) => { + this.searchResultsDetails = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + descriptionsRow.add(descriptionsLabel); + descriptionsRow.add(descriptionsSwitch); + searchOptionsFrame.add(descriptionsRow); + + let highlightSearchResultRow = new PW.FrameBoxRow(); + let highlightSearchResultLabel = new Gtk.Label({ + label: _("Highlight search result terms"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let highlightSearchResultSwitch = new Gtk.Switch({ halign: Gtk.Align.END }); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + highlightSearchResultSwitch.connect('notify::active', (widget) => { + this.highlightSearchResultTerms = widget.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + highlightSearchResultRow.add(highlightSearchResultLabel); + highlightSearchResultRow.add(highlightSearchResultSwitch); + searchOptionsFrame.add(highlightSearchResultRow); + + let maxSearchResultsRow = new PW.FrameBoxRow(); + let maxSearchResultsLabel = new Gtk.Label({ + label: _('Max Search Results'), + use_markup: true, + xalign: 0, + hexpand: true + }); + let maxSearchResultsScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ + lower: 2, + upper: 10, + step_increment: 1, + page_increment: 1, + page_size: 0 + }), + digits: 0, + round_digits: 0, + hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + maxSearchResultsScale.set_value(this.maxSearchResults); + maxSearchResultsScale.connect('value-changed', (widget) => { + this.maxSearchResults = widget.get_value(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + + maxSearchResultsRow.add(maxSearchResultsLabel); + maxSearchResultsRow.add(maxSearchResultsScale); + searchOptionsFrame.add( maxSearchResultsRow); + this.mainBox.append(searchOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + this.resetButton.connect('clicked', ()=> { + this.searchResultsDetails = this._settings.get_default_value('show-search-result-details').unpack(); + this.openWindowsSearchProvider = this._settings.get_default_value('search-provider-open-windows').unpack(); + this.recentFilesSearchProvider = this._settings.get_default_value('search-provider-recent-files').unpack(); + this.highlightSearchResultTerms = this._settings.get_default_value('highlight-search-result-terms').unpack(); + this.maxSearchResults = this._settings.get_default_value('max-search-results').unpack(); + descriptionsSwitch.set_active(this.searchResultsDetails); + openWindowsSwitch.set_active(this.openWindowsSearchProvider); + highlightSearchResultSwitch.set_active(this.highlightSearchResultTerms); + maxSearchResultsScale.set_value(this.maxSearchResults); + recentFilesSwitch.set_active(this.recentFilesSearchProvider); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(false); + }); + + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + this.saveButton.connect('clicked', ()=> { + this._settings.set_boolean('show-search-result-details', this.searchResultsDetails); + this._settings.set_boolean('search-provider-open-windows', this.openWindowsSearchProvider); + this._settings.set_boolean('search-provider-recent-files', this.recentFilesSearchProvider); + this._settings.set_boolean('highlight-search-result-terms', this.highlightSearchResultTerms); + this._settings.set_int('max-search-results', this.maxSearchResults); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + checkIfResetButtonSensitive(){ + return ( + this.searchResultsDetails !== this._settings.get_default_value('show-search-result-details').unpack() || + this.openWindowsSearchProvider !== this._settings.get_default_value('search-provider-open-windows').unpack() || + this.recentFilesSearchProvider !== this._settings.get_default_value('search-provider-recent-files').unpack() || + this.highlightSearchResultTerms !== this._settings.get_default_value('highlight-search-result-terms').unpack() || + this.maxSearchResults !== this._settings.get_default_value('max-search-results').unpack()) ? true : false; + } +}); + +var MenuSettingsCategoriesPage = GObject.registerClass( + class Arc_Menu_MenuSettingsCategoriesPage extends Gtk.Box { + _init(settings, settingType) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.settingType = settingType; + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.categoriesFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value(this.settingType).deep_unpack()); + this.mainBox.append(this.categoriesFrame); + + this.buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.categoriesFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value(this.settingType).deep_unpack()); + this.categoriesFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.categoriesFrame.count; i++) { + let frame = this.categoriesFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value(this.settingType, new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + this.buttonRow.append(this.resetButton); + this.buttonRow.append(this.saveButton); + this.append(this.buttonRow); + } + + getSensitive(){ + let defaultExtraCategories = this._settings.get_default_value(this.settingType).deep_unpack(); + let currentExtraCategories = this._settings.get_value(this.settingType).deep_unpack(); + return !Utils.getArraysEqual(defaultExtraCategories, currentExtraCategories); + } + + _createFrame(extraCategories){ + for(let i = 0; i < extraCategories.length; i++){ + let categoryEnum = extraCategories[i][0]; + let name = Constants.Categories[categoryEnum].NAME; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = extraCategories[i][0]; + frameRow._shouldShow = extraCategories[i][1]; + frameRow._name = Constants.Categories[categoryEnum].NAME; + frameRow._gicon = Gio.icon_new_for_string(Constants.Categories[categoryEnum].ICON); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.categoriesFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + this.categoriesFrame.add(frameRow); + } + } +}); + +var ColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent, themeName="") { + this._settings = settings; + this.addResponse = false; + this.themeName = themeName; + super._init(_('Color Theme Name'), parent); + } + + _createLayout(vbox) { + let nameFrameRow = new PW.FrameBoxRow(); + let nameFrameLabel = new Gtk.Label({ + label: _('Name:'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + nameFrameRow.add(nameFrameLabel); + this.nameEntry = new Gtk.Entry(); + this.nameEntry.set_width_chars(35); + + nameFrameRow.add(this.nameEntry); + this.nameEntry.grab_focus(); + if(this.themeName!=""){ + this.nameEntry.set_text(this.themeName); + } + this.nameEntry.connect('changed',()=>{ + if(this.nameEntry.get_text().length > 0) + saveButton.set_sensitive(true); + else + saveButton.set_sensitive(false); + }); + + vbox.append(nameFrameRow); + let saveButton = new Gtk.Button({ + label: _("Save Theme"), + halign: Gtk.Align.END + }); + saveButton.set_sensitive(false); + saveButton.connect('clicked', ()=> { + this.themeName = this.nameEntry.get_text(); + this.addResponse=true; + this.response(-10); + }); + vbox.append(saveButton); + } + get_response(){ + return this.addResponse; + } +}); + +var ExportColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ExportColorThemeDialogWindow extends PW.DialogWindow { + + _init(settings, parent, themes=null) { + this._settings = settings; + this._themes = themes; + this.addResponse = false; + this.selectedThemes = []; + super._init(this._themes ? _('Select Themes to Import'): _('Select Themes to Export'), parent); + } + + _createLayout(vbox) { + vbox.spacing = 0; + this.checkButtonArray = []; + this.shouldToggle =true; + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + + let themesListButton = new Gtk.Button({ + label: this._themes ?_("Import"): _("Export"), + }); + + themesListButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + themesListButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + this.checkAllButton = new Gtk.CheckButton({ + margin_end: 23 + }); + + this.checkAllButton.set_halign(Gtk.Align.END); + this.checkAllButton.set_active(true); + this.checkAllButton.connect('toggled', () => { + let isActive = this.checkAllButton.get_active(); + if(this.shouldToggle){ + for(let i = 0; i< this.checkButtonArray.length; i++){ + this.checkButtonArray[i].set_active(isActive); + } + } + }); + let checkAllRow = new PW.FrameBoxRow(); + let checkAllLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + hexpand: true, + label: _("Select All"), + halign: Gtk.Align.END + }); + checkAllRow.add(checkAllLabel); + checkAllRow.add(this.checkAllButton); + vbox.append(checkAllRow); + vbox.append(themesListScrollWindow); + vbox.append(new PW.FrameBoxRow()); + vbox.append(themesListButton); + + this.color_themes = this._themes ? this._themes : this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let checkButton = new Gtk.CheckButton({ + margin_end: 20 + }); + checkButton.connect('toggled', () => { + if(checkButton.get_active()){ + this.selectedThemes.push(theme); + } + else{ + this.shouldToggle = false; + this.checkAllButton.set_active(false); + this.shouldToggle = true; + let index= this.selectedThemes.indexOf(theme); + this.selectedThemes.splice(index,1); + } + }); + this.checkButtonArray.push(checkButton); + frameRow.add(checkButton); + this.mainFrame.add(frameRow); + checkButton.set_active(true); + } + } + get_response(){ + return this.addResponse; + } +}); + +var ManageColorThemeDialogWindow = GObject.registerClass( + class Arc_Menu_ManageColorThemeDialogWindow extends PW.DialogWindow { + _init(settings, parent) { + this._settings = settings; + this.addResponse = false; + this.selectedThemes = []; + super._init( _('Manage Presets'), parent); + } + + _createLayout(vbox) { + let themesListScrollWindow = new Gtk.ScrolledWindow(); + themesListScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themesListScrollWindow.set_max_content_height(300); + themesListScrollWindow.set_min_content_height(300); + themesListScrollWindow.set_min_content_width(500); + themesListScrollWindow.set_min_content_width(500); + this.mainFrame = new PW.FrameBox(); + let buttonRow = new PW.FrameBoxRow(); + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + applyButton.set_sensitive(false); + applyButton.connect('clicked', () => { + this.addResponse = true; + this.response(-10); + }); + applyButton.set_halign(Gtk.Align.END); + + themesListScrollWindow.set_child(this.mainFrame); + vbox.append(themesListScrollWindow); + buttonRow.add(applyButton); + vbox.append(buttonRow); + + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i< this.color_themes.length; i++) { + let theme = this.color_themes[i]; + let frameRow = new PW.FrameBoxRow(); + let themeBox = new Gtk.Box(); + + let frameLabel = new Gtk.Label({ + use_markup: false, + xalign: 0, + label: theme[0], + hexpand: true + }); + let xpm = Utils.createXpmImage(theme[1], theme[2], theme[4], theme[5]); + let presetPreview = new Gtk.Image({ + hexpand: false, + margin_end: 5, + pixel_size: 42 + }); + presetPreview.set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_xpm_data(xpm)); + + themeBox.append(presetPreview); + themeBox.append(frameLabel); + frameRow.add(themeBox); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.mainFrame, + buttons: [applyButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', () => { + let dialog = new ColorThemeDialogWindow(this._settings, this, theme[0]); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()) { + let index = frameRow.get_index(); + let array = [dialog.themeName, theme[1], theme[2], theme[3], theme[4], theme[5], + theme[6], theme[7], theme[8], theme[9], theme[10], theme[11], theme[12]]; + this.color_themes.splice(index,1,array); + theme = array; + frameLabel.label = dialog.themeName; + dialog.destroy(); + } + else + dialog.destroy(); + }); + applyButton.set_sensitive(true); + }); + buttonBox.connect('move-up', () => { + let index = frameRow.get_index(); + if(index > 0){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index - 1, 0, theme); + } + }); + + buttonBox.connect('move-down', () => { + let index = frameRow.get_index(); + if(index + 1 < this.mainFrame.count){ + this.color_themes.splice(index, 1); + this.color_themes.splice(index + 1, 0, theme); + } + }); + + buttonBox.connect('delete', () => { + let index = frameRow.get_index(); + this.color_themes.splice(index, 1); + }); + + frameRow.add(buttonBox); + this.mainFrame.add(frameRow); + } + } + get_response(){ + return this.addResponse; + } +}); + +var OverrideArcMenuThemeWindow = GObject.registerClass({ + Signals: { + 'menu-theme-response': { param_types: [GObject.TYPE_INT] }, + }, +}, + class Arc_Menu_OverrideArcMenuThemeWindow extends Gtk.Box { + _init(settings, parentBox, parentMainBox) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + }); + this.parentBox = parentBox; + this._parentMainBox = parentMainBox; + this._settings = settings; + this.addResponse = false; + this.heightValue = this._settings.get_int('menu-height'); + this.rightPanelWidth = this._settings.get_int('right-panel-width'); + this.separatorColor = this._settings.get_string('separator-color'); + this.verticalSeparator = this._settings.get_boolean('vert-separator'); + this.customArcMenu = this._settings.get_boolean('enable-custom-arc-menu'); + + this.menuColor = this._settings.get_string('menu-color'); + this.menuForegroundColor = this._settings.get_string('menu-foreground-color'); + this.borderColor = this._settings.get_string('border-color'); + this.highlightColor = this._settings.get_string('highlight-color'); + this.highlightForegroundColor = this._settings.get_string('highlight-foreground-color'); + this.fontSize = this._settings.get_int('menu-font-size'); + this.borderSize = this._settings.get_int('menu-border-size'); + this.cornerRadius = this._settings.get_int('menu-corner-radius'); + this.menuMargin = this._settings.get_int('menu-margin'); + this.menuArrowSize = this._settings.get_int('menu-arrow-size'); + this.menuWidth = this._settings.get_int('menu-width'); + this.updatePresetComboBox = true; + this.shouldDeselect = true; + this._createLayout(this); + } + createIconList(store){ + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i= 0; i" + _('Menu Theme Presets') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(colorPresetHeaderLabel); + + this.colorPresetFrame = new PW.FrameBox(); + let colorPresetRow = new PW.FrameBoxRow(); + let colorPresetLabel = new Gtk.Label({ + label: _('Current Menu Theme Preset'), + xalign:0, + hexpand: true, + }); + let store = new Gtk.ListStore(); + store.set_column_types([GdkPixbuf.Pixbuf, GObject.TYPE_STRING]); + this.colorPresetCombo = new Gtk.ComboBox({ + model: store, + }); + + this.createIconList(store); + + let renderer = new Gtk.CellRendererPixbuf({xpad: 5}); + this.colorPresetCombo.pack_start(renderer, false); + this.colorPresetCombo.add_attribute(renderer, "pixbuf", 0); + renderer = new Gtk.CellRendererText(); + this.colorPresetCombo.pack_start(renderer, true); + this.colorPresetCombo.add_attribute(renderer, "text", 1); + + this.saveButton = new Gtk.Button({ + label: _("Save as Preset"), + hexpand: true, + halign: Gtk.Align.END + }); + this.checkIfPresetMatch(); + this.colorPresetCombo.connect('changed', (widget) => { + if(this.updatePresetComboBox){ + let index = widget.get_active(); + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Hightlight Foreground Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + if(index>=0){ + this.menuColor = this.color_themes[index][1]; + this.menuForegroundColor = this.color_themes[index][2]; + this.borderColor = this.color_themes[index][3]; + this.highlightColor = this.color_themes[index][4]; + this.highlightForegroundColor = this.color_themes[index][5]; + this.separatorColor = this.color_themes[index][6]; + this.fontSize = parseInt(this.color_themes[index][7]); + this.borderSize = parseInt(this.color_themes[index][8]); + this.cornerRadius = parseInt(this.color_themes[index][9]); + this.menuArrowSize = parseInt(this.color_themes[index][10]); + this.menuMargin = parseInt(this.color_themes[index][11]); + this.verticalSeparator = (this.color_themes[index][12] === 'true'); + + this.shouldDeselect = false; + this.presetName=this.color_themes[index][0]; + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + this.saveButton.set_sensitive(false); + applyButton.set_sensitive(true); + this.shouldDeselect = true; + resetButton.set_sensitive(this.checkIfResetButtonSensitive()); + } + } + }); + colorPresetRow.add(colorPresetLabel); + colorPresetRow.add(this.colorPresetCombo); + this.colorPresetFrame.add(colorPresetRow); + + let presetsButtonRow = new PW.FrameBoxRow(); + + this.saveButton.connect('clicked', () => { + /*let defaultArray = ["Theme Name","Background Color", "Foreground Color","Border Color", "Highlight Color", "Separator Color" + , "Font Size", "Border Size", "Corner Radius", "Arrow Size", "Menu Displacement", "Vertical Separator"];*/ + let dialog = new ColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let array = [dialog.themeName, this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + this.color_themes.push(array); + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + let manageButton = new Gtk.Button({ + label: _("Manage Presets") + }); + manageButton.connect('clicked', ()=> { + let dialog = new ManageColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response)=>{ + if(dialog.get_response()){ + this.color_themes = dialog.color_themes; + this._settings.set_value('color-themes',new GLib.Variant('aas',dialog.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + let addButton = new PW.Button({ + title: _("Browse Presets"), + icon_name: "browse-presets-symbolic", + hexpand: false + }); + addButton.connect('clicked', () => { + let settingsFile = Gio.File.new_for_path(Me.path + '/media/misc/ArcMenuDefaultPresets'); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + let colorThemes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + colorThemes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, colorThemes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + dialog.destroy(); + } + else + dialog.destroy(); + }); + }); + + presetsButtonRow.add(manageButton); + presetsButtonRow.add(addButton); + presetsButtonRow.add(this.saveButton); + this.colorPresetFrame.add(presetsButtonRow); + vbox.append(this.colorPresetFrame); + + this._settings.connect("changed::color-themes", () => { + store.clear(); + this.createIconList(store); + this.colorPresetCombo.model = store; + this.colorPresetCombo.show(); + + this.checkIfPresetMatch(); + }); + + let menuSettingsHeaderLabel = new Gtk.Label({ + label: "" + _('Theme Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + vbox.append(menuSettingsHeaderLabel); + + let themeSettingsFrame = new PW.FrameBox(); + let themeSettingsFrameScrollWindow = new Gtk.ScrolledWindow({ + vexpand: true, + valign: Gtk.Align.FILL + }); + themeSettingsFrameScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + themeSettingsFrameScrollWindow.set_min_content_height(250); + themeSettingsFrameScrollWindow.set_child(themeSettingsFrame); + vbox.append(themeSettingsFrameScrollWindow); + + //ROW 1 - MENU BACKGROUND COLOR-------------------------------------- + let menuBackgroudColorRow = new PW.FrameBoxRow(); + let menuBackgroudColorLabel = new Gtk.Label({ + label: _('Menu Background Color'), + xalign:0, + hexpand: true, + }); + let menuBackgroudColorChooser = new Gtk.ColorButton({use_alpha:true}); + let color = new Gdk.RGBA(); + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + menuBackgroudColorChooser.connect('color-set', () => { + this.menuColor = menuBackgroudColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuBackgroudColorRow.add(menuBackgroudColorLabel); + menuBackgroudColorRow.add(menuBackgroudColorChooser); + themeSettingsFrame.add(menuBackgroudColorRow); + + //ROW 2 - MENU FOREGROUND COLOR-------------------------------------- + let menuForegroundColorRow = new PW.FrameBoxRow(); + let menuForegroundColorLabel = new Gtk.Label({ + label: _('Menu Foreground Color'), + xalign:0, + hexpand: true, + }); + let menuForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + menuForegroundColorChooser.connect('color-set', () => { + this.menuForegroundColor = menuForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuForegroundColorRow.add(menuForegroundColorLabel); + menuForegroundColorRow.add(menuForegroundColorChooser); + themeSettingsFrame.add(menuForegroundColorRow); + + //ROW 3 - FONT SIZE-------------------------------------------------- + let fontSizeRow = new PW.FrameBoxRow(); + let fontSizeLabel = new Gtk.Label({ + label: _('Font Size'), + xalign:0, + hexpand: true, + }); + + let fontScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 8, upper: 14, step_increment: 1, page_increment: 1, page_size: 0 }), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + fontScale.set_format_value_func( (scale, value) => { + return value + "pt"; + }); + fontScale.set_value(this.fontSize); + fontScale.connect('value-changed', () => { + this.fontSize = fontScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + fontSizeRow.add(fontSizeLabel); + fontSizeRow.add(fontScale); + themeSettingsFrame.add(fontSizeRow); + + //ROW 4- Border Color------------------------------------------------- + let borderColorRow = new PW.FrameBoxRow(); + let borderColorLabel = new Gtk.Label({ + label: _('Border Color'), + xalign:0, + hexpand: true, + }); + let borderColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + borderColorChooser.connect('color-set', ()=>{ + this.borderColor = borderColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderColorRow.add(borderColorLabel); + borderColorRow.add(borderColorChooser); + themeSettingsFrame.add(borderColorRow); + + //ROW 5 - Border Size------------------------------------------------------- + let borderSizeRow = new PW.FrameBoxRow(); + let borderSizeLabel = new Gtk.Label({ + label: _('Border Size'), + xalign:0, + hexpand: true, + }); + let borderScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({lower: 0, upper: 4, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + borderScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + borderScale.set_value(this.borderSize); + borderScale.connect('value-changed', () => { + this.borderSize = borderScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + borderSizeRow.add(borderSizeLabel); + borderSizeRow.add(borderScale); + themeSettingsFrame.add(borderSizeRow); + + //ROW 6 - Active Item Background Color----------------------------------------------- + let itemColorRow = new PW.FrameBoxRow(); + let itemColorLabel = new Gtk.Label({ + label: _('Active Item Background Color'), + xalign:0, + hexpand: true, + }); + let itemColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + itemColorChooser.connect('color-set', () => { + this.highlightColor = itemColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemColorRow.add(itemColorLabel); + itemColorRow.add(itemColorChooser); + themeSettingsFrame.add(itemColorRow); + + //ROW 7 - Active Item Foreground Color----------------------------------------------- + let itemForegroundColorRow = new PW.FrameBoxRow(); + let itemForegroundColorLabel = new Gtk.Label({ + label: _('Active Item Foreground Color'), + xalign:0, + hexpand: true, + }); + let itemForegroundColorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + itemForegroundColorChooser.connect('color-set', () => { + this.highlightForegroundColor = itemForegroundColorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + itemForegroundColorRow.add(itemForegroundColorLabel); + itemForegroundColorRow.add(itemForegroundColorChooser); + themeSettingsFrame.add(itemForegroundColorRow); + + //ROW 8 - Corner Radius----------------------------------------------------- + let cornerRadiusRow = new PW.FrameBoxRow(); + let cornerRadiusLabel = new Gtk.Label({ + label: _('Corner Radius'), + xalign:0, + hexpand: true, + }); + let cornerScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + cornerScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + cornerScale.set_value(this.cornerRadius); + cornerScale.connect('value-changed', () => { + this.cornerRadius = cornerScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + cornerRadiusRow.add(cornerRadiusLabel); + cornerRadiusRow.add(cornerScale); + themeSettingsFrame.add(cornerRadiusRow); + + //ROW 9 - Menu Arrow Size------------------------------------------------------- + let menuMarginRow = new PW.FrameBoxRow(); + let menuMarginLabel = new Gtk.Label({ + label: _('Menu Arrow Size'), + xalign:0, + hexpand: true, + }); + let marginScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 30, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + marginScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + marginScale.set_value(this.menuMargin); + marginScale.connect('value-changed', () => { + this.menuMargin = marginScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuMarginRow.add(menuMarginLabel); + menuMarginRow.add(marginScale); + themeSettingsFrame.add(menuMarginRow); + + //ROW 10 - Menu Displacement------------------------------------------------------ + let menuArrowRow = new PW.FrameBoxRow(); + let menuArrowLabel = new Gtk.Label({ + label: _('Menu Displacement'), + xalign:0, + hexpand: true, + }); + let arrowScale = new Gtk.Scale({ + orientation: Gtk.Orientation.HORIZONTAL, + adjustment: new Gtk.Adjustment({ lower: 0,upper: 20, step_increment: 1, page_increment: 1, page_size: 0}), + digits: 0, round_digits: 0, hexpand: true, + draw_value: true, + value_pos: Gtk.PositionType.RIGHT + }); + arrowScale.set_format_value_func( (scale, value) => { + return "\t" + value + "px"; + }); + arrowScale.set_value(this.menuArrowSize); + arrowScale.connect('value-changed', () => { + this.menuArrowSize = arrowScale.get_value(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + menuArrowRow.add(menuArrowLabel); + menuArrowRow.add(arrowScale); + themeSettingsFrame.add(menuArrowRow); + + //ROW 11 - Vertical Separator------------------------------------------------------ + let vertSeparatorRow = new PW.FrameBoxRow(); + let vertSeparatorLabel = new Gtk.Label({ + label: _('Enable Vertical Separator'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let vertSeparatorSwitch = new Gtk.Switch({ halign: Gtk.Align.END}); + vertSeparatorSwitch.set_active(this.verticalSeparator); + vertSeparatorSwitch.connect('notify::active', (widget) => { + this.verticalSeparator = widget.get_active(); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + applyButton.set_sensitive(true); + resetButton.set_sensitive(true); + }); + vertSeparatorRow.add(vertSeparatorLabel); + vertSeparatorRow.add(vertSeparatorSwitch); + themeSettingsFrame.add(vertSeparatorRow); + + //ROW 12 - Separator Color------------------------------------------------------ + let separatorColorRow = new PW.FrameBoxRow(); + let separatorColorLabel = new Gtk.Label({ + label: _('Separator Color'), + use_markup: true, + xalign: 0, + hexpand: true, + selectable: false + }); + let colorChooser = new Gtk.ColorButton({use_alpha:true}); + color = new Gdk.RGBA(); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + colorChooser.connect('color-set', ()=>{ + this.separatorColor = colorChooser.get_rgba().to_string(); + applyButton.set_sensitive(true); + if(this.shouldDeselect) + this.checkIfPresetMatch(); + resetButton.set_sensitive(true); + }); + separatorColorRow.add(separatorColorLabel); + separatorColorRow.add(colorChooser); + themeSettingsFrame.add(separatorColorRow); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + this._parentMainBox.buttonRow = buttonRow; + let resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + valign: Gtk.Align.END, + vexpand: false + }); + resetButton.set_sensitive( this.checkIfResetButtonSensitive()); + resetButton.connect('clicked', ()=> { + this.separatorColor = this._settings.get_default_value('separator-color').unpack(); + this.verticalSeparator = this._settings.get_default_value('vert-separator').unpack(); + this.menuColor = this._settings.get_default_value('menu-color').unpack(); + this.menuForegroundColor = this._settings.get_default_value('menu-foreground-color').unpack(); + this.borderColor = this._settings.get_default_value('border-color').unpack(); + this.highlightColor = this._settings.get_default_value('highlight-color').unpack(); + this.highlightForegroundColor = this._settings.get_default_value('highlight-foreground-color').unpack(); + this.fontSize = this._settings.get_default_value('menu-font-size').unpack(); + this.borderSize = this._settings.get_default_value('menu-border-size').unpack(); + this.cornerRadius = this._settings.get_default_value('menu-corner-radius').unpack(); + this.menuMargin = this._settings.get_default_value('menu-margin').unpack(); + this.menuArrowSize = this._settings.get_default_value('menu-arrow-size').unpack(); + + color.parse(this.menuColor); + menuBackgroudColorChooser.set_rgba(color); + + color.parse(this.menuForegroundColor); + menuForegroundColorChooser.set_rgba(color); + + fontScale.set_value(this.fontSize); + + color.parse(this.borderColor); + borderColorChooser.set_rgba(color); + + borderScale.set_value(this.borderSize); + + color.parse(this.highlightColor); + itemColorChooser.set_rgba(color); + + color.parse(this.highlightForegroundColor); + itemForegroundColorChooser.set_rgba(color); + + cornerScale.set_value(this.cornerRadius); + marginScale.set_value(this.menuMargin); + arrowScale.set_value(this.menuArrowSize); + + vertSeparatorSwitch.set_active(this.verticalSeparator); + color.parse(this.separatorColor); + colorChooser.set_rgba(color); + + resetButton.set_sensitive(false); + applyButton.set_sensitive(true); + }); + + + let applyButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true, + halign: Gtk.Align.END + }); + applyButton.connect('clicked', ()=> { + applyButton.set_sensitive(false); + this.emit('menu-theme-response', -10); + }); + applyButton.set_sensitive(false); + + buttonRow.append(resetButton); + buttonRow.append(applyButton); + + this._parentMainBox.append(buttonRow); + } + get_response(){ + return this.addResponse; + } + checkIfPresetMatch(){ + this.presetName = "Custom Theme"; + let currentSettingsArray = [this.menuColor, this.menuForegroundColor, this.borderColor, this.highlightColor, this.highlightForegroundColor, this.separatorColor, + this.fontSize.toString(), this.borderSize.toString(), this.cornerRadius.toString(), this.menuArrowSize.toString(), + this.menuMargin.toString(), this.verticalSeparator.toString()]; + let all_color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0;i < all_color_themes.length;i++){ + this.isEqual=true; + for(let l = 0; l { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('directory-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name, frame._icon, frame._cmd]); + } + this._settings.set_value('directory-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('directory-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('directory-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = _(applicationShortcuts[i][0]); + let editable = true; + if(applicationShortcuts[i][2].startsWith("ArcMenu_")){ + editable = false; + } + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + frameRow._name = applicationName; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._gicon = Gio.icon_new_for_string(getIconPath(applicationShortcuts[i])); + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.resetButton, this.saveButton], + modifyButton: editable, + deleteButton: true + }); + + if(editable){ + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.DIRECTORIES, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + applicationIcon.gicon = Gio.icon_new_for_string(frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + } + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsShortcutApplicationsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsShortcutApplicationsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + let softwareShortcutsFrame = new PW.FrameBox(); + this.softwareShortcutsScrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.softwareShortcutsScrollWindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); + this.softwareShortcutsScrollWindow.set_min_content_height(300); + this.softwareShortcutsScrollWindow.set_child(softwareShortcutsFrame); + + let applicationShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._loadPinnedApps(applicationShortcuts,softwareShortcutsFrame); + this.mainBox.append(this.softwareShortcutsScrollWindow); + + let addPinnedAppsFrame = new PW.FrameBox(); + let addPinnedAppsFrameRow = new PW.FrameBoxRow(); + let addPinnedAppsFrameLabel = new Gtk.Label({ + label: _("Add More Apps"), + use_markup: true, + xalign: 0, + hexpand: true + }); + let addPinnedAppsButton = new PW.Button({ + icon_name: 'list-add-symbolic', + }); + addPinnedAppsButton.connect('clicked', ()=> { + let dialog = new AddAppsToPinnedListWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + let array=[]; + for(let i = 0;i { + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newPinnedApps = dialog.get_newPinnedAppsArray(); + this._loadPinnedApps([newPinnedApps],softwareShortcutsFrame); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + addCustomAppFrameRow.add(addCustomAppFrameLabel); + addCustomAppFrameRow.add(addCustomAppButton); + addCustomAppFrame.add(addCustomAppFrameRow); + this.mainBox.append(addCustomAppFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + softwareShortcutsFrame.remove_all_children(); + this._loadPinnedApps(this._settings.get_default_value('application-shortcuts-list').deep_unpack(), softwareShortcutsFrame); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < softwareShortcutsFrame.count; i++) { + let frame = softwareShortcutsFrame.get_index(i); + array.push([frame._name,frame._icon, frame._cmd]); + } + this._settings.set_value('application-shortcuts-list', new GLib.Variant('aas', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultShortcuts = this._settings.get_default_value('application-shortcuts-list').deep_unpack(); + let currentShortcuts = this._settings.get_value('application-shortcuts-list').deep_unpack(); + return !Utils.getArraysEqual(defaultShortcuts, currentShortcuts); + } + + _loadPinnedApps(applicationShortcuts,softwareShortcutsFrame){ + for(let i = 0; i < applicationShortcuts.length; i++){ + let applicationName = applicationShortcuts[i][0]; + + let frameRow = new PW.FrameBoxDragRow(this.softwareShortcutsScrollWindow); + let iconString; + frameRow._name = applicationShortcuts[i][0]; + frameRow._icon = applicationShortcuts[i][1]; + frameRow._cmd = applicationShortcuts[i][2]; + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + iconString = frameRow._icon; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + frameRow._gicon = Gio.icon_new_for_string(iconString); + let applicationIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let applicationImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + applicationImageBox.append(dragImage); + applicationImageBox.append(applicationIcon); + frameRow.add(applicationImageBox); + + let softwareShortcutsLabel = new Gtk.Label({ + label: _(applicationName), + use_markup: true, + xalign: 0, + hexpand: true + }); + + checkIfValidShortcut(frameRow, softwareShortcutsLabel, applicationIcon); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: softwareShortcutsFrame, + buttons: [this.saveButton, this.resetButton], + modifyButton: true, + deleteButton: true + }); + + buttonBox.connect('modify', ()=> { + let appArray = [frameRow._name,frameRow._icon,frameRow._cmd]; + let dialog = new AddCustomLinkDialogWindow(this._settings, this, Constants.DiaglogType.APPLICATIONS, true, appArray); + dialog.show(); + dialog.connect('response', ()=> { + if(dialog.get_response()) { + let newApplicationShortcut = dialog.get_newPinnedAppsArray(); + frameRow._name = newApplicationShortcut[0]; + frameRow._icon = newApplicationShortcut[1]; + frameRow._cmd = newApplicationShortcut[2]; + softwareShortcutsLabel.label = _(frameRow._name); + let iconString; + if(frameRow._icon === "" && Gio.DesktopAppInfo.new(frameRow._cmd)){ + iconString = Gio.DesktopAppInfo.new(frameRow._cmd).get_icon() ? Gio.DesktopAppInfo.new(frameRow._cmd).get_icon().to_string() : ""; + } + applicationIcon.gicon = Gio.icon_new_for_string(iconString ? iconString : frameRow._icon); + dialog.destroy(); + softwareShortcutsFrame.show(); + this.resetButton.set_sensitive(true); + this.saveButton.set_sensitive(true); + } + else + dialog.destroy(); + }); + }); + + frameRow.add(softwareShortcutsLabel); + frameRow.add(buttonBox); + softwareShortcutsFrame.add(frameRow); + } + } +}); +var MenuSettingsPowerOptionsPage = GObject.registerClass( + class Arc_Menu_MenuSettingsPowerOptionsPage extends Gtk.Box { + _init(settings) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.scrollBox = new Gtk.ScrolledWindow(); + this.scrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.scrollBox.set_child(this.mainBox); + this.append(this.scrollBox); + this._settings = settings; + this.powerOptionsFrame = new PW.FrameBox(); + + this.resetButton = new Gtk.Button({ + label: _("Restore Defaults"), + }); + this.saveButton = new Gtk.Button({ + label: _("Apply"), + hexpand: true + }); + + this._createFrame(this._settings.get_value("power-options").deep_unpack()); + this.mainBox.append(this.powerOptionsFrame); + + let buttonRow = new Gtk.Box({ + valign: Gtk.Align.END, + margin_top: 6, + margin_bottom: 6, + margin_start: 24, + margin_end: 24, + }); + + this.resetButton.set_sensitive(this.getSensitive()); + + this.resetButton.connect('clicked', ()=> { + this.saveButton.set_sensitive(true); + this.powerOptionsFrame.remove_all_children(); + this._createFrame(this._settings.get_default_value('power-options').deep_unpack()); + this.powerOptionsFrame.show(); + this.resetButton.set_sensitive(false); + }); + + this.saveButton.connect('clicked', ()=> { + let array = []; + for(let i = 0; i < this.powerOptionsFrame.count; i++) { + let frame = this.powerOptionsFrame.get_index(i); + array.push([frame._enum, frame._shouldShow]); + } + this._settings.set_value('power-options', new GLib.Variant('a(ib)', array)); + this.saveButton.set_sensitive(false); + this.resetButton.set_sensitive(this.getSensitive()); + }); + this.saveButton.set_halign(Gtk.Align.END); + this.saveButton.set_sensitive(false); + buttonRow.append(this.resetButton); + buttonRow.append(this.saveButton); + this.append(buttonRow); + } + + getSensitive(){ + let defaultPowerOptions = this._settings.get_default_value("power-options").deep_unpack(); + let currentPowerOptions = this._settings.get_value("power-options").deep_unpack(); + return !Utils.getArraysEqual(defaultPowerOptions, currentPowerOptions); + } + + _createFrame(powerOptions){ + for(let i = 0; i < powerOptions.length; i++){ + let powerType = powerOptions[i][0]; + let name = Constants.PowerOptions[powerType].TITLE; + + let frameRow = new PW.FrameBoxDragRow(this); + frameRow._enum = powerOptions[i][0]; + frameRow._shouldShow = powerOptions[i][1]; + frameRow._name = Constants.PowerOptions[powerType].TITLE; + frameRow._gicon = Gio.icon_new_for_string(Constants.PowerOptions[powerType].IMAGE); + frameRow.saveButton = this.saveButton; + frameRow.resetButton = this.resetButton; + frameRow.hasSwitch = true; + frameRow.switchActive = frameRow._shouldShow; + + let powerIcon = new Gtk.Image( { + gicon: frameRow._gicon, + pixel_size: 22 + }); + let powerImageBox = new Gtk.Box( { + margin_start: 0, + hexpand: false, + vexpand: false, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + powerImageBox.append(dragImage); + powerImageBox.append(powerIcon); + frameRow.add(powerImageBox); + + let powerLabel = new Gtk.Label({ + label: _(name), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let buttonBox = new PW.EditEntriesBox({ + frameRow: frameRow, + frame: this.powerOptionsFrame, + buttons: [this.saveButton, this.resetButton], + }); + + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + }); + + modifyButton.set_active(frameRow._shouldShow); + modifyButton.connect('notify::active', ()=> { + frameRow._shouldShow = modifyButton.get_active(); + this.saveButton.set_sensitive(true); + this.resetButton.set_sensitive(true); + }); + buttonBox.insert_column(0); + buttonBox.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + buttonBox.insert_column(0); + buttonBox.attach(modifyButton, 0, 0, 1, 1); + + frameRow.add(powerLabel); + frameRow.add(buttonBox); + this.powerOptionsFrame.add(frameRow); + } + } + }); + +var MiscPage = GObject.registerClass( + class Arc_Menu_MiscPage extends Gtk.ScrolledWindow { + _init(settings, parentBox) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let settingsHeaderLabel = new Gtk.Label({ + label: "" + _('Export or Import Settings') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsHeaderLabel); + + let importFrame = new PW.FrameBox(); + let importRow = new PW.FrameBoxRow(); + let importLabel = new Gtk.Label({ + label: _("All ArcMenu Settings"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let settingsImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + settingsImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import All ArcMenu Settings"), + secondaryText: _('Importing settings from file may replace ALL saved settings.\nThis includes all saved pinned apps.'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importButtonsRow = new PW.FrameBoxRow(); + let importButton = new Gtk.Button({ + label: _("Import from File"), + hexpand: true, + vexpand: true, + }); + importButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success_, pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + ); + }); + let exportButton = new Gtk.Button({ + label: _("Export to File"), + hexpand: true, + vexpand: true, + }); + exportButton.connect('clicked', ()=> { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE}, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + importRow.add(importLabel); + importRow.add(settingsImportInfoButton); + importButtonsRow.add(exportButton); + importButtonsRow.add(importButton); + importFrame.add(importRow); + importFrame.add(importButtonsRow); + this.mainBox.append(importFrame); + + let importColorPresetFrame = new PW.FrameBox(); + let importColorPresetRow = new PW.FrameBoxRow(); + let importColorPresetLabel = new Gtk.Label({ + label: _("Menu Theme Presets"), + use_markup: true, + xalign: 0, + hexpand: true + }); + + let colorThemesImportInfoButton = new PW.Button({ + icon_name: 'info-circle-symbolic' + }); + colorThemesImportInfoButton.connect('clicked', ()=> { + let dialog = new PW.MessageDialog({ + text: _("Export or Import Menu Theme Presets"), + secondaryText: _('Menu theme presets are located in the "Menu Theme" section'), + buttons: Gtk.ButtonsType.OK, + transient_for: this.get_root() + }); + dialog.connect ('response', ()=> dialog.destroy()); + dialog.show(); + }); + + let importColorPresetButtonsRow = new PW.FrameBoxRow(); + let importColorPresetButton = new Gtk.Button({ + label: _("Import Theme Preset"), + hexpand: true, + vexpand: true, + }); + importColorPresetButton.connect('clicked', ()=> { + this._showFileChooser( + _('Import Theme Preset'), + { action: Gtk.FileChooserAction.OPEN }, + "_Open", + filename => { + let settingsFile = Gio.File.new_for_path(filename); + let [ success, content, etags] = settingsFile.load_contents(null); + let string = ByteArray.toString(content); + let themes = string.split("\n") + themes.pop(); //remove last blank array + this.color_themes = []; + for(let i = 0; i < themes.length; i++){ + let array = themes[i].split('//') + array.pop(); + this.color_themes.push(array); + } + let dialog = new ExportColorThemeDialogWindow(this._settings, this, this.color_themes); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + let selectedThemes = dialog.selectedThemes; + this.color_themes = this._settings.get_value('color-themes').deep_unpack(); + for(let i = 0; i < selectedThemes.length; i++){ + this.color_themes.push(selectedThemes[i]); + } + + this._settings.set_value('color-themes',new GLib.Variant('aas',this.color_themes)); + + dialog.destroy(); + } + else + dialog.destroy(); + }); + } + ); + }); + let exportColorPresetButton = new Gtk.Button({ + label: _("Export Theme Preset"), + hexpand: true, + vexpand: true, + }); + exportColorPresetButton.connect('clicked', ()=> { + let dialog = new ExportColorThemeDialogWindow(this._settings, this); + dialog.show(); + dialog.connect('response', (response) => { + if(dialog.get_response()){ + this.selectedThemes = dialog.selectedThemes; + this._showFileChooser( + _('Export Theme Preset'), + { action: Gtk.FileChooserAction.SAVE }, + "_Save", + (filename) => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + for(let i = 0; i" + _('ArcMenu Settings Window Size') +"", + use_markup: true, + xalign: 0, + hexpand: true + }); + this.mainBox.append(settingsSizeHeaderLabel); + + let settingsSizeFrame = new PW.FrameBox(); + let settingsWidthRow = new PW.FrameBoxRow(); + let settingsWidthLabel = new Gtk.Label({ + label: _('Window Width'), + xalign:0, + hexpand: false, + }); + let settingsWidthScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 850, upper: 1800, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsWidthScale.set_value(this._settings.get_int("settings-width")); + settingsWidthScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-width", widget.get_value()) + }); + settingsWidthRow.add(settingsWidthLabel); + settingsWidthRow.add(settingsWidthScale); + settingsSizeFrame.add(settingsWidthRow); + + let settingsHeightRow = new PW.FrameBoxRow(); + let settingsHeightLabel = new Gtk.Label({ + label: _('Window Height'), + xalign:0, + hexpand: false, + }); + let settingsHeightScale = new Gtk.SpinButton({ + adjustment: new Gtk.Adjustment({ + lower: 300, upper: 1600, step_increment: 1, page_increment: 1, page_size: 0, + }), + climb_rate: 1, + digits: 0, + numeric: true, + hexpand: true, + halign: Gtk.Align.END + }); + settingsHeightScale.set_value(this._settings.get_int("settings-height")); + settingsHeightScale.connect('value-changed', (widget) => { + this._settings.set_int("settings-height", widget.get_value()) + }); + settingsHeightRow.add(settingsHeightLabel); + settingsHeightRow.add(settingsHeightScale); + settingsSizeFrame.add(settingsHeightRow); + + this.mainBox.append(settingsSizeFrame); + + let resetSettingsButton = new Gtk.Button({ + valign: Gtk.Align.END, + halign: Gtk.Align.START, + vexpand: true, + hexpand: false, + label: _("Reset all Settings"), + }); + let context = resetSettingsButton.get_style_context(); + context.add_class('suggested-action'); + resetSettingsButton.connect('clicked', (widget) => { + let dialog = new Gtk.MessageDialog({ + text: "" + _("Restore Default Settings?") + '\n' + _("All ArcMenu settings will be reset to the default value."), + use_markup: true, + buttons: Gtk.ButtonsType.YES_NO, + message_type: Gtk.MessageType.WARNING, + transient_for: this.get_root(), + modal: true + }); + dialog.connect('response', (widget, response) => { + if(response == Gtk.ResponseType.YES){ + GLib.spawn_command_line_sync('dconf reset -f /org/gnome/shell/extensions/arcmenu/'); + let children = [...parentBox.settingsFrameStack]; + for(let child of children){ + parentBox.settingsFrameStack.remove(child); + } + parentBox.populateSettingsFrameStack(); + } + dialog.destroy(); + }); + dialog.show(); + }); + + this.mainBox.append(resetSettingsButton); + } + _showFileChooser(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog({ + title: _(title), + transient_for: this.get_root(), + modal: true, + action: params.action, + }); + dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.connect("response", (self, response) => { + if(response === Gtk.ResponseType.ACCEPT){ + try { + acceptHandler(dialog.get_file().get_path()); + } catch(e) { + log('error from ArcMenu filechooser: ' + e); + } + } + dialog.destroy(); + }); + + dialog.show(); + } + }); + function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + return main; + }; + +var AboutPage = GObject.registerClass( + class Arc_Menu_AboutPage extends Gtk.ScrolledWindow { + _init(settings) { + super._init(); + this.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + + this.mainBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + margin_start: 24, + margin_end: 24, + spacing: 0, + vexpand: true, + valign: Gtk.Align.FILL + }); + + this.set_child(this.mainBox); + this._settings = settings; + + let releaseVersion; + if(Me.metadata.version) + releaseVersion = Me.metadata.version; + else + releaseVersion = 'unknown'; + + let commitVersion; + if(Me.metadata.commit) + commitVersion = Me.metadata.commit; + + let projectUrl = Me.metadata.url; + + let arcMenuImage = new Gtk.Image({ + margin_bottom: 5, + icon_name: 'arc-menu-logo', + pixel_size: 100, + }); + let arcMenuImageBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + margin_top: 10, + margin_bottom: 10, + hexpand: false, + vexpand: false + }); + arcMenuImageBox.append(arcMenuImage); + + let extensionInfoFrame = new PW.FrameBox(); + + let arcMenuVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let versionText = new Gtk.Label({ + label: _('ArcMenu Version'), + }); + let versionInfo = new Gtk.Label({ + label: releaseVersion + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + arcMenuVersionRow.add(versionText); + arcMenuVersionRow.add(versionInfo); + extensionInfoFrame.add(arcMenuVersionRow); + + let commitRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let commitText = new Gtk.Label({ + label: _('Git Commit'), + }); + let commitInfo = new Gtk.Label({ + label: commitVersion ? commitVersion : '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + commitRow.add(commitText); + commitRow.add(commitInfo); + if(commitVersion){ + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(commitRow); + } + + let gnomeVersionRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let gnomeVersionText = new Gtk.Label({ + label: _('GNOME Version'), + }); + let gnomeVersionInfo = new Gtk.Label({ + label: imports.misc.config.PACKAGE_VERSION + '', + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + gnomeVersionRow.add(gnomeVersionText); + gnomeVersionRow.add(gnomeVersionInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(gnomeVersionRow); + + let osRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let osText = new Gtk.Label({ + label: _('OS'), + }); + let osInfoText; + let name = GLib.get_os_info("NAME"); + let prettyName = GLib.get_os_info("PRETTY_NAME"); + if(prettyName) + osInfoText = prettyName; + else + osInfoText = name; + let versionID = GLib.get_os_info("VERSION_ID"); + if(versionID) + osInfoText += "; Version ID: " + versionID; + let buildID = GLib.get_os_info("BUILD_ID"); + if(buildID) + osInfoText += "; " + "Build ID: " +buildID; + + let osInfo = new Gtk.Label({ + label: osInfoText, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + osRow.add(osText); + osRow.add(osInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(osRow); + + let windowingRow = new PW.FrameBoxRow({ + selectable: false, + activatable: false + }); + let windowingText = new Gtk.Label({ + label: _('Session Type'), + }); + let windowingLabel; + if(Me.metadata.isWayland) + windowingLabel = "Wayland"; + else + windowingLabel = "X11"; + + let windowingInfo = new Gtk.Label({ + label: windowingLabel, + hexpand: true, + sensitive: false, + halign: Gtk.Align.END + }); + windowingRow.add(windowingText); + windowingRow.add(windowingInfo); + extensionInfoFrame.add(createSeparator()); + extensionInfoFrame.add(windowingRow); + + let arcMenuInfoBox = new Gtk.Box( { + orientation: Gtk.Orientation.VERTICAL, + hexpand: false, + vexpand: false + }); + let arcMenuLabel = new Gtk.Label({ + label: '' + _('ArcMenu') + '', + use_markup: true, + vexpand: true, + valign: Gtk.Align.FILL + }); + + let projectDescriptionLabel = new Gtk.Label({ + label: _('Application Menu Extension for GNOME'), + hexpand: false, + vexpand: false, + margin_bottom: 5 + }); + let linksBox = new Gtk.Box({ + hexpand: false, + vexpand: false, + valign: Gtk.Align.END, + halign: Gtk.Align.CENTER, + margin_top: 0, + margin_bottom: 0, + margin_start: 0, + margin_end: 0, + spacing: 0, + }); + + let pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/donate-icon.svg', 150, 50); + let donateImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let donateLinkButton = new Gtk.LinkButton({ + child: donateImage, + uri: 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=53CWA7NR743WC&item_name=Donate+to+support+my+work¤cy_code=USD&source=url', + }); + + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(Me.path + '/media/icons/prefs_icons/gitlab-icon.svg', 150, 50); + let gitlabImage = Gtk.Picture.new_for_pixbuf(pixbuf); + let projectLinkButton = new Gtk.LinkButton({ + child: gitlabImage, + uri: projectUrl, + }); + + linksBox.append(projectLinkButton); + linksBox.append(donateLinkButton); + + this.creditsScrollWindow = new Gtk.ScrolledWindow({ + margin_top: 10, + margin_bottom: 0, + hexpand: false, + }); + this.creditsScrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.creditsScrollWindow.set_max_content_height(200); + this.creditsScrollWindow.set_min_content_height(200); + this.creditsFrame = new PW.Notebook(); + this.creditsFrame.scrollable = true; + let developersPage = new PW.NotebookPage(_("Developers")); + this.creditsFrame.append_page(developersPage); + let translatorsPage = new PW.NotebookPage(_("Translators")); + this.creditsFrame.append_page(translatorsPage); + let contributorsPage = new PW.NotebookPage(_("Contributors")); + this.creditsFrame.append_page(contributorsPage ); + let artworkPage = new PW.NotebookPage(_("Artwork")); + this.creditsFrame.append_page(artworkPage); + this.creditsScrollWindow.set_child(this.creditsFrame); + let creditsLabel = new Gtk.Label({ + label: _(Constants.DEVELOPERS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + developersPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.TRANSLATORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + }); + translatorsPage.append(creditsLabel); + creditsLabel = new Gtk.Label({ + label: _(Constants.CONTRIBUTORS), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + contributorsPage.append(creditsLabel); + contributorsPage.hexpand = false; + creditsLabel = new Gtk.Label({ + label: _(Constants.ARTWORK), + use_markup: true, + halign: Gtk.Align.START, + hexpand: false, + vexpand: false, + wrap: true + }); + artworkPage.append(creditsLabel); + arcMenuImageBox.append(arcMenuLabel); + arcMenuImageBox.append(projectDescriptionLabel); + + let gnuSofwareLabel = new Gtk.Label({ + label: _(Constants.GNU_SOFTWARE), + use_markup: true, + justify: Gtk.Justification.CENTER + }); + let gnuSofwareLabelBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + valign: Gtk.Align.END, + vexpand: true, + margin_top: 5, + margin_bottom: 10 + }); + gnuSofwareLabelBox.append(gnuSofwareLabel); + + this.mainBox.append(arcMenuImageBox); + this.mainBox.append(arcMenuInfoBox); + this.mainBox.append(extensionInfoFrame); + + this.mainBox.append(this.creditsScrollWindow) + this.mainBox.append(gnuSofwareLabelBox); + this.mainBox.append(linksBox); + } +}); + +function createSeparator(){ + let separatorRow = new Gtk.ListBoxRow({ + selectable: false, + activatable: false + }); + separatorRow.set_child(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + return separatorRow; +} + +var ArcMenuPreferencesWidget = GObject.registerClass( +class Arc_Menu_ArcMenuPreferencesWidget extends Gtk.Box { + _init() { + super._init(); + + this.leftHeaderBox = new Gtk.Box({ + hexpand: true, + visible: true + }); + + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + + this.backButton = new Gtk.Button({ + child: new Gtk.Image({icon_name: 'go-previous-symbolic'}), + visible: true + }); + this.backButton.connect("clicked", () => { + this.leftHeaderBox.remove(this.backButton); + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + }); + + this.settingsFrameStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.CROSSFADE + }); + + this.settingsListStack = new Gtk.Stack({ + hhomogeneous: true, + transition_type: Gtk.StackTransitionType.SLIDE_LEFT_RIGHT + }); + + let mainStackListBox = new PW.StackListBox(this, {width_request: 215}); + + let mainStackBox = mainStackListBox.scrollWindow; + mainStackListBox.addRow("General", _("General"), 'homescreen-symbolic'); + mainStackListBox.addRow("MenuLayout", _("Menu Layout"), 'menu-layouts-symbolic') + mainStackListBox.addRow("MenuTheme", _("Menu Theme"), 'menu-theme-symbolic'); + mainStackListBox.addRow("MenuSettingsGeneral", _("Customize Menu"), 'menu-settings-symbolic', "MenuSettings"); + mainStackListBox.addRow("ButtonAppearance", _("Button Appearance"), 'arc-menu-symbolic') + mainStackListBox.addRow("Misc", _("Misc"), 'misc-symbolic') + mainStackListBox.addRow("About", _("About"), 'info-circle-symbolic'); + mainStackListBox.setSeparatorIndices([1, 4, 5]); + + let menuSettingsStackListBox = new PW.StackListBox(this, {width_request: 215}); + let menuSettingsListBox = menuSettingsStackListBox.scrollWindow; + menuSettingsStackListBox.addRow("MenuSettingsGeneral", _("Menu Settings"), 'menu-settings-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPinnedApps", _("Pinned Apps"), 'pinned-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutDirectories", _("Directory Shortcuts"), 'folder-documents-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsShortcutApplications", _("Application Shortcuts"), 'preferences-desktop-apps-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsPowerOptions", _("Power Options"), 'gnome-power-manager-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsSearchOptions", _("Search Options"), 'preferences-system-search-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsCategories", _("Extra Categories"), 'categories-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsNewApps", _("New Apps Tracker"), 'preferences-system-notifications-symbolic'); + menuSettingsStackListBox.addRow("MenuSettingsFineTune", _("Fine-Tune"), 'fine-tune-symbolic'); + menuSettingsStackListBox.setSeparatorIndices([1, 4, 8]); + + this.settingsListStack.add_named(mainStackBox, "Main"); + this.settingsListStack.add_named(menuSettingsListBox, "MenuSettings"); + + let sidebar = new Gtk.StackSidebar(); + sidebar.set_stack(this.settingsListStack); + this.append(this.settingsListStack); + this.append(sidebar); + + this.append(this.settingsFrameStack); + this.populateSettingsFrameStack(); + } + + populateSettingsFrameStack(){ + this.settingsFrameStack.add_named(new GeneralPage(this._settings), "General"); + this.menuLayoutPage = new MenuLayoutPage(this._settings); + this.settingsFrameStack.add_named(this.menuLayoutPage, "MenuLayout"); + this.settingsFrameStack.add_named(new MenuThemePage(this._settings), "MenuTheme"); + + this.settingsFrameStack.add_named(new MenuSettingsGeneralPage(this._settings), "MenuSettingsGeneral"); + this.settingsFrameStack.add_named(new MenuSettingsPinnedAppsPage(this._settings), "MenuSettingsPinnedApps"); + + let menuSettingsPinnedAppsPage = this.settingsFrameStack.get_child_by_name("MenuSettingsPinnedApps"); + + if(this.pinnedAppsChangedID){ + this._settings.disconnect(this.pinnedAppsChangedID); + this.pinnedAppsChangedID = null; + } + this.pinnedAppsChangedID = this._settings.connect("changed::pinned-app-list", () =>{ + menuSettingsPinnedAppsPage.frame.remove_all_children(); + menuSettingsPinnedAppsPage._loadPinnedApps(this._settings.get_strv('pinned-app-list')); + menuSettingsPinnedAppsPage.frame.show(); + }); + + this.settingsFrameStack.add_named(new MenuSettingsShortcutDirectoriesPage(this._settings), "MenuSettingsShortcutDirectories"); + this.settingsFrameStack.add_named(new MenuSettingsShortcutApplicationsPage(this._settings), "MenuSettingsShortcutApplications"); + this.settingsFrameStack.add_named(new MenuSettingsPowerOptionsPage(this._settings), "MenuSettingsPowerOptions"); + this.settingsFrameStack.add_named(new MenuSettingsSearchOptionsPage(this._settings), "MenuSettingsSearchOptions"); + this.settingsFrameStack.add_named(new MenuSettingsCategoriesPage(this._settings, "extra-categories"), "MenuSettingsCategories"); + this.settingsFrameStack.add_named(new MenuSettingsNewAppsPage(this._settings), "MenuSettingsNewApps"); + this.settingsFrameStack.add_named(new MenuSettingsFineTunePage(this._settings), "MenuSettingsFineTune"); + this.settingsFrameStack.add_named(new ButtonAppearancePage(this._settings), "ButtonAppearance"); + this.settingsFrameStack.add_named(new MiscPage(this._settings, this), "Misc"); + this.settingsFrameStack.add_named(new AboutPage(this._settings), "About"); + + this.show(); + + if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MAIN){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectFirstRow(); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.CUSTOMIZE_MENU){ + this.settingsListStack.set_visible_child_name("MenuSettings"); + this.settingsListStack.get_child_by_name('MenuSettings').listBox.selectRowAtIndex(0); + if(!this.backButton.get_parent()) + this.leftHeaderBox.append(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.MENU_LAYOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.BUTTON_APPEARANCE){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(4); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.LAYOUT_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayLayoutTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.RUNNER_TWEAKS){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(1); + this.menuLayoutPage.connect("realize", () => this.menuLayoutPage.displayRunnerTweaksPage()); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + else if(this._settings.get_int('prefs-visible-page') === Constants.PrefsVisiblePage.ABOUT){ + this.settingsListStack.set_visible_child_name("Main"); + this.settingsListStack.get_child_by_name('Main').listBox.selectRowAtIndex(6); + if(this.backButton.get_parent()) + this.leftHeaderBox.remove(this.backButton); + } + this._settings.set_int('prefs-visible-page', Constants.PrefsVisiblePage.MAIN); + } +}); + +function init() { + ExtensionUtils.initTranslations(Me.metadata['gettext-domain']); +} + +function buildPrefsWidget() { + this._settings = ExtensionUtils.getSettings(Me.metadata['settings-schema']); + let iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); + if(!iconTheme.get_search_path().includes(Me.path + "/media/icons/prefs_icons")) + iconTheme.add_search_path(Me.path + "/media/icons/prefs_icons"); + let widget = new ArcMenuPreferencesWidget(); + widget.connect("realize", () => { + let window = widget.get_root(); + + window.default_width = this._settings.get_int('settings-width'); + window.default_height = this._settings.get_int('settings-height'); + + window.set_title(_("ArcMenu Settings")); + window.get_titlebar().pack_start(widget.leftHeaderBox); + }); + + widget.show(); + return widget; +} + +function checkIfValidShortcut(frameRow, label, icon){ + if(frameRow._cmd.endsWith(".desktop") && !Gio.DesktopAppInfo.new(frameRow._cmd)){ + icon.icon_name = 'warning-symbolic'; + label.label = "" + _("Invalid Shortcut") + " "+ _(label.label); + } +} + +function getIconPath(listing){ + let path, icon; + + if(listing[2]=="ArcMenu_Home") + path = GLib.get_home_dir(); + else if(listing[2].startsWith("ArcMenu_")){ + let string = listing[2]; + path = string.replace("ArcMenu_",''); + if(path === "Documents") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS); + else if(path === "Downloads") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD); + else if(path === "Music") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC); + else if(path === "Pictures") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); + else if(path === "Videos") + path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS); + else + path = null; + } + else if(listing[1] == listing[2]) + path = listing[2]; + else if(listing[1] == "ArcMenu_Folder"){ + path = listing[2]; + } + else + path = null; + + if(path){ + let file = Gio.File.new_for_path(path); + try { + let info = file.query_info('standard::symbolic-icon', 0, null); + icon = info.get_symbolic_icon(); + } catch (e) { + if (e instanceof Gio.IOErrorEnum) { + if (!file.is_native()) { + icon = new Gio.ThemedIcon({ name: 'folder-remote-symbolic' }); + } else { + icon = new Gio.ThemedIcon({ name: 'folder-symbolic' }); + } + } + } + return icon.to_string(); + } + else{ + if(listing[2]=="ArcMenu_Network") + return 'network-workgroup-symbolic'; + else if(listing[2]=="ArcMenu_Computer") + return 'drive-harddisk-symbolic'; + else + return listing[1]; + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js new file mode 100644 index 0000000..0700025 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/prefsWidgets.js @@ -0,0 +1,793 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk} = imports.gi; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +var Notebook = GObject.registerClass(class Arc_Menu_Notebook extends Gtk.Notebook{ + _init() { + super._init({ + margin_start: 0, + margin_end: 0 + }); + } + + append_page(notebookPage) { + Gtk.Notebook.prototype.append_page.call( + this, + notebookPage, + notebookPage.getTitleLabel() + ); + } +}); + +var NotebookPage = GObject.registerClass(class Arc_Menu_NotebookPage extends Gtk.Box { + _init(title) { + super._init({ + orientation: Gtk.Orientation.VERTICAL, + margin_top: 24, + margin_bottom: 24, + margin_start: 24, + margin_end: 24, + spacing: 20, + homogeneous: false + }); + this._title = new Gtk.Label({ + label: "" + title + "", + use_markup: true, + xalign: 0 + }); + } + + getTitleLabel() { + return this._title; + } +}); + +var Button = GObject.registerClass(class Arc_Menu_Button extends Gtk.Button { + _init(params) { + super._init(); + this._params = params; + this.halign = Gtk.Align.END; + this.valign = Gtk.Align.CENTER; + this.box = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 5 + }); + this.set_child(this.box); + + if (this._params.icon_name) { + let image = new Gtk.Image({ + icon_name: this._params.icon_name, + halign: Gtk.Align.CENTER + }); + this.box.append(image); + } + if (this._params.tooltip_text){ + this.set_tooltip_text(this._params.tooltip_text); + } + if (this._params.title){ + let label = new Gtk.Label({ + label: _(this._params.title), + use_markup: true, + xalign: 0 + }); + if(this._params.icon_first) + this.box.append(label); + else + this.box.prepend(label); + } + } +}); + +var DialogWindow = GObject.registerClass(class Arc_Menu_DialogWindow extends Gtk.Dialog { + _init(title, parent) { + super._init({ + title: title, + transient_for: parent.get_root(), + modal: true + }); + let vbox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 20, + homogeneous: false, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + hexpand: true, + halign: Gtk.Align.FILL + }); + vbox.insert_after(this.get_content_area(), null); + this._createLayout(vbox); + } + + _createLayout(vbox) { + throw "Not implemented!"; + } +}); + +var MessageDialog = GObject.registerClass(class Arc_Menu_MessageDialog extends Gtk.MessageDialog { + _init(params) { + super._init({ + transient_for: params.transient_for, + modal: true, + buttons: params.buttons + }); + this.set_size_request(300, 50); + this.grid = new Gtk.Grid({ + row_spacing: 10, + column_spacing: 24, + margin_top: 24, + margin_bottom: 0, + margin_start: 24, + margin_end: 24, + hexpand: false, + halign: Gtk.Align.CENTER + }); + this.grid.insert_after(this.get_content_area(), null); + let text = new Gtk.Label({ + label: "" + _(params.text) + "", + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(text, 1, 0, 1, 1); + + if(params.secondaryText){ + let secondayText = new Gtk.Label({ + label: _(params.secondaryText), + use_markup: true, + hexpand: false, + halign: Gtk.Align.START, + wrap: true, + }); + this.grid.attach(secondayText, 1, 1, 1, 1); + } + + if(params.iconName){ + let image = new Gtk.Image({ + icon_name: params.iconName, + pixel_size: 48 + }); + this.grid.attach(image, 0, 0, 1, 2); + } + } +}); + +var FrameBox = GObject.registerClass(class Arc_Menu_FrameBox extends Gtk.Frame { + _init(params) { + super._init(params); + this._listBox = new Gtk.ListBox(); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.count = 0; + this.children = []; + Gtk.Frame.prototype.set_child.call(this, this._listBox); + } + + add(boxRow) { + this._listBox.append(boxRow); + this.children.push(boxRow); + this.count++; + } + show() { + this._listBox.show(); + super.show(); + } + length() { + return this._listBox.length; + } + remove(boxRow){ + if(boxRow){ + this._listBox.remove(boxRow); + this.children = this.children.filter(e => e !== boxRow) + this.count = this.count -1; + } + } + removeChildrenAfterIndex(index){ + let childrenCount = this.count; + for(let i = childrenCount - 1; i > index; i--){ + let child = this._listBox.get_row_at_index(i); + if(child) this.remove(child); + } + this._listBox.show(); + } + remove_all_children() { + for(let i = 0; i < this.children.length; i++){ + let child = this.children[i]; + this._listBox.remove(child); + } + this.children = []; + this.count = 0; + this._listBox.show(); + } + get_index(index){ + return this._listBox.get_row_at_index(index); + } + insert(row, pos){ + this._listBox.insert(row, pos); + this.children.push(row); + this.count++; + } +}); + +var FrameBoxRow = GObject.registerClass(class Arc_Menu_FrameBoxRow extends Gtk.ListBoxRow { + _init(params) { + super._init(params); + this.selectable = false; + this.activatable = false; + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var FrameBoxDragRow = GObject.registerClass(class Arc_Menu_FrameBoxDragRow extends Gtk.ListBoxRow { + _init(scrolledWindow) { + super._init(); + + this._grid = new Gtk.Grid({ + orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 5, + margin_bottom: 5, + margin_start: 5, + margin_end: 5, + column_spacing: 20, + row_spacing: 20 + }); + + let dragSource = new Gtk.DragSource({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dragSource); + + let dropTarget = new Gtk.DropTargetAsync({ + actions: Gdk.DragAction.MOVE + }); + this.add_controller(dropTarget); + + this.x = 0; + Gtk.ListBoxRow.prototype.set_child.call(this, this._grid); + dragSource.connect("drag-begin", (self, gdkDrag) => { + //get listbox parent + let listBox = self.get_widget().get_parent(); + //get widgets parent - the listBoxDragRow + listBox.dragRow = this; + + let alloc = self.get_widget().get_allocation(); + let dragWidget = self.get_widget().createDragRow(alloc); + listBox.dragWidget = dragWidget; + + let icon = Gtk.DragIcon.get_for_drag(gdkDrag); + icon.set_child(dragWidget); + + gdkDrag.set_hotspot(listBox.dragX, listBox.dragY); + }); + + dragSource.connect("prepare", (self, x, y) => { + //get listbox parent + this.set_state_flags(Gtk.StateFlags.NORMAL, true); + let listBox = self.get_widget().get_parent(); + //store drag start cursor location + listBox.dragX = x; + listBox.dragY = y; + return new Gdk.ContentProvider(Arc_Menu_FrameBoxDragRow); + }); + + dragSource.connect("drag-end", (self, gdkDrag, deleteData)=> { + deleteData = true; + let listBox = self.get_widget().get_parent(); + listBox.dragWidget = null; + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drag-enter", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + let widget = self.get_widget(); + + listBox.startIndex = widget.get_index(); + listBox.drag_highlight_row(widget); + + if(!scrolledWindow) + return true; + + let height = widget.get_height(); + let scrollHeight = scrolledWindow.get_height(); + let widgetLoc = widget.get_index() * height; + let value = scrolledWindow.vadjustment.value; + + if((widgetLoc + (height * 4)) > (value + scrollHeight)) + scrolledWindow.vadjustment.value += height; + else if((widgetLoc - (height * 2)) < value) + scrolledWindow.vadjustment.value -= height; + }); + + dropTarget.connect("drag-leave", (self, gdkDrop, x, y, selection, info, time)=> { + let listBox = self.get_widget().get_parent(); + listBox.drag_unhighlight_row(); + }); + + dropTarget.connect("drop", (self, gdkDrop, x, y, selection, info, time)=> { + //get listbox parent + let listBox = this.get_parent(); + let index = this.get_index(); + if(index === listBox.dragRow.get_index()){ + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + } + listBox.remove(listBox.dragRow); + listBox.show(); + listBox.insert(listBox.dragRow, index); + this.resetButton?.set_sensitive(true); + this.saveButton.set_sensitive(true); + gdkDrop.read_value_async(Arc_Menu_FrameBoxDragRow, 1, null, ()=>{ + gdkDrop.finish(Gdk.DragAction.MOVE); + }); + return true; + }); + } + + createDragRow(alloc){ + let dragWidget = new Gtk.ListBox(); + dragWidget.set_size_request(alloc.width, alloc.height); + + let dragRow = new FrameBoxRow(); + dragWidget.append(dragRow); + dragWidget.drag_highlight_row(dragRow); + + let image = new Gtk.Image( { + gicon: this._gicon, + pixel_size: 22 + }); + + let imageBox = new Gtk.Box({ + margin_start: 0, + hexpand: false, + vexpand: true, + spacing: 5, + }); + let dragImage = new Gtk.Image( { + gicon: Gio.icon_new_for_string("drag-symbolic"), + pixel_size: 12 + }); + + imageBox.append(dragImage); + imageBox.append(image); + + dragRow.add(imageBox); + + let label = new Gtk.Label({ + use_markup: true, + xalign: 0, + hexpand: true, + label: _(this._name) + }); + dragRow.add(label); + let grid = new Gtk.Grid({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }) + let editButton = new Button({ + icon_name: 'view-more-symbolic' + }); + grid.attach(editButton, 0, 0, 1, 1); + + if(this.hasSwitch){ + let modifyButton = new Gtk.Switch({ + valign: Gtk.Align.CENTER, + margin_start: 10, + active: this.switchActive + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(modifyButton, 0, 0, 1, 1); + } + if(this.hasEditButton){ + let editButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + grid.insert_column(0); + grid.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + grid.insert_column(0); + grid.attach(editButton, 0, 0, 1, 1); + } + dragRow.add(grid); + + return dragWidget; + } + + add(widget) { + this._grid.attach(widget, this.x, 0, 1, 1); + this.x++; + } + + setVerticalAlignmentBottom(){ + this._grid.vexpand = true; + this._grid.valign = Gtk.Align.END; + } +}); + +var EditEntriesBox = GObject.registerClass({ + Signals: { + 'modify': {}, + 'change': {}, + 'move-up': {}, + 'move-down': {}, + 'delete': {}, + }, +}, class Arc_Menu_EditEntriesBox extends Gtk.Grid{ + _init(params){ + super._init({ + margin_top: 0, + margin_bottom: 0, + vexpand: false, + hexpand: false, + column_spacing: 10 + }); + let editPopover = new Gtk.Popover(); + let frameRow = params.frameRow; + let frame = params.frame; + let buttons = params.buttons; + + let modifyButton, deleteButton, changeButton; + + if(params.modifyButton){ + modifyButton = new Gtk.Button({ + label: _("Modify"), + has_frame: false + }); + modifyButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('modify'); + }); + } + + if(params.changeButton){ + changeButton = new Button({ + icon_name: 'text-editor-symbolic', + }); + changeButton.connect('clicked', () => { + editPopover.popdown(); + this.emit('change'); + }); + } + + let editButton = new Gtk.MenuButton({ + icon_name: 'view-more-symbolic', + popover: editPopover, + }); + + this.attach(editButton, 0, 0, 1, 1); + + let editPopoverBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL + }); + + editPopover.set_child(editPopoverBox); + + let moveUpButton = new Gtk.Button({ + label: _("Move Up"), + has_frame: false + }); + moveUpButton.connect('clicked', ()=> { + this.emit('move-up'); + let index = frameRow.get_index(); + if(index > 0){ + frame.remove(frameRow); + frame.insert(frameRow, index - 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + let moveDownButton = new Gtk.Button({ + label: _("Move Down"), + has_frame: false + }); + moveDownButton.connect('clicked', ()=> { + this.emit('move-down'); + let index = frameRow.get_index(); + if(index + 1 < frame.count) { + frame.remove(frameRow); + frame.insert(frameRow, index + 1); + } + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + + if(params.deleteButton){ + deleteButton = new Gtk.Button({ + label: _("Delete"), + has_frame: false, + }); + deleteButton.connect('clicked', ()=> { + this.emit('delete'); + frame.remove(frameRow); + frame.show(); + buttons.forEach(button => button.set_sensitive(true)); + editPopover.popdown(); + }); + } + + if(params.changeButton){ + this.insert_column(0); + this.attach(Gtk.Separator.new(Gtk.Orientation.VERTICAL), 0, 0, 1, 1); + this.insert_column(0); + this.attach(changeButton, 0, 0, 1, 1); + } + + if(params.modifyButton){ + editPopoverBox.append(modifyButton); + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + } + + editPopoverBox.append(moveUpButton); + editPopoverBox.append(moveDownButton); + + if(params.deleteButton){ + editPopoverBox.append(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)); + editPopoverBox.append(deleteButton); + } + } +}); + +var StackListBox = GObject.registerClass(class Arc_Menu_StackListBox extends Gtk.ListBox{ + _init(widget, params){ + super._init(params); + this.valign = Gtk.Align.FILL; + this.vexpand = true; + this.hexpand = false; + this.settingsFrameStack = widget.settingsFrameStack; + this.settingsListStack = widget.settingsListStack + this.connect("row-selected", (self, row) => { + if(row){ + let stackName = row.stackName; + this.settingsFrameStack.set_visible_child_name(stackName); + if(row.nextPage){ + if(widget.backButton.get_parent()) + widget.leftHeaderBox.remove(widget.backButton); + widget.leftHeaderBox.prepend(widget.backButton); + this.settingsListStack.set_visible_child_name(row.nextPage); + this.settingsListStack.get_child_by_name(row.nextPage).listBox.selectFirstRow(); + } + } + }); + this.scrollWindow = new Gtk.ScrolledWindow({ + valign: Gtk.Align.FILL, + vexpand: true + }); + this.scrollWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.scrollWindow.set_child(this); + this.scrollWindow.listBox = this; + } + + getRowAtIndex(index){ + return this.get_row_at_index(index).get_children()[0]; + } + + getSelectedRow(){ + return this.get_selected_row().get_children()[0]; + } + + selectFirstRow(){ + this.select_row(this.get_row_at_index(0)); + } + + selectRowAtIndex(index){ + this.select_row(this.get_row_at_index(index)); + } + + addRow(name, translateableName, iconName, nextPage){ + let row1 = new Gtk.ListBoxRow(); + this.append(row1); + + let row = new Gtk.Grid({ + margin_top: 12, + margin_bottom: 12, + margin_start: 12, + margin_end: 12, + column_spacing: 10 + }); + row1.set_child(row); + row1.stackName = name; + row1.translateableName = translateableName; + + let image = new Gtk.Image({ + icon_name: iconName + }); + + let label = new Gtk.Label({ + label: translateableName, + halign: Gtk.Align.START, + }); + row.attach(image, 0, 0, 1, 1); + row.attach(label, 1, 0, 1, 1); + + if(nextPage){ + row1.nextPage = nextPage; + let image2 = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + hexpand: true + }); + row.attach(image2, 2, 0, 1, 1); + } + } + + setSeparatorIndices(indexArray){ + this.set_header_func((_row, _before) =>{ + for(let i = 0; i < indexArray.length; i++){ + if(_row.get_index() === indexArray[i]){ + let sep = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL); + sep.show(); + _row.set_header(sep); + + } + } + }); + } +}); + +var TileGrid = GObject.registerClass(class Arc_Menu_TileGrid extends Gtk.FlowBox{ + _init(maxColumns) { + super._init({ + row_spacing: 5, + column_spacing: 5, + vexpand: true, + hexpand: true, + valign: Gtk.Align.CENTER, + halign: Gtk.Align.CENTER, + max_children_per_line: maxColumns, + homogeneous: true, + selection_mode: Gtk.SelectionMode.NONE + }); + } +}); + +var IconGrid = GObject.registerClass(class Arc_Menu_IconGrid extends Gtk.FlowBox{ + _init() { + super._init({ + max_children_per_line: 7, + row_spacing: 10, + column_spacing: 10, + vexpand: true, + hexpand: false, + valign: Gtk.Align.START, + halign: Gtk.Align.CENTER, + homogeneous: true, + selection_mode: Gtk.SelectionMode.SINGLE + }); + this.childrenCount = 0; + } + + add(widget){ + this.insert(widget, -1); + this.childrenCount++; + } +}); + +var Tile = GObject.registerClass(class Arc_Menu_Tile extends FrameBox{ + _init(name, file, width, height, layout) { + super._init({ + hexpand: true, + vexpand: false, + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER + }); + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.orientation = Gtk.Orientation.VERTICAL, + this.activatable = true; + this.name = name; + this.layout = layout; + this._image = new Gtk.Image({ + + gicon: Gio.icon_new_for_string(file), + pixel_size: width + }); + this._label = new Gtk.Label({ label: _(this.name) }); + + this.box._grid.attach(this._image, 0, 0, 1, 1); + this.box._grid.attach(this._label, 0, 1, 1, 1); + this._listBox.append(this.box); + } +}); + +var LayoutTile = GObject.registerClass(class Arc_Menu_LayoutTile extends FrameBox{ + _init(name, file, layout) { + super._init({ + halign: Gtk.Align.FILL, + valign: Gtk.Align.CENTER, + hexpand: true, + vexpand: false + }); + this._listBox.set_selection_mode(Gtk.SelectionMode.NONE); + this.name = name; + this.layout = layout.MENU_TYPE; + + this.box = new FrameBoxRow(); + this.box.activatable = true; + this.box._grid.row_spacing = 0; + this.box._grid.column_spacing = 0; + + this._image = new Gtk.Image({ + hexpand: false, + halign: Gtk.Align.START, + gicon: Gio.icon_new_for_string(file), + pixel_size: 46 + }); + + let titleLabel = new Gtk.Label({ + label: "" + _("%s Menu Layouts", layout.TITLE).format(layout.TITLE) + "", + use_markup: true, + hexpand: true, + halign: Gtk.Align.CENTER, + vexpand: true, + valign: Gtk.Align.CENTER, + wrap: true, + }) + + let goNextImage = new Gtk.Image({ + gicon: Gio.icon_new_for_string('go-next-symbolic'), + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + hexpand: false, + vexpand: false, + }) + + this.box._grid.attach(this._image, 0, 0, 1, 2); + this.box._grid.attach(titleLabel, 1, 0, 1, 1); + this.box._grid.attach(goNextImage, 2, 0, 1, 2); + + this._listBox.append(this.box); + } +}); diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js new file mode 100644 index 0000000..eb51dff --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/recentFilesManager.js @@ -0,0 +1,111 @@ +const { Gtk, Gio, GLib } = imports.gi; +const ExtensionUtils = imports.misc.extensionUtils; +const Main = imports.ui.main; + +const LogEnabled = false; + +var isCanceled = false; +var currentQueries = []; + +var RecentFilesManager = class Arc_Menu_RecentFilesManager { + constructor() { + this._settings = ExtensionUtils.getSettings(); + this._recentManager = new Gtk.RecentManager(); + } + + filterRecentFiles(callback){ + isCanceled = false; + this._recentManager.get_items().sort((a, b) => b.get_modified() - a.get_modified()) + .forEach(item => { + this.queryFileExists(item) + .then(validFile => { + this.debugLog("Valid file - " + validFile.get_display_name()); + if(!isCanceled) + callback(validFile); + }) + .catch(err =>{ + this.debugLog(err); + }); + }); + } + + queryFileExists(item) { + return new Promise((resolve, reject) => { + let file = Gio.File.new_for_uri(item.get_uri()); + let cancellable = new Gio.Cancellable(); + + if(file === null) + reject("Recent file is null. Rejected."); + + //Create and store queryInfo to cancel any active queries when needed + let queryInfo = { + timeOutID: null, + cancellable, + reject, + item + }; + + currentQueries.push(queryInfo); + + file.query_info_async('standard::type,standard::is-hidden', 0, 0, cancellable, (source, res) => { + try { + let fileInfo = source.query_info_finish(res); + this.removeQueryInfoFromList(queryInfo); + if (fileInfo) { + let isHidden = fileInfo.get_attribute_boolean("standard::is-hidden"); + let showHidden = this._settings.get_boolean('show-hidden-recent-files'); + if(isHidden && !showHidden) + reject(item.get_display_name() + " is hidden. Rejected.") + resolve(item); + } + } + catch (err) { + if (err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + this.debugLog("Cancel Called: " + item.get_display_name()); + + this.removeQueryInfoFromList(queryInfo); + reject(err); + } + }); + }); + } + + removeQueryInfoFromList(queryInfo){ + let queryIndex = currentQueries.indexOf(queryInfo); + if(queryIndex !== -1) + currentQueries.splice(queryIndex, 1); + } + + cancelCurrentQueries(){ + if(currentQueries.length === 0) + return; + isCanceled = true; + this.debugLog("Canceling " + currentQueries.length + " queries...") + for(let queryInfo of currentQueries){ + this.debugLog("Cancel query - " + queryInfo.item.get_display_name()); + queryInfo.cancellable.cancel(); + queryInfo.cancellable = null; + queryInfo.reject("Query Canceled"); + } + currentQueries = null; + currentQueries = []; + this.debugLog("Cancel Finished"); + } + + debugLog(message){ + if (!LogEnabled) + return; + else log(message); + } + + getRecentManager(){ + return this._recentManager; + } + + destroy(){ + this.cancelCurrentQueries(); + this._settings = null; + this._recentManager = null; + } +} + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled new file mode 100644 index 0000000..473fe73 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/gschemas.compiled differ diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml new file mode 100644 index 0000000..9638cb6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/schemas/org.gnome.shell.extensions.arcmenu.gschema.xml @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 50 + Menu position alignment + Menu position alignment 0 = Left, 50 = Center, 100 = Right + + + 'Default' + menu layout + Menu Layout + + + 'Off' + Force the menu to a specific location + Force the menu to a specific location + + + false + disable hotkey on key release + disable hotkey on key release. + + + false + show ArcMenu on primary monitor when using hotkey + show ArcMenu on primary monitor when using hotkey. + + + false + show standalone Runner menu on primary monitor when using hotkey + show standalone Runner menu monitor when using hotkey. + + + 875 + ArcMenu Settings Width + ArcMenu Settings Width. + + + 725 + ArcMenu Settings Height + ArcMenu Settings Height. + + + [true, false, false] + Keeps track of available placement for ArcMenu. [Main Panel, Dash to Panel, Dash to Dock] + false = not avaliable, true = avaliable + + + "Panel" + Embed ArcMenu button into Dash instead of panel + Embed ArcMenu button into Dash instead of panel + + + 'Left' + Raven layout position. 'Left' or 'Right' side of screen + Raven layout position. 'Left' or 'Right' side of screen. + + + true + Enable Weather Widget raven layout + Enable Weather Widget raven layout. + + + true + Enable Clocks Widget raven layout + Enable Clocks Widget raven layout. + + + false + Enable Weather Widget Unity layout + Enable Weather Widget Unity layout. + + + false + Enable Clocks Widget Unity layout + Enable Clocks Widget Unity layout. + + + false + Enable Category Sub Menus + Enable Category Sub Menus. + + + 'Full_Color' + Category icon type. Full_Color or Symbolic + Category icon type. Full_Color or Symbolic + + + 'Symbolic' + Shortcut icon type. Full_Color or Symbolic + Shortcut icon type. Full_Color or Symbolic + + + false + disable the fade effect on scrollviews + ddisable the fade effect on scrollviews (may help improve performace) + + + false + Show a larger icon and extra app details + Show a larger icon and extra app details. + + + 5 + The amount of search results to display. + The amount of search results to display. + + + false + Highlight search results terms + Highlight search results terms. + + + false + Show search result description label + Show search result description label. + + + false + Show custom search provider - open windows + Show custom search provider - open windows. + + + false + Show custom search provider - recent files + Show custom search provider - recent files. + + + false + Show hidden recent files + Show hidden recent files. + + + false + Activate Categories on Hover + Activate Categories on Hover. + + + false + disable recently installed apps + disable recently installed apps. + + + false + disable tooltips + disable tooltips. + + + true + Separate All Programs by a Character Listing + Separate All Programs by a Character Listing. + + + true + Multi-lined labels for large icon application grid layouts + Multi-lined labels for large icon application grid layouts. + + + 'Pinned_Apps' + Set ArcMenu Layout Default View + Set ArcMenu Layout Default View. + + + 'Categories_List' + Set Tognee Layout Default View + Set Tognee Layout Default View. + + + true + Set Unity layout to display "Home Screen" as default + Set Unity layout to display "Home Screen" as default. False = Show all Apps + + + false + Remove the themes menu arrow and displacement + Remove the themes menu arrow and displacement + + + false + Remove border around the searchbox + Remove border around the searchbox + + + false + Disable the user avatar icon from the menu + Disable the user avatar icon from the menu + + + false + Enable an Activitities Overview Shortcut + Enable an Activitities Overview Shortcut + + + 'Bottom' + Searchbar location for layouts with default searchbar on bottom + Searchbar location for layouts with default searchbar on bottom + + + 'Top' + Searchbar location for layouts with default searchbar on top + Searchbar location for layouts with default searchbar on top + + + false + Flip menu horizontally + Flip menu horizontally + + + false + Windows layout - disable frequent apps + Windows layout - disable frequent apps + + + false + Windows layout - disable pinned apps + Windows layout - disable pinned apps + + + false + GNOME Dash Layout - Show Applications + GNOME Dash Layout - Show Applications + + + "rgb(61, 174, 235)" + Plasma Selected Item Color + Plasma Selected Item Color. + + + "rgba(245, 245, 245, .05)" + Plasma Selected Item Background Color + Plasma Selected Item Background Color. + + + true + Plasma Menu Hover to activate item + Plasma Menu Hover to activate item. + + + false + Runner layout - show frequent apps + Runner layout - show frequent apps + + + false + Runner layout - use current shell theme gap + Runner layout - use current shell theme gap + + + 400 + Runner layout - menu height + Runner layout - menu height + + + 500 + Runner layout - menu width + Runner layout - menu width + + + 0 + Runner layout - font size + Runner layout - font size + + + false + Eleven Layout - disable frequent apps + Eleven Layout - disable frequent apps + + + false + Used to reload theme + Used to reload theme. + + + false + Enable a vertical separator + Enable a vertical separator. + + + "rgb(32,32,32)" + Separator Color + Separator Color. + + + "rgba(53,53,53,0.987)" + Menu Background Color + Menu Background Color. + + + "rgb(223,223,223)" + Menu Foreground Color + Menu Foreground Color. + + + "rgb(32,32,32)" + Border Color + Border Color. + + + "rgb(21,83,158)" + Highlight/Active Menu Item Background Color + Highlight/Active Menu Item Background Color. + + + "rgba(255,255,255,1)" + Highlight/Active Menu Item Foreground Color + Highlight/Active Menu Item Foreground Color. + + + 9 + Menu font size + Menu font size. + + + 1 + Menu border size + Menu border size. + + + 5 + Menu corner radius + Menu corner radius. + + + 24 + Menu margin + Menu margin. + + + 12 + Menu arrow size + Menu arrow size. + + + 550 + Menu Height + Menu Height. + + + 290 + Menu width + Menu width. + + + 0 + Menu Width Adjustement. + Menu Width Adjustement. 0 Default. A negative value decreses the default width, positive increases width. + + + 205 + Right Panel width + Right Panel width. + + + 0 + Gap Adjustment + Gap Adjustment + + + "rgb(41, 165, 249)" + Recently Installed Application Inidcator Color + Recently Installed Application Inidcator Color.. + + + "rgba(196, 196, 196, 0.3)" + Recently Installed Application Inidcator Text Background Color + Recently Installed Application Inidcator Text Background Color.. + + + false + Enable Custom ArcMenu Theme + Enable Custom ArcMenu Theme. + + + false + Enable Custom ArcMenu Layout + Enable Custom ArcMenu Layout. + + + false + Show External Devices + Show External Devices. + + + false + Show Bookmarks + Show Bookmarks. + + + [(0, true), (1, true), (2, true), (3, true), (4, false), (5, false), (6, false)] + Power Options + See Constants.js PowerOptions + + + false + Display on all monitors + Display the menu on all monitors when using Dash to Panel. + + + 'Default' + Activities hotcorner action + Activities hotcorner action. + + + false + Override action of activities hot corner + Override action of activities hot corner. + + + false + Show/Hide Activities Button in panel + Show/Hide Activities Button in panel. + + + "sh -c 'notify-send \"$(date)\"'" + Custom hot corner terminal command + Custom hot corner terminal command. + + + 'Undefined' + Set a hotkey to open ArcMenu + Set a hotkey to open ArcMenu. + + + ["<Super>x"] + Custom keybind to open ArcMenu + Custom keybind to open ArcMenu. + + + false + Enable a standalone Runner menu. + Enable a standalone Runner menu. + + + 'Custom' + Set a hotkey to open the standalone Runner menu. + Set a hotkey to open the standalone Runner menu. + + + ["<Alt>1"] + Keybinding to open the standalone runner menu + Keybinding to open the standalone runner menu. + + + 'Left' + The menu position in the panel + The menu position in the panel. + + + 'Top' + Runner Menu Position + Runner Menu Position. + + + 'Icon' + Appearance of the menu button. + Appearance of the menu button. + + + 'Circular' + Appearance of the avatar icon. + Appearance of the avatar icon. + + + false + Enables the default menu button arrow. + Enables the default menu button arrow. + + + 'Default' + Size of the menu items icon. + Size of the menu items icon. Includes all application items, category items, search results. + + + 'Default' + Size of the menu grid icons. + Size of the menu grid icon. + + + 'Default' + Size of the button items in ArcMenu. + Size of the button items in ArcMenu. Includes all buttons inside the menu + + + 'Default' + Size of misc items in ArcMenu. + Size of misc items in ArcMenu. Includes searchbox icons, back menu item, all applications menu item, usermenu item. + + + 'Default' + Size of quicklink items in ArcMenu. + Size of quicklink items in ArcMenu. Includes places, shortcuts, external devices, bookmarks. + + + 'Applications' + Text of the menu button. + Text of the menu button. + + + 'Arc_Menu_Icon' + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + 0 + Icon of the menu button. + Icon of the menu button. + + + '' + File path of the custom icon for the menu button. + File path of the custom icon for the menu button. + + + 20 + Size of the icon in percentage. + Size of the icon in percentage. + + + -1 + Menu Button Padding. + Menu Button Padding. + + + 0 + Menu button position offset for main panel + Menu button position offset for main panel + + + false + Override border radius styling of the menu button + Override border radius of the menu button. + + + 0 + The border radius size of the menu button + The border radius size of the menu button. + + + 'rgb(240,240,240)' + Color for the menu button icon + Color for the menu button icon. + + + false + Allows changing the menu button icon color + Allows changing the menu button icon color. + + + 'rgb(240,240,240)' + Active color for the menu button icon + Active color for the menu button icon. + + + false + Allows changing the menu button icon active color + Allows changing the menu button icon active color. + + + 'rgb(214,214,214)' + Hover color for the menu button icon + Hover color for the menu button icon. + + + false + Allows changing the menu button icon hover color + Allows changing the menu button icon hover color. + + + 'rgba(238,238,236,0.1)' + Hover background color for the menu button icon + Hover background color for the menu button icon. + + + false + Allows changing the menu button hover background color + Allows changing the menu button hover background color. + + + 'rgba(238,238,236,0.18)' + Active background color for the menu button icon + Active background color for the menu button icon. + + + false + Allows changing the menu button active background color + Allows changing the menu button active background color. + + + [(0, true), (1, true), (2, false), (3, false), (4, false)] + Array of extra categories. See Constants.js - Categories + Array of extra categories. See Constants.js - Categories + + + [(0, false), (1, false), (2, false), (3, false), (4, false)] + Array of extra categories links for ArcMenu layout. See Constants.js - Categories + Array of extra categories for ArcMenu layout. See Constants.js - Categories + + + 'Bottom' + Display extra categories quick links on ArcMenu Layout home page + Display extra categories quick links on ArcMenu Layout home page + + + [] + List of recently installed apps + List of recently installed apps + + + [ "ArcMenu_WebBrowser","WebBrowser", "WebBrowser", + "Files", "", "org.gnome.Nautilus.desktop", + "Terminal", "", "org.gnome.Terminal.desktop", + "ArcMenu Settings", "ArcMenu_ArcMenuIcon", "gnome-extensions prefs arcmenu@arcmenu.com" + ] + + List of Apps Pinned to Menu + List of Apps Pinned to Menu + + + false + Toggle for enabling custom shortcuts. + Toggle for enabling custom shortcuts. + + + [["Home","ArcMenu_Home", "ArcMenu_Home"], ["Documents","ArcMenu_Documents", "ArcMenu_Documents"],["Downloads","ArcMenu_Downloads", "ArcMenu_Downloads"], + ["Music","ArcMenu_Music", "ArcMenu_Music"],["Pictures","ArcMenu_Pictures", "ArcMenu_Pictures"],["Videos","ArcMenu_Videos", "ArcMenu_Videos"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [["Software","system-software-install-symbolic", "ArcMenu_Software"], ["Settings","preferences-system-symbolic", "gnome-control-center.desktop"], + ["Tweaks","org.gnome.tweaks-symbolic", "org.gnome.tweaks.desktop"],["Terminal","utilities-terminal-symbolic", "org.gnome.Terminal.desktop"], + ["Activities Overview", "view-fullscreen-symbolic", "ArcMenu_ActivitiesOverview"]] + List of default directory paths used for links on the right side of ArcMenu + List of default directory paths used for links on the right side of ArcMenu. + + + [] + List of Unity Layout Pinned Apps + List of Uniity Layout Pinned Apps + + + 5 + Index of Unity Layout Pinned App Separator + Index of Unity Layout Pinned App Separator, 0 = none + + + ["Software","system-software-install-symbolic", "ArcMenu_Software", "Settings","preferences-system-symbolic", "gnome-control-center.desktop"] + List of Brisk Layout Shortcuts + List of Brisk Layout Shortcuts + + + [] + List of Mint Layout Pinned Apps + List of Mint Layout Pinned Apps + + + 5 + Index of Mint Layout Pinned App Separator + Index of Mint Layout Pinned App Separator, 0 = none + + + [['ArcMenu Style', 'rgba(53,53,53,0.987)', 'rgb(223,223,223)', 'rgb(32,32,32)', 'rgb(21,83,158)', 'rgba(255,255,255,1)', 'rgb(32,32,32)', '9', '1', '5', '12', '24', 'false'], + ['Simply Dark', 'rgba(28, 28, 28, 0.98)', 'rgba(211, 218, 227, 1)', 'rgb(63,62,64)', 'rgba(238, 238, 236, 0.1)', 'rgba(255,255,255,1)', 'rgb(63,62,64)', '9', '0', '0', '0', '0', 'false'], + ['Dark Blue Theme', 'rgb(25,31,34)', 'rgb(189,230,251)', 'rgb(41,50,55)', 'rgb(41,50,55)', 'rgba(255,255,255,1)', 'rgb(41,50,55)', '9', '1', '5', '12', '24', 'true'], + ['Light Blue Theme', 'rgb(255,255,255)', 'rgb(51,51,51)', 'rgb(235,235,235)', 'rgba(189,230,251,0.9)', 'rgba(89,89,89,1)', 'rgba(189,230,251,0.9)', '9', '1', '5', '12', '24', 'true']] + List of color-themes + List of color themes. + + + + 0 + Handles which page to open in ArcMenu Settings + See Constants.js PrefsVisiblePage + + + diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/search.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/search.js new file mode 100644 index 0000000..9085c77 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/search.js @@ -0,0 +1,872 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + * + * Credits: This file leverages the work from GNOME Shell search.js file + * (https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/search.js) + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const {Clutter, Gio, GLib, GObject, Shell, St } = imports.gi; +const AppDisplay = imports.ui.appDisplay; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const MW = Me.imports.menuWidgets; +const PopupMenu = imports.ui.popupMenu; +const { RecentFilesManager } = Me.imports.recentFilesManager; +const RemoteSearch = imports.ui.remoteSearch; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +const { OpenWindowSearchProvider } = Me.imports.searchProviders.openWindows; +const { RecentFilesSearchProvider } = Me.imports.searchProviders.recentFiles; + +const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers'; + +var ListSearchResult = GObject.registerClass(class Arc_Menu_ListSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']); + + super._init(menulayout, app, Constants.DisplayType.LIST, metaInfo) + + this.app = app; + let layoutProperties = this._menuLayout.layoutProperties; + this.searchType = layoutProperties.SearchDisplayType; + this.metaInfo = metaInfo; + this.provider = provider; + this._settings = this._menuLayout._settings; + this.resultsView = resultsView; + this.layout = this._settings.get_enum('menu-layout'); + + if(this.provider.id === 'org.gnome.Nautilus.desktop' || this.provider.id === 'arcmenu.recent-files') + this._path = this.metaInfo['description']; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.metaInfo['description'] && this.provider.appInfo.get_id() === 'org.gnome.Calculator.desktop' && !showSearchResultDescriptions) + this.label.text = this.metaInfo['name'] + " " + this.metaInfo['description']; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var AppSearchResult = GObject.registerClass(class Arc_Menu_AppSearchResult extends MW.ApplicationMenuItem{ + _init(provider, metaInfo, resultsView) { + let menulayout = resultsView._menuLayout; + let app = appSys.lookup_app(metaInfo['id']) || appSys.lookup_app(provider.id); + let displayType = menulayout.layoutProperties.SearchDisplayType; + super._init(menulayout, app, displayType, metaInfo); + this.app = app; + this.provider = provider; + this.metaInfo = metaInfo; + this.resultsView = resultsView; + + if(!this.app && this.metaInfo['description']) + this.description = this.metaInfo['description'].split('\n')[0]; + + let highlightSearchResultTerms = this._settings.get_boolean('highlight-search-result-terms'); + if(highlightSearchResultTerms){ + this._termsChangedId = this.resultsView.connect('terms-changed', this._highlightTerms.bind(this)); + this._highlightTerms(); + } + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._termsChangedId) { + this.resultsView.disconnect(this._termsChangedId); + this._termsChangedId = null; + } + } + + _highlightTerms() { + let showSearchResultDescriptions = this._settings.get_boolean("show-search-result-details"); + if(this.descriptionLabel && showSearchResultDescriptions){ + let descriptionMarkup = this.resultsView.highlightTerms(this.descriptionLabel.text.split('\n')[0]); + this.descriptionLabel.clutter_text.set_markup(descriptionMarkup); + } + + let labelMarkup = this.resultsView.highlightTerms(this.label.text.split('\n')[0]); + this.label.clutter_text.set_markup(labelMarkup); + } +}); + +var SearchResultsBase = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResultsBase extends St.BoxLayout { + _init(provider, resultsView) { + super._init({ vertical: true }); + this.provider = provider; + this.resultsView = resultsView; + this._menuLayout = resultsView._menuLayout; + this._terms = []; + + this._resultDisplayBin = new St.Bin({ + x_expand: true, + y_expand: true + }); + + this.add_child(this._resultDisplayBin); + + this._resultDisplays = {}; + this._clipboard = St.Clipboard.get_default(); + + this._cancellable = new Gio.Cancellable(); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + this._terms = []; + } + + _createResultDisplay(meta) { + if (this.provider.createResultObject) + return this.provider.createResultObject(meta, this.resultsView); + + return null; + } + + clear() { + this._cancellable.cancel(); + for (let resultId in this._resultDisplays) + this._resultDisplays[resultId].destroy(); + this._resultDisplays = {}; + this._clearResultDisplay(); + this.hide(); + } + + _setMoreCount(count) { + } + + _ensureResultActors(results, callback) { + let metasNeeded = results.filter( + resultId => this._resultDisplays[resultId] === undefined + ); + + if (metasNeeded.length === 0) { + callback(true); + } else { + this._cancellable.cancel(); + this._cancellable.reset(); + + this.provider.getResultMetas(metasNeeded, metas => { + if (this._cancellable.is_cancelled()) { + if (metas.length > 0) + log(`Search provider ${this.provider.id} returned results after the request was canceled`); + callback(false); + return; + } + if (metas.length != metasNeeded.length) { + log('Wrong number of result metas returned by search provider ' + this.provider.id + + ': expected ' + metasNeeded.length + ' but got ' + metas.length); + callback(false); + return; + } + if (metas.some(meta => !meta.name || !meta.id)) { + log('Invalid result meta returned from search provider ' + this.provider.id); + callback(false); + return; + } + + metasNeeded.forEach((resultId, i) => { + let meta = metas[i]; + let display = this._createResultDisplay(meta); + this._resultDisplays[resultId] = display; + }); + callback(true); + }, this._cancellable); + } + } + + updateSearch(providerResults, terms, callback) { + this._terms = terms; + if (providerResults.length == 0) { + this._clearResultDisplay(); + this.hide(); + callback(); + } else { + let maxResults = this._getMaxDisplayedResults(); + let results = this.provider.filterResults(providerResults, maxResults); + let moreCount = Math.max(providerResults.length - results.length, 0); + + this._ensureResultActors(results, successful => { + if (!successful) { + this._clearResultDisplay(); + callback(); + return; + } + + // To avoid CSS transitions causing flickering when + // the first search result stays the same, we hide the + // content while filling in the results. + this.hide(); + this._clearResultDisplay(); + results.forEach(resultId => { + this._addItem(this._resultDisplays[resultId]); + }); + + this._setMoreCount(this.provider.canLaunchSearch ? moreCount : 0); + this.show(); + callback(); + }); + } + } +}); + +var ListSearchResults = GObject.registerClass( +class ArcMenu_ListSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._menuLayout = resultsView._menuLayout; + this.searchType = this._menuLayout.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._container = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + x_expand: true, + y_expand: true, + }); + + if(this.searchType === Constants.DisplayType.GRID){ + this.add_style_class_name('margin-box'); + } + + this.providerInfo = new ArcSearchProviderInfo(provider, this._menuLayout); + this.providerInfo.connect('activate', () => { + if (provider.canLaunchSearch) { + provider.launchSearch(this._terms); + this._menuLayout.arcMenu.toggle(); + } + }); + + this._container.add_child(this.providerInfo); + + this._content = new St.BoxLayout({ + vertical: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + + this._container.add_child(this._content); + this._resultDisplayBin.set_child(this._container); + } + + _setMoreCount(count) { + this.providerInfo.setMoreCount(count); + } + + _getMaxDisplayedResults() { + return this._settings.get_int('max-search-results'); + } + + _clearResultDisplay() { + this._content.remove_all_children(); + } + + _createResultDisplay(meta) { + return super._createResultDisplay(meta, this.resultsView) || + new ListSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + if(display.get_parent()) + display.get_parent().remove_child(display); + this._content.add_child(display); + } + + getFirstResult() { + if (this._content.get_n_children() > 0) + return this._content.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var AppSearchResults = GObject.registerClass( +class ArcMenu_AppSearchResults extends SearchResultsBase { + _init(provider, resultsView) { + super._init(provider, resultsView); + this._parentContainer = resultsView; + this._menuLayout = resultsView._menuLayout; + this._settings = this._menuLayout._settings; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this.layout = this._menuLayout._settings.get_enum('menu-layout'); + + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + + this.rtl = this._menuLayout.mainBox.get_text_direction() == Clutter.TextDirection.RTL; + + let layout = new Clutter.GridLayout({ + orientation: Clutter.Orientation.VERTICAL, + column_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.ColumnSpacing : 0, + row_spacing: this.searchType === Constants.DisplayType.GRID ? this.layoutProperties.RowSpacing : 0, + }); + this._grid = new St.Widget({ + x_expand: true, + x_align: this.searchType === Constants.DisplayType.LIST ? Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, + layout_manager: layout + }); + layout.hookup_style(this._grid); + + if(this.searchType === Constants.DisplayType.GRID){ + let spacing = this.layoutProperties.ColumnSpacing; + + this._grid.style = "padding: 0px 0px 10px 0px; spacing: " + spacing + "px;"; + this._resultDisplayBin.x_align = Clutter.ActorAlign.CENTER; + } + + this._resultDisplayBin.set_child(this._grid); + } + + _getMaxDisplayedResults() { + let maxDisplayedResults; + if(this.searchType === Constants.DisplayType.GRID) + maxDisplayedResults = this._menuLayout.getColumnsFromGridIconSizeSetting(); + else + maxDisplayedResults = this._settings.get_int('max-search-results'); + return maxDisplayedResults; + } + + _clearResultDisplay() { + this.itemCount = 0; + this.gridTop = -1; + this.gridLeft = 0; + this._grid.remove_all_children(); + } + + _createResultDisplay(meta) { + return new AppSearchResult(this.provider, meta, this.resultsView); + } + + _addItem(display) { + const GridColumns = this.searchType === Constants.DisplayType.LIST ? 1 : this._menuLayout.getColumnsFromGridIconSizeSetting(); + if(!this.rtl && (this.itemCount % GridColumns === 0)){ + this.gridTop++; + this.gridLeft = 0; + } + else if(this.rtl && (this.gridLeft === 0)){ + this.gridTop++; + this.gridLeft = GridColumns; + } + this._grid.layout_manager.attach(display, this.gridLeft, this.gridTop, 1, 1); + display.gridLocation = [this.gridLeft, this.gridTop]; + + if(!this.rtl) + this.gridLeft++; + else if(this.rtl) + this.gridLeft--; + this.itemCount++; + } + + getFirstResult() { + if (this._grid.get_n_children() > 0) + return this._grid.get_child_at_index(0)._delegate; + else + return null; + } +}); + +var SearchResults = GObject.registerClass({ + Signals: { 'terms-changed': {}, + 'have-results': {}, + 'no-results': {} }, +}, class ArcMenu_SearchResults extends St.BoxLayout { + _init(menuLayout) { + super._init({ + vertical: true, + y_expand: true, + x_expand: true, + x_align: Clutter.ActorAlign.FILL + }); + this._menuLayout = menuLayout; + this.layoutProperties = this._menuLayout.layoutProperties; + this.searchType = this.layoutProperties.SearchDisplayType; + this._settings = this._menuLayout._settings; + this.layout = this._settings.get_enum('menu-layout'); + + this._content = new St.BoxLayout({ + vertical: true, + x_align: Clutter.ActorAlign.FILL + }); + + this.add_child(this._content); + + this._statusText = new St.Label(); + this._statusBin = new St.Bin({ + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER, + x_expand: true, + y_expand: true + }); + + if(menuLayout._settings.get_boolean('enable-custom-arc-menu')) + this._statusText.style_class = 'arc-menu-status-text'; + else + this._statusText.style_class = ''; + + this.add_child(this._statusBin); + this._statusBin.set_child(this._statusText); + + this._highlightDefault = true; + this._defaultResult = null; + this._startingSearch = false; + + this._terms = []; + this._results = {}; + + this._providers = []; + + this._highlightRegex = null; + + this.recentFilesManager = new RecentFilesManager(); + + this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA }); + this.disabledID = this._searchSettings.connect('changed::disabled', this._reloadRemoteProviders.bind(this)); + this.enabledID = this._searchSettings.connect('changed::enabled', this._reloadRemoteProviders.bind(this)); + this.disablExternalID = this._searchSettings.connect('changed::disable-external', this._reloadRemoteProviders.bind(this)); + this.sortOrderID = this._searchSettings.connect('changed::sort-order', this._reloadRemoteProviders.bind(this)); + + this._searchTimeoutId = null; + this._cancellable = new Gio.Cancellable(); + + this._registerProvider(new AppDisplay.AppSearchProvider()); + + this.installChangedID = appSys.connect('installed-changed', this._reloadRemoteProviders.bind(this)); + + this._reloadRemoteProviders(); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + get terms() { + return this._terms; + } + + setStyle(style){ + if(this._statusText){ + this._statusText.style_class = style; + } + } + + _onDestroy(){ + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + if(this.disabledID){ + this._searchSettings.disconnect(this.disabledID); + this.disabledID = null; + } + if(this.enabledID){ + this._searchSettings.disconnect(this.enabledID); + this.enabledID = null; + } + if(this.disablExternalID){ + this._searchSettings.disconnect(this.disablExternalID); + this.disablExternalID = null; + } + if(this.sortOrderID){ + this._searchSettings.disconnect(this.sortOrderID); + this.sortOrderID = null; + } + if(this.installChangedID){ + appSys.disconnect(this.installChangedID); + this.installChangedID = null; + } + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + this.recentFilesManager.destroy(); + this.recentFilesManager = null; + + this._content.destroy_all_children(); + } + + _reloadRemoteProviders() { + let currentTerms = this._terms; + //cancel any active search + if (this._terms.length !== 0) + this._reset(); + + this._oldProviders = null; + let remoteProviders = this._providers.filter(p => p.isRemoteProvider); + + remoteProviders.forEach(provider => { + this._unregisterProvider(provider); + }); + + if(this._settings.get_boolean('search-provider-open-windows')) + this._registerProvider(new OpenWindowSearchProvider()); + if(this._settings.get_boolean('search-provider-recent-files')) + this._registerProvider(new RecentFilesSearchProvider(this.recentFilesManager)); + + RemoteSearch.loadRemoteSearchProviders(this._searchSettings, providers => { + providers.forEach(this._registerProvider.bind(this)); + }); + + //restart any active search + if(currentTerms.length > 0) + this.setTerms(currentTerms); + } + + _registerProvider(provider) { + provider.searchInProgress = false; + this._providers.push(provider); + this._ensureProviderDisplay(provider); + } + + _unregisterProvider(provider) { + let index = this._providers.indexOf(provider); + this._providers.splice(index, 1); + + if (provider.display){ + provider.display.destroy(); + } + } + + _gotResults(results, provider) { + this._results[provider.id] = results; + this._updateResults(provider, results); + } + + _clearSearchTimeout() { + if (this._searchTimeoutId) { + GLib.source_remove(this._searchTimeoutId); + this._searchTimeoutId = null; + } + } + + _reset() { + this._terms = []; + this._results = {}; + this._clearDisplay(); + this._clearSearchTimeout(); + this._defaultResult = null; + this._startingSearch = false; + + this._updateSearchProgress(); + } + + _doSearch() { + this._startingSearch = false; + + let previousResults = this._results; + this._results = {}; + + this._providers.forEach(provider => { + provider.searchInProgress = true; + + let previousProviderResults = previousResults[provider.id]; + if (this._isSubSearch && previousProviderResults) + provider.getSubsearchResultSet(previousProviderResults, + this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + else + provider.getInitialResultSet(this._terms, + results => { + this._gotResults(results, provider); + }, + this._cancellable); + }); + + this._updateSearchProgress(); + + this._clearSearchTimeout(); + } + + _onSearchTimeout() { + this._searchTimeoutId = null; + this._doSearch(); + return GLib.SOURCE_REMOVE; + } + + setTerms(terms) { + // Check for the case of making a duplicate previous search before + // setting state of the current search or cancelling the search. + // This will prevent incorrect state being as a result of a duplicate + // search while the previous search is still active. + let searchString = terms.join(' '); + let previousSearchString = this._terms.join(' '); + if (searchString == previousSearchString) + return; + + this._startingSearch = true; + + this.recentFilesManager.cancelCurrentQueries(); + + this._cancellable.cancel(); + this._cancellable.reset(); + + if (terms.length == 0) { + this._reset(); + return; + } + + let isSubSearch = false; + if (this._terms.length > 0) + isSubSearch = searchString.indexOf(previousSearchString) == 0; + + this._terms = terms; + this._isSubSearch = isSubSearch; + this._updateSearchProgress(); + + if (this._searchTimeoutId === null) + this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, this._onSearchTimeout.bind(this)); + + + + const escapedTerms = terms + .map(term => Shell.util_regex_escape(term)) + .filter(term => term.length > 0); + + if (escapedTerms.length === 0) + return; + + this._highlightRegex = new RegExp('(%s)'.format( + escapedTerms.join('|')), 'gi'); + + this.emit('terms-changed'); + } + + _ensureProviderDisplay(provider) { + if (provider.display) + return; + + let providerDisplay; + if (provider.appInfo) + providerDisplay = new ListSearchResults(provider, this); + else + providerDisplay = new AppSearchResults(provider, this); + providerDisplay.hide(); + this._content.add_child(providerDisplay); + provider.display = providerDisplay; + } + + _clearDisplay() { + this._providers.forEach(provider => { + provider.display.clear(); + }); + } + + _maybeSetInitialSelection() { + let newDefaultResult = null; + + let providers = this._providers; + for (let i = 0; i < providers.length; i++) { + let provider = providers[i]; + let display = provider.display; + + if (!display.visible) + continue; + + let firstResult = display.getFirstResult(); + if (firstResult) { + newDefaultResult = firstResult; + break; // select this one! + } + } + + if (newDefaultResult !== this._defaultResult) { + this._setSelected(this._defaultResult, false); + this._setSelected(newDefaultResult, this._highlightDefault); + + this._defaultResult = newDefaultResult; + } + } + + get searchInProgress() { + if (this._startingSearch) + return true; + + return this._providers.some(p => p.searchInProgress); + } + + _updateSearchProgress() { + let haveResults = this._providers.some(provider => { + let display = provider.display; + return (display.getFirstResult() != null); + }); + + this._statusBin.visible = !haveResults; + if (haveResults) + this.emit("have-results") + else if (!haveResults) { + if (this.searchInProgress) + this._statusText.set_text(_("Searching...")); + else + this._statusText.set_text(_("No results.")); + + this.emit("no-results") + } + } + + _updateResults(provider, results) { + let terms = this._terms; + let display = provider.display; + display.updateSearch(results, terms, () => { + provider.searchInProgress = false; + + this._maybeSetInitialSelection(); + this._updateSearchProgress(); + }); + } + + highlightDefault(highlight) { + this._highlightDefault = highlight; + this._setSelected(this._defaultResult, highlight); + } + + getTopResult(){ + return this._defaultResult; + } + + getProviders(){ + return this._providers; + } + + setProvider(providerID){ + if(!this._oldProviders) + this._oldProviders = this._providers; + this._clearDisplay(); + this._providers = this._oldProviders; + if(providerID === Constants.CategoryType.ALL_PROGRAMS){ + this._providers = this._providers.filter(p => (p.appInfo ? false : true)); + } + else if(providerID !== Constants.CategoryType.SEARCH_RESULTS){ + this._providers = this._providers.filter(p => (p.appInfo ? p.appInfo.get_id() : p) === providerID); + } + } + + _setSelected(result, selected) { + if(!result) + return; + + if(selected) + result.add_style_pseudo_class('active'); + else + result.remove_style_pseudo_class('active'); + } + + hasActiveResult(){ + return (this._defaultResult ? true : false) && this._highlightDefault; + } + + highlightTerms(text) { + if (!this._highlightRegex) + return GLib.markup_escape_text(text, -1); + + let escaped = []; + let lastMatchEnd = 0; + let match; + while ((match = this._highlightRegex.exec(text))) { + if (match.index > lastMatchEnd) { + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd, match.index), -1); + escaped.push(unmatched); + } + let matched = GLib.markup_escape_text(match[0], -1); + escaped.push('%s'.format(matched)); + lastMatchEnd = match.index + match[0].length; + } + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd), -1); + escaped.push(unmatched); + + return escaped.join(''); + } +}); + +var ArcSearchProviderInfo = GObject.registerClass(class Arc_Menu_ArcSearchProviderInfo extends MW.ArcMenuPopupBaseMenuItem{ + _init(provider, menuLayout) { + super._init(menuLayout); + this.provider = provider; + this._menuLayout = menuLayout; + this._settings = this._menuLayout._settings; + + this.description = this.provider.appInfo.get_description(); + if(this.description) + this.description = this.description.split('\n')[0]; + + this.label = new St.Label({ + text: provider.appInfo.get_name(), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER, + style: 'text-align: left;' + }); + + this.label.style = 'font-weight: bold;'; + this.style = "padding: 10px 0px;"; + this.add_child(this.label); + + this._moreText = ""; + } + + setMoreCount(count) { + this._moreText = ngettext("%d more", "%d more", count).format(count); + + if(count > 0) + this.label.text = this.provider.appInfo.get_name() + " (" + this._moreText + ")"; + else + this.label.text = this.provider.appInfo.get_name(); + } +}); diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js new file mode 100644 index 0000000..933a1e6 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/openWindows.js @@ -0,0 +1,93 @@ +const { Meta, Gio, St, Shell } = imports.gi; + +const Main = imports.ui.main; +const { getWindows } = imports.ui.altTab; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(app, size) { + return app + ? app.create_icon_texture(size) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var OpenWindowSearchProvider = class { + constructor() { + this.id = 'arcmenu.open-windows'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + + this._appWindows = []; + this._windowTracker = Shell.WindowTracker.get_default(); + + this.appInfo = { + get_description: () => _('List of open windows across all workspaces'), + get_name: () => _('Open Windows'), + get_id: () => 'arcmenu.open-windows', + get_icon: () => Gio.icon_new_for_string('focus-windows-symbolic'), + } + } + + getResultMetas(winIds, callback) { + const metas = winIds.map(winId => { + const aw = this._getAppWindow(winId); + return aw ? { + id: winId, + name: aw.window.title ?? aw.app.get_name(), + description: aw.window.get_workspace() ? _("'%s' on Workspace %d").format(aw.app.get_name(), aw.window.get_workspace().index() + 1) : aw.app.get_name(), + createIcon: (size) => createIcon(aw.app, size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this._appWindows = getWindows(null).map(window => { + return { + window, + app: this._windowTracker.get_window_app(window), + } + }); + + callback(this._getFilteredWindowIds(terms, this._appWindows)); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const appWindows = previousResults.map(winId => this._getAppWindow(winId)).filter(aw => aw !== undefined); + callback(this._getFilteredWindowIds(terms, appWindows)); + } + + activateResult(winId, _terms) { + const window = this._getAppWindow(winId)?.window; + if (window) + Main.activateWindow(window); + } + + launchSearch() { + + } + + _getFilteredWindowIds(terms, appWindows) { + terms = terms.map(term => term.toLowerCase()); + appWindows = appWindows.filter(aw => { + const title = aw.window.title?.toLowerCase(); + const appName = aw.app.get_name()?.toLowerCase(); + const appDescription = aw.app.get_description()?.toLowerCase(); + return terms.some(term => title?.includes(term) || appName?.includes(term) || appDescription?.includes(term)); + }); + + return appWindows.map(aw => aw.window.get_id().toString()); + } + + _getAppWindow(winId) { + winId = typeof winId === "string" ? parseInt(winId) : winId; + return this._appWindows.find(aw => aw.window.get_id() === winId); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js new file mode 100644 index 0000000..fb595e4 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/searchProviders/recentFiles.js @@ -0,0 +1,100 @@ +const { Meta, Gtk, Gio, GLib, St, Shell } = imports.gi; + +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +function createIcon(mimeType, size) { + let symbolicIcon = mimeType ? Gio.content_type_get_symbolic_icon(mimeType)?.to_string() : null; + return symbolicIcon + ? new St.Icon({ gicon: Gio.icon_new_for_string(symbolicIcon), icon_size: size }) + : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); +} + +var RecentFilesSearchProvider = class { + constructor(recentFilesManager) { + this.id = 'arcmenu.recent-files'; + this.isRemoteProvider = true; + this.canLaunchSearch = false; + this.recentFilesManager = recentFilesManager; + this._recentFiles = []; + + this.appInfo = { + get_description: () => _('Recent Files'), + get_name: () => _('Recent Files'), + get_id: () => 'arcmenu.recent-files', + get_icon: () => Gio.icon_new_for_string('document-open-recent-symbolic'), + } + } + + getResultMetas(fileUris, callback) { + const metas = fileUris.map(fileUri => { + const rf = this._getRecentFile(fileUri); + const file = Gio.File.new_for_uri(rf.get_uri()); + return rf ? { + id: fileUri, + name: rf.get_display_name(), + description: file.get_parent()?.get_path(), // can be null + createIcon: (size) => createIcon(rf.get_mime_type(), size), + } : undefined; + }).filter(m => m?.name !== undefined && m?.name !== null); + + callback(metas); + } + + filterResults(results, maxNumber) { + return results.slice(0, maxNumber); + } + + getInitialResultSet(terms, callback, _cancellable) { + this.recentFilesManager.cancelCurrentQueries(); + this._recentFiles = []; + this.recentFilesManager.filterRecentFiles(recentFile => { + this._recentFiles.push(recentFile); + callback(this._getFilteredFileUris(terms, this._recentFiles)); + }); + } + + getSubsearchResultSet(previousResults, terms, callback, _cancellable) { + const recentFiles = previousResults.map(fileUri => this._getRecentFile(fileUri)).filter(rf => rf !== undefined); + callback(this._getFilteredFileUris(terms, recentFiles)); + } + + activateResult(fileUri, _terms) { + const recentFile = this._getRecentFile(fileUri); + if (recentFile){ + let context = global.create_app_launch_context(0, -1); + + new Promise((resolve, reject) => { + Gio.AppInfo.launch_default_for_uri_async(recentFile.get_uri(), context, null, (o, res) => { + try { + Gio.AppInfo.launch_default_for_uri_finish(res); + resolve(); + } catch (e) { + Main.notifyError(_('Failed to open “%s”').format(recentFile.get_display_name()), e.message); + reject(e); + } + }); + }); + } + } + + launchSearch() { + } + + _getFilteredFileUris(terms, recentFiles) { + terms = terms.map(term => term.toLowerCase()); + recentFiles = recentFiles.filter(rf => { + const fileName = rf.get_display_name()?.toLowerCase(); + return terms.some(term => fileName?.includes(term)); + }); + + return recentFiles.map(rf => rf.get_uri()); + } + + _getRecentFile(fileUri) { + return this._recentFiles.find(rf => rf.get_uri() === fileUri); + } +} diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js new file mode 100644 index 0000000..6c0613d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/standaloneRunner.js @@ -0,0 +1,376 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const {Clutter, GLib, Shell, St} = imports.gi; +const appSys = Shell.AppSystem.get_default(); +const Constants = Me.imports.constants; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Utils = Me.imports.utils; +const _ = Gettext.gettext; + +var StandaloneRunner = class Arc_Menu_StandaloneRunner{ + constructor(settings) { + this._settings = settings; + + this.tooltipShowing = false; + this.tooltipHidingID = null; + this.tooltipShowingID = null; + this.dtpNeedsRelease = false; + + this.dummyWidget = new St.Widget({ width: 0, height: 0, opacity: 0 }); + Main.uiGroup.add_child(this.dummyWidget); + + //Create Main Menus - ArcMenu and arcMenu's context menu + this.arcMenu = new ArcMenu(this.dummyWidget, 0.5, St.Side.TOP, this); + this.arcMenu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); + + this.menuManager = new PopupMenu.PopupMenuManager(Main.panel); + this.menuManager._changeMenu = (menu) => {}; + this.menuManager.addMenu(this.arcMenu); + + if(!this.rise){ + let themeNode = this.arcMenu.actor.get_theme_node(); + this.rise = themeNode.get_length('-arrow-rise'); + } + + let rect = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryMonitor.index); + + //Position the runner menu in the center of the current monitor, at top of screen. + let positionX = Math.round(rect.x + (rect.width / 2)); + let positionY = rect.y + this.rise; + this.dummyWidget.set_position(positionX, positionY); + + //Context Menus for applications and other menu items + this.contextMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.contextMenuManager._changeMenu = (menu) => {}; + this.contextMenuManager._onMenuSourceEnter = (menu) =>{ + if (this.contextMenuManager.activeMenu && this.contextMenuManager.activeMenu != menu) + return Clutter.EVENT_STOP; + + return Clutter.EVENT_PROPAGATE; + } + + //Sub Menu Manager - Control all other popup menus + this.subMenuManager = new PopupMenu.PopupMenuManager(this.dummyWidget); + this.subMenuManager._changeMenu = (menu) => {}; + } + + initiate(){ + this.initiateRecentlyInstalledApps(); + + //Create Basic Layout + this.createLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.createLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + initiateRecentlyInstalledApps(){ + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this._settings.get_boolean('disable-recently-installed-apps')) + return; + + this._appList = this.listAllApps(); + //Update Categories on 'installed-changed' event------------------------------------- + this._installedChangedId = appSys.connect('installed-changed', () => { + this._newAppList = this.listAllApps(); + + //Filter to find if a new application has been installed + let newApps = this._newAppList.filter(app => !this._appList.includes(app)); + + //A New Application has been installed + //Save it in settings + if(newApps.length){ + let recentApps = this._settings.get_strv('recently-installed-apps'); + let newRecentApps = [...new Set(recentApps.concat(newApps))]; + this._settings.set_strv('recently-installed-apps', newRecentApps); + this.MenuLayout.reloadApplications(); + } + + this._appList = this._newAppList; + }); + } + + listAllApps(){ + let appList = appSys.get_installed().filter(appInfo => { + try { + appInfo.get_id(); // catch invalid file encodings + } catch (e) { + return false; + } + return appInfo.should_show(); + }); + return appList.map(app => app.get_id()); + } + + createMenuLayout(){ + this._forcedMenuLocation = false; + this.arcMenu.actor.style = null; + this.arcMenu.removeAll(); + this.section = new PopupMenu.PopupMenuSection(); + this.arcMenu.addMenuItem(this.section); + this.mainBox = new St.BoxLayout({ + vertical: false, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL + }); + this.mainBox._delegate = this.mainBox; + this.section.actor.add_child(this.mainBox); + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + reloadMenuLayout(){ + this._forcedMenuLocation = false; + + this.MenuLayout.destroy(); + this.MenuLayout = null; + + this.arcMenu.actor.style = null; + + const StandaloneRunner = true; + this.MenuLayout = Utils.getMenuLayout(this, Constants.MenuLayout.RUNNER, StandaloneRunner); + + this.updateStyle(); + + if(this.arcMenu.isOpen){ + if(this.MenuLayout.activeMenuItem) + this.MenuLayout.activeMenuItem.active = true; + else + this.mainBox.grab_key_focus(); + } + } + + updateStyle(){ + let customStyle = this._settings.get_boolean('enable-custom-arc-menu'); + + this.arcMenu.actor.set_style_class_name(null); + this.arcMenu.actor.style_class = customStyle ? 'arc-menu-boxpointer': 'popup-menu-boxpointer'; + this.arcMenu.actor.add_style_class_name(customStyle ? 'arc-menu' : 'popup-menu'); + + if(this.MenuLayout) + this.MenuLayout.updateStyle(); + } + + toggleMenu(){ + if(this.contextMenuManager.activeMenu) + this.contextMenuManager.activeMenu.toggle(); + if(this.subMenuManager.activeMenu) + this.subMenuManager.activeMenu.toggle(); + + if(!this.arcMenu.isOpen){ + this.MenuLayout.updateLocation(); + this.arcMenu.toggle(); + if(this.arcMenu.isOpen) + this.mainBox.grab_key_focus(); + } + else if(this.arcMenu.isOpen){ + this.arcMenu.toggle(); + } + } + + getActiveMenu(){ + if(this.contextMenuManager.activeMenu) + return this.contextMenuManager.activeMenu; + else if(this.subMenuManager.activeMenu) + return this.subMenuManager.activeMenu; + else if(this.arcMenu.isOpen) + return this.arcMenu; + else + return null; + } + + destroy(){ + if(this.createLayoutID){ + GLib.source_remove(this.createLayoutID); + this.createLayoutID = null; + } + + if(this.updateMenuLayoutID){ + GLib.source_remove(this.updateMenuLayoutID); + this.updateMenuLayoutID = null; + } + + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + + if(this._installedChangedId){ + appSys.disconnect(this._installedChangedId); + this._installedChangedId = null; + } + + if(this.MenuLayout) + this.MenuLayout.destroy(); + if(this.arcMenu) + this.arcMenu.destroy(); + if(this.dummyWidget){ + Main.uiGroup.remove_child(this.dummyWidget); + this.dummyWidget.destroy(); + } + } + + updateMenuLayout(){ + this.tooltipShowing = false; + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + if(this.MenuLayout){ + this.MenuLayout.destroy(); + this.MenuLayout = null; + } + this.updateMenuLayoutID = GLib.timeout_add(0, 100, () => { + this.createMenuLayout(); + this.updateMenuLayoutID = null; + return GLib.SOURCE_REMOVE; + }); + } + + loadExtraPinnedApps(){ + if(this.MenuLayout) + this.MenuLayout.loadExtraPinnedApps(); + } + + updateLocation(){ + if(this.MenuLayout) + this.MenuLayout.updateLocation(); + } + + displayPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.displayPinnedApps(); + } + + loadPinnedApps() { + if(this.MenuLayout) + this.MenuLayout.loadPinnedApps(); + } + + reload(){ + if(this.MenuLayout){ + this.reloadMenuLayout(); + } + } + + shouldLoadPinnedApps(){ + if(this.MenuLayout) + return this.MenuLayout.shouldLoadPinnedApps; + } + + setDefaultMenuView(){ + if(this.MenuLayout) + this.MenuLayout.setDefaultMenuView(); + } + + _onOpenStateChanged(menu, open) { + if(open){ + if(Main.panel.menuManager && Main.panel.menuManager.activeMenu) + Main.panel.menuManager.activeMenu.toggle(); + } + else{ + if(!this.arcMenu.isOpen){ + if (this.tooltipShowingID) { + GLib.source_remove(this.tooltipShowingID); + this.tooltipShowingID = null; + } + this.tooltipShowing = false; + if(this.activeTooltip){ + this.activeTooltip.hide(); + } + + if (this.tooltipHidingID) { + GLib.source_remove(this.tooltipHidingID); + this.tooltipHidingID = null; + } + } + } + } +}; + +var ArcMenu = class Arc_Menu_ArcMenu extends PopupMenu.PopupMenu{ + constructor(sourceActor, arrowAlignment, arrowSide, standaloneRunner) { + super(sourceActor, arrowAlignment, arrowSide); + this._settings = sourceActor._settings; + this.standaloneRunner = standaloneRunner; + Main.uiGroup.add_child(this.actor); + this.actor.hide(); + this._boxPointer.set_offscreen_redirect(Clutter.OffscreenRedirect.ON_IDLE); + this._menuClosedID = this.connect('menu-closed', () => this.standaloneRunner.setDefaultMenuView()); + this.connect('destroy', () => this._onDestroy()); + } + + open(animate){ + if(!this.isOpen) + this.standaloneRunner.arcMenu.actor._muteInput = false; + super.open(animate); + } + + close(animate){ + if(this.isOpen){ + if(this.standaloneRunner.contextMenuManager.activeMenu) + this.standaloneRunner.contextMenuManager.activeMenu.toggle(); + if(this.standaloneRunner.subMenuManager.activeMenu) + this.standaloneRunner.subMenuManager.activeMenu.toggle(); + } + + super.close(animate); + } + + _onDestroy(){ + if(this._menuClosedID){ + this.disconnect(this._menuClosedID) + this._menuClosedID = null; + } + } +}; diff --git a/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/utils.js b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/utils.js new file mode 100644 index 0000000..92207b5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/arcmenu@arcmenu.com/utils.js @@ -0,0 +1,687 @@ +/* + * ArcMenu - A traditional application menu for GNOME 3 + * + * ArcMenu Lead Developer and Maintainer + * Andrew Zaech https://gitlab.com/AndrewZaech + * + * ArcMenu Founder, Former Maintainer, and Former Graphic Designer + * LinxGem33 https://gitlab.com/LinxGem33 - (No Longer Active) + * + * 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 2 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 . + */ +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Constants = Me.imports.constants; +const {Gio, GLib} = imports.gi; + +const PowerManagerInterface = ` + + + + + + + + + + + + + + +`; +const PowerManager = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface); + +function canHibernate(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHibernate = needsAuth || result[0] === 'yes'; + asyncCallback(canHibernate, needsAuth); + } + }); +} + +function activateHibernate(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHibernateRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hibernate Error!"), _("System unable to hibernate.")); + else{ + proxy.HibernateRemote(true); + } + }); +} + +function canHybridSleep(asyncCallback){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error) + asyncCallback(false, false); + else{ + let needsAuth = result[0] === 'challenge'; + let canHybridSleep = needsAuth || result[0] === 'yes'; + asyncCallback(canHybridSleep, needsAuth); + } + }); +} + +function activateHybridSleep(){ + let proxy = new PowerManager(Gio.DBus.system, 'org.freedesktop.login1', '/org/freedesktop/login1'); + proxy.CanHybridSleepRemote((result, error) => { + if(error || result[0] !== 'yes') + imports.ui.main.notifyError(_("ArcMenu - Hybrid Sleep Error!"), _("System unable to hybrid sleep.")); + else{ + proxy.HybridSleepRemote(true); + } + }); +} + +function getMenuLayout(menuButton, layout, isStandaloneRunner){ + let MenuLayout = Me.imports.menulayouts; + switch(layout){ + case Constants.MenuLayout.ARCMENU: + return new MenuLayout.arcmenu.createMenu(menuButton); + case Constants.MenuLayout.BRISK: + return new MenuLayout.brisk.createMenu(menuButton); + case Constants.MenuLayout.WHISKER: + return new MenuLayout.whisker.createMenu(menuButton); + case Constants.MenuLayout.GNOME_MENU: + return new MenuLayout.gnomemenu.createMenu(menuButton); + case Constants.MenuLayout.MINT: + return new MenuLayout.mint.createMenu(menuButton); + case Constants.MenuLayout.GNOME_OVERVIEW: + return null; + case Constants.MenuLayout.ELEMENTARY: + return new MenuLayout.elementary.createMenu(menuButton); + case Constants.MenuLayout.REDMOND: + return new MenuLayout.redmond.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE: + return new MenuLayout.simple.createMenu(menuButton); + case Constants.MenuLayout.SIMPLE_2: + return new MenuLayout.simple2.createMenu(menuButton); + case Constants.MenuLayout.UNITY: + return new MenuLayout.unity.createMenu(menuButton); + case Constants.MenuLayout.BUDGIE: + return new MenuLayout.budgie.createMenu(menuButton); + case Constants.MenuLayout.INSIDER: + return new MenuLayout.insider.createMenu(menuButton); + case Constants.MenuLayout.RUNNER: + return new MenuLayout.runner.createMenu(menuButton, isStandaloneRunner); + case Constants.MenuLayout.CHROMEBOOK: + return new MenuLayout.chromebook.createMenu(menuButton); + case Constants.MenuLayout.RAVEN: + return new MenuLayout.raven.createMenu(menuButton); + case Constants.MenuLayout.TOGNEE: + return new MenuLayout.tognee.createMenu(menuButton); + case Constants.MenuLayout.PLASMA: + return new MenuLayout.plasma.createMenu(menuButton); + case Constants.MenuLayout.WINDOWS: + return new MenuLayout.windows.createMenu(menuButton); + case Constants.MenuLayout.LAUNCHER: + return new MenuLayout.launcher.createMenu(menuButton); + case Constants.MenuLayout.ELEVEN: + return new MenuLayout.eleven.createMenu(menuButton); + case Constants.MenuLayout.AZ: + return new MenuLayout.az.createMenu(menuButton); + default: + return new MenuLayout.arcmenu.createMenu(menuButton); + } +} + +function getSettings(schema, extensionUUID) { + let extension = imports.ui.main.extensionManager.lookup(extensionUUID); + + if (!extension) + throw new Error('ArcMenu - getSettings() unable to find extension'); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Expect USER extensions to have a schemas/ subfolder, otherwise assume a + // SYSTEM extension that has been installed in the same prefix as the shell + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error(`Schema ${schema} could not be found for extension ${extension.metadata.uuid}. Please check your installation`); + + return new Gio.Settings({ settings_schema: schemaObj }); +} + +function convertToGridLayout(item){ + const Clutter = imports.gi.Clutter; + const settings = item._settings; + const layoutProperties = item._menuLayout.layoutProperties; + + let icon = item._icon ? item._icon : item._iconBin; + + item.vertical = true; + if(item._ornamentLabel) + item.remove_child(item._ornamentLabel); + + item.tooltipLocation = Constants.TooltipLocation.BOTTOM_CENTERED; + item.label.x_align = item.label.y_align = Clutter.ActorAlign.CENTER; + item.label.y_expand = true; + + icon.y_align = Clutter.ActorAlign.CENTER; + icon.y_expand = true; + if(settings.get_boolean('multi-lined-labels')){ + icon.y_align = Clutter.ActorAlign.TOP; + icon.y_expand = false; + + let clutterText = item.label.get_clutter_text(); + clutterText.set({ + line_wrap: true, + line_wrap_mode: imports.gi.Pango.WrapMode.WORD_CHAR, + }); + } + + if(item._indicator){ + item.remove_child(item._indicator); + item.insert_child_at_index(item._indicator, 0); + item._indicator.x_align = Clutter.ActorAlign.CENTER; + item._indicator.y_align = Clutter.ActorAlign.START; + item._indicator.y_expand = false; + } + + const iconSizeEnum = settings.get_enum('menu-item-grid-icon-size'); + let defaultIconStyle = layoutProperties.DefaultIconGridStyle; + + iconSize = getGridIconStyle(iconSizeEnum, defaultIconStyle); + item.name = iconSize; +} + +function getIconSize(iconSizeEnum, defaultIconSize){ + const IconSizeEnum = iconSizeEnum; + let iconSize = defaultIconSize; + if(IconSizeEnum === Constants.IconSize.DEFAULT) + iconSize = defaultIconSize; + else if(IconSizeEnum === Constants.IconSize.EXTRA_SMALL) + iconSize = Constants.EXTRA_SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.SMALL) + iconSize = Constants.SMALL_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.MEDIUM) + iconSize = Constants.MEDIUM_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.LARGE) + iconSize = Constants.LARGE_ICON_SIZE; + else if(IconSizeEnum === Constants.IconSize.EXTRA_LARGE) + iconSize = Constants.EXTRA_LARGE_ICON_SIZE; + + return iconSize; +} + +function getGridIconSize(iconSizeEnum, defaultIconStyle){ + let iconSize; + if(iconSizeEnum === Constants.GridIconSize.DEFAULT){ + Constants.GridIconInfo.forEach((info) => { + if(info.NAME === defaultIconStyle){ + iconSize = info.ICON_SIZE; + } + }); + } + else + iconSize = Constants.GridIconInfo[iconSizeEnum - 1].ICON_SIZE; + + return iconSize; +} + +function getGridIconStyle(iconSizeEnum, defaultIconStyle){ + const IconSizeEnum = iconSizeEnum; + let iconStyle = defaultIconStyle; + if(IconSizeEnum === Constants.GridIconSize.DEFAULT) + iconStyle = defaultIconStyle; + else if(IconSizeEnum === Constants.GridIconSize.SMALL) + iconStyle = 'SmallIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM) + iconStyle = 'MediumIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE) + iconStyle = 'LargeIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.SMALL_RECT) + iconStyle = 'SmallRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.MEDIUM_RECT) + iconStyle = 'MediumRectIconGrid'; + else if(IconSizeEnum === Constants.GridIconSize.LARGE_RECT) + iconStyle = 'LargeRectIconGrid'; + + return iconStyle; +} + +function getCategoryDetails(currentCategory, categoryIconType){ + let name, gicon, iconName, fallbackIconName; + for(let entry of Constants.Categories){ + if(entry.CATEGORY === currentCategory){ + name = entry.NAME; + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + iconName = entry.FULL_COLOR_ICON; + else + iconName = entry.ICON; + return [name, gicon, iconName, fallbackIconName]; + } + } + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + name = _("Home Screen"); + gicon = Gio.icon_new_for_string(Me.path + '/media/icons/menu_icons/homescreen-symbolic.svg'); + return [name, gicon, iconName, fallbackIconName]; + } + else{ + name = currentCategory.get_name(); + if(categoryIconType === Constants.CategoryIconType.FULL_COLOR) + gicon = currentCategory.get_icon() ? currentCategory.get_icon() : null; + else + iconName = currentCategory.get_icon().to_string() + "-symbolic"; + fallbackIconName = currentCategory.get_icon() ? currentCategory.get_icon().to_string() : null; + return [name, gicon, iconName, fallbackIconName]; + } +} + +function activateCategory(currentCategory, menuLayout, menuItem, extraParams = false){ + if(currentCategory === Constants.CategoryType.HOME_SCREEN){ + menuLayout.activeCategory = _("Pinned Apps"); + menuLayout.displayPinnedApps(); + } + else if(currentCategory === Constants.CategoryType.PINNED_APPS) + menuLayout.displayPinnedApps(); + else if(currentCategory === Constants.CategoryType.FREQUENT_APPS){ + menuLayout.setFrequentAppsList(menuItem); + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + } + else if(currentCategory === Constants.CategoryType.ALL_PROGRAMS) + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + else if(currentCategory === Constants.CategoryType.RECENT_FILES) + menuLayout.displayRecentFiles(); + else + menuLayout.displayCategoryAppList(menuItem.appList, currentCategory, extraParams ? menuItem : null); + + menuLayout.activeCategoryType = currentCategory; +} + +function getMenuButtonIcon(settings, path){ + let iconType = settings.get_enum('menu-button-icon'); + + if(iconType === Constants.MenuIcon.CUSTOM){ + if(path && GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else if(iconType === Constants.MenuIcon.DISTRO_ICON){ + let iconEnum = settings.get_int('distro-icon'); + path = Me.path + Constants.DistroIcons[iconEnum].PATH; + if(Constants.DistroIcons[iconEnum].PATH === 'start-here-symbolic') + return 'start-here-symbolic'; + else if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + else{ + let iconEnum = settings.get_int('arc-menu-icon'); + path = Me.path + Constants.MenuIcons[iconEnum].PATH; + if(GLib.file_test(path, GLib.FileTest.IS_REGULAR)) + return path; + } + + global.log("ArcMenu Error - Failed to set menu button icon. Set to System Default."); + return 'start-here-symbolic'; +} + +function findSoftwareManager(){ + let softwareManager = null; + let appSys = imports.gi.Shell.AppSystem.get_default(); + + for(let softwareManagerID of Constants.SoftwareManagerIDs){ + if(appSys.lookup_app(softwareManagerID)){ + softwareManager = softwareManagerID; + break; + } + } + + return softwareManager; +} + +function createXpmImage(color1, color2, color3, color4){ + let width = 42; + let height = 14; + let colors = 5; + let xpm = [width + " " + height + " " + colors + " " + 1, "1 c " + rgbStringToHex(color1), "2 c " + rgbStringToHex(color2), + "3 c " + rgbStringToHex(color3), "4 c " + rgbStringToHex(color4), "x c #AAAAAA"]; + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + for(let i = 0; i < height - 2; i++) + xpm.push("x1111111111222222222233333333334444444444x"); + xpm.push("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + return xpm; +} + +function areaOfTriangle(p1, p2, p3){ + return Math.abs((p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1])) / 2.0); +} + +function ensureActorVisibleInScrollView(actor) { + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2; + + let parent = actor.get_parent(); + while (!(parent instanceof imports.gi.St.ScrollView)) { + if (!parent) + return; + + box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + parent = parent.get_parent(); + } + + let adjustment = parent.vscroll.adjustment; + let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values(); + + let offset = 0; + let vfade = parent.get_effect("fade"); + if (vfade) + offset = vfade.fade_margins.top; + + if (y1 < value + offset) + value = Math.max(0, y1 - offset); + else if (y2 > value + pageSize - offset) + value = Math.min(upper, y2 + offset - pageSize); + else + return; + adjustment.set_value(value); +} + +function getArraysEqual(a, b) { + if(a instanceof Array && b instanceof Array){ + if (a.length !== b.length) + return false; + for(let i = 0; i < a.length; i++) + if (!getArraysEqual(a[i], b[i])) + return false; + return true; + } + else + return a === b; +} + +function createTooltip(button, widget, titleLabel, description, displayType){ + let lbl = titleLabel.clutter_text; + lbl.get_allocation_box(); + let isEllipsized = lbl.get_layout().is_ellipsized(); + if(displayType !== Constants.DisplayType.BUTTON && (isEllipsized || description)){ + let titleText, descriptionText; + if(isEllipsized && description){ + titleText = titleLabel.text.replace(/\n/g, " "); + descriptionText = description; + } + else if(isEllipsized && !description) + titleText = titleLabel.text.replace(/\n/g, " "); + else if(!isEllipsized && description) + descriptionText = description; + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, descriptionText); + widget.tooltip._onHover(); + } + else if(displayType === Constants.DisplayType.BUTTON){ + let titleText = titleLabel.text.replace(/\n/g, " "); + widget.tooltip = new Me.imports.menuWidgets.Tooltip(button, widget.actor, titleText, null); + widget.tooltip.location = Constants.TooltipLocation.TOP_CENTERED; + widget.tooltip._onHover(); + } +} + +function getDashToPanelPosition(settings, index){ + var positions = null; + var side; + + try{ + positions = JSON.parse(settings.get_string('panel-positions')) + } catch(e){ + log('Error parsing Dash to Panel positions: ' + e.message); + } + + if(!positions) + side = settings.get_string('panel-position'); + else{ + side = positions[index]; + } + + if (side === 'TOP') + return imports.gi.St.Side.TOP; + else if (side === 'RIGHT') + return imports.gi.St.Side.RIGHT; + else if (side === 'BOTTOM') + return imports.gi.St.Side.BOTTOM; + else if (side === 'LEFT') + return imports.gi.St.Side.LEFT; + else + return imports.gi.St.Side.BOTTOM; +} + +function getStylesheet(){ + let stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + + if(!stylesheet.query_exists(null)){ + GLib.spawn_command_line_sync("mkdir " + GLib.get_home_dir() + "/.local/share/arcmenu"); + GLib.spawn_command_line_sync("touch " + GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + stylesheet = Gio.File.new_for_path(GLib.get_home_dir() + "/.local/share/arcmenu/stylesheet.css"); + } + + return stylesheet; +} + +function rgbStringToHex(colorString) { + let [r, g, b, a_] = parseRgbString(colorString) + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); +} + +function clutterColorToRGBA(color) { + return `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`; +} + +function parseRgbString(colorString){ + if(colorString.includes('rgba')) + colorString = colorString.replace('rgba(',''); + if(colorString.includes('rgb')) + colorString = colorString.replace('rgb(',''); + colorString = colorString.replace(')',''); + let rgbaColor = colorString.split(","); + + let r = parseFloat(rgbaColor[0]); + let g = parseFloat(rgbaColor[1]); + let b = parseFloat(rgbaColor[2]); + let a; + if(rgbaColor[3] != undefined) + a = parseFloat(rgbaColor[3]); + else + a = 1; + return [r, g, b, a]; +} + +function modifyColorLuminance(colorString, luminanceFactor, overrideAlpha){ + let Clutter = imports.gi.Clutter; + let color = Clutter.color_from_string(colorString)[1]; + let [hue, lum, sat] = color.to_hls(); + let modifiedLum = lum; + + if(lum >= .85) //if lum is too light, force darken + modifiedLum = Math.min((1 - Math.abs(luminanceFactor)) * modifiedLum, 1); + else if(lum <= .15) //if lum is too dark, force lighten + modifiedLum = Math.max((1 - Math.abs(luminanceFactor)) * modifiedLum, 0); + else if(luminanceFactor >= 0) //otherwise, darken or lighten based on luminanceFactor + modifiedLum = Math.min((1 + luminanceFactor) * modifiedLum, 1); + else + modifiedLum = Math.max((1 + luminanceFactor) * modifiedLum, 0); + + let alpha = (color.alpha / 255).toPrecision(3); + if(overrideAlpha) + alpha = overrideAlpha; + + let modifiedColor = Clutter.color_from_hls(hue, modifiedLum, sat); + + return `rgba(${modifiedColor.red}, ${modifiedColor.green}, ${modifiedColor.blue}, ${alpha})` +} + +function createStylesheet(settings){ + let customarcMenu = settings.get_boolean('enable-custom-arc-menu'); + let separatorColor = settings.get_string('separator-color'); + let menuColor = settings.get_string('menu-color'); + let menuForegroundColor = settings.get_string('menu-foreground-color'); + let borderColor = settings.get_string('border-color'); + let highlightColor = settings.get_string('highlight-color'); + let highlightForegroundColor = settings.get_string('highlight-foreground-color'); + let fontSize = settings.get_int('menu-font-size'); + let borderSize = settings.get_int('menu-border-size'); + let cornerRadius = settings.get_int('menu-corner-radius'); + let menuMargin = settings.get_int('menu-margin'); + let menuArrowSize = settings.get_int('menu-arrow-size'); + let leftPanelWidth = settings.get_int('menu-width'); + let leftPanelWidthSmall = settings.get_int('menu-width') - 65; + let rightPanelWidth = settings.get_int('right-panel-width'); + let rightPanelWidthPlus45 = settings.get_int('right-panel-width') + 45; + let rightPanelWidthPlus70 = settings.get_int('right-panel-width') + 70; + let avatarStyle = settings.get_enum('avatar-style'); + let avatarRadius = avatarStyle == 0 ? 999 : 0; + let menuButtonColor = settings.get_string('menu-button-color'); + let menuButtonHoverColor = settings.get_string('menu-button-hover-color'); + let menuButtonActiveColor = settings.get_string('menu-button-active-color'); + let menuButtonHoverBackgroundcolor = settings.get_string('menu-button-hover-backgroundcolor'); + let menuButtonActiveBackgroundcolor = settings.get_string('menu-button-active-backgroundcolor'); + let gapAdjustment = settings.get_int('gap-adjustment'); + let indicatorColor = settings.get_string('indicator-color'); + let indicatorTextBackgroundColor = settings.get_string('indicator-text-color'); + let plasmaSelectedItemColor = settings.get_string('plasma-selected-color'); + let plasmaSelectedItemBackgroundColor = settings.get_string('plasma-selected-background-color'); + let plasmaSearchBarTop = settings.get_enum('searchbar-default-top-location'); + let menuButtonBorderRadius = settings.get_int('menu-button-border-radius'); + let tooltipStyle, separatorColorStyle = "\n", smallButtonHoverStyle = "\n"; + let plasmaButtonStyle = plasmaSearchBarTop === Constants.SearchbarLocation.TOP ? 'border-top-width: 2px;' : 'border-bottom-width: 2px;'; + if(customarcMenu){ + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\nbox-shadow: 0 0 1px 0px " + separatorColor + ";\nfont-size:" + fontSize + "pt;\npadding: 3px 8px;\nmin-height: 0px;" + + "\ncolor:" + menuForegroundColor+ ";\nbackground-color:" + modifyColorLuminance(menuColor, 0.05, 1) + ";\nmax-width:550px;\n}\n\n"; + separatorColorStyle = ".separator-color-style{\nbackground-color: " + separatorColor + ";\n}\n\n"; + smallButtonHoverStyle = ".arc-menu .popup-menu-item .arcmenu-small-button.selected{\nbackground-color: " + modifyColorLuminance(highlightColor, -0.25) + "\n}\n\n"; + } + else + tooltipStyle = ".tooltip-menu-item{\nborder-radius: 8px;\npadding: 3px 8px;\nmax-width:550px;\nmin-height: 0px;\n}\n\n"; + + let menuButtonStyle = ''; + if(settings.get_boolean('override-menu-button-color')) + menuButtonStyle += ".arc-menu-icon, .arc-menu-text, .arc-menu-arrow{\ncolor: " + menuButtonColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover{\nbackground-color: " + menuButtonHoverBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-hover-color')) + menuButtonStyle += ".arc-menu-panel-menu:hover .arc-menu-icon, .arc-menu-panel-menu:hover .arc-menu-text" + +", .arc-menu-panel-menu:hover .arc-menu-arrow{\ncolor: " + menuButtonHoverColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-color')) + menuButtonStyle += ".arc-menu-icon:active, .arc-menu-text:active, .arc-menu-arrow:active{\ncolor: " + menuButtonActiveColor + ";\n}\n\n"; + if(settings.get_boolean('override-menu-button-active-background-color')) + menuButtonStyle += ".arc-menu-panel-menu:active{\nbackground-color: " + menuButtonActiveBackgroundcolor + ";\n}\n\n"; + if(settings.get_boolean('menu-button-override-border-radius')){ + let border = menuButtonBorderRadius === 0 ? 1 : 3; + menuButtonStyle += ".arc-menu-panel-menu{\nborder-radius: " + menuButtonBorderRadius + "px;\nborder: " + border + "px solid transparent;\n}\n\n"; + } + + let iconGridStyle = "\ntext-align: center;\n border-radius: 8px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n"; + + let stylesheetCSS = "#arc-search{\nwidth: " + leftPanelWidth + "px;\n}\n\n" + +".arc-menu-status-text{\ncolor:" + menuForegroundColor + ";\nfont-size:" + fontSize + "pt;\n}\n\n" + +".search-statustext{\nfont-size:11pt;\n}\n\n" + + +"#ExtraLargeIconGrid{\nwidth: 150px;\n height: 150px;" + iconGridStyle + "}\n\n" + + +"#LargeIconGrid{\nwidth: 95px;\n height: 95px;" + iconGridStyle + "}\n\n" + + +"#MediumIconGrid{\nwidth: 87px;\n height: 87px;" + iconGridStyle + "}\n\n" + + +"#SmallIconGrid{\nwidth: 80px;\n height: 80px;" + iconGridStyle + "}\n\n" + + +"#LargeRectIconGrid{\nwidth: 95px;\n height: 85px;" + iconGridStyle + "}\n\n" + + +"#MediumRectIconGrid{\nwidth: 92px;\n height: 78px;" + iconGridStyle + "}\n\n" + + +"#SmallRectIconGrid{\nwidth: 85px;\n height: 70px;" + iconGridStyle + "}\n\n" + + +".left-panel{\nwidth:" + leftPanelWidth + "px;\n}\n\n" + +".left-panel-small{\nwidth:" + leftPanelWidthSmall + "px;\n}\n\n" + +".right-panel{\nwidth:" + rightPanelWidth + "px;\n}\n\n" + +".right-panel-plus45{\nwidth:" + rightPanelWidthPlus45 + "px;\n}\n\n" + +".right-panel-plus70{\nwidth:" + rightPanelWidthPlus70 + "px;\n}\n\n" + +".default-search-entry{\nmax-width: 17.667em;\n}\n\n" + +".arc-search-entry{\nmax-width: 17.667em;\nfont-size:" + fontSize + "pt;\nborder-color:" + separatorColor + ";\nborder-width: 1px;\n" + +"color:" + menuForegroundColor + ";\nbackground-color:" + modifyColorLuminance(menuColor, -0.1, 1) + ";\n}\n\n" + +".arc-search-entry:focus{\nborder-color:" + highlightColor + ";\nborder-width: 1px;\nbox-shadow: inset 0 0 0 1px " + modifyColorLuminance(highlightColor, 0.05) + ";\n}\n\n" + +".arc-search-entry StLabel.hint-text{\ncolor: " + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +"#ArcSearchEntry{\nmin-height: 0px;\nborder-radius: 8px;\nborder-width: 1px;\npadding: 7px 9px;\n}\n\n" + +"#ArcSearchEntryRound{\nmin-height: 0px;\nborder-radius: 18px;\nborder-width: 1px;\npadding: 7px 12px;\n}\n\n" + + menuButtonStyle + +".symbolic-icons{\n-st-icon-style: symbolic;\n}\n\n" + +".regular-icons{\n-st-icon-style: regular;\n}\n\n" + +".arcmenu-menu-item{\nborder-radius: 8px;\n}\n\n" + +".margin-box{\nmargin: 0px 4px;\n}\n\n" + +"#arc-menu-launcher-button{\nmax-width: 90px;\nborder-radius: 0px;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\nborder-color: transparent;\nborder-bottom-width: 3px;\n}\n\n" + +"#arc-menu-launcher-button.active-item, #arc-menu-launcher-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + +"\nborder-color: " + plasmaSelectedItemColor + ";\nborder-bottom-width: 3px;\n}\n\n" + + +"#arc-menu-plasma-button{\nwidth: 90px;\n height: 65px;\nborder-radius: 8px;\n text-align: center;\n padding: 5px;\n spacing: 0px;\n margin: 0px;\n\n" + plasmaButtonStyle + ";\nborder-color: transparent;\n}\n\n" + +"#arc-menu-plasma-button:active-item, .arc-menu-plasma-button:active{\nbackground-color: " + plasmaSelectedItemBackgroundColor + ";\n" + + plasmaButtonStyle + "\nborder-color: " + plasmaSelectedItemColor + ";\n}\n\n" + + +"StScrollView .small-vfade{\n-st-vfade-offset: 44px;\n}\n\n" + + +".arc-menu-button{\n-st-icon-style: symbolic;\nborder-width: 1px;\nborder-radius: 8px;\npadding: 8px;\n}\n\n" + +".arcmenu-small-button{\n-st-icon-style: symbolic;\nborder-radius: 8px;\npadding: 3px 8px;\n}\n\n" + +smallButtonHoverStyle + + +".arc-menu-menu-item-indicator{\ncolor: " + indicatorColor + ";\n}\n\n" + +".arc-menu-menu-item-text-indicator{\nbackground-color: " + indicatorTextBackgroundColor + ";\n}\n\n" + + +tooltipStyle + + +".arc-menu{\n-boxpointer-gap: " + gapAdjustment + "px;\nmin-width: 15em;\ncolor: #D3DAE3;\nborder-image: none;\n" + +"box-shadow: none;\nfont-size:" + fontSize + "pt;\n}\n\n" + +".arc-menu .popup-sub-menu{\npadding-bottom: 1px;\nbackground-color: " + modifyColorLuminance(menuColor, 0.04) + ";\n}\n\n" + +".arc-menu .popup-menu-item{\nspacing: 6px; \nborder: none;\ncolor:" + menuForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:active{\nbackground-color:" + modifyColorLuminance(highlightColor, -0.15) + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item.selected{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:checked{\nbackground-color:" + highlightColor + "; \ncolor: " + highlightForegroundColor + ";\n}\n\n" + +".arc-menu .popup-menu-item:insensitive{\ncolor:" + modifyColorLuminance(menuForegroundColor, 0, 0.6) + ";\n}\n\n" + +".arc-menu-boxpointer{ \n-arrow-border-radius:" + cornerRadius + "px;\n" + +"-arrow-background-color:" + menuColor + ";\n" + +"-arrow-border-color:" + borderColor + ";\n" + +"-arrow-border-width:" + borderSize + "px;\n" + +"-arrow-base:" + menuMargin + "px;\n" + +"-arrow-rise:" + menuArrowSize + "px;\n}\n\n" + +".arc-menu .popup-menu-content{\npadding: 16px 0px;\nmargin: 0;\nbackground-color: transparent;\nborder-radius: 0px;\nbox-shadow: 0;\n}\n\n" + + +".arcmenu-separator{\npadding: 0px;\nheight: 1px;\nmargin: 0px 20px;\n}\n\n" + + separatorColorStyle + +".menu-user-avatar{\nbackground-size: contain;\nborder-radius: " + avatarRadius + "px;\n}\n\n"; + + let stylesheet = getStylesheet(); + if(stylesheet){ + try{ + stylesheet.replace_contents(stylesheetCSS, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + } + catch(e){ + global.log("ArcMenu Error - Failed to update stylesheet. " + e.message); + } + } + else + global.log("ArcMenu Error - Failed to find stylesheet."); +} diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/appfolders.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/appfolders.js new file mode 100644 index 0000000..9548559 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/appfolders.js @@ -0,0 +1,225 @@ +'use strict'; + +const { Shell, GLib, Clutter } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const transparent = Clutter.Color.from_pixel(0x00000000); +const FOLDER_DIALOG_ANIMATION_TIME = 200; +const FRAME_UPDATE_PERIOD = 16; + +let original_zoomAndFadeIn = null; +let original_zoomAndFadeOut = null; +let sigma = 30; +let brightness = 0.6; + +let _zoomAndFadeIn = function () { + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.child.set({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + }); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + effect.sigma = 0; + Utils.ease_property(effect, 'sigma', 0, sigma, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + effect.brightness = 1.0; + Utils.ease_property(effect, 'brightness', 1.0, brightness, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + + this._needsZoomAndFade = false; + + if (this._sourceMappedId === 0) { + this._sourceMappedId = this._source.connect( + 'notify::mapped', this._zoomAndFadeOut.bind(this)); + } +} + +let _zoomAndFadeOut = function () { + if (!this._isOpen) + return; + + if (!this._source.mapped) { + this.hide(); + return; + } + + let [sourceX, sourceY] = + this._source.get_transformed_position(); + let [dialogX, dialogY] = + this.child.get_transformed_position(); + + this.set_background_color(transparent); + + let effect = this.get_effect("appfolder-blur"); + + Utils.ease_property(effect, 'sigma', effect.sigma, 0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + Utils.ease_property(effect, 'brightness', effect.brightness, 1.0, FOLDER_DIALOG_ANIMATION_TIME, FRAME_UPDATE_PERIOD); + + this.child.ease({ + translation_x: sourceX - dialogX, + translation_y: sourceY - dialogY, + scale_x: this._source.width / this.child.width, + scale_y: this._source.height / this.child.height, + opacity: 0, + duration: FOLDER_DIALOG_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this.child.set({ + translation_x: 0, + translation_y: 0, + scale_x: 1, + scale_y: 1, + opacity: 255, + }); + this.hide(); + + this._popdownCallbacks.forEach(func => func()); + this._popdownCallbacks = []; + }, + }); + + this._needsZoomAndFade = false; +} + + +var AppFoldersBlur = class AppFoldersBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + } + + enable() { + this._log("blurring appfolders"); + + if (Main.overview._overview.controls._appDisplay._folderIcons.length > 0) { + this.blur_appfolders(); + } + this.connections.connect(Main.overview._overview.controls._appDisplay, 'view-loaded', () => { + this.blur_appfolders(); + }) + } + + blur_appfolders() { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + icon._ensureFolderDialog(); + + if (original_zoomAndFadeIn == null) { + original_zoomAndFadeIn = icon._dialog._zoomAndFadeIn; + } + if (original_zoomAndFadeOut == null) { + original_zoomAndFadeOut = icon._dialog._zoomAndFadeOut; + } + + let effect = new Shell.BlurEffect({ + name: "appfolder-blur", + sigma: sigma, + brightness: brightness, + mode: 1 + }); + icon._dialog.remove_effect_by_name("appfolder-blur"); + icon._dialog.add_effect(effect); + + // HACK + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("appfolders hack level 1"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("appfolders hack level 2"); + this.paint_signals.disconnect_all(); + + Utils.setTimeout(() => { + this.paint_signals.connect(Main.overview._overview, effect); + this.paint_signals.connect(icon._dialog, effect); + }, 100); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + icon._dialog._viewBox.set_style_class_name('app-folder-dialog transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + + icon._dialog._zoomAndFadeIn = _zoomAndFadeIn; + icon._dialog._zoomAndFadeOut = _zoomAndFadeOut; + }); + } + + set_sigma(s) { + sigma = s; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + set_brightness(b) { + brightness = b; + if (this.prefs.BLUR_APPFOLDERS.get()) + this.blur_appfolders(); + } + + disable() { + this._log("removing blur from appfolders"); + + if (original_zoomAndFadeIn != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeIn = original_zoomAndFadeIn; + }); + } + if (original_zoomAndFadeOut != null) { + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) + icon._dialog._zoomAndFadeOut = original_zoomAndFadeOut; + }); + } + Main.overview._overview.controls._appDisplay._folderIcons.forEach(icon => { + if (icon._dialog) { + icon._dialog.remove_effect_by_name("appfolder-blur") + icon._dialog._viewBox.remove_style_class_name('transparent-app-folder-dialogs-' + 100 * this.prefs.APPFOLDER_DIALOG_OPACITY.get()); + } + }); + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/applications.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/applications.js new file mode 100644 index 0000000..e044464 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/applications.js @@ -0,0 +1,274 @@ +'use strict'; + +const { Shell, Clutter, Meta, GLib } = imports.gi; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; +const BlurMode = Shell.BlurMode; + +var ApplicationsBlur = class ApplicationsBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + + this.windowMap = new Map(); + this.blurActorMap = new Map(); + } + + enable() { + this._log("blurring applications..."); + + // iterate through existing windows and add blur as needed + for (let workspace = 0; workspace < global.workspace_manager.get_n_workspaces(); ++workspace) { + let metaWorkspace = global.workspace_manager.get_workspace_by_index(workspace); + let windows = metaWorkspace.list_windows(); + windows.forEach((meta_window) => { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + }) + } + + // blur every new window + this.connections.connect(global.display, 'window-created', (meta_display, meta_window) => { + this._log("window created"); + if (meta_window) { + let window_actor = meta_window.get_compositor_private(); + this.track_new(window_actor, meta_window); + } + }); + + // workaround for blur being in front of target windows + this.connections.connect(global.display, 'notify::focus-window', () => { + if (this.blurActorMap.size > 0) { + let callbackId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + this.blurActorMap.forEach((blurActor, pid) => { + let actor = this.windowMap.get(pid).get_compositor_private(); + if (actor !== null && actor.get_parent() === blurActor.get_parent()) { + global.window_group.set_child_below_sibling(blurActor, actor); + } + }) + }) + } + }) + } + + // Blurs and add the needed signals to every new tracked window + track_new(window_actor, meta_window) { + // TODO change the pid to a more unique one, to prevent collisions? + let pid = Date.now(); + + window_actor['blur_provider_pid'] = pid; + meta_window['blur_provider_pid'] = pid; + + // remove the blur when the window is destroyed + this.connections.connect(window_actor, 'destroy', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (this.blurActorMap.has(pid)) { + this.remove_blur(pid) + } + }); + + // update the blur when the mutter-hint is changed + this.connections.connect(meta_window, 'notify::mutter-hints', (meta_window) => { + this._log("mutter-hint changed"); + let pid = meta_window.blur_provider_pid; + let window_actor = meta_window.get_compositor_private(); + this.update_blur(window_actor, meta_window, pid) + }); + + this.update_blur(window_actor, meta_window, pid); + } + + // This method is basically a catch-all for blurring windows. It handles the decisions + // to call different methods that handle removing, setting, and updating blur + update_blur(window_actor, meta_window, pid) { + let mutter_hint = meta_window.get_mutter_hints(); + + // check if the window wants blur and update it accordingly + if (mutter_hint != null && mutter_hint.includes("blur-provider")) { + // get blur effect parameters + let sigma = this.parse_sigma_value(mutter_hint); + let brightness = this.prefs.BRIGHTNESS.get(); + + // if the provided sigma value is incorrect + if (sigma == null || sigma < 0 || sigma > 111) { + this._log("sigma value is null or outside of range (0-111), defaulting to extension setting") + sigma = this.prefs.SIGMA.get(); + } + + // check wether the actor is already blurred and act consequently + if (this.blurActorMap.has(pid)) { + if (sigma == 0) { + // actor already blurred, should not be anymore + this.remove_blur(pid); + } else { + // actor already blurred, update it + this.update_blur_effect( + this.blurActorMap.get(pid), + sigma, + brightness + ); + } + } else if (sigma != 0) { + // actor not blurred, blur it + this.set_blur( + pid, + window_actor, + meta_window, + this.create_blur_effect(sigma, brightness) + ) + } + } else if (this.blurActorMap.has(pid)) { + // remove blur if the mutter_hint no longer contains our blur-provider value + this.remove_blur(pid); + } + } + + // Returns a new blur effect + create_blur_effect(sigma, brightness) { + return new Shell.BlurEffect({ + sigma: sigma, + brightness: brightness, + mode: BlurMode.BACKGROUND + }); + } + + // Add the blur effect to the actor + set_blur(pid, window_actor, meta_window, blurEffect) { + let blurActor = this.create_blur_actor(meta_window, window_actor, blurEffect); + + // if hacks are selected, force the repaint the window to prevent artifacts + if (this.prefs.HACKS_LEVEL.get() >= 1) { + this._log("applications hack level 1 or 2"); + this.paint_signals.disconnect_all(); + this.paint_signals.connect(blurActor, blurEffect); + } else { + this.paint_signals.disconnect_all(); + } + + global.window_group.insert_child_below(blurActor, window_actor); + + // registed the blur actor/effect + blurActor['blur_provider_pid'] = pid; + this.blurActorMap.set(pid, blurActor); + this.windowMap.set(pid, meta_window); + + // hide if window become invisible + this.connections.connect(window_actor, 'notify::visible', (window_actor) => { + let pid = window_actor.blur_provider_pid; + if (window_actor.visible) { + this.blurActorMap.get(pid).show(); + } else { + this.blurActorMap.get(pid).hide(); + } + }); + } + + // Returns a new already blurred widget, configured to follow the size and + // position of its target window + create_blur_actor(meta_window, window_actor, blurEffect) { + // create the constraints in size and position to its target window + let frame = meta_window.get_frame_rect(); + let buffer = meta_window.get_buffer_rect(); + + const offsetX = frame.x - buffer.x; + const offsetY = frame.y - buffer.y; + const offsetWidth = buffer.width - frame.width; + const offsetHeight = buffer.height - frame.height; + + let constraintPosX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.X, + offset: offsetX + }); + let constraintPosY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.Y, + offset: offsetY + }); + + let constraintSizeX = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.WIDTH, + offset: -offsetWidth + }); + let constraintSizeY = new Clutter.BindConstraint({ + source: window_actor, + coordinate: Clutter.BindCoordinate.HEIGHT, + offset: -offsetHeight + }); + + // create the actor and add the constraints + let blurActor = new Clutter.Actor(); + blurActor.add_constraint(constraintPosX); + blurActor.add_constraint(constraintPosY); + blurActor.add_constraint(constraintSizeX); + blurActor.add_constraint(constraintSizeY); + + // add the effect + blurActor.add_effect_with_name('blur-effect', blurEffect); + + return blurActor; + } + + // Updates the blur effect by overwriting its sigma and brightness values + update_blur_effect(blur_actor, sigma, brightness) { + let effect = blur_actor.get_effect('blur-effect'); + effect.sigma = sigma; + effect.brightness = brightness; + } + + // Removes the blur actor from the shell and unregister it + remove_blur(pid) { + // global.window_group is null when restarting the shell, causing an innocent crash crash + if (global.window_group == null) + return + + global.window_group.remove_actor(this.blurActorMap.get(pid)); + this.blurActorMap.delete(pid); + this.windowMap.delete(pid); + } + + // When given the xprop property, returns either a valid sigma value between 0 and 111 + // or null if the parsing is incorrect + parse_sigma_value(property) { + let result = property.match("(blur-provider=)(\\d{1,3})") + if (result == null) { + return null; + } else { + return result[2]; + } + } + + disable() { + this._log("removing blur from applications..."); + + this.blurActorMap.forEach(((value, key) => { + this.remove_blur(key) + })); + this.connections.disconnect_all(); + this.paint_signals.disconnect_all(); + } + + // Updates each blur effect to use new sigma value + set_sigma(s) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_sigma(s) + }) + } + + // Updates each blur effect to use new brightness value + set_brightness(b) { + this.blurActorMap.forEach((actor, _) => { + actor.get_effect('blur-effect').set_brightness(b) + }) + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/connections.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/connections.js new file mode 100644 index 0000000..3517a27 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/connections.js @@ -0,0 +1,81 @@ +'use strict'; + +const GObject = imports.gi.GObject; + + +var Connections = class Connections { + constructor() { + this.buffer = []; + } + + process_connection(actor, id) { + let infos = { + actor: actor, + id: id + }; + + if (actor.connect && (!(actor instanceof GObject.Object) || GObject.signal_lookup('destroy', actor))) { + let destroy_id = actor.connect('destroy', () => { + actor.disconnect(id); + actor.disconnect(destroy_id); + + let index = this.buffer.indexOf(infos); + if (index >= 0) { + this.buffer.splice(index, 1) + } + }) + } + + this.buffer.push(infos) + } + + connect(actor, signal, handler) { + let id = actor.connect(signal, handler); + this.process_connection(actor, id); + } + + connect_after(actor, signal, handler) { + let id = actor.connect_after(signal, handler); + + this.process_connection(actor, id); + } + + disconnect_all_for(actor) { + let actor_connections = [] + + this.buffer.forEach((infos) => { + if (infos.actor == actor) { + actor_connections.push(infos) + } + }); + + actor_connections.forEach((connection) => { + // disconnect + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + + // remove from buffer + let index = this.buffer.indexOf(connection); + this.buffer.splice(index, 1); + }) + } + + disconnect_all() { + this.buffer.forEach((connection) => { + try { + connection.actor.disconnect(connection.id) + } catch (e) { + this._log(`error removing connection: ${e}; continuing`) + } + }) + this.buffer = []; + } + + // no need to check if DEBUG here, the log function is only used on error + _log(str) { + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash.js new file mode 100644 index 0000000..650bf69 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash.js @@ -0,0 +1,51 @@ +'use strict'; + +const { St, Shell, Meta } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; + + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring dash"); + this.update(); + } + + update() { + if (Main.overview.dash.constructor.name == "Dash") { + Main.overview.dash.get_child_at_index(0).style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + // set search entry the same opacity as the dash + Main.overview._overview._controls._searchEntry.style = "background-color:rgba(0,0,0," + this.prefs.DASH_OPACITY.get() + ")"; + } + + disable() { + this._log("removing blur from dash"); + + if (Main.overview.dash.constructor.name == "Dash") { + if (Main.screenShield && !Main.screenShield.locked) { + try { + Main.overview.dash.get_child_at_index(0).style = null; + } catch (e) { + this._log(e); + } + } + } + Main.overview._overview._controls._searchEntry.style = null; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js new file mode 100644 index 0000000..166f147 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/dash_to_dock.js @@ -0,0 +1,235 @@ +'use strict'; + +const { St, Shell, GLib } = imports.gi; +const Main = imports.ui.main; +const Signals = imports.signals; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +// This type of object is created for every dash found, and talks to the main DashBlur thanks +// to signals. This allows to dynamically track the created dashes for each screen. +class DashInfos { + constructor(dash_blur, dash, dash_box, background_parent, effect, prefs) { + // the parent DashBlur object, to communicate + this.dash_blur = dash_blur; + // the blurred dash + this.dash = dash; + // the actually blurred box + this.dash_box = dash_box; + this.background_parent = background_parent; + this.effect = effect; + this.prefs = prefs; + + dash_blur.connections.connect(dash_blur, 'remove-dashes', () => { + this._log("removing blur from dash"); + this.dash.get_parent().remove_child(this.background_parent); + this.dash.remove_style_class_name('blurred-dash'); + }); + + dash_blur.connections.connect(dash_blur, 'update-sigma', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'update-brightness', () => { + this.effect.brightness = this.dash_blur.brightness; + }); + + dash_blur.connections.connect(dash_blur, 'show', () => { + this.effect.sigma = this.dash_blur.sigma; + }); + + dash_blur.connections.connect(dash_blur, 'hide', () => { + this.effect.sigma = 0; + }); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +var DashBlur = class DashBlur { + constructor(connections, prefs) { + this.dashes = []; + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.sigma = prefs.SIGMA.get(); + this.brightness = prefs.BRIGHTNESS.get(); + } + + enable() { + this.connections.connect(Main.uiGroup, 'actor-added', (_, actor) => { + if ((actor.get_name() == "dashtodockContainer") && (actor.constructor.name == 'DashToDock')) + this.try_blur(actor); + }); + + this.blur_existing_dashes(); + } + + // Finds all existing dashes on every monitor, and call `try_blur` on them + // We cannot only blur `Main.overview.dash`, as there could be multiple screens + blur_existing_dashes() { + this._log("searching for dash"); + // blur every dash found + Main.uiGroup.get_children().filter((child) => { + // filter by name + return (child.get_name() == "dashtodockContainer") && (child.constructor.name == 'DashToDock') + }).forEach(this.try_blur.bind(this)); + } + + // Tries to blur the dash contained in the given actor + try_blur(dash_container) { + let dash_box = dash_container._slider.get_child(); + // verify that we did not already blur that dash + if (!dash_box.get_children().some((c) => { + return c.get_name() == "dash-blurred-background-parent" + })) { + // finally blur the dash + this._log("dash to dock found, blurring it"); + let dash = dash_box.get_children().find(c => { return c.get_name() == 'dash' }) + this.dashes.push(this.blur_dash_from(dash, dash_container)); + } + } + + // Blurs the dash and returns a `DashInfos` containing its informations + blur_dash_from(dash, dash_container) { + // the effect to be applied + let effect = new Shell.BlurEffect({ + brightness: this.brightness, + sigma: this.sigma, + mode: 1 + }); + + // dash background parent, not visible + let background_parent = new St.Widget({ + name: 'dash-blurred-background-parent', + style_class: 'dash-blurred-background-parent', + width: 0, + height: 0 + }); + + // dash background widget + let background = new St.Widget({ + name: 'dash-blurred-background', + style_class: 'dash-blurred-background', + x: 0, + y: dash_container._slider.y, + width: dash.width, + height: dash.height, + }); + + // updates size and position on change + this.connections.connect(dash_container._slider, 'notify::y', _ => { + background.y = dash_container._slider.y; + }); + this.connections.connect(dash, 'notify::width', _ => { + background.width = dash.width; + }); + this.connections.connect(dash, 'notify::height', _ => { + background.height = dash.height; + }); + + + // HACK + { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the dash buttons to cause artefacts on the dash itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("dash hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { + effect.queue_repaint() + }; + + dash._box.get_children().forEach((icon) => { + try { + let zone = icon.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._box, 'actor-added', (_, actor) => { + try { + let zone = actor.get_child_at_index(0); + this.connections.connect(zone, 'enter-event', rp); + this.connections.connect(zone, 'leave-event', rp); + this.connections.connect(zone, 'button-press-event', rp); + } catch (e) { + this._log(`${e}, continuing`); + } + }) + + this.connections.connect(dash._showAppsIcon, 'enter-event', rp); + this.connections.connect(dash._showAppsIcon, 'leave-event', rp); + this.connections.connect(dash._showAppsIcon, 'button-press-event', rp); + + this.connections.connect(dash, 'leave-event', rp); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("dash hack level 2"); + + this.paint_signals.connect(background, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + + // add the widget to the dash + background.add_effect(effect); + background_parent.add_child(background); + dash.get_parent().insert_child_at_index(background_parent, 0); + + // remove background color + dash.set_style_class_name('blurred-dash'); + + // returns infos + return new DashInfos(this, dash, dash._background, background_parent, effect, this.prefs); + } + + set_sigma(sigma) { + this.sigma = sigma; + this.emit('update-sigma', true); + } + + set_brightness(brightness) { + this.brightness = brightness; + this.emit('update-brightness', true); + } + + disable() { + this._log("removing blur from dashes"); + + this.emit('remove-dashes', true); + + this.dashes = []; + this.connections.disconnect_all(); + } + + show() { + this.emit('show', true); + } + hide() { + this.emit('hide', true); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + +Signals.addSignalMethods(DashBlur.prototype); \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/extension.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/extension.js new file mode 100644 index 0000000..4d5c4c9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/extension.js @@ -0,0 +1,224 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); + +const Settings = Me.imports.settings; +const Connections = Me.imports.connections; + +const Panel = Me.imports.panel; +const Dash = Me.imports.dash; +const Overview = Me.imports.overview; +const DashToDock = Me.imports.dash_to_dock; +const Lockscreen = Me.imports.lockscreen; +const AppFolders = Me.imports.appfolders; +const WindowList = Me.imports.window_list; +const Applications = Me.imports.applications; + + +class Extension { + constructor() { } + + enable() { + this._prefs = new Settings.Prefs; + + this._log("enabling extension..."); + this._connections = []; + + this._panel_blur = new Panel.PanelBlur(new Connections.Connections, this._prefs); + this._dash_blur = new Dash.DashBlur(new Connections.Connections, this._prefs); + this._dash_to_dock_blur = new DashToDock.DashBlur(new Connections.Connections, this._prefs); + this._overview_blur = new Overview.OverviewBlur(new Connections.Connections, this._prefs); + this._lockscreen_blur = new Lockscreen.LockscreenBlur(new Connections.Connections, this._prefs); + this._appfolders_blur = new AppFolders.AppFoldersBlur(new Connections.Connections, this._prefs); + this._window_list_blur = new WindowList.WindowListBlur(new Connections.Connections, this._prefs); + this._applications_blur = new Applications.ApplicationsBlur(new Connections.Connections, this._prefs); + + + this._connections.push(this._panel_blur.connections, this._dash_blur.connections, + this._dash_to_dock_blur.connections, this._overview_blur.connections, + this._lockscreen_blur.connections, this._appfolders_blur.connections, + this._window_list_blur.connections, this._applications_blur.connections); + + this._connect_to_settings(); + + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } + + this._update_sigma(); + this._update_brightness(); + + this._log("extension enabled."); + } + + disable() { + this._log("disabling extension..."); + + this._panel_blur.disable(); + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + this._overview_blur.disable(); + this._lockscreen_blur.disable(); + this._appfolders_blur.disable(); + this._window_list_blur.disable(); + this._applications_blur.disable(); + + this._panel_blur = null; + this._dash_blur = null; + this._dash_to_dock_blur = null; + this._overview_blur = null; + this._lockscreen_blur = null; + this._appfolders_blur = null; + this._window_list_blur = null; + this._applications_blur = null; + + this._disconnect_settings(); + + // in theory, this shouldn't be needed if we switch to making modules responsible for disconnecting their own + // signals. For now, I will leave this small bit of code in. Calling disable on all modules has already + // done the same thing + this._connections.forEach((connections) => { + connections.disconnect_all(); + }) + this._connections = []; + + this._log("extension disabled."); + + this._prefs = null; + } + + _connect_to_settings() { + this._prefs.SIGMA.changed(() => { + this._update_sigma(); + }); + this._prefs.BRIGHTNESS.changed(() => { + this._update_brightness(); + }); + + this._prefs.BLUR_DASH.changed(() => { + if (this._prefs.BLUR_DASH.get()) { + this._dash_blur.enable(); + this._dash_to_dock_blur.enable(); + } else { + this._dash_blur.disable(); + this._dash_to_dock_blur.disable(); + } + }); + this._prefs.BLUR_PANEL.changed(() => { + if (this._prefs.BLUR_PANEL.get()) { + this._panel_blur.enable(); + } else { + this._panel_blur.disable(); + } + }); + this._prefs.BLUR_OVERVIEW.changed(() => { + if (this._prefs.BLUR_OVERVIEW.get()) { + this._overview_blur.enable(); + } else { + this._overview_blur.disable(); + } + }); + this._prefs.BLUR_LOCKSCREEN.changed(() => { + if (this._prefs.BLUR_LOCKSCREEN.get()) { + this._lockscreen_blur.enable(); + } else { + this._lockscreen_blur.disable(); + } + }); + this._prefs.BLUR_APPFOLDERS.changed(() => { + if (this._prefs.BLUR_APPFOLDERS.get()) { + this._appfolders_blur.enable(); + } else { + this._appfolders_blur.disable(); + } + }); + this._prefs.BLUR_WINDOW_LIST.changed(() => { + if (this._prefs.BLUR_WINDOW_LIST.get()) { + this._window_list_blur.enable(); + } else { + this._window_list_blur.disable(); + } + }); + this._prefs.BLUR_APPLICATIONS.changed(() => { + if (this._prefs.BLUR_APPLICATIONS.get()) { + this._applications_blur.enable(); + } else { + this._applications_blur.disable(); + } + }) + this._prefs.DASH_OPACITY.changed(() => { + this._dash_blur.update(); + }); + this._prefs.APPFOLDER_DIALOG_OPACITY.changed(() => { + this._appfolders_blur.blur_appfolders(); + }); + this._prefs.STATIC_BLUR.changed(() => { + this._panel_blur.change_blur_type(); + }); + this._prefs.HIDETOPBAR.changed(() => { + this._panel_blur.connect_to_overview(); + }); + } + + _disconnect_settings() { + this._prefs.SIGMA.disconnect(); + this._prefs.BRIGHTNESS.disconnect(); + } + + _update_sigma() { + let sigma = this._prefs.SIGMA.get(); + + this._panel_blur.set_sigma(sigma); + this._dash_to_dock_blur.set_sigma(sigma); + this._overview_blur.set_sigma(sigma); + this._lockscreen_blur.set_sigma(sigma); + this._appfolders_blur.set_sigma(sigma); + this._window_list_blur.set_sigma(sigma); + this._applications_blur.set_sigma(sigma); + } + + _update_brightness() { + let brightness = this._prefs.BRIGHTNESS.get(); + + this._panel_blur.set_brightness(brightness); + this._dash_to_dock_blur.set_brightness(brightness); + this._overview_blur.set_brightness(brightness); + this._lockscreen_blur.set_brightness(brightness); + this._appfolders_blur.set_brightness(brightness); + this._window_list_blur.set_brightness(brightness); + this._applications_blur.set_brightness(brightness); + } + + _log(str) { + if (this._prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} + + +// Called on gnome-shell loading, even if extension is deactivated +function init() { + return new Extension(); +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/lockscreen.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/lockscreen.js new file mode 100644 index 0000000..e6d39b5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/lockscreen.js @@ -0,0 +1,64 @@ +'use strict'; + +const { St, Shell } = imports.gi; +const Main = imports.ui.main; +const Background = imports.ui.background; + +let sigma = 30; +let brightness = 0.6; + +const original_createBackground = imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects; + + +var LockscreenBlur = class LockscreenBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + } + + enable() { + this._log("blurring lockscreen"); + + this.update_lockscreen(); + } + + update_lockscreen() { + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = this._createBackground; + } + + _createBackground() { + for (const widget of this._backgroundGroup) { + const effect = widget.get_effect('blur'); + + if (effect) { + effect.set({ + brightness: brightness, + sigma: sigma, + }); + } + } + } + + set_sigma(s) { + sigma = s; + this.update_lockscreen(); + } + + set_brightness(b) { + brightness = b; + this.update_lockscreen(); + } + + disable() { + this._log("removing blur from lockscreen"); + + imports.ui.unlockDialog.UnlockDialog.prototype._updateBackgroundEffects = original_createBackground; + + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/metadata.json b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/metadata.json new file mode 100644 index 0000000..820fa02 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/metadata.json @@ -0,0 +1,12 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Adds a blur look to different parts of the GNOME Shell, including the top panel, dash and overview.\n\nYou can support my work by sponsoring me on:\n- github: https://github.com/sponsors/aunetx\n- ko-fi: https://ko-fi.com/aunetx\n\nNote: if the extension shows an error after updating, please make sure to restart your session to see if it persists. This is due to a bug in gnome shell, which I can't fix by myself.", + "name": "Blur my Shell", + "shell-version": [ + "40", + "41" + ], + "url": "https://github.com/aunetx/gnome-shell-extension-blur-my-shell", + "uuid": "blur-my-shell@aunetx", + "version": 29 +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/overview.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/overview.js new file mode 100644 index 0000000..ffd86f9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/overview.js @@ -0,0 +1,161 @@ +'use strict'; + +const { Shell, Gio, Meta } = imports.gi; +const Main = imports.ui.main; +const WorkspaceAnimationController = imports.ui.workspaceAnimation.WorkspaceAnimationController; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; + + +var OverviewBlur = class OverviewBlur { + constructor(connections, prefs) { + this.connections = connections; + this.effects = []; + this.prefs = prefs; + this._workspace_switch_bg_actors = []; + } + + enable() { + this._log("blurring overview"); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this._log("updated background"); + this.update_backgrounds(); + }); + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this._log("changed monitors"); + this.update_backgrounds(); + } + }); + + // add css class names, to change folders and workspace-switch background + Main.uiGroup.add_style_class_name("blurred-overview"); + + // update background on extension activation + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + this.update_backgrounds(); + } catch (error) { this._log(`could not blur overview: ${error}`); } + + // store original methods for restoring them on disable() + this._origPrepareSwitch = WorkspaceAnimationController.prototype._prepareWorkspaceSwitch; + this._origFinishSwitch = WorkspaceAnimationController.prototype._finishWorkspaceSwitch; + + const outerThis = this; + + // create blurred background actors for each monitor during a workspace switch + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = function (...params) { + outerThis._log("prepare workspace switch"); + outerThis._origPrepareSwitch.apply(this, params); + + Main.layoutManager.monitors.forEach(monitor => { + if (!(Meta.prefs_get_workspaces_only_on_primary() && (monitor != Main.layoutManager.primaryMonitor))) { + const bg_actor = outerThis.create_background_actor(monitor); + Main.uiGroup.insert_child_above(bg_actor, global.window_group); + + // store the actors so that we can delete them later + outerThis._workspace_switch_bg_actors.push(bg_actor); + } + }); + }; + + // remove the workspace-switch actors when the switch is done + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = function (...params) { + outerThis._log("finish workspace switch"); + outerThis._origFinishSwitch.apply(this, params); + + outerThis._workspace_switch_bg_actors.forEach(actor => { + actor.destroy(); + }); + outerThis._workspace_switch_bg_actors = []; + }; + } + + update_backgrounds() { + // remove every old background + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + actor.destroy(); + } + }); + this.effects = []; + + // add new backgrounds + Main.layoutManager.monitors.forEach(monitor => { + const bg_actor = this.create_background_actor(monitor); + Main.layoutManager.overviewGroup.insert_child_at_index(bg_actor, monitor.index); + }); + } + + create_background_actor(monitor) { + let bg_actor = new Meta.BackgroundActor; + + let background = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - monitor.index - 1); + + if (!background) { + this._log("could not get background for overview"); + return bg_actor; + } + + bg_actor.set_content(background.get_content()); + + let effect = new Shell.BlurEffect({ + brightness: this.prefs.BRIGHTNESS.get(), + sigma: this.prefs.SIGMA.get(), + mode: 0 + }); + bg_actor.add_effect(effect); + this.effects.push(effect); + + bg_actor.set_x(monitor.x); + bg_actor.set_y(monitor.y); + + return bg_actor; + } + + set_sigma(s) { + this.effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.effects.forEach(effect => { + effect.brightness = b; + }); + } + + disable() { + this._log("removing blur from overview"); + Main.layoutManager.overviewGroup.get_children().forEach(actor => { + if (actor.constructor.name == 'Meta_BackgroundActor') { + Main.layoutManager.overviewGroup.remove_child(actor); + } + }); + Main.uiGroup.remove_style_class_name("blurred-overview"); + + this.effects = []; + this.connections.disconnect_all(); + + // restore original behavior + if (this._origPrepareSwitch) { + WorkspaceAnimationController.prototype._prepareWorkspaceSwitch = this._origPrepareSwitch; + } + + if (this._origFinishSwitch) { + WorkspaceAnimationController.prototype._finishWorkspaceSwitch = this._origFinishSwitch; + } + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`); + } +}; diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/paint_signals.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/paint_signals.js new file mode 100644 index 0000000..0c3dc4f --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/paint_signals.js @@ -0,0 +1,59 @@ +'use strict' + +const { GObject, Clutter } = imports.gi; + + +var PaintSignals = class PaintSignals { + constructor(connections) { + this.buffer = []; + this.connections = connections + } + + connect(actor, blur_effect) { + let paint_effect = new EmitPaintSignal(); + let infos = { + actor: actor, + paint_effect: paint_effect + }; + let counter = 0; + + actor.add_effect(paint_effect); + this.connections.connect(paint_effect, 'update-blur', () => { + try { + // checking if blur_effect.queue_repaint() has been recently called + if (counter === 0) { + counter = 2; + blur_effect.queue_repaint(); + } + else counter--; + } catch (e) { } + }); + + this.buffer.push(infos) + } + + disconnect_all() { + this.buffer.forEach((infos) => { + this.connections.disconnect_all_for(infos.paint_effect); + infos.actor.remove_effect(infos.paint_effect); + }); + + this.buffer = [] + } +} + +var EmitPaintSignal = GObject.registerClass({ + GTypeName: 'EmitPaintSignal', + Signals: { + 'update-blur': { + param_types: [] + }, + } +}, + class EmitPaintSignal extends Clutter.Effect { + vfunc_paint(node, paint_context, paint_flags) { + this.emit("update-blur"); + super.vfunc_paint(node, paint_context, paint_flags); + } + } +); \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/panel.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/panel.js new file mode 100644 index 0000000..930ca4d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/panel.js @@ -0,0 +1,245 @@ +'use strict'; + +const { St, Shell, Meta, Gio, GLib } = imports.gi; +const Main = imports.ui.main; +const Config = imports.misc.config; +const backgroundSettings = new Gio.Settings({ schema: 'org.gnome.desktop.background' }) + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + +const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.'); + + +var PanelBlur = class PanelBlur { + constructor(connections, prefs) { + this.connections = connections; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.prefs = prefs; + this.effect = new Shell.BlurEffect({ + brightness: prefs.BRIGHTNESS.get(), + sigma: prefs.SIGMA.get(), + mode: prefs.STATIC_BLUR.get() ? 0 : 1 + }); + this.background_parent = new St.Widget({ + name: 'topbar-blurred-background-parent', + style_class: 'topbar-blurred-background-parent', + x: this.monitor.x, + y: this.monitor.y, + width: this.monitor.width, + height: 0, + }); + this.background = prefs.STATIC_BLUR.get() ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.background_parent.add_child(this.background); + } + + enable() { + this._log("blurring top panel"); + + if (GS_MAJOR < 42) { + // hide corners, can't style them + Main.panel._leftCorner.hide(); + Main.panel._rightCorner.hide(); + this.connections.connect(Main.panel._leftCorner, 'show', () => { Main.panel._leftCorner.hide(); }); + this.connections.connect(Main.panel._rightCorner, 'show', () => { Main.panel._rightCorner.hide(); }); + } + + // insert background parent + let children = Main.layoutManager.panelBox.get_children(); + for (let i = 0; i < children.length; ++i) + if (children[i].name == 'topbar-blurred-background-parent') + Main.layoutManager.panelBox.remove_child(children[i]); + Main.layoutManager.panelBox.insert_child_at_index(this.background_parent, 0); + + // remove background + Main.panel.add_style_class_name('transparent-panel'); + + // perform updates + this.change_blur_type(); + Utils.setTimeout(() => { this.change_blur_type() }, 500); + + // connect to panel size change + this.connections.connect(Main.panel, 'notify::height', () => { + this.update_size(this.prefs.STATIC_BLUR.get()); + }); + + // connect to every background change (even without changing image) + this.connections.connect(Main.layoutManager._backgroundGroup, 'notify', () => { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + }) + + // connect to monitors change + this.connections.connect(Main.layoutManager, 'monitors-changed', () => { + if (Main.screenShield && !Main.screenShield.locked) { + this.update_wallpaper(this.prefs.STATIC_BLUR.get()); + this.update_size(this.prefs.STATIC_BLUR.get()); + } + }); + + this.connect_to_overview(); + } + + change_blur_type() { + let is_static = this.prefs.STATIC_BLUR.get(); + + // reset widgets to right state + this.background_parent.remove_child(this.background); + this.background.remove_effect(this.effect); + this.background = is_static ? new Meta.BackgroundActor : new St.Widget({ + style_class: 'topbar-blurred-background', + x: 0, + y: 0, + width: this.monitor.width, + height: Main.panel.height, + }); + this.effect.set_mode(is_static ? 0 : 1); + this.background.add_effect(this.effect); + this.background_parent.add_child(this.background); + + // perform updates + this.update_wallpaper(is_static); + this.update_size(is_static); + + // HACK + if (!is_static) { + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("panel hack level 1"); + this.paint_signals.disconnect_all(); + + let rp = () => { this.effect.queue_repaint() }; + + this.connections.connect(Main.panel, 'enter-event', rp); + this.connections.connect(Main.panel, 'leave-event', rp); + this.connections.connect(Main.panel, 'button-press-event', rp); + + Main.panel.get_children().forEach(child => { + this.connections.connect(child, 'enter-event', rp); + this.connections.connect(child, 'leave-event', rp); + this.connections.connect(child, 'button-press-event', rp); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("panel hack level 2"); + this.paint_signals.disconnect_all(); + + this.paint_signals.connect(this.background, this.effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + } + } + + update_wallpaper(is_static) { + // if static blur, get right wallpaper and update blur with it + if (is_static) { + // the try/catch behaviour is used to prevent bugs like #136 and #137 + try { + let bg = Main.layoutManager._backgroundGroup.get_child_at_index(Main.layoutManager.monitors.length - this.monitor.index - 1); + this.background.set_content(bg.get_content()); + } catch (error) { this._log(`could not blur panel: ${error}`) } + } + } + + update_size(is_static) { + this.background_parent.width = Main.panel.width; + this.background.width = Main.panel.width; + let panel_box = Main.layoutManager.panelBox; + this.background.height = panel_box.height; + let clip_box = panel_box.get_parent(); + if (is_static) { + this.background.set_clip( + clip_box.x, + clip_box.y, + panel_box.width, + panel_box.height + ); + this.background.x = -clip_box.x; + this.background.y = -clip_box.y; + } + } + + // returns either the primary monitor, or a dummy one if none is connected + get monitor() { + if (Main.layoutManager.primaryMonitor != null) { + return Main.layoutManager.primaryMonitor + } else { + return { x: 0, y: 0, width: 0, index: 0 } + } + } + + // connect when overview if opened/closed to hide/show the blur in consequence + // if HIDETOPBAR set, we need just to hide the blur when showing appgrid (so no shadow is cropped) + connect_to_overview() { + this.connections.disconnect_all_for(Main.overview._overview._controls._appDisplay); + this.connections.disconnect_all_for(Main.overview); + + if (!this.prefs.HIDETOPBAR.get()) { + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } else { + this.connections.connect(Main.overview._overview._controls._appDisplay, 'show', () => { + this.hide(); + }); + this.connections.connect(Main.overview._overview._controls._appDisplay, 'hide', () => { + this.show(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + } + + set_sigma(s) { + this.effect.sigma = s; + } + + set_brightness(b) { + this.effect.brightness = b; + } + + disable() { + this._log("removing blur from top panel"); + Main.panel.remove_style_class_name('transparent-panel'); + + if (GS_MAJOR < 42) { + Main.panel._leftCorner.show(); + Main.panel._rightCorner.show(); + } + + try { + Main.layoutManager.panelBox.remove_child(this.background_parent); + } catch (e) { } + + this.connections.disconnect_all(); + } + + show() { + this.background_parent.show(); + } + hide() { + this.background_parent.hide(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.js new file mode 100644 index 0000000..b8c1c41 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.js @@ -0,0 +1,187 @@ +'use strict'; + +const { GObject, Gtk } = imports.gi; + +const ExtensionUtils = imports.misc.extensionUtils; +const Extension = ExtensionUtils.getCurrentExtension(); +let Settings = Extension.imports.settings; +let config = new Settings.Prefs(); + + +const BlurMyShellPrefsWidget = GObject.registerClass({ + GTypeName: 'BlurMyShellPrefsWidget', + Template: Extension.dir.get_child('prefs.ui').get_uri(), + InternalChildren: [ + 'sigma_scale', + 'brightness_scale', + 'blur_dash', + 'blur_panel', + 'blur_overview', + 'blur_applications', + 'blur_lockscreen', + 'blur_appfolders', + 'blur_window_list', + 'hacks_level0', + 'hacks_level1', + 'hacks_level2', + 'dash_opacity_scale', + 'appfolder_dialog_opacity_scale', + 'static_blur', + 'hidetopbar', + 'debug_mode' + ], +}, class BlurMyShellPrefsWidget extends Gtk.Box { + _init(params = {}) { + super._init(params); + + // ! sigma + this._sigma_scale.set_value(config.SIGMA.get()); + + // ! brightness + this._brightness_scale.set_value(config.BRIGHTNESS.get()); + + // ! blur dash + this._blur_dash.set_active(config.BLUR_DASH.get()); + + // ! blur panel + this._blur_panel.set_active(config.BLUR_PANEL.get()); + + // ! blur overview + this._blur_overview.set_active(config.BLUR_OVERVIEW.get()); + + // ! blur applications + this._blur_applications.set_active(config.BLUR_APPLICATIONS.get()); + + // ! blur lockscreen + this._blur_lockscreen.set_active(config.BLUR_LOCKSCREEN.get()); + + // ! blur appfolders + this._blur_appfolders.set_active(config.BLUR_APPFOLDERS.get()); + + // ! blur window list + this._blur_window_list.set_active(config.BLUR_WINDOW_LIST.get()); + + // ! dash hacks + if (config.HACKS_LEVEL.get() == 0) { + this._hacks_level0.set_active(true); + } else if (config.HACKS_LEVEL.get() == 1) { + this._hacks_level1.set_active(true); + } else if (config.HACKS_LEVEL.get() == 2) { + this._hacks_level2.set_active(true); + } else { + this._log(`hack level out-of-bound: ${hack_level}, defaulting to 1.`); + this._hacks_level0.set_active(true); + } + + // ! dash opacity + this._dash_opacity_scale.set_value(config.DASH_OPACITY.get()); + + // ! appfolder dialog opacity + this._appfolder_dialog_opacity_scale.set_value(config.APPFOLDER_DIALOG_OPACITY.get()); + + // ! static panel blur + this._static_blur.set_active(config.STATIC_BLUR.get()); + + // ! hidetopbar compatibility + this._hidetopbar.set_active(config.HIDETOPBAR.get()); + + // ! debug mode + this._debug_mode.set_active(config.DEBUG.get()); + } + + sigma_changed(w) { + let value = w.get_value(); + config.SIGMA.set(value); + } + + brightness_changed(w) { + let value = w.get_value(); + config.BRIGHTNESS.set(value); + } + + blur_dash_toggled(w) { + let value = w.get_active(); + config.BLUR_DASH.set(value); + } + + blur_panel_toggled(w) { + let value = w.get_active(); + config.BLUR_PANEL.set(value); + } + + blur_overview_toggled(w) { + let value = w.get_active(); + config.BLUR_OVERVIEW.set(value); + } + + blur_applications_toggled(w) { + let value = w.get_active(); + config.BLUR_APPLICATIONS.set(value); + } + + blur_lockscreen_toggled(w) { + let value = w.get_active(); + config.BLUR_LOCKSCREEN.set(value); + } + + blur_appfolders_toggled(w) { + let value = w.get_active(); + config.BLUR_APPFOLDERS.set(value); + } + + blur_window_list_toggled(w) { + let value = w.get_active(); + config.BLUR_WINDOW_LIST.set(value); + } + + hacks_level0_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(0) } + } + + hacks_level1_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(1) } + } + + hacks_level2_toggled(w) { + let is_active = w.get_active(); + if (is_active) { config.HACKS_LEVEL.set(2) } + } + + dash_opacity_changed(w) { + let value = w.get_value(); + config.DASH_OPACITY.set(value); + } + + appfolder_dialog_opacity_changed(w) { + let value = w.get_value(); + config.APPFOLDER_DIALOG_OPACITY.set(value); + } + + static_blur_toggled(w) { + let value = w.get_active(); + config.STATIC_BLUR.set(value); + } + + hidetopbar_toggled(w) { + let value = w.get_active(); + config.HIDETOPBAR.set(value); + } + + debug_mode_toggled(w) { + let value = w.get_active(); + config.DEBUG.set(value); + } + + _log(str) { + if (config.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +}); + +function init() { } + +function buildPrefsWidget() { + return new BlurMyShellPrefsWidget(); +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.ui b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.ui new file mode 100644 index 0000000..a5d30c7 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/prefs.ui @@ -0,0 +1,410 @@ + + + + + diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled new file mode 100644 index 0000000..ca00e0c Binary files /dev/null and b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/gschemas.compiled differ diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml new file mode 100644 index 0000000..4417dce --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/schemas/org.gnome.shell.extensions.blur-my-shell.gschema.xml @@ -0,0 +1,95 @@ + + + + + + 30 + Global sigma (gaussian blur radius) to use + + + + + 0.6 + Global brightness to use + + + + + true + Boolean, whether to blur the dash or not + + + + + true + Boolean, whether to blur the panel or not + + + + + true + Boolean, whether to blur the overview or not + + + + + true + Boolean, whether to blur lockscreen or not + + + + + true + Boolean, whether to blur appfolders or not + + + + + true + Boolean, whether to blur window list extension or not + + + + + false + Boolean, whether to blur applications that request it or not + + + + + 1 + Level of hacks to use (from 0 to 2) + + + + + 0.12 + Opacity of dash to use + + + + + 0.12 + Opacity of appfolder dialog to use + + + + + true + Boolean, whether to have a static blur on panel or a dynamic one + + + + + false + Boolean, whether to try compatibility with hidetopbar@mathieu.bidon.ca or not + + + + + false + Boolean, set to true to activate debug mode (more verbose journalctl logs) + + + + \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/settings.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/settings.js new file mode 100644 index 0000000..69a0093 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/settings.js @@ -0,0 +1,274 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Extension = imports.misc.extensionUtils.getCurrentExtension(); + +const SCHEMA_PATH = 'org.gnome.shell.extensions.blur-my-shell'; + +function get_local_gsettings(schema_path) { + const GioSSS = Gio.SettingsSchemaSource; + let schemaDir = Extension.dir.get_child('schemas'); + let schemaSource = GioSSS.get_default(); + + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory( + schemaDir.get_path(), + schemaSource, + false); + } + + let schemaObj = schemaSource.lookup(schema_path, true); + if (!schemaObj) { + throw new Error( + `Schema ${schema_path} could not be found for extension ${Extension.metadata.uuid}` + ); + } + return new Gio.Settings({ + settings_schema: schemaObj + }); +}; + +var Prefs = class Prefs { + constructor() { + var settings = this.settings = get_local_gsettings(SCHEMA_PATH); + this.SIGMA = { + key: 'sigma', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BRIGHTNESS = { + key: 'brightness', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.BLUR_DASH = { + key: 'blur-dash', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_PANEL = { + key: 'blur-panel', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_OVERVIEW = { + key: 'blur-overview', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_LOCKSCREEN = { + key: 'blur-lockscreen', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPLICATIONS = { + key: 'blur-applications', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_APPFOLDERS = { + key: 'blur-appfolders', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.BLUR_WINDOW_LIST = { + key: 'blur-window-list', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HACKS_LEVEL = { + key: 'hacks-level', + get: function () { + return settings.get_int(this.key); + }, + set: function (v) { + settings.set_int(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.DASH_OPACITY = { + key: 'dash-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.APPFOLDER_DIALOG_OPACITY = { + key: 'appfolder-dialog-opacity', + get: function () { + return settings.get_double(this.key); + }, + set: function (v) { + settings.set_double(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + }, + }; + + this.STATIC_BLUR = { + key: 'static-blur', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.HIDETOPBAR = { + key: 'hidetopbar', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + + this.DEBUG = { + key: 'debug', + get: function () { + return settings.get_boolean(this.key); + }, + set: function (v) { + settings.set_boolean(this.key, v); + }, + changed: function (cb) { + return settings.connect('changed::' + this.key, cb); + }, + disconnect: function () { + return settings.disconnect.apply(settings, arguments); + } + }; + } +}; \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/stylesheet.css b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/stylesheet.css new file mode 100644 index 0000000..a094537 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/stylesheet.css @@ -0,0 +1,436 @@ +#panel.transparent-panel { + background: transparent; + transition-duration: 500ms; +} + +.blurred-overview .app-folder { + background-color: rgba(0, 0, 0, 0.12); +} + + +.blurred-overview .workspace-animation { + background-color: transparent !important; +} + +.transparent-app-folder-dialogs .edit-folder-button { + background: transparent; + border-radius: 19px; +} + +.blurred-dash .dash-background { + background: transparent; +} + +/* +! TRANSPARENT APPFOLDER DIALOGS + +python generator: + +```py +for e in range(0,101):print(".transparent-app-folder-dialogs-"+str(e)+"\n{background-color: rgba(0, 0, 0, "+str(round(e/100,2))+");}") +``` +*/ + +.transparent-app-folder-dialogs-0 { + background-color: rgba(0, 0, 0, 0.0); +} + +.transparent-app-folder-dialogs-1 { + background-color: rgba(0, 0, 0, 0.01); +} + +.transparent-app-folder-dialogs-2 { + background-color: rgba(0, 0, 0, 0.02); +} + +.transparent-app-folder-dialogs-3 { + background-color: rgba(0, 0, 0, 0.03); +} + +.transparent-app-folder-dialogs-4 { + background-color: rgba(0, 0, 0, 0.04); +} + +.transparent-app-folder-dialogs-5 { + background-color: rgba(0, 0, 0, 0.05); +} + +.transparent-app-folder-dialogs-6 { + background-color: rgba(0, 0, 0, 0.06); +} + +.transparent-app-folder-dialogs-7 { + background-color: rgba(0, 0, 0, 0.07); +} + +.transparent-app-folder-dialogs-8 { + background-color: rgba(0, 0, 0, 0.08); +} + +.transparent-app-folder-dialogs-9 { + background-color: rgba(0, 0, 0, 0.09); +} + +.transparent-app-folder-dialogs-10 { + background-color: rgba(0, 0, 0, 0.1); +} + +.transparent-app-folder-dialogs-11 { + background-color: rgba(0, 0, 0, 0.11); +} + +.transparent-app-folder-dialogs-12 { + background-color: rgba(0, 0, 0, 0.12); +} + +.transparent-app-folder-dialogs-13 { + background-color: rgba(0, 0, 0, 0.13); +} + +.transparent-app-folder-dialogs-14 { + background-color: rgba(0, 0, 0, 0.14); +} + +.transparent-app-folder-dialogs-15 { + background-color: rgba(0, 0, 0, 0.15); +} + +.transparent-app-folder-dialogs-16 { + background-color: rgba(0, 0, 0, 0.16); +} + +.transparent-app-folder-dialogs-17 { + background-color: rgba(0, 0, 0, 0.17); +} + +.transparent-app-folder-dialogs-18 { + background-color: rgba(0, 0, 0, 0.18); +} + +.transparent-app-folder-dialogs-19 { + background-color: rgba(0, 0, 0, 0.19); +} + +.transparent-app-folder-dialogs-20 { + background-color: rgba(0, 0, 0, 0.2); +} + +.transparent-app-folder-dialogs-21 { + background-color: rgba(0, 0, 0, 0.21); +} + +.transparent-app-folder-dialogs-22 { + background-color: rgba(0, 0, 0, 0.22); +} + +.transparent-app-folder-dialogs-23 { + background-color: rgba(0, 0, 0, 0.23); +} + +.transparent-app-folder-dialogs-24 { + background-color: rgba(0, 0, 0, 0.24); +} + +.transparent-app-folder-dialogs-25 { + background-color: rgba(0, 0, 0, 0.25); +} + +.transparent-app-folder-dialogs-26 { + background-color: rgba(0, 0, 0, 0.26); +} + +.transparent-app-folder-dialogs-27 { + background-color: rgba(0, 0, 0, 0.27); +} + +.transparent-app-folder-dialogs-28 { + background-color: rgba(0, 0, 0, 0.28); +} + +.transparent-app-folder-dialogs-29 { + background-color: rgba(0, 0, 0, 0.29); +} + +.transparent-app-folder-dialogs-30 { + background-color: rgba(0, 0, 0, 0.3); +} + +.transparent-app-folder-dialogs-31 { + background-color: rgba(0, 0, 0, 0.31); +} + +.transparent-app-folder-dialogs-32 { + background-color: rgba(0, 0, 0, 0.32); +} + +.transparent-app-folder-dialogs-33 { + background-color: rgba(0, 0, 0, 0.33); +} + +.transparent-app-folder-dialogs-34 { + background-color: rgba(0, 0, 0, 0.34); +} + +.transparent-app-folder-dialogs-35 { + background-color: rgba(0, 0, 0, 0.35); +} + +.transparent-app-folder-dialogs-36 { + background-color: rgba(0, 0, 0, 0.36); +} + +.transparent-app-folder-dialogs-37 { + background-color: rgba(0, 0, 0, 0.37); +} + +.transparent-app-folder-dialogs-38 { + background-color: rgba(0, 0, 0, 0.38); +} + +.transparent-app-folder-dialogs-39 { + background-color: rgba(0, 0, 0, 0.39); +} + +.transparent-app-folder-dialogs-40 { + background-color: rgba(0, 0, 0, 0.4); +} + +.transparent-app-folder-dialogs-41 { + background-color: rgba(0, 0, 0, 0.41); +} + +.transparent-app-folder-dialogs-42 { + background-color: rgba(0, 0, 0, 0.42); +} + +.transparent-app-folder-dialogs-43 { + background-color: rgba(0, 0, 0, 0.43); +} + +.transparent-app-folder-dialogs-44 { + background-color: rgba(0, 0, 0, 0.44); +} + +.transparent-app-folder-dialogs-45 { + background-color: rgba(0, 0, 0, 0.45); +} + +.transparent-app-folder-dialogs-46 { + background-color: rgba(0, 0, 0, 0.46); +} + +.transparent-app-folder-dialogs-47 { + background-color: rgba(0, 0, 0, 0.47); +} + +.transparent-app-folder-dialogs-48 { + background-color: rgba(0, 0, 0, 0.48); +} + +.transparent-app-folder-dialogs-49 { + background-color: rgba(0, 0, 0, 0.49); +} + +.transparent-app-folder-dialogs-50 { + background-color: rgba(0, 0, 0, 0.5); +} + +.transparent-app-folder-dialogs-51 { + background-color: rgba(0, 0, 0, 0.51); +} + +.transparent-app-folder-dialogs-52 { + background-color: rgba(0, 0, 0, 0.52); +} + +.transparent-app-folder-dialogs-53 { + background-color: rgba(0, 0, 0, 0.53); +} + +.transparent-app-folder-dialogs-54 { + background-color: rgba(0, 0, 0, 0.54); +} + +.transparent-app-folder-dialogs-55 { + background-color: rgba(0, 0, 0, 0.55); +} + +.transparent-app-folder-dialogs-56 { + background-color: rgba(0, 0, 0, 0.56); +} + +.transparent-app-folder-dialogs-57 { + background-color: rgba(0, 0, 0, 0.57); +} + +.transparent-app-folder-dialogs-58 { + background-color: rgba(0, 0, 0, 0.58); +} + +.transparent-app-folder-dialogs-59 { + background-color: rgba(0, 0, 0, 0.59); +} + +.transparent-app-folder-dialogs-60 { + background-color: rgba(0, 0, 0, 0.6); +} + +.transparent-app-folder-dialogs-61 { + background-color: rgba(0, 0, 0, 0.61); +} + +.transparent-app-folder-dialogs-62 { + background-color: rgba(0, 0, 0, 0.62); +} + +.transparent-app-folder-dialogs-63 { + background-color: rgba(0, 0, 0, 0.63); +} + +.transparent-app-folder-dialogs-64 { + background-color: rgba(0, 0, 0, 0.64); +} + +.transparent-app-folder-dialogs-65 { + background-color: rgba(0, 0, 0, 0.65); +} + +.transparent-app-folder-dialogs-66 { + background-color: rgba(0, 0, 0, 0.66); +} + +.transparent-app-folder-dialogs-67 { + background-color: rgba(0, 0, 0, 0.67); +} + +.transparent-app-folder-dialogs-68 { + background-color: rgba(0, 0, 0, 0.68); +} + +.transparent-app-folder-dialogs-69 { + background-color: rgba(0, 0, 0, 0.69); +} + +.transparent-app-folder-dialogs-70 { + background-color: rgba(0, 0, 0, 0.7); +} + +.transparent-app-folder-dialogs-71 { + background-color: rgba(0, 0, 0, 0.71); +} + +.transparent-app-folder-dialogs-72 { + background-color: rgba(0, 0, 0, 0.72); +} + +.transparent-app-folder-dialogs-73 { + background-color: rgba(0, 0, 0, 0.73); +} + +.transparent-app-folder-dialogs-74 { + background-color: rgba(0, 0, 0, 0.74); +} + +.transparent-app-folder-dialogs-75 { + background-color: rgba(0, 0, 0, 0.75); +} + +.transparent-app-folder-dialogs-76 { + background-color: rgba(0, 0, 0, 0.76); +} + +.transparent-app-folder-dialogs-77 { + background-color: rgba(0, 0, 0, 0.77); +} + +.transparent-app-folder-dialogs-78 { + background-color: rgba(0, 0, 0, 0.78); +} + +.transparent-app-folder-dialogs-79 { + background-color: rgba(0, 0, 0, 0.79); +} + +.transparent-app-folder-dialogs-80 { + background-color: rgba(0, 0, 0, 0.8); +} + +.transparent-app-folder-dialogs-81 { + background-color: rgba(0, 0, 0, 0.81); +} + +.transparent-app-folder-dialogs-82 { + background-color: rgba(0, 0, 0, 0.82); +} + +.transparent-app-folder-dialogs-83 { + background-color: rgba(0, 0, 0, 0.83); +} + +.transparent-app-folder-dialogs-84 { + background-color: rgba(0, 0, 0, 0.84); +} + +.transparent-app-folder-dialogs-85 { + background-color: rgba(0, 0, 0, 0.85); +} + +.transparent-app-folder-dialogs-86 { + background-color: rgba(0, 0, 0, 0.86); +} + +.transparent-app-folder-dialogs-87 { + background-color: rgba(0, 0, 0, 0.87); +} + +.transparent-app-folder-dialogs-88 { + background-color: rgba(0, 0, 0, 0.88); +} + +.transparent-app-folder-dialogs-89 { + background-color: rgba(0, 0, 0, 0.89); +} + +.transparent-app-folder-dialogs-90 { + background-color: rgba(0, 0, 0, 0.9); +} + +.transparent-app-folder-dialogs-91 { + background-color: rgba(0, 0, 0, 0.91); +} + +.transparent-app-folder-dialogs-92 { + background-color: rgba(0, 0, 0, 0.92); +} + +.transparent-app-folder-dialogs-93 { + background-color: rgba(0, 0, 0, 0.93); +} + +.transparent-app-folder-dialogs-94 { + background-color: rgba(0, 0, 0, 0.94); +} + +.transparent-app-folder-dialogs-95 { + background-color: rgba(0, 0, 0, 0.95); +} + +.transparent-app-folder-dialogs-96 { + background-color: rgba(0, 0, 0, 0.96); +} + +.transparent-app-folder-dialogs-97 { + background-color: rgba(0, 0, 0, 0.97); +} + +.transparent-app-folder-dialogs-98 { + background-color: rgba(0, 0, 0, 0.98); +} + +.transparent-app-folder-dialogs-99 { + background-color: rgba(0, 0, 0, 0.99); +} + +.transparent-app-folder-dialogs-100 { + background-color: rgba(0, 0, 0, 1.0); +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/utilities.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/utilities.js new file mode 100644 index 0000000..5dbc319 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/utilities.js @@ -0,0 +1,39 @@ +'use strict' + +const GLib = imports.gi.GLib; + +let clearTimeout, clearInterval; +clearInterval = clearTimeout = GLib.Source.remove; + +var setTimeout = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_REMOVE; + }); +}; + +var setInterval = function(func, delay, ...args) { + return GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => { + func(...args); + return GLib.SOURCE_CONTINUE; + }); +}; + +var easeOutQuad = function(t, begin, end, duration) { + t /= duration + return begin + (t * (2 - t) * (end - begin)) +}; + +var ease_property = function(object, property, begin, end, duration, update) { + let start = Date.now(); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, update, () => { + let time = Date.now() - start; + if (time < duration) { + object[property] = easeOutQuad(time, begin, end, duration); + return GLib.SOURCE_CONTINUE; + } else { + object[property] = end; + return GLib.SOURCE_REMOVE; + } + }); +}; \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/window_list.js b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/window_list.js new file mode 100644 index 0000000..ca8708d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/blur-my-shell@aunetx/window_list.js @@ -0,0 +1,128 @@ +'use strict'; + +const { St, Shell, Meta, Gio } = imports.gi; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Settings = Me.imports.settings; +const Utils = Me.imports.utilities; +const PaintSignals = Me.imports.paint_signals; + + +var WindowListBlur = class WindowListBlur { + constructor(connections, prefs) { + this.connections = connections; + this.prefs = prefs; + this.paint_signals = new PaintSignals.PaintSignals(connections); + this.blur_effects = []; + } + + enable() { + this._log("blurring window list"); + + // add the blur if window-list found + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_blur(child)); + + // listen to new actors in `Main.layoutManager.uiGroup` and blur if window-list + this.connections.connect(Main.layoutManager.uiGroup, 'actor-added', (_, child) => this.try_blur(child)); + + // connect to overview + this.connections.connect(Main.overview, 'showing', () => { + this.hide(); + }); + this.connections.connect(Main.overview, 'hidden', () => { + this.show(); + }); + } + + try_blur(child) { + if (child.constructor.name == "WindowList" && child.style != "background:transparent;") { + this._log("found window list to blur"); + + child.style = "background:transparent;"; + let effect = new Shell.BlurEffect({ + name: 'window-list-blur', + sigma: this.prefs.SIGMA.get(), + brightness: this.prefs.BRIGHTNESS.get(), + mode: 1 + }); + child.add_effect(effect); + this.blur_effects.push(effect); + + // ! DIRTY PART: hack because `Shell.BlurEffect` does not repaint when shadows are under it + // ! this does not entirely fix this bug (shadows caused by windows still cause artefacts) + // ! but it prevents the shadows of the panel buttons to cause artefacts on the panel itself + // ! note: issue opened at https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2857 + + if (this.prefs.HACKS_LEVEL.get() == 1) { + this._log("window list hack level 1"); + + child._windowList.get_children().forEach(child => { + this.connections.connect(child, 'button-press-event', () => { effect.queue_repaint(); }); + }); + } else if (this.prefs.HACKS_LEVEL.get() == 2) { + this._log("window list hack level 2"); + + this.paint_signals.connect(child, effect); + } else { + this.paint_signals.disconnect_all(); + } + + // ! END OF DIRTY PART + + child._windowList.get_children().forEach(window => this.blur_window_button(window)); + this.connections.connect(child._windowList, 'actor-added', (_, window) => { + this.blur_window_button(window); + }) + } + } + + blur_window_button(window) { + window.get_child_at_index(0).style = "box-shadow:none;background-color:rgba(0,0,0,0.2);border-radius:5px;"; + } + + try_remove_blur(child) { + if (child.constructor.name == "WindowList" && child.style == "background:transparent;") { + child.style = null; + child.remove_effect_by_name('window-list-blur'); + + child._windowList.get_children().forEach(child => { + child.get_child_at_index(0).style = null; + }); + } + } + + set_sigma(s) { + this.blur_effects.forEach(effect => { + effect.sigma = s; + }); + } + + set_brightness(b) { + this.blur_effects.forEach(effect => { + effect.brightness = b; + }); + } + + hide() { + this.set_sigma(0); + } + + show() { + this.set_sigma(this.prefs.SIGMA.get()); + } + + disable() { + this._log("removing blur from window list"); + + Main.layoutManager.uiGroup.get_children().forEach(child => this.try_remove_blur(child)) + + this.blur_effects = []; + this.connections.disconnect_all(); + } + + _log(str) { + if (this.prefs.DEBUG.get()) + log(`[Blur my Shell] ${str}`) + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING new file mode 100644 index 0000000..8d61b15 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/COPYING @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/README.md b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/README.md new file mode 100644 index 0000000..5000de1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/README.md @@ -0,0 +1,189 @@ +

+ +

+

+ + + + +

+ +![](media/design/png/dtp-main-p2.png) + +### Introduction + +Dash to Panel is an icon taskbar for Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications. + +Beyond that, just about every aspect of the panel is fully customizable. From positioning and scaling panel elements to running indicators to multi-monitor display, to window previews and even intellihide, Dash to Panel has everything you need to make your workspace feel like home. + +### Features + +|Customizable appearance| +|:-----:| +|![screenshot](media/design/gif/customizable.gif)| +|Hide & show panel elements and set their positions, sizes & colors| + +## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Customizable running indicators
MetroCiliora/Dashes
CilioraSquares/Segmented
DashesDots/Solid
Set position, style, weight & color of running indicators to easily and quickly identify focused and unfocused applications
+ +## + +|Live Previews on Hover| +|:-----:| +|![screenshot](media/design/gif/previews.gif)| +|Hover over the launcher icon for an open application to get a live window preview| + +## +|Launch by Number| +|:-----:| +|![](media/design/png/indicators-num.png.png)| +|Optionally launch your favorite applications via keyboard| + +## + +|Panel Intellihide| +|:-----:| +|![Intellihide](media/design/gif/Intellihide.gif)| +|Hide and reveal the panel according to your set preferences| + +## +|Additional Features|Feature Implemented| +|:-----|:-----:| +|Add "Show Desktop" button to panel|![](media/design/png/done.png)| +|Isolate running apps by workspaces and/or monitors|![](media/design/png/done.png)| +|Custom click behaviors (launch new window, cycle open windows, minimize, etc)|![](media/design/png/done.png)| +|Integrate native Gnome appMenu into right-click secondary menu|![](media/design/png/done.png)| +|Multi-monitor support|![](media/design/png/done.png)| +|Dynamic transparency|![](media/design/png/done.png)| +|Ungroup application windows|![](media/design/png/done.png)| +|Export and import settings|![](media/design/png/done.png)| +## + +### Installation + +**To install the most recent official release: +[Visit Dash-to-Panel at GNOME Extensions](https://extensions.gnome.org/extension/1160/dash-to-panel/)** + +To install a development version from source, please see the [Installation wiki page](https://github.com/jderose9/dash-to-panel/wiki/Installation). + +## +### FAQ + +How do I customize the panel? [See the Wiki](https://github.com/home-sweet-gnome/dash-to-panel/wiki/Enable-and-Customize#customize-it) + +How do I embed my bottom left notification drawer into the panel like a system tray? [Top Icons Plus](https://extensions.gnome.org/extension/2311/topicons-plus) or [(K)StatusNotifierItem/AppIndicator Support](https://extensions.gnome.org/extension/615/appindicator-support) + +How do I add a traditional start menu? [Arc Menu](https://extensions.gnome.org/extension/3628/arcmenu/) + +How do I disable the hot corner? [No Topleft Hot Corner](https://extensions.gnome.org/extension/118/no-topleft-hot-corner) + +How do I move the notifications to somewhere other than the top center? [Panel OSD](https://extensions.gnome.org/extension/708/panel-osd) + +How do I display Minimize & Maximize buttons? In the Tweak Tool application, turn on `Windows > Titlebar Buttons > Minimize & Maximize`. + +How do I reset the extension to its default settings? `dconf reset -f /org/gnome/shell/extensions/dash-to-panel/`. + +## +### Themes +While this extension works well with most popular Gnome Shell themes, the following themes are known to have explicitly added custom styles for this extension: +- [Ciliora Tertia](https://github.com/zagortenay333/ciliora-tertia-shell) / [Ciliora Secunda](https://github.com/zagortenay333/ciliora-secunda-shell) +- [Plano](https://github.com/lassekongo83/plano-theme) + + +## +### Compatibility + +This extension has been tested with Gnome 3.18+. + +This extension manipulates the Gnome Main Panel, aka Top Bar. So, most other extensions which operate on the top bar should be compatible. + +## +### Volunteers needed! + +This extension could be even better with your help! Any items in the issue tracker labelled `help wanted` or `good first issue` are up for grabs. For more info, see the [Contributing wiki page](https://github.com/jderose9/dash-to-panel/wiki/Contributing). + +## +### Credits + +This extension is developed and maintained by [@jderose9](https://github.com/jderose9) and [@charlesg99](https://github.com/charlesg99). + +Significant portions of code in this extension were derived from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html). + +Additional credits: This extension leverages the work for [ZorinOS Taskbar](https://github.com/ZorinOS/zorin-taskbar) (used in [ZorinOS](https://zorinos.com/)) to show window previews and allow the dash from [Dash-to-Dock](https://micheleg.github.io/dash-to-dock/index.html) to be embedded in the Gnome main panel. +Code to set anchor position taken from [Thoma5/gnome-shell-extension-bottompanel](https://github.com/Thoma5/gnome-shell-extension-bottompanel). +Pattern for moving panel contents based on [Frippery Move Clock](http://frippery.org/extensions/) by R M Yorston. +Ideas for recursing child actors and assigning inline styles are based on code from the extension [StatusAreaHorizontalSpacing](https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension). +## + +#### Thanks to the following people for contributing via pull requests: + +- @franglais125 for launching apps by number (w/ overlay), bug fixes, and issue support +- @LinxGem33 and @sbarrett322 for artwork, logos, screenshots and design effort +- @dziku1337 for peek mode in window previews +- @robrobinbin for configuring appMenu on/off in the panel +- @MartinPL for toggling favorites on/off in panel +- @jackwickham for thumbnail middle and right click actions +- @abakkk for centering the taskbar icons in the panel, and animated taskbar hovering +- @quasoft for changing of font weight of ungrouped application titles +- @jordanribera for using icon's dominant color as running indicator color +- @tper0700 for dynamically building context menu based on system capabilities +- @levacic for configurable minimized application title font color +- @l3nn4rt for toggling workspace switch popup +- @hlechner for adjustable show desktop line color and window preview icon size +- @ArtyomZorin for animated urgent icons +- @jvpessoa10 for additional click window cycle options +- @marksvc for assigning percent of display for panel length +- @philippun1 for GNOME 40 support :rocket: + +#### Bug Fixes: +@imrvelj, @Teslator, @bil-elmoussaoui, @brandon-schumann, @sw9, @rockon999 , @lexruee, @3v1n0, @freeroot, @moqmar, @ArtyomZorin, @lkc0987, @saibotk, @vanillajonathan, @Zkdc, @leebickmtu, @l3nn4rt, @Melix19, @Aikatsui, @melix99, @kyrillzorin, @oneshadab, , @CorvetteCole + +#### Documentation Improvements: +@BoQsc, @zakkak, @dandv + +#### Translations: +@frnogueira / @victorwpbastos (pt_BR), @zeten30 (cs), @franglais125 / @calotam / @oeramirez (es), @LaurentTreguier / @SolarLiner (fr), @elsieholmes (uk), @hosiet (zh\_CN), @jonnius / @linuxr01 (de), @urbalazs / @pappfer (hu), @crayxt (kk), @pkomur / @MartinPL / @alex4401 (pl), @AlexGluck / @GoodNike / @rjapolov / @vantu5z (ru), @sicklylife-jp / @ryonakano (ja), @oltulu / @TeknoMobil / @daenney (tr), @sbadux / @kowalski7cc / @l3nn4rt (it), @OriginCode / @pan93412 (zh\_TW), @ojn (sv), @frandieguez (gl) + + +## +### License & Terms ![](media/design/png/copyleft-16.png) + +Dash to Panel is available under the terms of the GPL-v2 or later license See [`COPYING`](https://github.com/jderose9/dash-to-panel/blob/master/COPYING) for details. + +![](https://img.shields.io/badge/Language-JavaScript-yellow.svg) ![](https://img.shields.io/badge/Licence-GPL--2.0-blue.svg) diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui new file mode 100644 index 0000000..ed7ef90 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/Settings.ui @@ -0,0 +1,7508 @@ + + + + + + True + False + vertical + 1 + 1 + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animation type + 0 + + + + + True + False + center + + Simple + Ripple + Plank + + + + + + + + + + True + True + False + + + True + False + 12 + 12 + 12 + 12 + 24 + 32 + + + True + False + 12 + Duration + True + 0 + end + + 0 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_duration_adjustment + 0 + 0 + right + True + + 0 + 1 + + + + + + True + False + Rotation + 0 + end + + 1 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_rotation_adjustment + 0 + 0 + right + True + + 1 + 1 + + + + + + True + False + Travel + 0 + end + + 2 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_travel_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + Zoom + 0 + end + + 3 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_zoom_adjustment + 0 + 0 + right + True + + 3 + 1 + + + + + + True + False + Convexity + 0 + end + + 4 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_convexity_adjustment + 1 + 1 + right + True + + 4 + 1 + + + + + + True + False + Extent + 0 + end + + 5 + 0 + + + + + + True + True + end + True + animate_appicon_hover_options_extent_adjustment + 0 + 0 + right + True + + 5 + 1 + + + + + + + + + + 100 + 1 + 10 + + + 0 + 300 + 1 + 5 + + + -30 + 30 + 1 + 5 + + + 0 + 100 + 1 + 5 + + + 100 + 250 + 1 + 5 + + + 0 + 3 + 0.1 + 1 + + + 1 + 10 + 0.1 + 1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + True + Nothing yet! + True + + + + + + + + + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + When set to minimize, double clicking minimizes all the windows of the application. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Toggle single / Cycle multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behavior for Shift+Middle-Click. + True + 40 + 0 + + + 1 + 0 + + + + + + True + False + True + Shift+Middle-Click action + 0 + + 0 + 0 + + + + + + True + False + center + + Raise windows + Minimize window + Launch new instance + Cycle through windows + Cycle windows + minimize + Toggle single / Preview multiple + Quit + + + 0 + 1 + 2 + + + + + + + + + + + + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Integrate <i>AppMenu</i> items + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + center + 12 + 12 + 12 + 12 + 32 + + + True + False + True + <i>Show Details</i> menu item + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 1 + 5 + + + 5 + 1 + 5 + + + 50 + 9999 + 25 + 100 + + + 5 + 100 + 5 + 5 + + + True + False + 12 + 12 + vertical + 1 + 1 + + + True + False + 12 + 12 + 12 + 12 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Highlight focused application + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 8 + + + True + False + True + Icon dominant color + 0 + + 0 + 0 + + + + + + True + True + end + center + + + + + True + False + True + Custom color + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + Highlight opacity + 0 + + 2 + 0 + + + + + + True + True + end + 5 + focus_highlight_opacity_adjustment + 5 + + 2 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator size (px) + 0 + + 0 + 0 + + + + + + True + True + end + 0 + dot_size_adjustment + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Indicator color - Icon Dominant + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + vertical + + + True + False + + + True + False + True + Indicator color - Override Theme + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + True + False + vertical + + + True + False + 12 + + + True + False + True + Use different for unfocused + 0 + + + + + True + True + end + center + + + + + + + True + False + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 1 window open (or ungrouped) + 0 + + 0 + 0 + + + + + + True + False + end + + + Apply to all + True + True + True + + + + + True + True + True + end + + + + 0 + 1 + + + + + + True + False + True + 2 windows open + 0 + + 1 + 0 + + + + + + True + True + True + end + + 1 + 1 + + + + + + True + False + True + 3 windows open + 0 + + 2 + 0 + + + + + + True + True + True + end + + 2 + 1 + + + + + + True + False + True + 4+ windows open + 0 + + 3 + 0 + + + + + + True + True + True + end + + 3 + 1 + + + + + + + + + + + + + + + + + + 6 + 24 + 1 + 100 + + + 1000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + group_apps_label_font_size_adjustment + True + + 0 + 1 + + + + + + True + False + True + Font size (px) of the application titles (default is 14) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font weight of application titles + 0 + + 0 + 0 + + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Font color of the minimized application titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Maximum width (px) of the application titles (default is 160) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + group_apps_label_max_width_adjustment + True + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use a fixed width for the application titles + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display running indicators on unfocused applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use the favorite icons as application launchers + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + 10 + 2000 + 10 + 100 + + + 10 + 4000 + 10 + 100 + + + 10000 + 10 + 100 + + + 1 + 9990 + 10 + 100 + + + 1 + 5000 + 10 + 100 + + + True + False + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + True + + + True + False + True + Only hide the panel when it is obstructed by windows + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + The panel hides from + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Require pressure at the edge of the screen to reveal the panel + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 4 + + + True + False + True + Required pressure threshold (px) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_threshold_adjustment + True + + 0 + 1 + + + + + + True + False + True + Required pressure timeout (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_pressure_time_adjustment + True + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Allow the panel to be revealed while in fullscreen mode + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Only hide secondary panels (requires multi-monitors option) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>i + + 0 + 1 + 2 + + + + + + True + False + True + Keyboard shortcut to reveal and hold the panel + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Hide and reveal animation duration (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + intellihide_animation_time_adjustment + True + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before hiding the panel (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_close_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Delay before enabling intellihide on start (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 10 + intellihide_enable_hide_delay_adjustment + True + 10 + + 0 + 1 + + + + + + + + + + + + + + 9999 + 25 + 100 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + 255 + 10 + 25 + + + 1000 + 10 + 50 + + + 50 + 500 + 10 + 50 + + + 100 + 5 + 10 + + + 50 + 1 + 5 + + + 100 + 800 + 10 + 50 + + + 9999 + 25 + 100 + + + 6 + 24 + 1 + 100 + + + 8 + 48 + 1 + 100 + + + True + True + 460 + 480 + + + True + False + True + True + natural + natural + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + preview_timeout_adjustment + True + + 0 + 1 + + + + + + True + False + True + Time (ms) before showing (400 is default) + True + 0 + + 0 + 0 + + + + + + True + False + True + Animation time (ms) + 0 + + 2 + 0 + + + + + + True + True + end + 4 + 0 + preview_animation_time_adjustment + True + + 2 + 1 + + + + + + True + False + vertical + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + + + True + True + False + 12 + 4 + + + 4 + True + False + start + 4 + Immediate on application icon click + True + + + + + + 1 + 0 + + + + + + True + True + end + center + 4 + 25 + leave_timeout_adjustment + True + 25 + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Middle click on the preview to close the window + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + 0 + 0 + 2 + + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + 2 + 0 + + + + + + True + False + True + Window previews padding (px) + True + 0 + + 3 + 0 + + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + 3 + 1 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 1 + 1 + + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + 1 + 0 + + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + + + Fixed + True + True + True + end + + + + 2 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use custom opacity for the previews background + True + 0 + + 0 + 0 + + + + + + True + False + True + If disabled, the previews background have the same opacity as the panel + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + center + 5 + preview_opacity_adjustment + 5 + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + + + True + False + end + 32 + + + Bottom + True + True + False + center + center + True + + + + + + Top + True + True + False + center + center + preview_title_position_bottom_button + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 32 + + + True + False + 8 + + + True + True + end + center + + + + + True + True + end + 4 + 6 + preview_custom_icon_size_adjustment + True + 6 + + + + 0 + 1 + + + + + + True + False + True + Icon size (px) of the window preview + True + 0 + + 1 + 0 + + + + + + True + False + True + If disabled, the previews icon size will be based on headerbar size + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + True + end + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + 0 + 1 + + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + 0 + 0 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + 0 + 0 + + + + + + True + False + end + center + + inherit from theme + normal + lighter + bold + bolder + + + 0 + 1 + + + + + 3 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + 0 + 0 + + + + + + True + True + True + end + + 0 + 1 + + + + + 4 + 0 + 2 + + + + + + + + + + True + True + 6 + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 2 + 0 + 2 + + + + + + True + False + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 0 + peek_mode_opacity_adjustment + True + + 0 + 1 + + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + 1 + 0 + 2 + + + + + 3 + 0 + 2 + + + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_icon_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + + + 2000 + 10 + 50 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + 4 + 50 + scroll_panel_options_delay_adjustment + True + 50 + + 0 + 1 + 2 + + + + + + True + False + True + Delay between mouse scroll events (ms) + True + 0 + + 0 + 0 + + + + + + True + False + True + Use this value to limit the number of captured mouse scroll events. + True + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show popup when changing workspace + True + 0 + + 0 + 0 + + + + + + True + False + True + This affects workspace popup when scrolling on the panel only. + True + 0 + + + 1 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + + + + + + + 10000 + 250 + 1000 + + + True + False + 12 + 12 + 12 + 12 + vertical + 1 + 1 + + + True + False + 0 + + + True + False + none + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Super + Super + Alt + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys prefix + 0 + + 0 + 0 + + + + + + True + False + Hotkeys will either be Super+Number or Super+Alt+Num + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + 100 + 80 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + center + + Never + Show temporarily + Always visible + + + 0 + 1 + 2 + + + + + + True + False + True + Number overlay + 0 + + 0 + 0 + + + + + + True + False + Temporarily show the application numbers over the icons when using the hotkeys. + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + shortcut_time_adjustment + + 0 + 1 + + + + + + True + False + True + Hide timeout (ms) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + center + 12 + e.g. <Super>q + + 0 + 1 + 2 + + + + + + True + False + True + Shortcut to show the overlay for 2 seconds + 0 + + 0 + 0 + + + + + + True + False + Syntax: <Shift>, <Ctrl>, <Alt>, <Super> + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show window previews on hotkey + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show previews when the application have multiple instances + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + end + center + + Number row + Numeric keypad + Both + + + 0 + 1 + 2 + + + + + + True + False + True + Hotkeys are activated with + 0 + + 0 + 0 + + + + + + True + False + Select which keyboard number keys are used to activate the hotkeys + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + 100 + 1 + 10 + + + True + False + vertical + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Current Show Applications icon + True + 0 + + 0 + 0 + + + + + + 32 + 32 + True + False + end + gtk-missing-image + 32 + + 0 + 1 + + + + + + 140 + True + + 1 + 1 + + + + + + True + False + True + Custom Show Applications image icon + True + 0 + + 1 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + True + 6 + 32 + + + True + True + end + 0 + show_applications_side_padding_adjustment + + 0 + 1 + + + + + + True + False + True + Show Applications icon side padding (px) + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Override escape key and return to desktop + True + 0 + + 0 + 0 + + + + + + + + + + 5000 + 10 + 100 + + + 5000 + 10 + 100 + + + 1 + 40 + 1 + 10 + + + True + False + vertical + + + True + False + none + 1 + 1 + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_width_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Override Show Desktop line color + 0 + + 1 + 0 + + + + + + True + False + 12 + end + + + True + True + True + end + True + + + + + True + True + end + center + + + + 1 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Reveal the desktop when hovering the Show Desktop button + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 4 + + + True + False + True + Delay before revealing the desktop (ms) + True + 0 + + 0 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_delay_adjustment + True + 1 + + 0 + 1 + + + + + + True + False + True + Fade duration (ms) + True + 0 + + 1 + 0 + + + + + + True + True + end + 4 + 1 + show_showdesktop_time_adjustment + True + 1 + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 2000 + 1 + 10 + + + 200 + 1 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + 100 + 5 + 10 + + + True + False + vertical + 1 + 1 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + + + True + False + True + The panel background opacity is affected by + 0 + + 0 + 0 + + + + + + True + False + center + + All windows + Focused windows + Maximized windows + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_distance_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Change opacity when a window gets closer than (px) + True + 0 + + 0 + 0 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + + + True + False + 12 + Change opacity to (%) + True + 0 + + + + + True + True + end + 0 + trans_opacity_min_adjustment + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 50 + trans_anim_time_adjustment + True + 50 + + 0 + 1 + + + + + + True + False + True + Opacity change animation duration (ms) + True + 0 + + 0 + 0 + + + + + + + + + + + + 0.33 + 1 + 0.01 + 0.1 + + + 0.33 + 1 + 0.01 + 0.1 + + + True + True + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + 32 + + + True + False + True + Display the main panel on + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Display panels on all monitors + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Panel Intellihide + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + True + False + True + Hide and reveal the panel according to preferences + True + 40 + 0 + + + 1 + 0 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + + + True + False + True + Order and positions on monitor + 0 + + 0 + 0 + + + + + + True + False + center + + 0 + 1 + + + + + + Apply changes to all monitors + True + True + False + 12 + 4 + 4 + + 1 + 0 + 2 + + + + + + True + False + 6 + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 6 + 6 + 12 + 32 + + + True + True + baseline + True + panel_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + Panel thickness (default is 48) + 0 + + 1 + 0 + + + + + + True + False + Panel length (%) (default is 100) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + panel_length_adjustment + 0 + 0 + right + True + + 2 + 1 + + + + + + True + False + center + + Start + Middle + End + + + 3 + 1 + + + + + + True + False + Anchor + 0 + + 3 + 0 + + + + + + True + False + True + Panel screen position + 0 + + 0 + 0 + + + + + + True + False + 32 + + + Bottom + True + True + False + center + center + + True + + + + + + Top + True + True + False + center + center + + position_bottom_button + + + + + + Left + True + True + False + center + center + + position_bottom_button + + + + + + Right + True + True + False + center + center + + position_bottom_button + + + + 0 + 1 + + + + + + + 1 + 0 + + + + + + + + + + 2 + 0 + 2 + + + + + + + + True + False + 6 + none + + + + + + + + + + + + + + + + True + False + Position + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + App Icon Margin (default is 8) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_margin_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 32 + + + True + False + App Icon Padding (default is 4) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + appicon_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator position + 0 + + + + + True + False + 32 + + + Bottom + True + True + False + center + True + + + + + + Top + True + True + False + center + dots_bottom_button + + + + + + Left + True + True + False + center + dots_bottom_button + + + + + + Right + True + True + False + center + dots_bottom_button + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Focused app) + 0 + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Running indicator style (Unfocused apps) + 0 + + + + + True + False + end + center + + Dots + Squares + Dashes + Segmented + Solid + Ciliora + Metro + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background color + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + end + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + True + True + + + True + False + vertical + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme background opacity + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Panel background opacity (%) + True + 0 + + 0 + 0 + + + + + + True + True + end + center + 0 + trans_opacity_adjustment + + 0 + 1 + + + + + + True + False + True + vertical + + + True + False + True + Dynamic background opacity + True + 0 + + + + + True + False + True + Change opacity when a window gets close to the panel + True + 40 + 0 + + + + + 1 + 0 + + + + + + True + False + end + center + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Override panel theme gradient + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + 12 + 12 + 6 + + + True + False + True + Gradient top color and opacity (%) + 0 + + 0 + 0 + + + + + + True + False + True + Gradient bottom color and opacity (%) + 0 + + 1 + 0 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity1_adjustment + + + + 0 + 1 + + + + + + True + False + 6 + + + True + True + True + + + + + True + True + end + center + 0 + trans_gradient_opacity2_adjustment + + + + 1 + 1 + + + + + 1 + 0 + 2 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animate hovering app icons + 0 + + 2 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 2 + 1 + + + + + + + + + + + + + + + + + + True + False + Style + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Show favorite applications + 0 + + 0 + 0 + + + + + + True + False + True + Show running applications + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show favorite applications on secondary panels + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + True + end + center + + 0 + 1 + 2 + + + + + + True + False + True + Show <i>AppMenu</i> button + True + 0 + + 0 + 0 + + + + + + True + False + True + Top Bar > Show App Menu must be enabled in Tweak Tool + True + True + 0 + + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 4 + 32 + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + True + False + True + Show window previews on hover + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Show tooltip on hover + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Isolate Workspaces + True + 0 + + 0 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Isolate monitors + True + 0 + + 1 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Click empty space to close overview + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Disable show overview on startup + True + 0 + + 0 + 0 + + + + + + + + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Ungroup applications + True + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + + + + + + + + + + + + + + + + + + + + + True + False + Behavior + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Behaviour when clicking on the icon of a running application. + True + 0 + + + 1 + 0 + + + + + + True + False + True + Click action + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + + + + True + False + center + + Cycle windows + minimize + Cycle through windows + Toggle single / Preview multiple + Toggle windows + Raise windows + Launch new instance + + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + False + 0 + + + True + False + 12 + 12 + 12 + 12 + 16 + 6 + + + True + False + vertical + + + True + False + True + Scroll panel action + 0 + + + + + True + False + True + Behavior when mouse scrolling over the panel. + True + 0 + + + + + 0 + 0 + + + + + + True + False + vertical + + + True + False + True + Scroll icon action + 0 + + + + + True + False + True + Behavior when mouse scrolling over an application icon. + True + 0 + + + + + 1 + 0 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + True + False + center + True + + Do nothing + Switch workspace + Cycle windows + Change volume + + + 0 + 2 + + + + + + True + False + center + True + + Do nothing + Cycle windows + Same as panel + + + 1 + 2 + + + + + + True + True + True + end + center + + + True + False + emblem-system-symbolic + + + + + 1 + 1 + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl. + True + True + 0 + + + 1 + 0 + + + + + + True + False + True + Use hotkeys to activate apps + 0 + + 0 + 0 + + + + + + True + False + 6 + + + True + True + True + center + center + + + True + False + emblem-system-symbolic + + + + + + + + True + True + end + center + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + True + False + Action + + + + + + + True + False + 24 + 24 + 24 + 24 + vertical + 24 + + + True + False + 0 + + + True + True + none + + + 100 + True + True + + + True + False + 12 + 12 + 6 + 6 + 12 + 32 + + + True + False + Tray Font Size (0 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_size_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + LeftBox Font Size (0 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + leftbox_size_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + Tray Item Padding (-1 = theme default) + 0 + + 0 + 0 + + + + + + True + True + baseline + True + tray_padding_adjustment + 0 + 0 + right + True + + + 0 + 1 + + + + + + True + False + Status Icon Padding (-1 = theme default) + 0 + + 1 + 0 + + + + + + True + True + baseline + True + statusicon_padding_adjustment + 0 + 0 + right + True + + + 1 + 1 + + + + + + True + False + LeftBox Padding (-1 = theme default) + 0 + + 2 + 0 + + + + + + True + True + baseline + True + leftbox_padding_adjustment + 0 + 0 + right + True + + + 2 + 1 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Animate switching applications + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + True + end + center + + 1 + 1 + + + + + + True + False + True + Animate launching new windows + 0 + + 1 + 0 + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + Keep original gnome-shell dash (overview) + 0 + + 0 + 0 + + + + + + True + True + end + center + + 0 + 1 + + + + + + True + False + True + Force Activities hot corner on primary monitor + 0 + + 3 + 0 + + + + + + True + True + end + center + + 3 + 1 + + + + + + True + False + True + Activate panel menu buttons (e.g. date menu) on click only + 0 + + 2 + 0 + + + + + + True + True + end + center + + 2 + 1 + + + + + + True + False + True + Keep original gnome-shell top panel + 0 + + 1 + 0 + + + + + + True + True + end + center + + 1 + 1 + + + + + + + + + + + + + + + + + True + False + 0 + + + True + False + none + + + 100 + True + True + + + True + False + 12 + 12 + 12 + 12 + 20 + 32 + + + True + False + True + App icon secondary (right-click) menu + 0 + + 0 + 0 + + + + + + True + True + True + center + + + True + False + emblem-system-symbolic + + + + + 0 + 1 + + + + + + + + + + + + + + + + + Advanced Options + False + True + True + start + + + + + + + + + True + False + center + Fine-Tune + + + + + + + False + 24 + 24 + 24 + 24 + True + True + vertical + 5 + + + True + False + vertical + + + True + False + <b>Dash-to-Panel</b> + True + + + + + True + False + center + + + True + False + end + version: + + + + + True + False + start + ... + + + + + + + GitHub + True + True + True + center + https://github.com/jderose9/dash-to-panel + + + + + + + False + 20 + 0 + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + 12 + True + Use the buttons below to create a settings file from your current preferences that can be imported on a different machine. + True + 0 + + + 1 + 0 + 2 + + + + + + True + False + start + Export and import settings + + 0 + 0 + 2 + + + + + + Export to file + True + True + True + + 2 + 0 + + + + + + Import from file + True + True + True + + 2 + 1 + + + + + + + + + + + + + + + + + True + True + end + <span size="small">This program comes with ABSOLUTELY NO WARRANTY. See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span> + True + center + True + + + + + + + + + True + False + About + + + + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js new file mode 100644 index 0000000..e79eae8 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/appIcons.js @@ -0,0 +1,1964 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const Config = imports.misc.config; +const AppDisplay = imports.ui.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Util = imports.misc.util; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Taskbar = Me.imports.taskbar; +const Progress = Me.imports.progress; +const _ = imports.gettext.domain(Utils.TRANSLATION_DOMAIN).gettext; + +//timeout names +const T1 = 'setStyleTimeout'; +const T2 = 'mouseScrollTimeout'; +const T3 = 'showDotsTimeout'; +const T4 = 'overviewWindowDragEndTimeout'; +const T5 = 'switchWorkspaceTimeout'; +const T6 = 'displayProperIndicatorTimeout'; + +//right padding defined for .overview-label in stylesheet.css +const TITLE_RIGHT_PADDING = 8; + +let LABEL_GAP = 5; +let MAX_INDICATORS = 4; +var DEFAULT_PADDING_SIZE = 4; + +let DOT_STYLE = { + DOTS: "DOTS", + SQUARES: "SQUARES", + DASHES: "DASHES", + SEGMENTED: "SEGMENTED", + CILIORA: "CILIORA", + METRO: "METRO", + SOLID: "SOLID" +} + +let DOT_POSITION = { + TOP: "TOP", + BOTTOM: "BOTTOM", + LEFT: 'LEFT', + RIGHT: 'RIGHT' +} + +let recentlyClickedAppLoopId = 0; +let recentlyClickedApp = null; +let recentlyClickedAppWindows = null; +let recentlyClickedAppIndex = 0; +let recentlyClickedAppMonitorIndex; + +let tracker = Shell.WindowTracker.get_default(); +let menuRedisplayFunc = !!(AppDisplay.AppMenu || AppDisplay.AppIconMenu).prototype._rebuildMenu ? '_rebuildMenu' : '_redisplay'; + +/** + * Extend AppIcon + * + * - Apply a css class based on the number of windows of each application (#N); + * - Draw a dot for each window of the application based on the default "dot" style which is hidden (#N); + * a class of the form "running#N" is applied to the AppWellIcon actor. + * like the original .running one. + * - add a .focused style to the focused app + * - Customize click actions. + * - Update minimization animation target + * + */ + +var taskbarAppIcon = Utils.defineClass({ + Name: 'DashToPanel.TaskbarAppIcon', + Extends: AppDisplay.AppIcon, + ParentConstrParams: [[0, 'app'], [2]], + + _init: function(appInfo, panel, iconParams, previewMenu, iconAnimator) { + this.dtpPanel = panel; + this._nWindows = 0; + this.window = appInfo.window; + this.isLauncher = appInfo.isLauncher; + this._previewMenu = previewMenu; + this.iconAnimator = iconAnimator; + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + // Fix touchscreen issues before the listener is added by the parent constructor. + this._onTouchEvent = function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) { + // Open the popup menu on long press. + this._setPopupTimeout(); + } else if (this._menuTimeoutId != 0 && (event.type() == Clutter.EventType.TOUCH_END || event.type() == Clutter.EventType.TOUCH_CANCEL)) { + // Activate/launch the application. + this.activate(1); + this._removeMenuTimeout(); + } + // Disable dragging via touch screen as it's buggy as hell. Not perfect for tablet users, but the alternative is way worse. + // Also, EVENT_PROPAGATE launches applications twice with this solution, so this.activate(1) above must only be called if there's already a window. + return Clutter.EVENT_STOP; + }; + // Hack for missing TOUCH_END event. + this._onLeaveEvent = function(actor, event) { + this.actor.fake_release(); + if (this._menuTimeoutId != 0) this.activate(1); // Activate/launch the application if TOUCH_END didn't fire. + this._removeMenuTimeout(); + }; + + this.callParent('_init', appInfo.app, iconParams); + + Utils.wrapActor(this.icon); + Utils.wrapActor(this); + + this._dot.set_width(0); + this._isGroupApps = Me.settings.get_boolean('group-apps'); + + this._container = new St.Widget({ style_class: 'dtp-container', layout_manager: new Clutter.BinLayout() }); + this._dotsContainer = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._dtpIconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(), style: getIconContainerStyle(panel.checkIfVertical()) }); + + this.actor.remove_actor(this._iconContainer); + + this._dtpIconContainer.add_child(this._iconContainer); + + if (appInfo.window) { + let box = new St.BoxLayout(); + + this._windowTitle = new St.Label({ + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.START, + style_class: 'overview-label' + }); + + this._updateWindowTitle(); + this._updateWindowTitleStyle(); + + this._scaleFactorChangedId = Utils.getStageTheme().connect('changed', () => this._updateWindowTitleStyle()); + + box.add_child(this._dtpIconContainer); + box.add_child(this._windowTitle); + + this._dotsContainer.add_child(box); + } else { + this._dotsContainer.add_child(this._dtpIconContainer); + } + + this._container.add_child(this._dotsContainer); + this.actor.set_child(this._container); + + if (panel.checkIfVertical()) { + this.actor.set_width(panel.geom.w); + } + + // Monitor windows-changes instead of app state. + // Keep using the same Id and function callback (that is extended) + if(this._stateChangedId > 0) { + this.app.disconnect(this._stateChangedId); + this._stateChangedId = 0; + } + + this._onAnimateAppiconHoverChanged(); + this._setAppIconPadding(); + this._showDots(); + + this._focusWindowChangedId = global.display.connect('notify::focus-window', + Lang.bind(this, this._onFocusAppChanged)); + + this._windowEnteredMonitorId = this._windowLeftMonitorId = 0; + this._stateChangedId = this.app.connect('windows-changed', Lang.bind(this, this.onWindowsChanged)); + + if (!this.window) { + if (Me.settings.get_boolean('isolate-monitors')) { + this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this)); + this._windowLeftMonitorId = Utils.DisplayWrapper.getScreen().connect('window-left-monitor', this.onWindowEnteredOrLeft.bind(this)); + } + + this._titleWindowChangeId = 0; + this._minimizedWindowChangeId = 0; + } else { + this._titleWindowChangeId = this.window.connect('notify::title', + Lang.bind(this, this._updateWindowTitle)); + + this._minimizedWindowChangeId = this.window.connect('notify::minimized', + Lang.bind(this, this._updateWindowTitleStyle)); + } + + this._scrollEventId = this.actor.connect('scroll-event', this._onMouseScroll.bind(this)); + + this._overviewWindowDragEndId = Main.overview.connect('window-drag-end', + Lang.bind(this, this._onOverviewWindowDragEnd)); + + this._switchWorkspaceId = global.window_manager.connect('switch-workspace', + Lang.bind(this, this._onSwitchWorkspace)); + + this._hoverChangeId = this.actor.connect('notify::hover', () => this._onAppIconHoverChanged()); + + this._dtpSettingsSignalIds = [ + Me.settings.connect('changed::animate-appicon-hover', Lang.bind(this, this._onAnimateAppiconHoverChanged)), + Me.settings.connect('changed::dot-position', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-size', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-focused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-style-unfocused', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-override', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-different', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-1', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-2', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-3', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::dot-color-unfocused-4', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-dominant', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-color', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::focus-highlight-opacity', Lang.bind(this, this._settingsChangeRefresh)), + Me.settings.connect('changed::group-apps-label-font-size', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-weight', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-font-color-minimized', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-label-max-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-use-fixed-width', Lang.bind(this, this._updateWindowTitleStyle)), + Me.settings.connect('changed::group-apps-underline-unfocused', Lang.bind(this, this._settingsChangeRefresh)) + ] + + this.forcedOverview = false; + + this._progressIndicator = new Progress.ProgressIndicator(this, panel.progressManager); + + this._numberOverlay(); + }, + + getDragActor: function() { + return this.app.create_icon_texture(this.dtpPanel.taskbar.iconSize); + }, + + // Used by TaskbarItemContainer to animate appIcons on hover + getCloneButton: function() { + // The source of the clone is this._container, + // using this.actor directly would break DnD style. + let clone = new Clutter.Clone({ + source: this.actor.child, + x: this.actor.child.x, y: this.actor.child.y, + width: this.actor.child.width, height: this.actor.child.height, + pivot_point: new Utils.getPoint({ x: 0.5, y: 0.5 }), + opacity: 255, + reactive: false, + x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER, + }); + + // "clone" of this.actor + return new St.Button({ + child: clone, + x: this.actor.x, y: this.actor.y, + width: this.actor.width, height: this.actor.height, + reactive: false, + }); + }, + + shouldShowTooltip: function() { + if (!Me.settings.get_boolean('show-tooltip') || + (!this.isLauncher && Me.settings.get_boolean("show-window-previews") && + this.getAppIconInterestingWindows().length > 0)) { + return false; + } else { + return this.actor.hover && !this.window && + (!this._menu || !this._menu.isOpen) && + (this._previewMenu.getCurrentAppIcon() !== this); + } + }, + + _onAppIconHoverChanged: function() { + if (!Me.settings.get_boolean('show-window-previews') || + (!this.window && !this._nWindows)) { + return; + } + + if (this.actor.hover) { + this._previewMenu.requestOpen(this); + } else { + this._previewMenu.requestClose(); + } + }, + + _onDestroy: function() { + this.callParent('_onDestroy'); + this._destroyed = true; + + this._timeoutsHandler.destroy(); + + this._previewMenu.close(true); + + // Disconect global signals + // stateChangedId is already handled by parent) + + if(this._overviewWindowDragEndId) + Main.overview.disconnect(this._overviewWindowDragEndId); + + if(this._focusWindowChangedId) + global.display.disconnect(this._focusWindowChangedId); + + if(this._titleWindowChangeId) + this.window.disconnect(this._titleWindowChangeId); + + if(this._minimizedWindowChangeId) + this.window.disconnect(this._minimizedWindowChangeId); + + if (this._windowEnteredMonitorId) { + Utils.DisplayWrapper.getScreen().disconnect(this._windowEnteredMonitorId); + Utils.DisplayWrapper.getScreen().disconnect(this._windowLeftMonitorId); + } + + if(this._switchWorkspaceId) + global.window_manager.disconnect(this._switchWorkspaceId); + + if(this._scaleFactorChangedId) + Utils.getStageTheme().disconnect(this._scaleFactorChangedId); + + if (this._hoverChangeId) { + this.actor.disconnect(this._hoverChangeId); + } + + if (this._scrollEventId) { + this.actor.disconnect(this._scrollEventId); + } + + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + }, + + onWindowsChanged: function() { + this._updateWindows(); + this.updateIcon(); + }, + + onWindowEnteredOrLeft: function() { + if (this._checkIfFocusedApp()) { + this._updateWindows(); + this._displayProperIndicator(); + } + }, + + updateTitleStyle: function() { + this._updateWindowTitleStyle(); + }, + + // Update indicator and target for minimization animation + updateIcon: function() { + + // If (for unknown reason) the actor is not on the stage the reported size + // and position are random values, which might exceeds the integer range + // resulting in an error when assigned to the a rect. This is a more like + // a workaround to prevent flooding the system with errors. + if (this.actor.get_stage() == null) + return; + + let rect = new Meta.Rectangle(); + + [rect.x, rect.y] = this.actor.get_transformed_position(); + [rect.width, rect.height] = this.actor.get_transformed_size(); + + let windows = this.window ? [this.window] : this.getAppIconInterestingWindows(true); + windows.forEach(function(w) { + w.set_icon_geometry(rect); + }); + }, + + _onAnimateAppiconHoverChanged: function() { + if (Me.settings.get_boolean('animate-appicon-hover')) { + this._container.add_style_class_name('animate-appicon-hover'); + + // Workaround to prevent scaled icon from being ugly when it is animated on hover. + // It increases the "resolution" of the icon without changing the icon size. + this.icon.createIcon = (iconSize) => this.app.create_icon_texture(2 * iconSize); + this._iconIconBinActorAddedId = this.icon._iconBin.connect('actor-added', () => { + if (this.icon._iconBin.child.mapped) { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + } else { + let iconMappedId = this.icon._iconBin.child.connect('notify::mapped', () => { + this.icon._iconBin.child.set_size(this.icon.iconSize, this.icon.iconSize); + this.icon._iconBin.child.disconnect(iconMappedId); + }); + } + }); + if (this.icon._iconBin.child) + this.icon._createIconTexture(this.icon.iconSize); + } else { + this._container.remove_style_class_name('animate-appicon-hover'); + + if (this._iconIconBinActorAddedId) { + this.icon._iconBin.disconnect(this._iconIconBinActorAddedId); + this._iconIconBinActorAddedId = 0; + this.icon.createIcon = Lang.bind(this, this._createIcon); + } + } + }, + + _onMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-icon-action'); + + if (scrollAction === 'PASS_THROUGH') { + return this.dtpPanel._onPanelMouseScroll(actor, event); + } else if (scrollAction === 'NOTHING' || (!this.window && !this._nWindows)) { + return; + } + + let direction = Utils.getMouseScrollDirection(event); + + if (direction && !this._timeoutsHandler.getId(T2)) { + this._timeoutsHandler.add([T2, Me.settings.get_int('scroll-icon-delay'), () => {}]); + + let windows = this.getAppIconInterestingWindows(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + Utils.activateSiblingWindow(windows, direction, this.window); + } + }, + + _showDots: function() { + // Just update style if dots already exist + if (this._focusedDots && this._unfocusedDots) { + this._updateWindows(); + return; + } + + if (!this._isGroupApps) { + this._focusedDots = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + visible: false + }); + + let mappedId = this.actor.connect('notify::mapped', () => { + this._displayProperIndicator(); + this.actor.disconnect(mappedId); + }); + } else { + this._focusedDots = new St.DrawingArea(), + this._unfocusedDots = new St.DrawingArea(); + this._focusedDots._tweeningToSize = null, + this._unfocusedDots._tweeningToSize = null; + + this._focusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._focusedDots, Me.settings.get_string('dot-style-focused'), true); + this._displayProperIndicator(); + })); + + this._unfocusedDots.connect('repaint', Lang.bind(this, function() { + if(this._dashItemContainer.animatingOut) { + // don't draw and trigger more animations if the icon is in the middle of + // being added to the panel + return; + } + this._drawRunningIndicator(this._unfocusedDots, Me.settings.get_string('dot-style-unfocused'), false); + this._displayProperIndicator(); + })); + + this._dotsContainer.add_child(this._unfocusedDots); + + this._updateWindows(); + + this._timeoutsHandler.add([T3, 0, () => { + this._resetDots(); + this._displayProperIndicator(); + }]); + } + + this._dotsContainer.add_child(this._focusedDots); + }, + + _resetDots: function() { + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + [this._focusedDots, this._unfocusedDots].forEach(d => { + d._tweeningToSize = null; + d.set_size(-1, -1); + d.x_expand = d.y_expand = false; + + d[isHorizontalDots ? 'width' : 'height'] = 1; + d[(isHorizontalDots ? 'y' : 'x') + '_expand'] = true; + }); + }, + + _settingsChangeRefresh: function() { + if (this._isGroupApps) { + this._updateWindows(); + this._resetDots(); + this._focusedDots.queue_repaint(); + this._unfocusedDots.queue_repaint(); + } + + this._displayProperIndicator(true); + }, + + _updateWindowTitleStyle: function() { + if (this._windowTitle) { + let useFixedWidth = Me.settings.get_boolean('group-apps-use-fixed-width'); + let variableWidth = !useFixedWidth || this.dtpPanel.checkIfVertical() || this.dtpPanel.taskbar.fullScrollView; + let fontWeight = Me.settings.get_string('group-apps-label-font-weight'); + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let fontColor = this.window.minimized ? + Me.settings.get_string('group-apps-label-font-color-minimized') : + Me.settings.get_string('group-apps-label-font-color'); + let scaleFactor = Utils.getScaleFactor(); + let maxLabelWidth = Me.settings.get_int('group-apps-label-max-width') * scaleFactor; + + this._windowTitle[(maxLabelWidth > 0 ? 'show' : 'hide')](); + + this._windowTitle.clutter_text.natural_width = useFixedWidth ? maxLabelWidth : 0; + this._windowTitle.clutter_text.natural_width_set = useFixedWidth; + this._windowTitle.set_width(variableWidth ? -1 : maxLabelWidth + TITLE_RIGHT_PADDING * scaleFactor); + + this._windowTitle.set_style('font-size: ' + Me.settings.get_int('group-apps-label-font-size') * fontScale + 'px;' + + 'font-weight: ' + fontWeight + ';' + + (useFixedWidth ? '' : 'max-width: ' + maxLabelWidth + 'px;') + + 'color: ' + fontColor); + } + }, + + _updateWindowTitle: function() { + if (this._windowTitle.text != this.window.title) { + this._windowTitle.text = (this.window.title ? this.window.title : this.app.get_name()).replace(/\r?\n|\r/g, '').trim(); + + if (this._focusedDots) { + this._displayProperIndicator(); + } + } + }, + + _setIconStyle: function(isFocused) { + let inlineStyle = 'margin: 0;'; + + if(Me.settings.get_boolean('focus-highlight') && + this._checkIfFocusedApp() && !this.isLauncher && + (!this.window || isFocused) && !this._isThemeProvidingIndicator() && this._checkIfMonitorHasFocus()) { + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let isWide = this._isWideDotStyle(focusedDotStyle); + let pos = Me.settings.get_string('dot-position'); + let highlightMargin = isWide ? Me.settings.get_int('dot-size') : 0; + + if(!this.window) { + let containerWidth = this._dtpIconContainer.get_width() / Utils.getScaleFactor();; + let backgroundSize = containerWidth + "px " + + (containerWidth - (pos == DOT_POSITION.BOTTOM ? highlightMargin : 0)) + "px;"; + + if (focusedDotStyle == DOT_STYLE.CILIORA || focusedDotStyle == DOT_STYLE.SEGMENTED) + highlightMargin += 1; + + if (this._nWindows > 1 && focusedDotStyle == DOT_STYLE.METRO) { + let bgSvg = '/img/highlight_stacked_bg'; + + if (pos == DOT_POSITION.LEFT || pos == DOT_POSITION.RIGHT) { + bgSvg += (this.dtpPanel.checkIfVertical() ? '_2' : '_3'); + } + + inlineStyle += "background-image: url('" + Me.path + bgSvg + ".svg');" + + "background-position: 0 " + (pos == DOT_POSITION.TOP ? highlightMargin : 0) + "px;" + + "background-size: " + backgroundSize; + } + } + + let highlightColor = this._getFocusHighlightColor(); + inlineStyle += "background-color: " + cssHexTocssRgba(highlightColor, Me.settings.get_int('focus-highlight-opacity') * 0.01); + } + + if(this._dotsContainer.get_style() != inlineStyle && this._dotsContainer.mapped) { + if (!this._isGroupApps) { + //when the apps are ungrouped, set the style synchronously so the icons don't jump around on taskbar redraw + this._dotsContainer.set_style(inlineStyle); + } else if (!this._timeoutsHandler.getId(T1)) { + //graphical glitches if i dont set this on a timeout + this._timeoutsHandler.add([T1, 0, () => this._dotsContainer.set_style(inlineStyle)]); + } + } + }, + + _checkIfFocusedApp: function() { + return tracker.focus_app == this.app; + }, + + _checkIfMonitorHasFocus: function() { + return global.display.focus_window && + (!Me.settings.get_boolean('multi-monitors') || // only check same monitor index if multi window is enabled. + !Me.settings.get_boolean('isolate-monitors') || + global.display.focus_window.get_monitor() === this.dtpPanel.monitor.index); + }, + + _setAppIconPadding: function() { + let padding = getIconPadding(this.dtpPanel.monitor.index); + let margin = Me.settings.get_int('appicon-margin'); + + this.actor.set_style('padding:' + (this.dtpPanel.checkIfVertical() ? margin + 'px 0' : '0 ' + margin + 'px;')); + this._iconContainer.set_style('padding: ' + padding + 'px;'); + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + + if (this._draggable) { + this._draggable.fakeRelease(); + } + + if (this.isDragged) { + return; + } + + if (!this._menu) { + this._menu = new taskbarSecondaryMenu(this, this.dtpPanel); + this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { + this.activateWindow(window, Me.settings); + })); + this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + + this._menuManager.addMenu(this._menu); + } + + this.emit('menu-state-changed', true); + + this._previewMenu.close(true); + + this.actor.set_hover(true); + this._menu.actor.add_style_class_name('dashtopanelSecondaryMenu'); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + _onFocusAppChanged: function(windowTracker) { + this._displayProperIndicator(true); + }, + + _onOverviewWindowDragEnd: function(windowTracker) { + this._timeoutsHandler.add([T4, 0, () => this._displayProperIndicator()]); + }, + + _onSwitchWorkspace: function(windowTracker) { + if (this._isGroupApps) { + this._timeoutsHandler.add([T5, 0, () => this._displayProperIndicator(true)]); + } else { + this._displayProperIndicator(); + } + }, + + _displayProperIndicator: function (force) { + let isFocused = this._isFocusedWindow(); + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + + this._setIconStyle(isFocused); + + if(!this._isGroupApps) { + if (this.window && (Me.settings.get_boolean('group-apps-underline-unfocused') || isFocused)) { + let align = Clutter.ActorAlign[position == DOT_POSITION.TOP || position == DOT_POSITION.LEFT ? 'START' : 'END']; + + this._focusedDots.set_size(0, 0); + this._focusedDots[isHorizontalDots ? 'height' : 'width'] = this._getRunningIndicatorSize(); + + this._focusedDots.y_align = this._focusedDots.x_align = Clutter.ActorAlign.FILL; + this._focusedDots[(isHorizontalDots ? 'y' : 'x') + '_align'] = align; + this._focusedDots.background_color = this._getRunningIndicatorColor(isFocused); + this._focusedDots.show(); + } else if (this._focusedDots.visible) { + this._focusedDots.hide(); + } + } else { + let sizeProp = isHorizontalDots ? 'width' : 'height'; + let containerSize = this._container[sizeProp]; + let focusedDotStyle = Me.settings.get_string('dot-style-focused'); + let unfocusedDotStyle = Me.settings.get_string('dot-style-unfocused'); + let focusedIsWide = this._isWideDotStyle(focusedDotStyle); + let unfocusedIsWide = this._isWideDotStyle(unfocusedDotStyle); + + let newFocusedDotsSize = 0; + let newFocusedDotsOpacity = 0; + let newUnfocusedDotsSize = 0; + let newUnfocusedDotsOpacity = 0; + + isFocused = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + this._timeoutsHandler.add([T6, 0, () => { + if (!this._destroyed) { + if(isFocused) + this.actor.add_style_class_name('focused'); + else + this.actor.remove_style_class_name('focused'); + } + }]); + + if(focusedIsWide) { + newFocusedDotsSize = (isFocused && this._nWindows > 0) ? containerSize : 0; + newFocusedDotsOpacity = 255; + } else { + newFocusedDotsSize = containerSize; + newFocusedDotsOpacity = (isFocused && this._nWindows > 0) ? 255 : 0; + } + + if(unfocusedIsWide) { + newUnfocusedDotsSize = (!isFocused && this._nWindows > 0) ? containerSize : 0; + newUnfocusedDotsOpacity = 255; + } else { + newUnfocusedDotsSize = containerSize; + newUnfocusedDotsOpacity = (!isFocused && this._nWindows > 0) ? 255 : 0; + } + + // Only animate if... + // animation is enabled in settings + // AND (going from a wide style to a narrow style indicator or vice-versa + // OR going from an open app to a closed app or vice versa) + if(Me.settings.get_boolean('animate-app-switch') && + ((focusedIsWide != unfocusedIsWide) || + (this._focusedDots[sizeProp] != newUnfocusedDotsSize || this._unfocusedDots[sizeProp] != newFocusedDotsSize))) { + this._animateDotDisplay(this._focusedDots, newFocusedDotsSize, this._unfocusedDots, newUnfocusedDotsOpacity, force, sizeProp); + this._animateDotDisplay(this._unfocusedDots, newUnfocusedDotsSize, this._focusedDots, newFocusedDotsOpacity, force, sizeProp); + } else { + this._focusedDots.opacity = newFocusedDotsOpacity; + this._unfocusedDots.opacity = newUnfocusedDotsOpacity; + this._focusedDots[sizeProp] = newFocusedDotsSize; + this._unfocusedDots[sizeProp] = newUnfocusedDotsSize; + } + } + }, + + _animateDotDisplay: function (dots, newSize, otherDots, newOtherOpacity, force, sizeProp) { + if((dots[sizeProp] != newSize && dots._tweeningToSize !== newSize) || force) { + let tweenOpts = { + time: Taskbar.DASH_ANIMATION_TIME, + transition: 'easeInOutCubic', + onComplete: Lang.bind(this, function() { + if(newOtherOpacity > 0) + otherDots.opacity = newOtherOpacity; + dots._tweeningToSize = null; + }) + }; + + if(newOtherOpacity == 0) + otherDots.opacity = newOtherOpacity; + + tweenOpts[sizeProp] = newSize; + dots._tweeningToSize = newSize; + + Utils.animate(dots, tweenOpts); + } + }, + + _isFocusedWindow: function() { + let focusedWindow = global.display.focus_window; + + while (focusedWindow) { + if (focusedWindow == this.window) { + return true; + } + + focusedWindow = focusedWindow.get_transient_for(); + } + + return false; + }, + + _isWideDotStyle: function(dotStyle) { + return dotStyle == DOT_STYLE.SEGMENTED || + dotStyle == DOT_STYLE.CILIORA || + dotStyle == DOT_STYLE.METRO || + dotStyle == DOT_STYLE.SOLID; + }, + + _isThemeProvidingIndicator: function () { + // This is an attempt to determine if the theme is providing their own + // running indicator by way of a border image on the icon, for example in + // the theme Ciliora + return (this.icon.actor.get_stage() && + this.icon.actor.get_theme_node().get_border_image()); + }, + + activate: function(button, handleAsGrouped) { + let event = Clutter.get_current_event(); + let modifiers = event ? event.get_state() : 0; + + // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.) + modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK); + + // We don't change the CTRL-click behaviour: in such case we just chain + // up the parent method and return. + if (modifiers & Clutter.ModifierType.CONTROL_MASK) { + // Keep default behaviour: launch new window + // By calling the parent method I make it compatible + // with other extensions tweaking ctrl + click + this.callParent('activate', button); + return; + } + + // We check what type of click we have and if the modifier SHIFT is + // being used. We then define what buttonAction should be for this + // event. + let buttonAction = 0; + if (button && button == 2 ) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-middle-click-action'); + else + buttonAction = Me.settings.get_string('middle-click-action'); + } + else if (button && button == 1) { + if (modifiers & Clutter.ModifierType.SHIFT_MASK) + buttonAction = Me.settings.get_string('shift-click-action'); + else + buttonAction = Me.settings.get_string('click-action'); + } + + let appCount = this.getAppIconInterestingWindows().length; + let previewedAppIcon = this._previewMenu.getCurrentAppIcon(); + this._previewMenu.close(Me.settings.get_boolean('window-preview-hide-immediate-click')); + + // We check if the app is running, and that the # of windows is > 0 in + // case we use workspace isolation, + let appIsRunning = this.app.state == Shell.AppState.RUNNING && appCount > 0; + + // We customize the action only when the application is already running + if (appIsRunning && !this.isLauncher) { + if (this.window && !handleAsGrouped) { + //ungrouped applications behaviors + switch (buttonAction) { + case 'RAISE': case 'CYCLE': case 'CYCLE-MIN': case 'MINIMIZE': case 'TOGGLE-SHOWPREVIEW': case 'TOGGLE-CYCLE': + if (!Main.overview._shown && + (buttonAction == 'MINIMIZE' || buttonAction == 'TOGGLE-SHOWPREVIEW' || buttonAction == 'TOGGLE-CYCLE' || buttonAction == 'CYCLE-MIN') && + (this._isFocusedWindow() || (buttonAction == 'MINIMIZE' && (button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK)))) { + this.window.minimize(); + } else { + Main.activateWindow(this.window); + } + + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "QUIT": + this.window.delete(global.get_current_time()); + break; + } + } else { + //grouped application behaviors + let monitor = this.dtpPanel.monitor; + let appHasFocus = this._checkIfFocusedApp() && this._checkIfMonitorHasFocus(); + + switch (buttonAction) { + case "RAISE": + activateAllWindows(this.app, monitor); + break; + + case "LAUNCH": + this._launchNewInstance(); + break; + + case "MINIMIZE": + // In overview just activate the app, unless the acion is explicitely + // requested with a keyboard modifier + if (!Main.overview._shown || modifiers){ + // If we have button=2 or a modifier, allow minimization even if + // the app is not focused + if (appHasFocus || button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) { + // minimize all windows on double click and always in the case of primary click without + // additional modifiers + let all_windows = (button == 1 && ! modifiers) || event.get_click_count() > 1; + minimizeWindow(this.app, all_windows, monitor); + } + else + activateAllWindows(this.app, monitor); + } + else + this.app.activate(); + break; + + case "CYCLE": + if (!Main.overview._shown){ + if (appHasFocus) + cycleThroughWindows(this.app, false, false, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "CYCLE-MIN": + if (!Main.overview._shown){ + if (appHasFocus || (recentlyClickedApp == this.app && recentlyClickedAppWindows[recentlyClickedAppIndex % recentlyClickedAppWindows.length] == "MINIMIZE")) + cycleThroughWindows(this.app, false, true, monitor); + else { + activateFirstWindow(this.app, monitor); + } + } + else + this.app.activate(); + break; + case "TOGGLE-SHOWPREVIEW": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + if (event.get_click_count() > 1) { + // minimize all windows if double clicked + minimizeWindow(this.app, true, monitor); + } else if (previewedAppIcon != this) { + this._previewMenu.open(this); + } + + this.emit('sync-tooltip'); + } + } + else + this.app.activate(); + break; + case "TOGGLE-CYCLE": + if (!Main.overview._shown) { + if (appCount == 1) { + if (appHasFocus) + minimizeWindow(this.app, false, monitor); + else + activateFirstWindow(this.app, monitor); + } else { + cycleThroughWindows(this.app, false, false, monitor); + } + } + else + this.app.activate(); + break; + case "QUIT": + closeAllWindows(this.app, monitor); + break; + } + } + } + else { + this._launchNewInstance(); + } + + Main.overview.hide(); + }, + + _launchNewInstance: function() { + if (this.app.can_open_new_window()) { + let appActions = this.app.get_app_info().list_actions(); + let newWindowIndex = appActions.indexOf('new-window'); + + if(Me.settings.get_boolean('animate-window-launch')) { + this.animateLaunch(); + } + + if (newWindowIndex < 0) { + this.app.open_new_window(-1); + } else { + this.app.launch_action(appActions[newWindowIndex], global.get_current_time(), -1); + } + } else { + let windows = this.window ? [this.window] : this.app.get_windows(); + + if (windows.length) { + Main.activateWindow(windows[0]); + } else { + this.app.activate(); + } + } + }, + + _updateWindows: function() { + let windows = [this.window]; + + if (!this.window) { + windows = this.getAppIconInterestingWindows(); + + this._nWindows = windows.length; + + for (let i = 1; i <= MAX_INDICATORS; i++){ + let className = 'running'+i; + if(i != this._nWindows) + this.actor.remove_style_class_name(className); + else + this.actor.add_style_class_name(className); + } + } + + this._previewMenu.update(this, windows); + }, + + _getRunningIndicatorCount: function() { + return Math.min(this._nWindows, MAX_INDICATORS); + }, + + _getRunningIndicatorSize: function() { + return Me.settings.get_int('dot-size') * Utils.getScaleFactor(); + }, + + _getRunningIndicatorColor: function(isFocused) { + let color; + const fallbackColor = new Clutter.Color({ red: 82, green: 148, blue: 226, alpha: 255 }); + + if (Me.settings.get_boolean('dot-color-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) { + color = Clutter.color_from_string(palette.original)[1]; + } else { // unable to determine color, fall back to theme + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + } else if(Me.settings.get_boolean('dot-color-override')) { + let dotColorSettingPrefix = 'dot-color-'; + + if(!isFocused && Me.settings.get_boolean('dot-color-unfocused-different')) + dotColorSettingPrefix = 'dot-color-unfocused-'; + + color = Clutter.color_from_string(Me.settings.get_string(dotColorSettingPrefix + (this._getRunningIndicatorCount() || 1) ))[1]; + } else { + // Re-use the style - background color, and border width and color - + // of the default dot + let themeNode = this._dot.get_theme_node(); + color = themeNode.get_background_color(); + + // theme didn't provide one, use a default + if(color.alpha == 0) color = fallbackColor; + } + + return color; + }, + + _getFocusHighlightColor: function() { + if (Me.settings.get_boolean('focus-highlight-dominant')) { + let dce = new Utils.DominantColorExtractor(this.app); + let palette = dce._getColorPalette(); + if (palette) return palette.original; + } + return Me.settings.get_string('focus-highlight-color'); + }, + + _drawRunningIndicator: function(area, type, isFocused) { + let n = this._getRunningIndicatorCount(); + + if (!n) { + return; + } + + let position = Me.settings.get_string('dot-position'); + let isHorizontalDots = position == DOT_POSITION.TOP || position == DOT_POSITION.BOTTOM; + let bodyColor = this._getRunningIndicatorColor(isFocused); + let [areaWidth, areaHeight] = area.get_surface_size(); + let cr = area.get_context(); + let size = this._getRunningIndicatorSize(); + + let areaSize = areaWidth; + let startX = 0; + let startY = 0; + + if (isHorizontalDots) { + if (position == DOT_POSITION.BOTTOM) { + startY = areaHeight - size; + } + } else { + areaSize = areaHeight; + + if (position == DOT_POSITION.RIGHT) { + startX = areaWidth - size; + } + } + + if (type == DOT_STYLE.SOLID || type == DOT_STYLE.METRO) { + if (type == DOT_STYLE.SOLID || n <= 1) { + cr.translate(startX, startY); + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [areaSize, size] : [size, areaSize])); + cr.fill(); + } else { + let blackenedLength = (1 / 48) * areaSize; // need to scale with the SVG for the stacked highlight + let darkenedLength = isFocused ? (2 / 48) * areaSize : (10 / 48) * areaSize; + let blackenedColor = bodyColor.shade(.3); + let darkenedColor = bodyColor.shade(.7); + let solidDarkLength = areaSize - darkenedLength; + let solidLength = solidDarkLength - blackenedLength; + + cr.translate(startX, startY); + + Clutter.cairo_set_source_color(cr, bodyColor); + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [solidLength, size] : [size, solidLength])); + cr.fill(); + Clutter.cairo_set_source_color(cr, blackenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidLength, 0, 1, size] : [0, solidLength, size, 1]); + cr.fill(); + Clutter.cairo_set_source_color(cr, darkenedColor); + cr.newSubPath(); + cr.rectangle.apply(cr, isHorizontalDots ? [solidDarkLength, 0, darkenedLength, size] : [0, solidDarkLength, size, darkenedLength]); + cr.fill(); + } + } else { + let spacing = Math.ceil(areaSize / 18); // separation between the indicators + let length; + let dist; + let indicatorSize; + let translate; + let preDraw = () => {}; + let draw; + let drawDash = (i, dashLength) => { + dist = i * dashLength + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0, dashLength, size] : [0, dist, size, dashLength])); + }; + + switch (type) { + case DOT_STYLE.CILIORA: + spacing = size; + length = areaSize - (size * (n - 1)) - (spacing * (n - 1)); + translate = () => cr.translate(startX, startY); + preDraw = () => { + cr.newSubPath(); + cr.rectangle.apply(cr, [0, 0].concat(isHorizontalDots ? [length, size] : [size, length])); + }; + draw = i => { + dist = length + (i * spacing) + ((i - 1) * size); + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DOTS: + let radius = size / 2; + + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = (2 * i + 1) * radius + i * spacing; + cr.arc.apply(cr, (isHorizontalDots ? [dist, radius] : [radius, dist]).concat([radius, 0, 2 * Math.PI])); + }; + break; + case DOT_STYLE.SQUARES: + translate = () => { + indicatorSize = Math.floor((areaSize - n * size - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => { + dist = i * size + i * spacing; + cr.rectangle.apply(cr, (isHorizontalDots ? [dist, 0] : [0, dist]).concat([size, size])); + }; + break; + case DOT_STYLE.DASHES: + length = Math.floor(areaSize / 4) - spacing; + translate = () => { + indicatorSize = Math.floor((areaSize - n * length - (n - 1) * spacing) / 2); + cr.translate.apply(cr, isHorizontalDots ? [indicatorSize, startY] : [startX, indicatorSize]); + } + draw = i => drawDash(i, length); + break; + case DOT_STYLE.SEGMENTED: + length = Math.ceil((areaSize - ((n - 1) * spacing)) / n); + translate = () => cr.translate(startX, startY); + draw = i => drawDash(i, length); + break; + } + + translate(); + + Clutter.cairo_set_source_color(cr, bodyColor); + preDraw(); + for (let i = 0; i < n; i++) { + cr.newSubPath(); + draw(i); + } + cr.fill(); + } + + cr.$dispose(); + }, + + _numberOverlay: function() { + // Add label for a Hot-Key visual aid + this._numberOverlayLabel = new St.Label({ style_class: 'badge' }); + this._numberOverlayBin = new St.Bin({ + child: this._numberOverlayLabel, y: 2 + }); + this._numberOverlayLabel.add_style_class_name('number-overlay'); + this._numberOverlayOrder = -1; + this._numberOverlayBin.hide(); + + this._dtpIconContainer.add_child(this._numberOverlayBin); + }, + + updateHotkeyNumberOverlay: function() { + this.updateNumberOverlay(this._numberOverlayBin, true); + }, + + updateNumberOverlay: function(bin, fixedSize) { + // We apply an overall scale factor that might come from a HiDPI monitor. + // Clutter dimensions are in physical pixels, but CSS measures are in logical + // pixels, so make sure to consider the scale. + // Set the font size to something smaller than the whole icon so it is + // still visible. The border radius is large to make the shape circular + let [minWidth, natWidth] = this._dtpIconContainer.get_preferred_width(-1); + let font_size = Math.round(Math.max(12, 0.3 * natWidth) / Utils.getScaleFactor()); + let size = Math.round(font_size * 1.3); + let label = bin.child; + let style = 'font-size: ' + font_size + 'px;' + + 'border-radius: ' + this.icon.iconSize + 'px;' + + 'height: ' + size +'px;'; + + if (fixedSize || label.get_text().length == 1) { + style += 'width: ' + size + 'px;'; + } else { + style += 'padding: 0 2px;'; + } + + bin.x = fixedSize ? natWidth - size - 2 : 2; + label.set_style(style); + }, + + setNumberOverlay: function(number) { + this._numberOverlayOrder = number; + this._numberOverlayLabel.set_text(number.toString()); + }, + + toggleNumberOverlay: function(activate) { + if (activate && this._numberOverlayOrder > -1) + this._numberOverlayBin.show(); + else + this._numberOverlayBin.hide(); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + this._previewMenu.close(true); + } + + return DND.DragMotionResult.CONTINUE; + }, + + // Disable all DnD methods on gnome-shell 3.34 + _onDragBegin: function() {}, + _onDragEnd: function() {}, + acceptDrop: function() { return false; }, + + getAppIconInterestingWindows: function(isolateMonitors) { + return getInterestingWindows(this.app, this.dtpPanel.monitor, isolateMonitors); + } +}); +taskbarAppIcon.prototype.scaleAndFade = taskbarAppIcon.prototype.undoScaleAndFade = () => {}; + +function minimizeWindow(app, param, monitor){ + // Param true make all app windows minimize + let windows = getInterestingWindows(app, monitor); + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + for (let i = 0; i < windows.length; i++) { + let w = windows[i]; + if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()){ + w.minimize(); + // Just minimize one window. By specification it should be the + // focused window on the current workspace. + if(!param) + break; + } + } +} + +/* + * By default only non minimized windows are activated. + * This activates all windows in the current workspace. + */ +function activateAllWindows(app, monitor){ + + // First activate first window so workspace is switched if needed, + // then activate all other app windows in the current workspace. + let windows = getInterestingWindows(app, monitor); + let w = windows[0]; + Main.activateWindow(w); + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + + if (windows.length <= 0) + return; + + for (let i = windows.length - 1; i >= 0; i--){ + if (windows[i].get_workspace().index() == activeWorkspace){ + Main.activateWindow(windows[i]); + } + } +} + +function activateFirstWindow(app, monitor){ + + let windows = getInterestingWindows(app, monitor); + Main.activateWindow(windows[0]); +} + +function cycleThroughWindows(app, reversed, shouldMinimize, monitor) { + // Store for a little amount of time last clicked app and its windows + // since the order changes upon window interaction + let MEMORY_TIME=3000; + + let app_windows = getInterestingWindows(app, monitor); + + if(shouldMinimize) + app_windows.push("MINIMIZE"); + + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, resetRecentlyClickedApp); + + // If there isn't already a list of windows for the current app, + // or the stored list is outdated, use the current windows list. + if (!recentlyClickedApp || + recentlyClickedApp.get_id() != app.get_id() || + recentlyClickedAppWindows.length != app_windows.length || + recentlyClickedAppMonitorIndex != monitor.index) { + recentlyClickedApp = app; + recentlyClickedAppWindows = app_windows; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = monitor.index; + } + + if (reversed) { + recentlyClickedAppIndex--; + if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1; + } else { + recentlyClickedAppIndex++; + } + let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; + + if(recentlyClickedAppWindows[index] === "MINIMIZE") + minimizeWindow(app, true, monitor); + else + Main.activateWindow(recentlyClickedAppWindows[index]); +} + +function resetRecentlyClickedApp() { + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + + recentlyClickedAppLoopId=0; + recentlyClickedApp =null; + recentlyClickedAppWindows = null; + recentlyClickedAppIndex = 0; + recentlyClickedAppMonitorIndex = null; + + return false; +} + +function closeAllWindows(app, monitor) { + let windows = getInterestingWindows(app, monitor); + for (let i = 0; i < windows.length; i++) + windows[i].delete(global.get_current_time()); +} + +// Filter out unnecessary windows, for instance +// nautilus desktop window. +function getInterestingWindows(app, monitor, isolateMonitors) { + let windows = app.get_windows().filter(function(w) { + return !w.skip_taskbar; + }); + + // When using workspace or monitor isolation, we filter out windows + // that are not in the current workspace or on the same monitor as the appicon + if (Me.settings.get_boolean('isolate-workspaces')) + windows = windows.filter(function(w) { + return w.get_workspace().index() == Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace_index(); + }); + + if (monitor && Me.settings.get_boolean('multi-monitors') && (isolateMonitors || Me.settings.get_boolean('isolate-monitors'))) { + windows = windows.filter(function(w) { + return w.get_monitor() == monitor.index; + }); + } + + return windows; +} + +function cssHexTocssRgba(cssHex, opacity) { + var bigint = parseInt(cssHex.slice(1), 16); + var r = (bigint >> 16) & 255; + var g = (bigint >> 8) & 255; + var b = bigint & 255; + + return 'rgba(' + [r, g, b].join(',') + ',' + opacity + ')'; +} + +function getIconPadding(monitorIndex) { + let panelSize = PanelSettings.getPanelSize(Me.settings, monitorIndex); + let padding = Me.settings.get_int('appicon-padding'); + let availSize = panelSize - Taskbar.MIN_ICON_SIZE - panelSize % 2; + + if (padding * 2 > availSize) { + padding = availSize * .5; + } + + return padding; +} + +/** + * Extend AppMenu (AppIconMenu for pre gnome 41) + * + * - set popup arrow side based on taskbar orientation + * - Add close windows option based on quitfromdash extension + * (https://github.com/deuill/shell-extension-quitfromdash) + */ + +var taskbarSecondaryMenu = Utils.defineClass({ + Name: 'DashToPanel.SecondaryMenu', + Extends: (AppDisplay.AppMenu || AppDisplay.AppIconMenu), + ParentConstrParams: [[0]], + + _init: function(source, panel) { + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later + this.callParent('_init', source); + + let side = panel.getPosition(); + // Change the initialized side where required. + this._arrowSide = side; + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + }, + + // helper function for the quit windows abilities + _closeWindowInstance: function(metaWindow) { + metaWindow.delete(global.get_current_time()); + }, + + _dtpRedisplay: function(parentFunc) { + this.callParent(parentFunc); + + // Remove "Show Details" menu item + if(!Me.settings.get_boolean('secondarymenu-contains-showdetails')) { + let existingMenuItems = this._getMenuItems(); + for(let idx in existingMenuItems) { + if(existingMenuItems[idx].actor.label_actor.text == _("Show Details")) { + this.box.remove_child(existingMenuItems[idx].actor); + if(existingMenuItems[idx-1] instanceof PopupMenu.PopupSeparatorMenuItem) + this.box.remove_child(existingMenuItems[idx-1].actor); + break; + } + } + } + + // prepend items from the appMenu (for native gnome apps) + if(Me.settings.get_boolean('secondarymenu-contains-appmenu')) { + let appMenu = this._source.app.menu; + if(appMenu) { + let remoteMenu = new imports.ui.remoteMenu.RemoteMenu(this._source.actor, this._source.app.menu, this._source.app.action_group); + let appMenuItems = remoteMenu._getMenuItems(); + for(var i = 0, l = appMenuItems.length || 0; i < l; ++i) { + let menuItem = appMenuItems[i]; + let labelText = menuItem.actor.label_actor.text; + if(labelText == _("New Window") || labelText == _("Quit")) + continue; + + if(menuItem instanceof PopupMenu.PopupSeparatorMenuItem) + continue; + + // this ends up getting called multiple times, and bombing due to the signal id's being invalid + // on a 2nd pass. disconnect the base handler and attach our own that wraps the id's in if statements + menuItem.disconnect(menuItem._popupMenuDestroyId) + menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) { + if(menuItem._popupMenuDestroyId) { + menuItem.disconnect(menuItem._popupMenuDestroyId); + menuItem._popupMenuDestroyId = 0; + } + if(menuItem._activateId) { + menuItem.disconnect(menuItem._activateId); + menuItem._activateId = 0; + } + if(menuItem._activeChangeId) { + menuItem.disconnect(menuItem._activeChangeId); + menuItem._activeChangeId = 0; + } + if(menuItem._sensitiveChangeId) { + menuItem.disconnect(menuItem._sensitiveChangeId); + menuItem._sensitiveChangeId = 0; + } + this.disconnect(menuItem._parentSensitiveChangeId); + if (menuItem == this._activeMenuItem) + this._activeMenuItem = null; + })); + + menuItem.actor.get_parent().remove_child(menuItem.actor); + if(menuItem instanceof PopupMenu.PopupSubMenuMenuItem) { + let newSubMenuMenuItem = new PopupMenu.PopupSubMenuMenuItem(labelText); + let appSubMenuItems = menuItem.menu._getMenuItems(); + for(let appSubMenuIdx in appSubMenuItems){ + let subMenuItem = appSubMenuItems[appSubMenuIdx]; + subMenuItem.actor.get_parent().remove_child(subMenuItem.actor); + newSubMenuMenuItem.menu.addMenuItem(subMenuItem); + } + this.addMenuItem(newSubMenuMenuItem, i); + } else + this.addMenuItem(menuItem, i); + } + + if(i > 0) { + let separator = new PopupMenu.PopupSeparatorMenuItem(); + this.addMenuItem(separator, i); + } + } + } + + // quit menu + let app = this._source.app; + let window = this._source.window; + let count = window ? 1 : getInterestingWindows(app).length; + if ( count > 0) { + this._appendSeparator(); + let quitFromTaskbarMenuText = ""; + if (count == 1) + quitFromTaskbarMenuText = _("Quit"); + else + quitFromTaskbarMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + + this._quitfromTaskbarMenuItem = this._appendMenuItem(quitFromTaskbarMenuText); + this._quitfromTaskbarMenuItem.connect('activate', Lang.bind(this, function() { + let app = this._source.app; + let windows = window ? [window] : app.get_windows(); + for (i = 0; i < windows.length; i++) { + this._closeWindowInstance(windows[i]) + } + })); + } + } +}); +Signals.addSignalMethods(taskbarSecondaryMenu.prototype); +adjustMenuRedisplay(taskbarSecondaryMenu.prototype); + +/** + * This function is used for extendDashItemContainer + */ +function ItemShowLabel() { + if (!this._labelText) + return; + + this.label.set_text(this._labelText); + this.label.opacity = 0; + this.label.show(); + + let [stageX, stageY] = this.get_transformed_position(); + let node = this.label.get_theme_node(); + + let itemWidth = this.allocation.x2 - this.allocation.x1; + let itemHeight = this.allocation.y2 - this.allocation.y1; + + let labelWidth = this.label.get_width(); + let labelHeight = this.label.get_height(); + + let position = this._dtpPanel.getPosition(); + let labelOffset = node.get_length('-x-offset'); + + // From TaskbarItemContainer + if (this._getIconAnimationOffset) + labelOffset += this._getIconAnimationOffset(); + + let xOffset = Math.floor((itemWidth - labelWidth) / 2); + let x = stageX + xOffset + let y = stageY + (itemHeight - labelHeight) * .5; + + switch(position) { + case St.Side.TOP: + y = stageY + labelOffset + itemHeight; + break; + case St.Side.BOTTOM: + y = stageY - labelHeight - labelOffset; + break; + case St.Side.LEFT: + x = stageX + labelOffset + itemWidth; + break; + case St.Side.RIGHT: + x = stageX - labelWidth - labelOffset; + break; + } + + // keep the label inside the screen border + // Only needed for the x coordinate. + + // Leave a few pixel gap + let gap = LABEL_GAP; + let monitor = Main.layoutManager.findMonitorForActor(this); + if ( x - monitor.x < gap) + x += monitor.x - x + labelOffset; + else if ( x + labelWidth > monitor.x + monitor.width - gap) + x -= x + labelWidth -( monitor.x + monitor.width) + gap; + + this.label.set_position(Math.round(x), Math.round(y)); + + let duration = Dash.DASH_ITEM_LABEL_SHOW_TIME; + + if (duration > 1) { + duration /= 1000; + } + + Utils.animate(this.label, { + opacity: 255, + time: duration, + transition: 'easeOutQuad', + }); +}; + +/** + * A wrapper class around the ShowAppsIcon class. + * + * - Pass settings to the constructor + * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class) + * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class) + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon + * use of this class in place of the original showAppsButton. + * + */ +var ShowAppsIconWrapper = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconWrapper', + + _init: function(dtpPanel) { + this.realShowAppsIcon = new Dash.ShowAppsIcon(); + + Utils.wrapActor(this.realShowAppsIcon); + Utils.wrapActor(this.realShowAppsIcon.toggleButton); + + /* the variable equivalent to toggleButton has a different name in the appIcon class + (actor): duplicate reference to easily reuse appIcon methods */ + this.actor = this.realShowAppsIcon.toggleButton; + this.realShowAppsIcon.show(false); + + // Re-use appIcon methods + this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; + this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; + this._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; + + // No action on clicked (showing of the appsview is controlled elsewhere) + this._onClicked = Lang.bind(this, function(actor, button) { + this._removeMenuTimeout(); + }); + + this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); + this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent)); + this.actor.connect('clicked', Lang.bind(this, this._onClicked)); + this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu)); + + this._menu = null; + this._menuManager = new PopupMenu.PopupMenuManager(this.actor); + this._menuTimeoutId = 0; + + this.realShowAppsIcon._dtpPanel = dtpPanel; + Taskbar.extendDashItemContainer(this.realShowAppsIcon); + + let customIconPath = Me.settings.get_string('show-apps-icon-file'); + + this.realShowAppsIcon.icon.createIcon = function(size) { + this._iconActor = new St.Icon({ icon_name: 'view' + (Config.PACKAGE_VERSION < '3.20' ? '' : '-app') + '-grid-symbolic', + icon_size: size, + style_class: 'show-apps-icon', + track_hover: true }); + + if (customIconPath) { + this._iconActor.gicon = new Gio.FileIcon({ file: Gio.File.new_for_path(customIconPath) }); + } + + return this._iconActor; + }; + + this._changedShowAppsIconId = Me.settings.connect('changed::show-apps-icon-file', () => { + customIconPath = Me.settings.get_string('show-apps-icon-file'); + this.realShowAppsIcon.icon._createIconTexture(this.realShowAppsIcon.icon.iconSize); + }); + + this._changedAppIconPaddingId = Me.settings.connect('changed::appicon-padding', () => this.setShowAppsPadding()); + this._changedAppIconSidePaddingId = Me.settings.connect('changed::show-apps-icon-side-padding', () => this.setShowAppsPadding()); + + this.setShowAppsPadding(); + }, + + _onButtonPress: function(_actor, event) { + let button = event.get_button(); + if (button == 1) { + this._setPopupTimeout(); + } else if (button == 3) { + this.popupMenu(); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + }, + + _onLeaveEvent: function(_actor, _event) { + this.actor.fake_release(); + this._removeMenuTimeout(); + }, + + _onTouchEvent: function(actor, event) { + if (event.type() == Clutter.EventType.TOUCH_BEGIN) + this._setPopupTimeout(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMenuPoppedDown: function() { + this._menu.sourceActor = this.actor; + this.actor.sync_hover(); + this.emit('menu-state-changed', false); + }, + + setShowAppsPadding: function() { + let padding = getIconPadding(this.realShowAppsIcon._dtpPanel.monitor.index); + let sidePadding = Me.settings.get_int('show-apps-icon-side-padding'); + let isVertical = this.realShowAppsIcon._dtpPanel.checkIfVertical(); + + this.actor.set_style('padding:' + (padding + (isVertical ? sidePadding : 0)) + 'px ' + (padding + (isVertical ? 0 : sidePadding)) + 'px;'); + }, + + createMenu: function() { + if (!this._menu) { + this._menu = new MyShowAppsIconMenu(this.actor, this.realShowAppsIcon._dtpPanel); + this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { + if (!isPoppedUp) + this._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(this, function() { + this._menu.close(); + })); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + this._menuManager.addMenu(this._menu); + } + }, + + popupMenu: function() { + this._removeMenuTimeout(); + this.actor.fake_release(); + this.createMenu(this.actor); + + //this.emit('menu-state-changed', true); + + this.actor.set_hover(true); + this._menu.popup(); + this._menuManager.ignoreRelease(); + this.emit('sync-tooltip'); + + return false; + }, + + shouldShowTooltip: function() { + return Me.settings.get_boolean('show-tooltip') && + (this.actor.hover && (!this._menu || !this._menu.isOpen)); + }, + + destroy: function() { + Me.settings.disconnect(this._changedShowAppsIconId); + Me.settings.disconnect(this._changedAppIconSidePaddingId); + Me.settings.disconnect(this._changedAppIconPaddingId); + + this.realShowAppsIcon.destroy(); + } +}); +Signals.addSignalMethods(ShowAppsIconWrapper.prototype); + +/** + * A menu for the showAppsIcon + */ +var MyShowAppsIconMenu = Utils.defineClass({ + Name: 'DashToPanel.ShowAppsIconMenu', + Extends: taskbarSecondaryMenu, + ParentConstrParams: [[0], [1]], + + _dtpRedisplay: function() { + this.removeAll(); + + // Only add menu entries for commands that exist in path + function _appendItem(obj, info) { + if (Utils.checkIfCommandExists(info.cmd[0])) { + let item = obj._appendMenuItem(_(info.title)); + + item.connect('activate', function() { + Util.spawn(info.cmd); + }); + return item; + } + + return null; + } + + function _appendList(obj, commandList, titleList) { + if (commandList.length != titleList.length) { + return; + } + + for (var entry = 0; entry < commandList.length; entry++) { + _appendItem(obj, { + title: titleList[entry], + cmd: commandList[entry].split(' ') + }); + } + } + + if (this.sourceActor != Main.layoutManager.dummyCursor) { + _appendItem(this, { + title: 'Power options', + cmd: ['gnome-control-center', 'power'] + }); + + _appendItem(this, { + title: 'Event logs', + cmd: ['gnome-logs'] + }); + + _appendItem(this, { + title: 'System', + cmd: ['gnome-control-center', 'info-overview'] + }); + + _appendItem(this, { + title: 'Device Management', + cmd: ['gnome-control-center', 'display'] + }); + + _appendItem(this, { + title: 'Disk Management', + cmd: ['gnome-disks'] + }); + + _appendList( + this, + Me.settings.get_strv('show-apps-button-context-menu-commands'), + Me.settings.get_strv('show-apps-button-context-menu-titles') + ) + + this._appendSeparator(); + } + + _appendItem(this, { + title: 'Terminal', + cmd: ['gnome-terminal'] + }); + + _appendItem(this, { + title: 'System monitor', + cmd: ['gnome-system-monitor'] + }); + + _appendItem(this, { + title: 'Files', + cmd: ['nautilus'] + }); + + _appendItem(this, { + title: 'Extensions', + cmd: ['gnome-shell-extension-prefs'] + }); + + _appendItem(this, { + title: 'Settings', + cmd: ['gnome-control-center', 'wifi'] + }); + + _appendList( + this, + Me.settings.get_strv('panel-context-menu-commands'), + Me.settings.get_strv('panel-context-menu-titles') + ) + + this._appendSeparator(); + + let lockTaskbarMenuItem = this._appendMenuItem(Me.settings.get_boolean('taskbar-locked') ? _('Unlock taskbar') : _('Lock taskbar')); + lockTaskbarMenuItem.connect('activate', () => { + Me.settings.set_boolean('taskbar-locked', !Me.settings.get_boolean('taskbar-locked')); + }); + + let settingsMenuItem = this._appendMenuItem(_('Dash to Panel Settings')); + settingsMenuItem.connect('activate', function () { + let command = ["gnome-shell-extension-prefs"]; + + if (Config.PACKAGE_VERSION > '3.36') { + command = ["gnome-extensions", "prefs"]; + } + + Util.spawn(command.concat([Me.metadata.uuid])); + }); + + if(this._source._dtpPanel) { + this._appendSeparator(); + let item = this._appendMenuItem(this._source._dtpPanel._restoreWindowList ? _('Restore Windows') : _('Show Desktop')); + item.connect('activate', Lang.bind(this._source._dtpPanel, this._source._dtpPanel._onShowDesktopButtonPress)); + } + } +}); +adjustMenuRedisplay(MyShowAppsIconMenu.prototype); + +function adjustMenuRedisplay(menuProto) { + menuProto[menuRedisplayFunc] = function() { this._dtpRedisplay(menuRedisplayFunc) }; +} + +var getIconContainerStyle = function(isVertical) { + let style = 'padding: '; + + if (Me.settings.get_boolean('group-apps')) { + style += (isVertical ? '0;' : '0 ' + DEFAULT_PADDING_SIZE + 'px;'); + } else { + style += (isVertical ? '' : '0 ') + DEFAULT_PADDING_SIZE + 'px;'; + } + + return style; +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js new file mode 100644 index 0000000..57d2f13 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/convenience.js @@ -0,0 +1,89 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // Check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) + Gettext.bindtextdomain(domain, localeDir.get_path()); + else + Gettext.bindtextdomain(domain, Config.LOCALEDIR); +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // Check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + else + schemaSource = GioSSS.get_default(); + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) + throw new Error('Schema ' + schema + ' could not be found for extension ' + + extension.metadata.uuid + '. Please check your installation.'); + + return new Gio.Settings({ + settings_schema: schemaObj + }); +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js new file mode 100644 index 0000000..7ab80f2 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/extension.js @@ -0,0 +1,149 @@ +/* + * Dash-To-Panel extension for Gnome 3 + * Copyright 2016 Jason DeRose (jderose9) and Charles Gagnon (charlesg99) + * + * 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 2 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 . + * + */ + + +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Lang = imports.lang; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const ExtensionUtils = imports.misc.extensionUtils; +const Mainloop = imports.mainloop; +const Signals = imports.signals; + +const Me = ExtensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const PanelManager = Me.imports.panelManager; +const Utils = Me.imports.utils; + +const UBUNTU_DOCK_UUID = 'ubuntu-dock@ubuntu.com'; + +let panelManager; +let extensionChangedHandler; +let disabledUbuntuDock; +let extensionSystem = (Main.extensionManager || imports.ui.extensionSystem); + +function init() { + this._realHasOverview = Main.sessionMode.hasOverview; + + Convenience.initTranslations(Utils.TRANSLATION_DOMAIN); + + //create an object that persists until gnome-shell is restarted, even if the extension is disabled + Me.persistentStorage = {}; +} + +function enable() { + // The Ubuntu Dock extension might get enabled after this extension + extensionChangedHandler = extensionSystem.connect('extension-state-changed', (data, extension) => { + if (extension.uuid === UBUNTU_DOCK_UUID && extension.state === 1) { + _enable(); + } + }); + + //create a global object that can emit signals and conveniently expose functionalities to other extensions + global.dashToPanel = {}; + Signals.addSignalMethods(global.dashToPanel); + + _enable(); +} + +function _enable() { + let ubuntuDock = Main.extensionManager ? + Main.extensionManager.lookup(UBUNTU_DOCK_UUID) : //gnome-shell >= 3.33.4 + ExtensionUtils.extensions[UBUNTU_DOCK_UUID]; + + if (ubuntuDock && ubuntuDock.stateObj && ubuntuDock.stateObj.dockManager) { + // Disable Ubuntu Dock + let extensionOrder = (extensionSystem.extensionOrder || extensionSystem._extensionOrder); + + Utils.getStageTheme().get_theme().unload_stylesheet(ubuntuDock.stylesheet); + ubuntuDock.stateObj.disable(); + disabledUbuntuDock = true; + ubuntuDock.state = 2; //ExtensionState.DISABLED + extensionOrder.splice(extensionOrder.indexOf(UBUNTU_DOCK_UUID), 1); + + //reset to prevent conflicts with the ubuntu-dock + if (panelManager) { + disable(true); + } + } + + if (panelManager) return; //already initialized + + Me.settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + Me.desktopSettings = Convenience.getSettings('org.gnome.desktop.interface'); + + Main.layoutManager.startInOverview = !Me.settings.get_boolean('hide-overview-on-startup'); + + if (Me.settings.get_boolean('hide-overview-on-startup') && Main.layoutManager._startingUp) { + Main.sessionMode.hasOverview = false; + Main.layoutManager.connect('startup-complete', () => { + Main.sessionMode.hasOverview = this._realHasOverview + }); + } + + panelManager = new PanelManager.dtpPanelManager(); + + panelManager.enable(); + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(this, function() { + if(Me.settings.get_boolean('show-appmenu')) + Main.wm._toggleAppMenu(); + else + panelManager.primaryPanel.taskbar.popupFocusedAppSecondaryMenu(); + }), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); +} + +function disable(reset) { + panelManager.disable(); + Me.settings.run_dispose(); + Me.desktopSettings.run_dispose(); + + delete Me.settings; + panelManager = null; + + Utils.removeKeybinding('open-application-menu'); + Utils.addKeybinding( + 'open-application-menu', + new Gio.Settings({ schema_id: WindowManager.SHELL_KEYBINDINGS_SCHEMA }), + Lang.bind(Main.wm, Main.wm._toggleAppMenu), + Shell.ActionMode.NORMAL | Shell.ActionMode.POPUP + ); + + if (!reset) { + extensionSystem.disconnect(extensionChangedHandler); + delete global.dashToPanel; + + // Re-enable Ubuntu Dock if it was disabled by dash to panel + if (disabledUbuntuDock && Main.sessionMode.allowExtensions) { + (extensionSystem._callExtensionEnable || extensionSystem.enableExtension).call(extensionSystem, UBUNTU_DOCK_UUID); + } + } + + Main.sessionMode.hasOverview = this._realHasOverview; +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg new file mode 100644 index 0000000..977146b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg new file mode 100644 index 0000000..47aa802 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg new file mode 100644 index 0000000..80420fd --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/img/highlight_stacked_bg_3.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js new file mode 100644 index 0000000..8fb1e97 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/intellihide.js @@ -0,0 +1,401 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +var GrabHelper = imports.ui.grabHelper; +const Layout = imports.ui.layout; +const Main = imports.ui.main; +const OverviewControls = imports.ui.overviewControls; +const PointerWatcher = imports.ui.pointerWatcher; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +//timeout intervals +const CHECK_POINTER_MS = 200; +const CHECK_GRAB_MS = 400; +const POST_ANIMATE_MS = 50; +const MIN_UPDATE_MS = 250; + +//timeout names +const T1 = 'checkGrabTimeout'; +const T2 = 'limitUpdateTimeout'; +const T3 = 'postAnimateTimeout'; +const T4 = 'panelBoxClipTimeout'; + +var SIDE_CONTROLS_ANIMATION_TIME = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / (OverviewControls.SIDE_CONTROLS_ANIMATION_TIME > 1 ? 1000 : 1); + +var Hold = { + NONE: 0, + TEMPORARY: 1, + PERMANENT: 2 +}; + +var Intellihide = Utils.defineClass({ + Name: 'DashToPanel.Intellihide', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._panelBox = dtpPanel.panelBox; + this._panelManager = dtpPanel.panelManager; + this._proximityManager = this._panelManager.proximityManager; + this._holdStatus = Hold.NONE; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._intellihideChangedId = Me.settings.connect('changed::intellihide', () => this._changeEnabledStatus()); + this._intellihideOnlySecondaryChangedId = Me.settings.connect('changed::intellihide-only-secondary', () => this._changeEnabledStatus()); + + this.enabled = false; + this._changeEnabledStatus(); + }, + + enable: function() { + this.enabled = true; + this._monitor = this._dtpPanel.monitor; + this._animationDestination = -1; + this._pendingUpdate = false; + this._hoveredOut = false; + this._windowOverlap = false; + this._translationProp = 'translation_' + (this._dtpPanel.checkIfVertical() ? 'x' : 'y'); + + this._panelBox.translation_y = 0; + this._panelBox.translation_x = 0; + + this._setTrackPanel(true); + this._bindGeneralSignals(); + + if (Me.settings.get_boolean('intellihide-hide-from-windows')) { + this._proximityWatchId = this._proximityManager.createWatch( + this._panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('intellihide-behaviour')], + 0, 0, + overlap => { + this._windowOverlap = overlap; + this._queueUpdatePanelPosition(); + } + ); + } + + this._setRevealMechanism(); + this._queueUpdatePanelPosition(); + }, + + disable: function(reset) { + if (this._proximityWatchId) { + this._proximityManager.removeWatch(this._proximityWatchId); + } + + this._setTrackPanel(false); + + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + + this._removeRevealMechanism(); + + this._revealPanel(!reset); + + this.enabled = false; + }, + + destroy: function() { + Me.settings.disconnect(this._intellihideChangedId); + Me.settings.disconnect(this._intellihideOnlySecondaryChangedId); + + if (this.enabled) { + this.disable(); + } + }, + + toggle: function() { + this[this._holdStatus & Hold.PERMANENT ? 'release' : 'revealAndHold'](Hold.PERMANENT); + }, + + revealAndHold: function(holdStatus) { + if (this.enabled && !this._holdStatus) { + this._revealPanel(); + } + + this._holdStatus |= holdStatus; + }, + + release: function(holdStatus) { + this._holdStatus -= holdStatus; + + if (this.enabled && !this._holdStatus) { + this._queueUpdatePanelPosition(); + } + }, + + reset: function() { + this.disable(true); + this.enable(); + }, + + _changeEnabledStatus: function() { + let intellihide = Me.settings.get_boolean('intellihide'); + let onlySecondary = Me.settings.get_boolean('intellihide-only-secondary'); + let enabled = intellihide && !(this._dtpPanel.isPrimary && onlySecondary); + + if (this.enabled !== enabled) { + this[enabled ? 'enable' : 'disable'](); + } + }, + + _bindGeneralSignals: function() { + this._signalsHandler.add( + [ + this._dtpPanel.taskbar, + 'menu-closed', + () => this._panelBox.sync_hover() + ], + [ + Me.settings, + [ + 'changed::intellihide-use-pressure', + 'changed::intellihide-hide-from-windows', + 'changed::intellihide-behaviour', + 'changed::intellihide-pressure-threshold', + 'changed::intellihide-pressure-time' + ], + () => this.reset() + ], + [ + this._panelBox, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._dtpPanel.taskbar.previewMenu, + 'open-state-changed', + () => this._queueUpdatePanelPosition() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._queueUpdatePanelPosition() + ] + ); + }, + + _onHoverChanged: function() { + this._hoveredOut = !this._panelBox.hover; + this._queueUpdatePanelPosition(); + }, + + _setTrackPanel: function(enable) { + let trackedIndex = Main.layoutManager._findActor(this._panelBox); + let actorData = Main.layoutManager._trackedActors[trackedIndex] + + actorData.affectsStruts = !enable; + actorData.trackFullscreen = !enable; + + this._panelBox.track_hover = enable; + this._panelBox.reactive = enable; + this._panelBox.visible = enable ? enable : this._panelBox.visible; + + Main.layoutManager._queueUpdateRegions(); + }, + + _setRevealMechanism: function() { + if (global.display.supports_extended_barriers() && Me.settings.get_boolean('intellihide-use-pressure')) { + this._edgeBarrier = this._createBarrier(); + this._pressureBarrier = new Layout.PressureBarrier( + Me.settings.get_int('intellihide-pressure-threshold'), + Me.settings.get_int('intellihide-pressure-time'), + Shell.ActionMode.NORMAL + ); + this._pressureBarrier.addBarrier(this._edgeBarrier); + this._signalsHandler.add([this._pressureBarrier, 'trigger', () => this._queueUpdatePanelPosition(true)]); + } else { + this._pointerWatch = PointerWatcher.getPointerWatcher() + .addWatch(CHECK_POINTER_MS, (x, y) => this._checkMousePointer(x, y)); + } + }, + + _removeRevealMechanism: function() { + if (this._pointerWatch) { + PointerWatcher.getPointerWatcher()._removeWatch(this._pointerWatch); + } + + if (this._pressureBarrier) { + this._pressureBarrier.destroy(); + this._edgeBarrier.destroy(); + } + }, + + _createBarrier: function() { + let position = this._dtpPanel.geom.position; + let opts = { display: global.display }; + + if (this._dtpPanel.checkIfVertical()) { + opts.y1 = this._monitor.y; + opts.y2 = this._monitor.y + this._monitor.height; + opts.x1 = opts.x2 = this._monitor.x; + } else { + opts.x1 = this._monitor.x; + opts.x2 = this._monitor.x + this._monitor.width; + opts.y1 = opts.y2 = this._monitor.y; + } + + if (position == St.Side.TOP) { + opts.directions = Meta.BarrierDirection.POSITIVE_Y; + } else if (position == St.Side.BOTTOM) { + opts.y1 = opts.y2 = opts.y1 + this._monitor.height; + opts.directions = Meta.BarrierDirection.NEGATIVE_Y; + } else if (position == St.Side.LEFT) { + opts.directions = Meta.BarrierDirection.POSITIVE_X; + } else { + opts.x1 = opts.x2 = opts.x1 + this._monitor.width; + opts.directions = Meta.BarrierDirection.NEGATIVE_X; + } + + return new Meta.Barrier(opts); + }, + + _checkMousePointer: function(x, y) { + let position = this._dtpPanel.geom.position; + + if (!this._panelBox.hover && !Main.overview.visible && + ((position == St.Side.TOP && y <= this._monitor.y + 1) || + (position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - 1) || + (position == St.Side.LEFT && x <= this._monitor.x + 1) || + (position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - 1)) && + ((x >= this._monitor.x && x < this._monitor.x + this._monitor.width) && + (y >= this._monitor.y && y < this._monitor.y + this._monitor.height))) { + this._queueUpdatePanelPosition(true); + } + }, + + _queueUpdatePanelPosition: function(fromRevealMechanism) { + if (!fromRevealMechanism && this._timeoutsHandler.getId(T2) && !Main.overview.visible) { + //unless this is a mouse interaction or entering/leaving the overview, limit the number + //of updates, but remember to update again when the limit timeout is reached + this._pendingUpdate = true; + } else if (!this._holdStatus) { + this._checkIfShouldBeVisible(fromRevealMechanism) ? this._revealPanel() : this._hidePanel(); + this._timeoutsHandler.add([T2, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + } + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdatePanelPosition(); + } + }, + + _checkIfShouldBeVisible: function(fromRevealMechanism) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || + this._panelBox.get_hover() || this._checkIfGrab()) { + return true; + } + + if (fromRevealMechanism) { + let mouseBtnIsPressed = global.get_pointer()[2] & Clutter.ModifierType.BUTTON1_MASK; + + //the user is trying to reveal the panel + if (this._monitor.inFullscreen && !mouseBtnIsPressed) { + return Me.settings.get_boolean('intellihide-show-in-fullscreen'); + } + + return !mouseBtnIsPressed; + } + + if (!Me.settings.get_boolean('intellihide-hide-from-windows')) { + return this._panelBox.hover; + } + + return !this._windowOverlap; + }, + + _checkIfGrab: function() { + if (GrabHelper._grabHelperStack.some(gh => gh._owner == this._dtpPanel.panel.actor)) { + //there currently is a grab on a child of the panel, check again soon to catch its release + this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]); + + return true; + } + }, + + _revealPanel: function(immediate) { + if (!this._panelBox.visible) { + this._panelBox.visible = true; + this._dtpPanel.taskbar._shownInitially = false; + } + + this._animatePanel(0, immediate); + }, + + _hidePanel: function(immediate) { + let position = this._dtpPanel.geom.position; + let size = this._panelBox[position == St.Side.LEFT || position == St.Side.RIGHT ? 'width' : 'height']; + let coefficient = position == St.Side.TOP || position == St.Side.LEFT ? -1 : 1; + + this._animatePanel(size * coefficient, immediate); + }, + + _animatePanel: function(destination, immediate) { + let animating = Utils.isAnimating(this._panelBox, this._translationProp); + + if (!((animating && destination === this._animationDestination) || + (!animating && destination === this._panelBox[this._translationProp]))) { + //the panel isn't already at, or animating to the asked destination + if (animating) { + Utils.stopAnimations(this._panelBox); + } + + this._animationDestination = destination; + + if (immediate) { + this._panelBox[this._translationProp] = destination; + this._panelBox.visible = !destination; + } else { + let tweenOpts = { + //when entering/leaving the overview, use its animation time instead of the one from the settings + time: Main.overview.visible ? + SIDE_CONTROLS_ANIMATION_TIME : + Me.settings.get_int('intellihide-animation-time') * 0.001, + //only delay the animation when hiding the panel after the user hovered out + delay: destination != 0 && this._hoveredOut ? Me.settings.get_int('intellihide-close-delay') * 0.001 : 0, + transition: 'easeOutQuad', + onComplete: () => { + this._panelBox.visible = !destination; + Main.layoutManager._queueUpdateRegions(); + this._timeoutsHandler.add([T3, POST_ANIMATE_MS, () => this._queueUpdatePanelPosition()]); + } + }; + + tweenOpts[this._translationProp] = destination; + Utils.animate(this._panelBox, tweenOpts); + } + } + + this._hoveredOut = false; + }, +}); \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8425f68 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/cs/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..86da090 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/de/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..7a5af2f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/es/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..70da5fa Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/fr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..f52e89a Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/gl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2fd26da Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/hu/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..c467e93 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/it/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bd1a46 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ja/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..84eac31 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/kk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..99b526b Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pl/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..8ae66e3 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/pt_BR/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..0d64932 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/ru/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..e7cacbb Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/sv/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..3bc58a5 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/tr/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..2993304 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/uk/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..26ed613 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_CN/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo new file mode 100644 index 0000000..ed1cc6d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/locale/zh_TW/LC_MESSAGES/dash-to-panel.mo differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json new file mode 100644 index 0000000..4b11eea --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/metadata.json @@ -0,0 +1,13 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "An icon taskbar for the Gnome Shell. This extension moves the dash into the gnome main panel so that the application launchers and system tray are combined into a single panel, similar to that found in KDE Plasma and Windows 7+. A separate dock is no longer needed for easy access to running and favorited applications.\n\nFor a more traditional experience, you may also want to use Tweak Tool to enable Windows > Titlebar Buttons > Minimize & Maximize.\n\nFor the best support, please report any issues on Github. Dash-to-panel is developed and maintained by @jderose9 and @charlesg99.", + "extension-id": "dash-to-panel", + "gettext-domain": "dash-to-panel", + "name": "Dash to Panel", + "shell-version": [ + "40" + ], + "url": "https://github.com/home-sweet-gnome/dash-to-panel", + "uuid": "dash-to-panel@jderose9.github.com", + "version": 44 +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js new file mode 100644 index 0000000..57600a5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/overview.js @@ -0,0 +1,708 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Intellihide = Me.imports.intellihide; +const Utils = Me.imports.utils; + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Lang = imports.lang; +const Main = imports.ui.main; +const Shell = imports.gi.Shell; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; +const Mainloop = imports.mainloop; +const IconGrid = imports.ui.iconGrid; +const OverviewControls = imports.ui.overviewControls; +const Workspace = imports.ui.workspace; +const St = imports.gi.St; +const WorkspaceThumbnail = imports.ui.workspaceThumbnail; + +const Meta = imports.gi.Meta; + +const GS_HOTKEYS_KEY = 'switch-to-application-'; +const BACKGROUND_MARGIN = 12; +const SMALL_WORKSPACE_RATIO = 0.15; +const DASH_MAX_HEIGHT_RATIO = 0.15; + + +//timeout names +const T1 = 'swipeEndTimeout'; + +var dtpOverview = Utils.defineClass({ + Name: 'DashToPanel.Overview', + + _init: function() { + this._numHotkeys = 10; + this._timeoutsHandler = new Utils.TimeoutsHandler(); + }, + + enable : function(panel) { + this._panel = panel; + this.taskbar = panel.taskbar; + + this._injectionsHandler = new Utils.InjectionsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._optionalWorkspaceIsolation(); + this._optionalHotKeys(); + this._optionalNumberOverlay(); + this._optionalClickToExit(); + this._toggleDash(); + this._hookupAllocation(); + + this._signalsHandler.add([ + Me.settings, + 'changed::stockgs-keep-dash', + () => this._toggleDash() + ]); + + }, + + disable: function () { + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', Workspace.WorkspaceBackground.prototype.vfunc_allocate); + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', OverviewControls.ControlsManagerLayout.prototype.vfunc_allocate); + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = this._oldComputeWorkspacesBoxForState; + + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); + + this._toggleDash(true); + + // Remove key bindings + this._disableHotKeys(); + this._disableExtraShortcut(); + this._disableClickToExit(); + }, + + _toggleDash: function(visible) { + // To hide the dash, set its width to 1, so it's almost not taken into account by code + // calculaing the reserved space in the overview. The reason to keep it at 1 is + // to allow its visibility change to trigger an allocaion of the appGrid which + // in turn is triggergin the appsIcon spring animation, required when no other + // actors has this effect, i.e in horizontal mode and without the workspaceThumnails + // 1 static workspace only) + + if (visible === undefined) { + visible = Me.settings.get_boolean('stockgs-keep-dash'); + } + + let visibilityFunc = visible ? 'show' : 'hide'; + let width = visible ? -1 : 1; + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + + overviewControls.dash.actor[visibilityFunc](); + overviewControls.dash.actor.set_width(width); + + // This force the recalculation of the icon size + overviewControls.dash._maxHeight = -1; + }, + + /** + * Isolate overview to open new windows for inactive apps + */ + _optionalWorkspaceIsolation: function() { + let label = 'optionalWorkspaceIsolation'; + + this._signalsHandler.add([ + Me.settings, + 'changed::isolate-workspaces', + Lang.bind(this, function() { + this._panel.panelManager.allPanels.forEach(p => p.taskbar.resetAppIcons()); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + else + Lang.bind(this, disable)(); + }) + ]); + + if (Me.settings.get_boolean('isolate-workspaces')) + Lang.bind(this, enable)(); + + function enable() { + this._injectionsHandler.removeWithLabel(label); + + this._injectionsHandler.addWithLabel(label, [ + Shell.App.prototype, + 'activate', + IsolatedOverview + ]); + + this._signalsHandler.removeWithLabel(label); + + this._signalsHandler.addWithLabel(label, [ + global.window_manager, + 'switch-workspace', + () => this._panel.panelManager.allPanels.forEach(p => p.taskbar.handleIsolatedWorkspaceSwitch()) + ]); + } + + function disable() { + this._signalsHandler.removeWithLabel(label); + this._injectionsHandler.removeWithLabel(label); + } + + function IsolatedOverview() { + // These lines take care of Nautilus for icons on Desktop + let activeWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = this.get_windows().filter(w => w.get_workspace().index() == activeWorkspace.index()); + + if (windows.length > 0 && + (!(windows.length == 1 && windows[0].skip_taskbar) || + this.is_on_workspace(activeWorkspace))) + return Main.activateWindow(windows[0]); + + return this.open_new_window(-1); + } + }, + + // Hotkeys + _activateApp: function(appIndex) { + let seenApps = {}; + let apps = []; + + this.taskbar._getAppIcons().forEach(function(appIcon) { + if (!seenApps[appIcon.app]) { + apps.push(appIcon); + } + + seenApps[appIcon.app] = (seenApps[appIcon.app] || 0) + 1; + }); + + this._showOverlay(); + + if (appIndex < apps.length) { + let appIcon = apps[appIndex]; + let seenAppCount = seenApps[appIcon.app]; + let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows; + + if (Me.settings.get_boolean('shortcut-previews') && windowCount > 1 && + !(Clutter.get_current_event().get_state() & ~(Clutter.ModifierType.MOD1_MASK | Clutter.ModifierType.MOD4_MASK))) { //ignore the alt (MOD1_MASK) and super key (MOD4_MASK) + if (this._hotkeyPreviewCycleInfo && this._hotkeyPreviewCycleInfo.appIcon != appIcon) { + this._endHotkeyPreviewCycle(); + } + + if (!this._hotkeyPreviewCycleInfo) { + this._hotkeyPreviewCycleInfo = { + appIcon: appIcon, + currentWindow: appIcon.window, + keyFocusOutId: appIcon.actor.connect('key-focus-out', () => appIcon.actor.grab_key_focus()), + capturedEventId: global.stage.connect('captured-event', (actor, e) => { + if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == (Clutter.KEY_Super_L || Clutter.Super_L)) { + this._endHotkeyPreviewCycle(true); + } + + return Clutter.EVENT_PROPAGATE; + }) + }; + + appIcon._hotkeysCycle = appIcon.window; + appIcon.window = null; + appIcon._previewMenu.open(appIcon); + appIcon.actor.grab_key_focus(); + } + + appIcon._previewMenu.focusNext(); + } else { + // Activate with button = 1, i.e. same as left click + let button = 1; + this._endHotkeyPreviewCycle(); + appIcon.activate(button, true); + } + } + }, + + _endHotkeyPreviewCycle: function(focusWindow) { + if (this._hotkeyPreviewCycleInfo) { + global.stage.disconnect(this._hotkeyPreviewCycleInfo.capturedEventId); + this._hotkeyPreviewCycleInfo.appIcon.actor.disconnect(this._hotkeyPreviewCycleInfo.keyFocusOutId); + + if (focusWindow) { + this._hotkeyPreviewCycleInfo.appIcon._previewMenu.activateFocused(); + } + + this._hotkeyPreviewCycleInfo.appIcon.window = this._hotkeyPreviewCycleInfo.currentWindow; + delete this._hotkeyPreviewCycleInfo.appIcon._hotkeysCycle; + this._hotkeyPreviewCycleInfo = 0; + } + }, + + _optionalHotKeys: function() { + this._hotKeysEnabled = false; + if (Me.settings.get_boolean('hot-keys')) + this._enableHotKeys(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys')) + Lang.bind(this, this._enableHotKeys)(); + else + Lang.bind(this, this._disableHotKeys)(); + }) + ]); + }, + + _resetHotkeys: function() { + this._disableHotKeys(); + this._enableHotKeys(); + }, + + _enableHotKeys: function() { + if (this._hotKeysEnabled) + return; + + //3.32 introduced app hotkeys, disable them to prevent conflicts + if (Main.wm._switchToApplication) { + for (let i = 1; i < 10; ++i) { + Utils.removeKeybinding(GS_HOTKEYS_KEY + i); + } + } + + // Setup keyboard bindings for taskbar elements + let shortcutNumKeys = Me.settings.get_string('shortcut-num-keys'); + let bothNumKeys = shortcutNumKeys == 'BOTH'; + let keys = []; + + if (bothNumKeys || shortcutNumKeys == 'NUM_ROW') { + keys.push('app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'); // Regular numbers + } + + if (bothNumKeys || shortcutNumKeys == 'NUM_KEYPAD') { + keys.push('app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-'); // Key-pad numbers + } + + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + let appNum = i; + + Utils.addKeybinding(key + (i + 1), Me.settings, () => this._activateApp(appNum)); + } + }, this); + + this._hotKeysEnabled = true; + + if (Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + }, + + _disableHotKeys: function() { + if (!this._hotKeysEnabled) + return; + + let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-', // Regular numbers + 'app-hotkey-kp-', 'app-shift-hotkey-kp-', 'app-ctrl-hotkey-kp-']; // Key-pad numbers + keys.forEach( function(key) { + for (let i = 0; i < this._numHotkeys; i++) { + Utils.removeKeybinding(key + (i + 1)); + } + }, this); + + if (Main.wm._switchToApplication) { + let gsSettings = new Gio.Settings({ schema_id: imports.ui.windowManager.SHELL_KEYBINDINGS_SCHEMA }); + + for (let i = 1; i < 10; ++i) { + Utils.addKeybinding(GS_HOTKEYS_KEY + i, gsSettings, Main.wm._switchToApplication.bind(Main.wm)); + } + } + + this._hotKeysEnabled = false; + + this.taskbar.toggleNumberOverlay(false); + }, + + _optionalNumberOverlay: function() { + // Enable extra shortcut + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + + this._signalsHandler.add([ + Me.settings, + 'changed::hot-keys', + Lang.bind(this, this._checkHotkeysOptions) + ], [ + Me.settings, + 'changed::hotkeys-overlay-combo', + Lang.bind(this, function() { + if (Me.settings.get_boolean('hot-keys') && Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.taskbar.toggleNumberOverlay(true); + else + this.taskbar.toggleNumberOverlay(false); + }) + ], [ + Me.settings, + 'changed::shortcut-num-keys', + () => this._resetHotkeys() + ]); + }, + + _checkHotkeysOptions: function() { + if (Me.settings.get_boolean('hot-keys')) + this._enableExtraShortcut(); + else + this._disableExtraShortcut(); + }, + + _enableExtraShortcut: function() { + Utils.addKeybinding('shortcut', Me.settings, () => this._showOverlay(true)); + }, + + _disableExtraShortcut: function() { + Utils.removeKeybinding('shortcut'); + }, + + _showOverlay: function(overlayFromShortcut) { + //wait for intellihide timeout initialization + if (!this._panel.intellihide) { + return; + } + + // Restart the counting if the shortcut is pressed again + if (this._numberOverlayTimeoutId) { + Mainloop.source_remove(this._numberOverlayTimeoutId); + this._numberOverlayTimeoutId = 0; + } + + let hotkey_option = Me.settings.get_string('hotkeys-overlay-combo'); + + if (hotkey_option === 'NEVER') + return; + + if (hotkey_option === 'TEMPORARILY' || overlayFromShortcut) + this.taskbar.toggleNumberOverlay(true); + + this._panel.intellihide.revealAndHold(Intellihide.Hold.TEMPORARY); + + let timeout = Me.settings.get_int('overlay-timeout'); + + if (overlayFromShortcut) { + timeout = Me.settings.get_int('shortcut-timeout'); + } + + // Hide the overlay/dock after the timeout + this._numberOverlayTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, function() { + this._numberOverlayTimeoutId = 0; + + if (hotkey_option != 'ALWAYS') { + this.taskbar.toggleNumberOverlay(false); + } + + this._panel.intellihide.release(Intellihide.Hold.TEMPORARY); + })); + }, + + _optionalClickToExit: function() { + this._clickToExitEnabled = false; + if (Me.settings.get_boolean('overview-click-to-exit')) + this._enableClickToExit(); + + this._signalsHandler.add([ + Me.settings, + 'changed::overview-click-to-exit', + Lang.bind(this, function() { + if (Me.settings.get_boolean('overview-click-to-exit')) + Lang.bind(this, this._enableClickToExit)(); + else + Lang.bind(this, this._disableClickToExit)(); + }) + ]); + }, + + _enableClickToExit: function() { + if (this._clickToExitEnabled) + return; + + let view = imports.ui.appDisplay; + this._oldOverviewReactive = Main.overview._overview.reactive + + Main.overview._overview.reactive = true; + + this._clickAction = new Clutter.ClickAction(); + this._clickAction.connect('clicked', () => { + + if (this._swiping) + return Clutter.EVENT_PROPAGATE; + + let [x, y] = global.get_pointer(); + let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); + + Main.overview.toggle(); + }); + Main.overview._overview.add_action(this._clickAction); + + this._clickToExitEnabled = true; + }, + + _disableClickToExit: function () { + if (!this._clickToExitEnabled) + return; + + Main.overview._overview.remove_action(this._clickAction); + Main.overview._overview.reactive = this._oldOverviewReactive; + + this._signalsHandler.removeWithLabel('clickToExit'); + + this._clickToExitEnabled = false; + }, + + _onSwipeBegin: function() { + this._swiping = true; + return true; + }, + + _onSwipeEnd: function() { + this._timeoutsHandler.add([ + T1, + 0, + () => this._swiping = false + ]); + return true; + }, + + _hookupAllocation: function() { + Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', function vfunc_allocate(container, box) { + const childBox = new Clutter.ActorBox(); + + const { spacing } = this; + + let startY = 0; + let startX = 0; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) { + startY = Main.layoutManager.panelBox.height; + box.y1 += startY; + } + + const panel = global.dashToPanel.panels[0]; + if(panel) { + switch (panel.getPosition()) { + case St.Side.TOP: + startY = panel.panelBox.height; + box.y1 += startY; + break; + case St.Side.LEFT: + startX = panel.panelBox.width; + box.x1 += startX; + break; + case St.Side.RIGHT: + box.x2 -= panel.panelBox.width; + break; + + } + } + + + const [width, height] = box.get_size(); + let availableHeight = height; + + // Search entry + let [searchHeight] = this._searchEntry.get_preferred_height(width); + childBox.set_origin(startX, startY); + childBox.set_size(width, searchHeight); + this._searchEntry.allocate(childBox); + + availableHeight -= searchHeight + spacing; + + // Dash + const maxDashHeight = Math.round(box.get_height() * DASH_MAX_HEIGHT_RATIO); + this._dash.setMaxSize(width, maxDashHeight); + + let [, dashHeight] = this._dash.get_preferred_height(width); + if (Me.settings.get_boolean('stockgs-keep-dash')) + dashHeight = Math.min(dashHeight, maxDashHeight); + else + dashHeight = spacing*5; // todo: determine proper spacing for window labels on maximized windows on workspace display + childBox.set_origin(startX, startY + height - dashHeight); + childBox.set_size(width, dashHeight); + this._dash.allocate(childBox); + + availableHeight -= dashHeight + spacing; + + // Workspace Thumbnails + let thumbnailsHeight = 0; + if (this._workspacesThumbnails.visible) { + const { expandFraction } = this._workspacesThumbnails; + [thumbnailsHeight] = + this._workspacesThumbnails.get_preferred_height(width); + thumbnailsHeight = Math.min( + thumbnailsHeight * expandFraction, + height * WorkspaceThumbnail.MAX_THUMBNAIL_SCALE); + childBox.set_origin(startX, startY + searchHeight + spacing); + childBox.set_size(width, thumbnailsHeight); + this._workspacesThumbnails.allocate(childBox); + } + + // Workspaces + let params = [box, startX, startY, searchHeight, dashHeight, thumbnailsHeight]; + const transitionParams = this._stateAdjustment.getStateTransitionParams(); + + // Update cached boxes + for (const state of Object.values(OverviewControls.ControlsState)) { + this._cachedWorkspaceBoxes.set( + state, this._computeWorkspacesBoxForState(state, ...params)); + } + + let workspacesBox; + if (!transitionParams.transitioning) { + workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); + } else { + const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); + const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); + workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._workspacesDisplay.allocate(workspacesBox); + + // AppDisplay + if (this._appDisplay.visible) { + const workspaceAppGridBox = + this._cachedWorkspaceBoxes.get(OverviewControls.ControlsState.APP_GRID); + + if (Config.PACKAGE_VERSION > '40.3') { + const monitor = Main.layoutManager.findMonitorForActor(this._container); + const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); + const workAreaBox = new Clutter.ActorBox(); + + workAreaBox.set_origin(startX, startY); + workAreaBox.set_size(workArea.width, workArea.height); + + params = [workAreaBox, searchHeight, dashHeight, workspaceAppGridBox] + } else { + params = [box, startX, searchHeight, dashHeight, workspaceAppGridBox]; + } + + let appDisplayBox; + if (!transitionParams.transitioning) { + appDisplayBox = + this._getAppDisplayBoxForState(transitionParams.currentState, ...params); + } else { + const initialBox = + this._getAppDisplayBoxForState(transitionParams.initialState, ...params); + const finalBox = + this._getAppDisplayBoxForState(transitionParams.finalState, ...params); + + appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); + } + + this._appDisplay.allocate(appDisplayBox); + } + + // Search + childBox.set_origin(0, startY + searchHeight + spacing); + childBox.set_size(width, availableHeight); + + this._searchController.allocate(childBox); + + this._runPostAllocation(); + }); + + this._oldComputeWorkspacesBoxForState = OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState; + OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = function _computeWorkspacesBoxForState(state, box, startX, startY, searchHeight, dashHeight, thumbnailsHeight) { + const workspaceBox = box.copy(); + const [width, height] = workspaceBox.get_size(); + const { spacing } = this; + const { expandFraction } = this._workspacesThumbnails; + + switch (state) { + case OverviewControls.ControlsState.HIDDEN: + break; + case OverviewControls.ControlsState.WINDOW_PICKER: + workspaceBox.set_origin(startX, + startY + searchHeight + spacing + + thumbnailsHeight + spacing * expandFraction); + workspaceBox.set_size(width, + height - + dashHeight - spacing - + searchHeight - spacing - + thumbnailsHeight - spacing * expandFraction); + break; + case OverviewControls.ControlsState.APP_GRID: + workspaceBox.set_origin(startX, startY + searchHeight + spacing); + workspaceBox.set_size( + width, + Math.round(height * SMALL_WORKSPACE_RATIO)); + break; + } + + return workspaceBox; + } + + Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', function vfunc_allocate(box) { + const [width, height] = box.get_size(); + const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const scaledHeight = height - (BACKGROUND_MARGIN * 2 * scaleFactor); + const scaledWidth = (scaledHeight / height) * width; + + const scaledBox = box.copy(); + scaledBox.set_origin( + box.x1 + (width - scaledWidth) / 2, + box.y1 + (height - scaledHeight) / 2); + scaledBox.set_size(scaledWidth, scaledHeight); + + const progress = this._stateAdjustment.value; + + if (progress === 1) + box = scaledBox; + else if (progress !== 0) + box = box.interpolate(scaledBox, progress); + + this.set_allocation(box); + + const themeNode = this.get_theme_node(); + const contentBox = themeNode.get_content_box(box); + + this._bin.allocate(contentBox); + + + const [contentWidth, contentHeight] = contentBox.get_size(); + const monitor = Main.layoutManager.monitors[this._monitorIndex]; + let xOff = (contentWidth / this._workarea.width) * + (this._workarea.x - monitor.x); + let yOff = (contentHeight / this._workarea.height) * + (this._workarea.y - monitor.y); + + let startX = -xOff; + let startY = -yOff; + const panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == this._monitorIndex); + switch (panel.getPosition()) { + case St.Side.TOP: + yOff += panel.panelBox.height; + startY -= panel.panelBox.height; + break; + case St.Side.BOTTOM: + yOff += panel.panelBox.height; + break; + case St.Side.RIGHT: + xOff += panel.panelBox.width; + break; + } + contentBox.set_origin(startX, startY); + contentBox.set_size(xOff + contentWidth, yOff + contentHeight); + this._backgroundGroup.allocate(contentBox); + }); + + } +}); diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js new file mode 100644 index 0000000..5e0b5f9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panel.js @@ -0,0 +1,1512 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gtk = imports.gi.Gtk; +const Gi = imports._gi; +const AppIcons = Me.imports.appIcons; +const Utils = Me.imports.utils; +const Taskbar = Me.imports.taskbar; +const Pos = Me.imports.panelPositions; +const PanelSettings = Me.imports.panelSettings; +const PanelStyle = Me.imports.panelStyle; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Dash = imports.ui.dash; +const CtrlAltTab = imports.ui.ctrlAltTab; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const St = imports.gi.St; +const GLib = imports.gi.GLib; +const Meta = imports.gi.Meta; +const Pango = imports.gi.Pango; +const DND = imports.ui.dnd; +const Shell = imports.gi.Shell; +const PopupMenu = imports.ui.popupMenu; +const IconGrid = imports.ui.iconGrid; +const DateMenu = imports.ui.dateMenu; +const Volume = imports.ui.status.volume; +const Progress = Me.imports.progress; + +const Intellihide = Me.imports.intellihide; +const Transparency = Me.imports.transparency; +const _ = imports.gettext.domain(Me.imports.utils.TRANSLATION_DOMAIN).gettext; + +let tracker = Shell.WindowTracker.get_default(); +var panelBoxes = ['_leftBox', '_centerBox', '_rightBox']; + +//timeout names +const T1 = 'startDynamicTransparencyTimeout'; +const T2 = 'startIntellihideTimeout'; +const T3 = 'allocationThrottleTimeout'; +const T4 = 'showDesktopTimeout'; +const T5 = 'trackerFocusAppTimeout'; +const T6 = 'scrollPanelDelayTimeout'; +const T7 = 'waitPanelBoxAllocation'; + +var dtpPanel = Utils.defineClass({ + Name: 'DashToPanel-Panel', + Extends: St.Widget, + + _init: function(panelManager, monitor, panelBox, isStandalone) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this.panelManager = panelManager; + this.panelStyle = new PanelStyle.dtpPanelStyle(); + + this.monitor = monitor; + this.panelBox = panelBox; + + // when the original gnome-shell top panel is kept, all panels are "standalone", + // so in this case use isPrimary to get the panel on the primary dtp monitor, which + // might be different from the system's primary monitor. + this.isStandalone = isStandalone; + this.isPrimary = !isStandalone || (Me.settings.get_boolean('stockgs-keep-top-panel') && + monitor == panelManager.dtpPrimaryMonitor); + + this._sessionStyle = null; + this._unmappedButtons = []; + this._elementGroups = []; + this.cornerSize = 0; + + let position = this.getPosition(); + + if (isStandalone) { + this.panel = new dtpSecondaryPanel({ name: 'panel', reactive: true }); + this.statusArea = this.panel.statusArea = {}; + + Utils.wrapActor(this.panel); + + //next 3 functions are needed by other extensions to add elements to the secondary panel + this.panel.addToStatusArea = function(role, indicator, position, box) { + return Main.panel.addToStatusArea.call(this, role, indicator, position, box); + }; + + this.panel._addToPanelBox = function(role, indicator, position, box) { + Main.panel._addToPanelBox.call(this, role, indicator, position, box); + }; + + this.panel._onMenuSet = function(indicator) { + Main.panel._onMenuSet.call(this, indicator); + }; + + this._leftBox = this.panel._leftBox = new St.BoxLayout({ name: 'panelLeft' }); + this._centerBox = this.panel._centerBox = new St.BoxLayout({ name: 'panelCenter' }); + this._rightBox = this.panel._rightBox = new St.BoxLayout({ name: 'panelRight' }); + + this.menuManager = this.panel.menuManager = new PopupMenu.PopupMenuManager(this.panel); + + this._setPanelMenu('aggregateMenu', dtpSecondaryAggregateMenu, this.panel.actor); + this._setPanelMenu('dateMenu', DateMenu.DateMenuButton, this.panel.actor); + this._setPanelMenu('activities', Panel.ActivitiesButton, this.panel.actor); + + this.panel.add_child(this._leftBox); + this.panel.add_child(this._centerBox); + this.panel.add_child(this._rightBox); + } else { + this.panel = Main.panel; + this.statusArea = Main.panel.statusArea; + this.menuManager = Main.panel.menuManager; + + panelBoxes.forEach(p => this[p] = Main.panel[p]); + + ['activities', 'aggregateMenu', 'dateMenu'].forEach(b => { + let container = this.statusArea[b].container; + let parent = container.get_parent(); + + container._dtpOriginalParent = parent; + parent ? parent.remove_child(container) : null; + this.panel.actor.add_child(container); + }); + } + + // Create a wrapper around the real showAppsIcon in order to add a popupMenu. Most of + // its behavior is handled by the taskbar, but its positioning is done at the panel level + this.showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this); + this.panel.actor.add_child(this.showAppsIconWrapper.realShowAppsIcon); + + this.panel.actor._delegate = this; + + Utils.wrapActor(this.statusArea.activities); + + this.add_child(this.panel.actor); + + if (Main.panel._onButtonPress || Main.panel._tryDragWindow) { + this._signalsHandler.add([ + this.panel.actor, + [ + 'button-press-event', + 'touch-event' + ], + this._onButtonPress.bind(this) + ]); + } + + if (Main.panel._onKeyPress) { + this._signalsHandler.add([this.panel.actor, 'key-press-event', Main.panel._onKeyPress.bind(this)]); + } + + Main.ctrlAltTabManager.addGroup(this, _("Top Bar")+" "+ monitor.index, 'focus-top-bar-symbolic', + { sortGroup: CtrlAltTab.SortGroup.TOP }); + }, + + enable : function() { + let position = this.getPosition(); + + if (this.statusArea.aggregateMenu) { + Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll = 1; + } + + this.geom = this.getGeometry(); + + // The overview uses the panel height as a margin by way of a "ghost" transparent Clone + // This pushes everything down, which isn't desired when the panel is moved to the bottom + // I'm adding a 2nd ghost panel and will resize the top or bottom ghost depending on the panel position + this._myPanelGhost = new Clutter.Actor({ + x: this.geom.x, + y: this.geom.y , + reactive: false, + opacity: 0 + }); + + let isTop = this.geom.position == St.Side.TOP; + + if (isTop) { + this.panel._leftCorner = this.panel._leftCorner || new Panel.PanelCorner(St.Side.LEFT); + this.panel._rightCorner = this.panel._rightCorner || new Panel.PanelCorner(St.Side.RIGHT); + + Main.overview._overview.insert_child_at_index(this._myPanelGhost, 0); + } else { + let overviewControls = Main.overview._overview._controls || Main.overview._controls; + Main.overview._overview.add_actor(this._myPanelGhost); + } + + if (this.panel._leftCorner) { + Utils.wrapActor(this.panel._leftCorner); + Utils.wrapActor(this.panel._rightCorner); + + if (isTop) { + if (this.isStandalone) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + } else if (Config.PACKAGE_VERSION >= '3.32') { + this.panel.actor.remove_child(this.panel._leftCorner.actor); + this.panel.actor.remove_child(this.panel._rightCorner.actor); + } + } + + this._setPanelPosition(); + + if (!this.isStandalone) { + if (this.panel.vfunc_allocate) { + this._panelConnectId = 0; + Utils.hookVfunc(this.panel.__proto__, 'allocate', (box, flags) => this._mainPanelAllocate(0, box, flags)); + } else { + this._panelConnectId = this.panel.actor.connect('allocate', (actor, box, flags) => this._mainPanelAllocate(actor, box, flags)); + } + + // remove the extra space before the clock when the message-indicator is displayed + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', () => [0,0]); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', () => [0,0]); + } + } + + if (!DateMenu.IndicatorPad && this.statusArea.dateMenu) { + //3.36 switched to a size constraint applied on an anonymous child + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints = indicatorPad.get_constraints(); + indicatorPad.clear_constraints(); + } + + // The main panel's connection to the "allocate" signal is competing with this extension + // trying to move the centerBox over to the right, creating a never-ending cycle. + // Since we don't have the ID to disconnect that handler, wrap the allocate() function + // it calls instead. If the call didn't originate from this file, ignore it. + panelBoxes.forEach(b => { + this[b].allocate = (box, flags, isFromDashToPanel) => { + if (isFromDashToPanel) { + Utils.allocate(this[b], box, flags, true); + } + } + }); + + this.menuManager._oldChangeMenu = this.menuManager._changeMenu; + this.menuManager._changeMenu = (menu) => { + if (!Me.settings.get_boolean('stockgs-panelbtn-click-only')) { + this.menuManager._oldChangeMenu(menu); + } + }; + + this.dynamicTransparency = new Transparency.DynamicTransparency(this); + + this.taskbar = new Taskbar.taskbar(this); + + this.panel.actor.add_child(this.taskbar.actor); + + this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')); + this._setShowDesktopButton(true); + + this._setAllocationMap(); + + this.panel.actor.add_style_class_name('dashtopanelMainPanel ' + this.getOrientation()); + + this._setPanelGhostSize(); + + this._timeoutsHandler.add([T2, Me.settings.get_int('intellihide-enable-start-delay'), () => this.intellihide = new Intellihide.Intellihide(this)]); + + this._signalsHandler.add( + // this is to catch changes to the theme or window scale factor + [ + Utils.getStageTheme(), + 'changed', + () => (this._resetGeometry(), this._setShowDesktopButtonStyle()), + ], + [ + // sync hover after a popupmenu is closed + this.taskbar, + 'menu-closed', + Lang.bind(this, function(){this.panel.actor.sync_hover();}) + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._adjustForOverview() + ], + [ + Main.overview, + 'hidden', + () => { + if (this.isPrimary) { + //reset the primary monitor when exiting the overview + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this.statusArea.activities.actor, + 'captured-event', + (actor, e) => { + // todo this is not being called right now, so the overview is not shown on the correct monitor + if (e.type() == Clutter.EventType.BUTTON_PRESS || e.type() == Clutter.EventType.TOUCH_BEGIN) { + //temporarily use as primary the monitor on which the activities btn was clicked + this.panelManager.setFocusedMonitor(this.monitor, true); + } + } + ], + [ + this._centerBox, + 'actor-added', + () => this._onBoxActorAdded(this._centerBox) + ], + [ + this._rightBox, + 'actor-added', + () => this._onBoxActorAdded(this._rightBox) + ], + [ + this.panel.actor, + 'scroll-event', + this._onPanelMouseScroll.bind(this) + ], + [ + Main.layoutManager, + 'startup-complete', + () => this._resetGeometry() + ] + ); + + this._bindSettingsChanges(); + + this.panelStyle.enable(this); + + if (this.checkIfVertical()) { + this._signalsHandler.add([ + this.panelBox, + 'notify::visible', + () => { + if (this.panelBox.visible) { + this._refreshVerticalAlloc(); + } + } + ]); + + this._setSearchEntryOffset(this.geom.w); + + if (this.statusArea.dateMenu) { + this._formatVerticalClock(); + + this._signalsHandler.add([ + this.statusArea.dateMenu._clock, + 'notify::clock', + () => this._formatVerticalClock() + ]); + } + } + + // Since we are usually visible but not usually changing, make sure + // most repaint requests don't actually require us to repaint anything. + // This saves significant CPU when repainting the screen. + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._initProgressManager(); + }, + + disable: function () { + this.panelStyle.disable(); + + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + this._disablePanelCornerSignals(); + + this.panel.actor.remove_child(this.taskbar.actor); + this._setAppmenuVisible(false); + + if (this.intellihide) { + this.intellihide.destroy(); + } + + this.dynamicTransparency.destroy(); + + this.progressManager.destroy(); + + this.taskbar.destroy(); + this.showAppsIconWrapper.destroy(); + + this.menuManager._changeMenu = this.menuManager._oldChangeMenu; + + this._myPanelGhost.get_parent().remove_actor(this._myPanelGhost); + this._setSearchEntryOffset(0); + + panelBoxes.forEach(b => delete this[b].allocate); + this._unmappedButtons.forEach(a => this._disconnectVisibleId(a)); + + if (this._dateMenuIndicatorPadContraints && this.statusArea.dateMenu) { + let indicatorPad = this.statusArea.dateMenu.get_first_child().get_first_child(); + + this._dateMenuIndicatorPadContraints.forEach(c => indicatorPad.add_constraint(c)); + } + + this._setVertical(this.panel.actor, false); + + if (!this.isStandalone) { + this.statusArea.dateMenu._clockDisplay.text = this.statusArea.dateMenu._clock.clock; + + ['vertical', 'horizontal', 'dashtopanelMainPanel'].forEach(c => this.panel.actor.remove_style_class_name(c)); + + if (!Main.sessionMode.isLocked) { + [['activities', 0], ['aggregateMenu', -1], ['dateMenu', 0]].forEach(b => { + let container = this.statusArea[b[0]].container; + let originalParent = container._dtpOriginalParent; + + this.panel.actor.remove_child(container); + originalParent ? originalParent.insert_child_at_index(container, b[1]) : null; + delete container._dtpOriginalParent; + }); + } + + if (!this.panel._leftCorner.actor.mapped) { + this.panel.actor.add_child(this.panel._leftCorner.actor); + this.panel.actor.add_child(this.panel._rightCorner.actor); + } + + this._setShowDesktopButton(false); + + delete Utils.getIndicators(this.statusArea.aggregateMenu._volume)._dtpIgnoreScroll; + + if (DateMenu.IndicatorPad) { + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_width', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_width); + Utils.hookVfunc(DateMenu.IndicatorPad.prototype, 'get_preferred_height', DateMenu.IndicatorPad.prototype.vfunc_get_preferred_height); + } + + if (this._panelConnectId) { + this.panel.actor.disconnect(this._panelConnectId); + } else { + Utils.hookVfunc(this.panel.__proto__, 'allocate', this.panel.__proto__.vfunc_allocate); + } + + this.panel.actor._delegate = this.panel; + } else { + this._removePanelMenu('dateMenu'); + this._removePanelMenu('aggregateMenu'); + this._removePanelMenu('activities'); + } + + Main.ctrlAltTabManager.removeGroup(this); + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) { + + // open overview so they can choose a window for focusing + // and ultimately dropping dragged item onto + if(Main.overview.shouldToggleByCornerOrButton()) + Main.overview.show(); + } + + return DND.DragMotionResult.CONTINUE; + }, + + getPosition: function() { + let position = PanelSettings.getPanelPosition(Me.settings, this.monitor.index); + + if (position == Pos.TOP) { + return St.Side.TOP; + } else if (position == Pos.RIGHT) { + return St.Side.RIGHT; + } else if (position == Pos.BOTTOM) { + return St.Side.BOTTOM; + } + + return St.Side.LEFT; + }, + + checkIfVertical: function() { + let position = this.getPosition(); + + return (position == St.Side.LEFT || position == St.Side.RIGHT); + }, + + getOrientation: function() { + return (this.checkIfVertical() ? 'vertical' : 'horizontal'); + }, + + updateElementPositions: function() { + let panelPositions = this.panelManager.panelsElementPositions[this.monitor.index] || Pos.defaults; + + this._updateGroupedElements(panelPositions); + + this._disablePanelCornerSignals(); + + if (this.getPosition() == St.Side.TOP) { + let visibleElements = panelPositions.filter(pp => pp.visible); + let connectCorner = (corner, button) => { + corner._button = button; + corner._buttonStyleChangedSignalId = button.connect('style-changed', () => { + corner.set_style_pseudo_class(button.get_style_pseudo_class()); + }); + } + + if (visibleElements[0].element == Pos.ACTIVITIES_BTN) { + connectCorner(this.panel._leftCorner, this.statusArea.activities); + } + + if (visibleElements[visibleElements.length - 1].element == Pos.SYSTEM_MENU) { + connectCorner(this.panel._rightCorner, this.statusArea.aggregateMenu); + } + } + + this.panel.actor.hide(); + this.panel.actor.show(); + }, + + _updateGroupedElements: function(panelPositions) { + let previousPosition = 0; + let previousCenteredPosition = 0; + let currentGroup = -1; + + this._elementGroups = []; + + panelPositions.forEach(pos => { + let allocationMap = this.allocationMap[pos.element]; + + if (allocationMap.actor) { + allocationMap.actor.visible = pos.visible; + + if (!pos.visible) { + return; + } + + let currentPosition = pos.position; + let isCentered = Pos.checkIfCentered(currentPosition); + + if (currentPosition == Pos.STACKED_TL && previousPosition == Pos.STACKED_BR) { + currentPosition = Pos.STACKED_BR; + } + + if (!previousPosition || + (previousPosition == Pos.STACKED_TL && currentPosition != Pos.STACKED_TL) || + (previousPosition != Pos.STACKED_BR && currentPosition == Pos.STACKED_BR) || + (isCentered && previousPosition != currentPosition && previousPosition != Pos.STACKED_BR)) { + this._elementGroups[++currentGroup] = { elements: [], index: this._elementGroups.length, expandableIndex: -1 }; + previousCenteredPosition = 0; + } + + if (pos.element == Pos.TASKBAR) { + this._elementGroups[currentGroup].expandableIndex = this._elementGroups[currentGroup].elements.length; + } + + if (isCentered && !this._elementGroups[currentGroup].isCentered) { + this._elementGroups[currentGroup].isCentered = 1; + previousCenteredPosition = currentPosition; + } + + this._elementGroups[currentGroup].position = previousCenteredPosition || currentPosition; + this._elementGroups[currentGroup].elements.push(allocationMap); + + allocationMap.position = currentPosition; + previousPosition = currentPosition; + } + }); + }, + + _disablePanelCornerSignals: function() { + if (this.panel._rightCorner && this.panel._rightCorner._buttonStyleChangedSignalId) { + this.panel._rightCorner._button.disconnect(this.panel._rightCorner._buttonStyleChangedSignalId); + delete this.panel._rightCorner._buttonStyleChangedSignalId; + } + + if (this.panel._leftCorner && this.panel._leftCorner._buttonStyleChangedSignalId) { + this.panel._leftCorner._button.disconnect(this.panel._leftCorner._buttonStyleChangedSignalId); + delete this.panel._leftCorner._buttonStyleChangedSignalId; + } + }, + + _bindSettingsChanges: function() { + let isVertical = this.checkIfVertical(); + + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::group-apps' + ], + () => this._resetGeometry() + ], + [ + Me.settings, + [ + 'changed::appicon-margin', + 'changed::appicon-padding' + ], + () => this.taskbar.resetAppIcons() + ], + [ + Me.settings, + 'changed::show-appmenu', + () => this._setAppmenuVisible(Me.settings.get_boolean('show-appmenu')) + ], + [ + Me.settings, + [ + 'changed::showdesktop-button-width', + 'changed::trans-use-custom-bg', + 'changed::desktop-line-use-custom-color', + 'changed::desktop-line-custom-color', + 'changed::trans-bg-color' + ], + () => this._setShowDesktopButtonStyle() + ], + [ + Me.desktopSettings, + 'changed::clock-format', + () => { + this._clockFormat = null; + + if (isVertical) { + this._formatVerticalClock(); + } + } + ], + [ + Me.settings, + 'changed::progress-show-bar', + () => this._initProgressManager() + ], + [ + Me.settings, + 'changed::progress-show-count', + () => this._initProgressManager() + ] + ); + + if (isVertical) { + this._signalsHandler.add([Me.settings, 'changed::group-apps-label-max-width', () => this._resetGeometry()]); + } + }, + + _setPanelMenu: function(propName, constr, container) { + if (!this.statusArea[propName]) { + this.statusArea[propName] = this._getPanelMenu(propName, constr); + this.menuManager.addMenu(this.statusArea[propName].menu); + container.insert_child_at_index(this.statusArea[propName].container, 0); + } + }, + + _removePanelMenu: function(propName) { + if (this.statusArea[propName]) { + let parent = this.statusArea[propName].container.get_parent(); + + if (parent) { + parent.remove_actor(this.statusArea[propName].container); + } + + //calling this.statusArea[propName].destroy(); is buggy for now, gnome-shell never + //destroys those panel menus... + //since we can't destroy the menu (hence properly disconnect its signals), let's + //store it so the next time a panel needs one of its kind, we can reuse it instead + //of creating a new one + let panelMenu = this.statusArea[propName]; + + this.menuManager.removeMenu(panelMenu.menu); + Me.persistentStorage[propName].push(panelMenu); + this.statusArea[propName] = null; + } + }, + + _getPanelMenu: function(propName, constr) { + Me.persistentStorage[propName] = Me.persistentStorage[propName] || []; + + if (!Me.persistentStorage[propName].length) { + Me.persistentStorage[propName].push(new constr()); + } + + return Me.persistentStorage[propName].pop(); + }, + + _setPanelGhostSize: function() { + this._myPanelGhost.set_size(this.width, this.checkIfVertical() ? 1 : this.height); + }, + + _setSearchEntryOffset: function(offset) { + if (this.isPrimary) { + //In the overview, when the panel is vertical the search-entry is the only element + //that doesn't natively take into account the size of a side dock, as it is always + //centered relatively to the monitor. This looks misaligned, adjust it here so it + //is centered like the rest of the overview elements. + let paddingSide = this.getPosition() == St.Side.LEFT ? 'left' : 'right'; + let scaleFactor = Utils.getScaleFactor(); + let style = offset ? 'padding-' + paddingSide + ':' + (offset / scaleFactor) + 'px;' : null; + let searchEntry = Main.overview._overview._controls._searchEntry; + searchEntry.get_parent().set_style(style); + } + }, + + _adjustForOverview: function() { + let isFocusedMonitor = this.panelManager.checkIfFocusedMonitor(this.monitor); + let isOverview = !!Main.overview.visibleTarget; + let isOverviewFocusedMonitor = isOverview && isFocusedMonitor; + let isShown = !isOverview || isOverviewFocusedMonitor; + + this.panelBox[isShown ? 'show' : 'hide'](); + + if (isOverview) { + this._myPanelGhost[isOverviewFocusedMonitor ? 'show' : 'hide'](); + + if (isOverviewFocusedMonitor) { + Utils.getPanelGhost().set_size(1, this.geom.position == St.Side.TOP ? 0 : 32); + } + } + }, + + _resetGeometry: function() { + this.geom = this.getGeometry(); + this._setPanelGhostSize(); + this._setPanelPosition(); + this.taskbar.resetAppIcons(true); + this.dynamicTransparency.updateExternalStyle(); + + if (this.intellihide && this.intellihide.enabled) { + this.intellihide.reset(); + } + + if (this.checkIfVertical()) { + this.showAppsIconWrapper.realShowAppsIcon.toggleButton.set_width(this.geom.w); + this._refreshVerticalAlloc(); + this._setSearchEntryOffset(this.geom.w); + } + }, + + getGeometry: function() { + let scaleFactor = Utils.getScaleFactor(); + let panelBoxTheme = this.panelBox.get_theme_node(); + let lrPadding = panelBoxTheme.get_padding(St.Side.RIGHT) + panelBoxTheme.get_padding(St.Side.LEFT); + let topPadding = panelBoxTheme.get_padding(St.Side.TOP); + let tbPadding = topPadding + panelBoxTheme.get_padding(St.Side.BOTTOM); + let position = this.getPosition(); + let length = PanelSettings.getPanelLength(Me.settings, this.monitor.index) / 100; + let anchor = PanelSettings.getPanelAnchor(Me.settings, this.monitor.index); + let anchorPlaceOnMonitor = 0; + let gsTopPanelOffset = 0; + let x = 0, y = 0; + let w = 0, h = 0; + + const panelSize = PanelSettings.getPanelSize(Me.settings, this.monitor.index); + this.dtpSize = panelSize * scaleFactor; + + if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.primaryMonitor == this.monitor) { + gsTopPanelOffset = Main.layoutManager.panelBox.height - topPadding; + } + + if (this.checkIfVertical()) { + if (!Me.settings.get_boolean('group-apps')) { + // add window title width and side padding of _dtpIconContainer when vertical + this.dtpSize += Me.settings.get_int('group-apps-label-max-width') + AppIcons.DEFAULT_PADDING_SIZE * 2 / scaleFactor; + } + + this.sizeFunc = 'get_preferred_height', + this.fixedCoord = { c1: 'x1', c2: 'x2' }, + this.varCoord = { c1: 'y1', c2: 'y2' }; + + w = this.dtpSize; + h = this.monitor.height * length - tbPadding - gsTopPanelOffset; + } else { + this.sizeFunc = 'get_preferred_width'; + this.fixedCoord = { c1: 'y1', c2: 'y2' }; + this.varCoord = { c1: 'x1', c2: 'x2' }; + + w = this.monitor.width * length - lrPadding; + h = this.dtpSize; + } + + if (position == St.Side.TOP || position == St.Side.LEFT) { + x = this.monitor.x; + y = this.monitor.y + gsTopPanelOffset; + } else if (position == St.Side.RIGHT) { + x = this.monitor.x + this.monitor.width - this.dtpSize - lrPadding; + y = this.monitor.y + gsTopPanelOffset; + } else { //BOTTOM + x = this.monitor.x; + y = this.monitor.y + this.monitor.height - this.dtpSize - tbPadding; + } + + if (this.checkIfVertical()) { + let viewHeight = this.monitor.height - gsTopPanelOffset; + + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (viewHeight - h) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = viewHeight - h; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + y = y + anchorPlaceOnMonitor; + } else { + if (anchor === Pos.MIDDLE) { + anchorPlaceOnMonitor = (this.monitor.width - w) / 2; + } else if (anchor === Pos.END) { + anchorPlaceOnMonitor = this.monitor.width - w; + } else { // Pos.START + anchorPlaceOnMonitor = 0; + } + x = x + anchorPlaceOnMonitor; + } + + return { + x: x, y: y, + w: w, h: h, + lrPadding: lrPadding, + tbPadding: tbPadding, + position: position + }; + }, + + _setAllocationMap: function() { + this.allocationMap = {}; + let setMap = (name, actor, isBox) => this.allocationMap[name] = { + actor: actor, + isBox: isBox || 0, + box: new Clutter.ActorBox() + }; + + setMap(Pos.SHOW_APPS_BTN, this.showAppsIconWrapper.realShowAppsIcon); + setMap(Pos.ACTIVITIES_BTN, this.statusArea.activities ? this.statusArea.activities.container : 0); + setMap(Pos.LEFT_BOX, this._leftBox, 1); + setMap(Pos.TASKBAR, this.taskbar.actor); + setMap(Pos.CENTER_BOX, this._centerBox, 1); + setMap(Pos.DATE_MENU, this.statusArea.dateMenu.container); + setMap(Pos.SYSTEM_MENU, this.statusArea.aggregateMenu.container); + setMap(Pos.RIGHT_BOX, this._rightBox, 1); + setMap(Pos.DESKTOP_BTN, this._showDesktopButton); + }, + + _mainPanelAllocate: function(actor, box, flags) { + Utils.setAllocation(this.panel.actor, box, flags); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + + let fixed = 0; + let centeredMonitorGroup; + let panelAlloc = new Clutter.ActorBox({ x1: 0, y1: 0, x2: this.geom.w, y2: this.geom.h }); + let assignGroupSize = (group, update) => { + group.size = 0; + group.tlOffset = 0; + group.brOffset = 0; + + group.elements.forEach(element => { + if (!update) { + element.box[this.fixedCoord.c1] = panelAlloc[this.fixedCoord.c1]; + element.box[this.fixedCoord.c2] = panelAlloc[this.fixedCoord.c2]; + element.natSize = element.actor[this.sizeFunc](-1)[1]; + } + + if (!group.isCentered || Pos.checkIfCentered(element.position)) { + group.size += element.natSize; + } else if (element.position == Pos.STACKED_TL) {  + group.tlOffset += element.natSize; + } else { // Pos.STACKED_BR + group.brOffset += element.natSize; + } + }); + + if (group.isCentered) { + group.size += Math.max(group.tlOffset, group.brOffset) * 2; + group.tlOffset = Math.max(group.tlOffset - group.brOffset, 0); + } + }; + let allocateGroup = (group, tlLimit, brLimit) => { + let startPosition = tlLimit; + let currentPosition = 0; + + if (group.expandableIndex >= 0) { + let availableSize = brLimit - tlLimit; + let expandable = group.elements[group.expandableIndex]; + let i = 0; + let l = this._elementGroups.length; + let tlSize = 0; + let brSize = 0; + + if (centeredMonitorGroup && (centeredMonitorGroup != group || expandable.position != Pos.CENTERED_MONITOR)) { + if (centeredMonitorGroup.index < group.index || (centeredMonitorGroup == group && expandable.position == Pos.STACKED_TL)) { + i = centeredMonitorGroup.index; + } else { + l = centeredMonitorGroup.index; + } + } + + for (; i < l; ++i) { + let refGroup = this._elementGroups[i]; + + if (i < group.index && (!refGroup.fixed || refGroup[this.varCoord.c2] > tlLimit)) { + tlSize += refGroup.size; + } else if (i > group.index && (!refGroup.fixed || refGroup[this.varCoord.c1] < brLimit)) { + brSize += refGroup.size; + } + } + + if (group.isCentered) { + availableSize -= Math.max(tlSize, brSize) * 2; + } else { + availableSize -= tlSize + brSize; + } + + if (availableSize < group.size) { + expandable.natSize -= (group.size - availableSize) * (group.isCentered && !Pos.checkIfCentered(expandable.position) ? .5 : 1); + assignGroupSize(group, true); + } + } + + if (group.isCentered) { + startPosition = tlLimit + (brLimit - tlLimit - group.size) * .5; + } else if (group.position == Pos.STACKED_BR) { + startPosition = brLimit - group.size; + } + + currentPosition = group.tlOffset + startPosition; + + group.elements.forEach(element => { + element.box[this.varCoord.c1] = Math.round(currentPosition); + element.box[this.varCoord.c2] = Math.round((currentPosition += element.natSize)); + + if (element.isBox) { + return element.actor.allocate(element.box, flags, true); + } + + Utils.allocate(element.actor, element.box, flags, false); + }); + + group[this.varCoord.c1] = startPosition; + group[this.varCoord.c2] = currentPosition; + group.fixed = 1; + ++fixed; + }; + + Utils.allocate(this.panel.actor, panelAlloc, flags); + + this._elementGroups.forEach(group => { + group.fixed = 0; + + assignGroupSize(group); + + if (group.position == Pos.CENTERED_MONITOR) { + centeredMonitorGroup = group; + } + }); + + if (centeredMonitorGroup) { + allocateGroup(centeredMonitorGroup, panelAlloc[this.varCoord.c1], panelAlloc[this.varCoord.c2]); + } + + let iterations = 0; //failsafe + while (fixed < this._elementGroups.length && ++iterations < 10) { + for (let i = 0, l = this._elementGroups.length; i < l; ++i) { + let group = this._elementGroups[i]; + + if (group.fixed) { + continue; + } + + let prevGroup = this._elementGroups[i - 1]; + let nextGroup = this._elementGroups[i + 1]; + let prevLimit = prevGroup && prevGroup.fixed ? prevGroup[this.varCoord.c2] : + centeredMonitorGroup && group.index > centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c2] : panelAlloc[this.varCoord.c1]; + let nextLimit = nextGroup && nextGroup.fixed ? nextGroup[this.varCoord.c1] : + centeredMonitorGroup && group.index < centeredMonitorGroup.index ? centeredMonitorGroup[this.varCoord.c1] : panelAlloc[this.varCoord.c2]; + + if (group.position == Pos.STACKED_TL) { + allocateGroup(group, panelAlloc[this.varCoord.c1], nextLimit); + } else if (group.position == Pos.STACKED_BR) { + allocateGroup(group, prevLimit, panelAlloc[this.varCoord.c2]); + } else if ((!prevGroup || prevGroup.fixed) && (!nextGroup || nextGroup.fixed)) { // CENTERED + allocateGroup(group, prevLimit, nextLimit); + } + } + } + + if (this.geom.position == St.Side.TOP) { + let childBoxLeftCorner = new Clutter.ActorBox(); + let childBoxRightCorner = new Clutter.ActorBox(); + let currentCornerSize = this.cornerSize; + let panelAllocFixedSize = box[this.fixedCoord.c2] - box[this.fixedCoord.c1]; + + [ , this.cornerSize] = this.panel._leftCorner.actor[this.sizeFunc](-1); + childBoxLeftCorner[this.varCoord.c1] = 0; + childBoxLeftCorner[this.varCoord.c2] = this.cornerSize; + childBoxLeftCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxLeftCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + childBoxRightCorner[this.varCoord.c1] = box[this.varCoord.c2] - this.cornerSize; + childBoxRightCorner[this.varCoord.c2] = box[this.varCoord.c2]; + childBoxRightCorner[this.fixedCoord.c1] = panelAllocFixedSize; + childBoxRightCorner[this.fixedCoord.c2] = panelAllocFixedSize + this.cornerSize; + + Utils.allocate(this.panel._leftCorner.actor, childBoxLeftCorner, flags); + Utils.allocate(this.panel._rightCorner.actor, childBoxRightCorner, flags); + + if (this.cornerSize != currentCornerSize) { + this._setPanelClip(); + } + } + }, + + _setPanelPosition: function() { + let clipContainer = this.panelBox.get_parent(); + + this.set_size(this.geom.w, this.geom.h); + clipContainer.set_position(this.geom.x, this.geom.y); + + this._setVertical(this.panel.actor, this.checkIfVertical()); + + // styles for theming + Object.keys(St.Side).forEach(p => { + let cssName = 'dashtopanel' + p.charAt(0) + p.slice(1).toLowerCase(); + + this.panel.actor[(St.Side[p] == this.geom.position ? 'add' : 'remove') + '_style_class_name'](cssName); + }); + + this._setPanelClip(clipContainer); + + Main.layoutManager._updateHotCorners(); + Main.layoutManager._updatePanelBarrier(this); + }, + + _setPanelClip: function(clipContainer) { + clipContainer = clipContainer || this.panelBox.get_parent(); + this._timeoutsHandler.add([T7, 0, () => Utils.setClip(clipContainer, clipContainer.x, clipContainer.y, this.panelBox.width, this.panelBox.height + this.cornerSize)]); + }, + + _onButtonPress: function(actor, event) { + let type = event.type(); + let isPress = type == Clutter.EventType.BUTTON_PRESS; + let button = isPress ? event.get_button() : -1; + let [stageX, stageY] = event.get_coords(); + + if (button == 3 && global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, stageX, stageY) == this.panel.actor) { + //right click on an empty part of the panel, temporarily borrow and display the showapps context menu + Main.layoutManager.setDummyCursorGeometry(stageX, stageY, 0, 0); + + this.showAppsIconWrapper.createMenu(); + this.showAppsIconWrapper._menu.sourceActor = Main.layoutManager.dummyCursor; + this.showAppsIconWrapper.popupMenu(); + + return Clutter.EVENT_STOP; + } else if (Main.modalCount > 0 || event.get_source() != actor || + (!isPress && type != Clutter.EventType.TOUCH_BEGIN) || + (isPress && button != 1)) { + return Clutter.EVENT_PROPAGATE; + } + + let params = this.checkIfVertical() ? [stageY, 'y', 'height'] : [stageX, 'x', 'width']; + let dragWindow = this._getDraggableWindowForPosition.apply(this, params.concat(['maximized_' + this.getOrientation() + 'ly'])); + + if (!dragWindow) + return Clutter.EVENT_PROPAGATE; + + global.display.begin_grab_op(dragWindow, + Meta.GrabOp.MOVING, + false, /* pointer grab */ + true, /* frame action */ + button, + event.get_state(), + event.get_time(), + stageX, stageY); + + return Clutter.EVENT_STOP; + }, + + _getDraggableWindowForPosition: function(stageCoord, coord, dimension, maximizedProp) { + let workspace = Utils.getCurrentWorkspace(); + let allWindowsByStacking = global.display.sort_windows_by_stacking( + workspace.list_windows() + ).reverse(); + + return Utils.find(allWindowsByStacking, metaWindow => { + let rect = metaWindow.get_frame_rect(); + + return metaWindow.get_monitor() == this.monitor.index && + metaWindow.showing_on_its_workspace() && + metaWindow.get_window_type() != Meta.WindowType.DESKTOP && + metaWindow[maximizedProp] && + stageCoord > rect[coord] && stageCoord < rect[coord] + rect[dimension]; + }); + }, + + _onBoxActorAdded: function(box) { + if (this.checkIfVertical()) { + this._setVertical(box, true); + } + }, + + _refreshVerticalAlloc: function() { + this._setVertical(this._centerBox, true); + this._setVertical(this._rightBox, true); + this._formatVerticalClock(); + }, + + _setVertical: function(actor, isVertical) { + let _set = (actor, isVertical) => { + if (!actor || actor instanceof Dash.DashItemContainer || actor instanceof Taskbar.TaskbarItemContainer) { + return; + } + + if (actor instanceof St.BoxLayout) { + actor.vertical = isVertical; + } else if ((actor._delegate || actor) instanceof PanelMenu.ButtonBox && actor != this.statusArea.appMenu) { + let child = actor.get_first_child(); + + if (isVertical && !actor.visible && !actor._dtpVisibleId) { + this._unmappedButtons.push(actor); + actor._dtpVisibleId = actor.connect('notify::visible', () => { + this._disconnectVisibleId(actor); + this._refreshVerticalAlloc(); + }); + actor._dtpDestroyId = actor.connect('destroy', () => this._disconnectVisibleId(actor)); + } + + if (child) { + let [, natWidth] = actor.get_preferred_width(-1); + + child.x_align = Clutter.ActorAlign[isVertical ? 'CENTER' : 'START']; + actor.set_width(isVertical ? this.dtpSize : -1); + isVertical = isVertical && (natWidth > this.dtpSize); + actor[(isVertical ? 'add' : 'remove') + '_style_class_name']('vertical'); + } + } + + actor.get_children().forEach(c => _set(c, isVertical)); + }; + + _set(actor, false); + _set(actor, isVertical); + }, + + _disconnectVisibleId: function(actor) { + actor.disconnect(actor._dtpVisibleId); + actor.disconnect(actor._dtpDestroyId); + + delete actor._dtpVisibleId; + delete actor._dtpDestroyId; + + this._unmappedButtons.splice(this._unmappedButtons.indexOf(actor), 1); + }, + + _setAppmenuVisible: function(isVisible) { + let parent; + let appMenu = this.statusArea.appMenu; + + if(appMenu) + parent = appMenu.container.get_parent(); + + if (parent) { + parent.remove_child(appMenu.container); + } + + if (isVisible && appMenu) { + this._leftBox.insert_child_above(appMenu.container, null); + } + }, + + _formatVerticalClock: function() { + // https://github.com/GNOME/gnome-desktop/blob/master/libgnome-desktop/gnome-wall-clock.c#L310 + if (this.statusArea.dateMenu) { + let datetime = this.statusArea.dateMenu._clock.clock; + let datetimeParts = datetime.split(' '); + let time = datetimeParts[1]; + let clockText = this.statusArea.dateMenu._clockDisplay.clutter_text; + let setClockText = text => { + let stacks = text instanceof Array; + let separator = '\n‧‧\n'; + + clockText.set_text((stacks ? text.join(separator) : text).trim()); + clockText.set_use_markup(stacks); + clockText.get_allocation_box(); + + return !clockText.get_layout().is_ellipsized(); + }; + + if (clockText.ellipsize == Pango.EllipsizeMode.NONE) { + //on gnome-shell 3.36.4, the clockdisplay isn't ellipsize anymore, so set it back + clockText.ellipsize = Pango.EllipsizeMode.END; + } + + if (!time) { + datetimeParts = datetime.split(' '); + time = datetimeParts.pop(); + datetimeParts = [datetimeParts.join(' '), time]; + } + + if (!setClockText(datetime) && + !setClockText(datetimeParts) && + !setClockText(time)) { + let timeParts = time.split('∶'); + + if (!this._clockFormat) { + this._clockFormat = Me.desktopSettings.get_string('clock-format'); + } + + if (this._clockFormat == '12h') { + timeParts.push.apply(timeParts, timeParts.pop().split(' ')); + } + + setClockText(timeParts); + } + } + }, + + _setShowDesktopButton: function (add) { + if (add) { + if(this._showDesktopButton) + return; + + this._showDesktopButton = new St.Bin({ style_class: 'showdesktop-button', + reactive: true, + can_focus: true, + // x_fill: true, + // y_fill: true, + track_hover: true }); + + this._setShowDesktopButtonStyle(); + + this._showDesktopButton.connect('button-press-event', () => this._onShowDesktopButtonPress()); + this._showDesktopButton.connect('enter-event', () => { + this._showDesktopButton.add_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + this._timeoutsHandler.add([T4, Me.settings.get_int('show-showdesktop-delay'), () => { + this._hiddenDesktopWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + this._toggleWorkspaceWindows(true, this._hiddenDesktopWorkspace); + }]); + } + }); + + this._showDesktopButton.connect('leave-event', () => { + this._showDesktopButton.remove_style_class_name(this._getBackgroundBrightness() ? + 'showdesktop-button-light-hovered' : 'showdesktop-button-dark-hovered'); + + if (Me.settings.get_boolean('show-showdesktop-hover')) { + if (this._timeoutsHandler.getId(T4)) { + this._timeoutsHandler.remove(T4); + } else if (this._hiddenDesktopWorkspace) { + this._toggleWorkspaceWindows(false, this._hiddenDesktopWorkspace); + } +  } + }); + + this.panel.actor.add_child(this._showDesktopButton); + } else { + if(!this._showDesktopButton) + return; + + this.panel.actor.remove_child(this._showDesktopButton); + this._showDesktopButton.destroy(); + this._showDesktopButton = null; + } + }, + + _setShowDesktopButtonStyle: function() { + let rgb = this._getBackgroundBrightness() ? "rgba(55, 55, 55, .2)" : "rgba(200, 200, 200, .2)"; + + let isLineCustom = Me.settings.get_boolean('desktop-line-use-custom-color'); + rgb = isLineCustom ? Me.settings.get_string('desktop-line-custom-color') : rgb; + + if (this._showDesktopButton) { + let buttonSize = Me.settings.get_int('showdesktop-button-width') + 'px;'; + let isVertical = this.checkIfVertical(); + + let sytle = "border: 0 solid " + rgb + ";"; + sytle += isVertical ? 'border-top-width:1px;height:' + buttonSize : 'border-left-width:1px;width:' + buttonSize; + + this._showDesktopButton.set_style(sytle); + this._showDesktopButton[(isVertical ? 'x' : 'y') + '_expand'] = true; + } + }, + + // _getBackgroundBrightness: return true if panel has a bright background color + _getBackgroundBrightness: function() { + return Utils.checkIfColorIsBright(this.dynamicTransparency.backgroundColorRgb); + }, + + _toggleWorkspaceWindows: function(hide, workspace) { + let time = Me.settings.get_int('show-showdesktop-time') * .001; + + workspace.list_windows().forEach(w => { + if (!w.minimized) { + let tweenOpts = { + opacity: hide ? 0 : 255, + time: time, + transition: 'easeOutQuad' + }; + + Utils.animateWindowOpacity(w.get_compositor_private(), tweenOpts); + } + }); + }, + + _onShowDesktopButtonPress: function() { + let label = 'trackerFocusApp'; + + this._signalsHandler.removeWithLabel(label); + this._timeoutsHandler.remove(T5); + + if(this._restoreWindowList && this._restoreWindowList.length) { + this._timeoutsHandler.remove(T4); + + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows(); + this._restoreWindowList.forEach(function(w) { + if(windows.indexOf(w) > -1) + Main.activateWindow(w); + }); + this._restoreWindowList = null; + } else { + let current_workspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + let windows = current_workspace.list_windows().filter(function (w) { + return w.showing_on_its_workspace() && !w.skip_taskbar; + }); + windows = global.display.sort_windows_by_stacking(windows); + + windows.forEach(function(w) { + w.minimize(); + }); + + this._restoreWindowList = windows; + + this._timeoutsHandler.add([T5, 20, () => this._signalsHandler.addWithLabel( + label, + [ + tracker, + 'notify::focus-app', + () => this._restoreWindowList = null + ] + )]); + } + + Main.overview.hide(); + }, + + _onPanelMouseScroll: function(actor, event) { + let scrollAction = Me.settings.get_string('scroll-panel-action'); + let direction = Utils.getMouseScrollDirection(event); + + if (!this._checkIfIgnoredScrollSource(event.get_source()) && !this._timeoutsHandler.getId(T6)) { + if (direction && scrollAction === 'SWITCH_WORKSPACE') { + let args = [global.display]; + + //adjust for horizontal workspaces + if (Utils.DisplayWrapper.getWorkspaceManager().layout_rows === 1) { + direction = direction == 'up' ? 'left' : 'right'; + } + + //gnome-shell < 3.30 needs an additional "screen" param + global.screen ? args.push(global.screen) : 0; + + let showWsPopup = Me.settings.get_boolean('scroll-panel-show-ws-popup'); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = { display: () => {} }; + Main.wm._showWorkspaceSwitcher.apply(Main.wm, args.concat([0, { get_name: () => 'switch---' + direction }])); + showWsPopup ? 0 : Main.wm._workspaceSwitcherPopup = null; + } else if (direction && scrollAction === 'CYCLE_WINDOWS') { + let windows = this.taskbar.getAppInfos().reduce((ws, appInfo) => ws.concat(appInfo.windows), []); + + Utils.activateSiblingWindow(windows, direction); + } else if (scrollAction === 'CHANGE_VOLUME' && !event.is_pointer_emulated()) { + var proto = Volume.Indicator.prototype; + var func = proto._handleScrollEvent || proto.vfunc_scroll_event || proto._onScrollEvent; + + func.call(Main.panel.statusArea.aggregateMenu._volume, 0, event); + } else { + return; + } + + var scrollDelay = Me.settings.get_int('scroll-panel-delay'); + + if (scrollDelay) { + this._timeoutsHandler.add([T6, scrollDelay, () => {}]); + } + } + }, + + _checkIfIgnoredScrollSource: function(source) { + let ignoredConstr = ['WorkspaceIndicator']; + + return source.get_parent()._dtpIgnoreScroll || ignoredConstr.indexOf(source.constructor.name) >= 0; + }, + + _initProgressManager: function() { + if(!this.progressManager && (Me.settings.get_boolean('progress-show-bar') || Me.settings.get_boolean('progress-show-count'))) + this.progressManager = new Progress.ProgressManager(); + }, +}); + +var dtpSecondaryPanel = Utils.defineClass({ + Name: 'DashToPanel-SecondaryPanel', + Extends: St.Widget, + + _init: function(params) { + this.callParent('_init', params); + }, + + vfunc_allocate: function(box, flags) { + Utils.setAllocation(this, box, flags); + } +}); + +var dtpSecondaryAggregateMenu = Utils.defineClass({ + Name: 'DashToPanel-SecondaryAggregateMenu', + Extends: PanelMenu.Button, + + _init: function() { + this.callParent('_init', 0.0, C_("System menu in the top bar", "System"), false); + + Utils.wrapActor(this); + + this.menu.actor.add_style_class_name('aggregate-menu'); + + let menuLayout = new Panel.AggregateLayout(); + this.menu.box.set_layout_manager(menuLayout); + + this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' }); + this.actor.add_child(this._indicators); + + this._power = new imports.ui.status.power.Indicator(); + this._volume = new imports.ui.status.volume.Indicator(); + this._brightness = new imports.ui.status.brightness.Indicator(); + this._system = new imports.ui.status.system.Indicator(); + + if (Config.PACKAGE_VERSION >= '3.28') { + this._thunderbolt = new imports.ui.status.thunderbolt.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._thunderbolt)); + } + + if (Config.PACKAGE_VERSION < '3.37') { + this._screencast = new imports.ui.status.screencast.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._screencast)); + } + + if (Config.PACKAGE_VERSION >= '3.24') { + this._nightLight = new imports.ui.status.nightLight.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._nightLight)); + } + + if (Config.HAVE_NETWORKMANAGER && Config.PACKAGE_VERSION >= '3.24') { + this._network = new imports.ui.status.network.NMApplet(); + this._indicators.add_child(Utils.getIndicators(this._network)); + } + + if (Config.HAVE_BLUETOOTH) { + this._bluetooth = new imports.ui.status.bluetooth.Indicator(); + this._indicators.add_child(Utils.getIndicators(this._bluetooth)); + } + + this._indicators.add_child(Utils.getIndicators(this._volume)); + this._indicators.add_child(Utils.getIndicators(this._power)); + + this.menu.addMenuItem(this._volume.menu); + this._volume._volumeMenu._readOutput(); + this._volume._volumeMenu._readInput(); + + this.menu.addMenuItem(this._brightness.menu); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + if (this._network) { + this.menu.addMenuItem(this._network.menu); + } + + if (this._bluetooth) { + this.menu.addMenuItem(this._bluetooth.menu); + } + + this.menu.addMenuItem(this._power.menu); + this._power._sync(); + + if (this._nightLight) { + this.menu.addMenuItem(this._nightLight.menu); + } + + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(this._system.menu); + + menuLayout.addSizeChild(this._power.menu.actor); + menuLayout.addSizeChild(this._system.menu.actor); + }, +}); diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js new file mode 100644 index 0000000..d572d8b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelManager.js @@ -0,0 +1,789 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * + * Code to re-anchor the panel was taken from Thoma5 BottomPanel: + * https://github.com/Thoma5/gnome-shell-extension-bottompanel + * + * Pattern for moving clock based on Frippery Move Clock by R M Yorston + * http://frippery.org/extensions/ + * + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Overview = Me.imports.overview; +const Panel = Me.imports.panel; +const PanelSettings = Me.imports.panelSettings; +const Proximity = Me.imports.proximity; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +const Config = imports.misc.config; +const Lang = imports.lang; +const Gi = imports._gi; +const GLib = imports.gi.GLib; +const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; + +const AppDisplay = imports.ui.appDisplay; +const BoxPointer = imports.ui.boxpointer; +const Dash = imports.ui.dash; +const IconGrid = imports.ui.iconGrid; +const LookingGlass = imports.ui.lookingGlass; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const Layout = imports.ui.layout; +const WM = imports.ui.windowManager; +const WorkspacesView = imports.ui.workspacesView; + +var dtpPanelManager = Utils.defineClass({ + Name: 'DashToPanel.PanelManager', + + _init: function() { + this.overview = new Overview.dtpOverview(); + this.panelsElementPositions = {}; + + this._saveMonitors(); + + Utils.getAppDisplayViews().forEach(v => { + Utils.wrapActor(v.view); + Utils.wrapActor(v.view._grid); + }); + }, + + enable: function(reset) { + let dtpPrimaryIndex = Me.settings.get_int('primary-monitor'); + + this.dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex] || Main.layoutManager.primaryMonitor; + this.proximityManager = new Proximity.ProximityManager(); + + this._oldGetShowAppsButton = imports.ui.main.overview.dash.showAppsButton; + + Utils.wrapActor(Main.panel); + Utils.wrapActor(Main.overview.dash || 0); + + this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel')); + this.allPanels = [ this.primaryPanel ]; + + this.overview.enable(this.primaryPanel); + + if (Me.settings.get_boolean('multi-monitors')) { + Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => { + this.allPanels.push(this._createPanel(m, true)); + }); + } + + global.dashToPanel.panels = this.allPanels; + global.dashToPanel.emit('panels-created'); + + this.allPanels.forEach(p => { + let panelPosition = p.getPosition(); + let leftOrRight = (panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT); + + p.panelBox.set_size( + leftOrRight ? -1 : p.geom.w + p.geom.lrPadding, + leftOrRight ? p.geom.h + p.geom.tbPadding : -1 + ); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => this._adjustPanelMenuButton(pmb, p.monitor, panelPosition)); + + p.taskbar.iconAnimator.start(); + }); + + //in 3.32, BoxPointer now inherits St.Widget + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + let panelManager = this; + + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', function(forWidth) { + let alloc = { min_size: 0, natural_size: 0 }; + + [alloc.min_size, alloc.natural_size] = this.vfunc_get_preferred_height(forWidth); + + return panelManager._getBoxPointerPreferredHeight(this, alloc); + }); + } + + this._updatePanelElementPositions(); + this.setFocusedMonitor(this.dtpPrimaryMonitor); + + if (this.primaryPanel.checkIfVertical()) { + Main.wm._getPositionForDirection = newGetPositionForDirection; + } + + if (reset) return; + + if (Config.PACKAGE_VERSION > '3.35.1') { + this._oldDoSpringAnimation = AppDisplay.BaseAppView.prototype._doSpringAnimation; + AppDisplay.BaseAppView.prototype._doSpringAnimation = newDoSpringAnimation; + } + + this._oldUpdatePanelBarrier = Main.layoutManager._updatePanelBarrier; + Main.layoutManager._updatePanelBarrier = (panel) => { + let panelUpdates = panel ? [panel] : this.allPanels; + + panelUpdates.forEach(p => newUpdatePanelBarrier.call(Main.layoutManager, p)); + }; + Main.layoutManager._updatePanelBarrier(); + + this._oldUpdateHotCorners = Main.layoutManager._updateHotCorners; + Main.layoutManager._updateHotCorners = Lang.bind(Main.layoutManager, newUpdateHotCorners); + Main.layoutManager._updateHotCorners(); + + this._forceHotCornerId = Me.settings.connect('changed::stockgs-force-hotcorner', () => Main.layoutManager._updateHotCorners()); + + if (Main.layoutManager._interfaceSettings) { + this._enableHotCornersId = Main.layoutManager._interfaceSettings.connect('changed::enable-hot-corners', () => Main.layoutManager._updateHotCorners()); + } + + Main.overview.getShowAppsButton = this._newGetShowAppsButton.bind(this); + + this._needsDashItemContainerAllocate = !Dash.DashItemContainer.prototype.hasOwnProperty('vfunc_allocate'); + + if (this._needsDashItemContainerAllocate) { + Utils.hookVfunc(Dash.DashItemContainer.prototype, 'allocate', this._newDashItemContainerAllocate); + } + + LookingGlass.LookingGlass.prototype._oldResize = LookingGlass.LookingGlass.prototype._resize; + LookingGlass.LookingGlass.prototype._resize = _newLookingGlassResize; + + LookingGlass.LookingGlass.prototype._oldOpen = LookingGlass.LookingGlass.prototype.open; + LookingGlass.LookingGlass.prototype.open = _newLookingGlassOpen; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + if (Config.PACKAGE_VERSION > '3.35.9') { + let currentAppsView; + + this._oldAnimateIconPosition = IconGrid.animateIconPosition; + IconGrid.animateIconPosition = newAnimateIconPosition.bind(this); + + this._signalsHandler.add( + [ + Utils.DisplayWrapper.getScreen(), + 'window-entered-monitor', + () => this._needsIconAllocate = 1 + ] + ); + + Utils.getAppDisplayViews().forEach(v => { + if (!v.control || v.control.has_style_pseudo_class('checked')) { + currentAppsView = v; + } + + if (v.control) { + this._signalsHandler.add( + [ + v.control, + 'clicked', + () => { + this._needsIconAllocate = currentAppsView != v; + currentAppsView = v; + } + ] + ); + } + + this._signalsHandler.add( + [ + v.view, + 'notify::visible', + () => this._needsIconAllocate = !(currentAppsView != v && !v.view.visible) + ], + [ + v.view._grid, + 'animation-done', + () => this._needsIconAllocate = 0 + ] + ); + }); + } + + //listen settings + this._signalsHandler.add( + [ + Me.settings, + [ + 'changed::primary-monitor', + 'changed::multi-monitors', + 'changed::isolate-monitors', + 'changed::panel-positions', + 'changed::panel-lengths', + 'changed::panel-anchors', + 'changed::stockgs-keep-top-panel' + ], + () => this._reset() + ], + [ + Me.settings, + 'changed::panel-element-positions', + () => this._updatePanelElementPositions() + ], + [ + Me.settings, + 'changed::intellihide-key-toggle-text', + () => this._setKeyBindings(true) + ], + [ + Utils.DisplayWrapper.getMonitorManager(), + 'monitors-changed', + () => { + if (Main.layoutManager.primaryMonitor) { + this._saveMonitors(); + this._reset(); + } + } + ] + ); + + Panel.panelBoxes.forEach(c => this._signalsHandler.add( + [Main.panel[c], 'actor-added', (parent, child) => this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, this.primaryPanel.getPosition())] + )); + + this._setKeyBindings(true); + + // keep GS overview.js from blowing away custom panel styles + if(!Me.settings.get_boolean('stockgs-keep-top-panel')) + Object.defineProperty(Main.panel, "style", {configurable: true, set: function(v) {}}); + }, + + disable: function(reset) { + this.overview.disable(); + this.proximityManager.destroy(); + + this.allPanels.forEach(p => { + p.taskbar.iconAnimator.pause(); + + this._findPanelMenuButtons(p.panelBox).forEach(pmb => { + if (pmb.menu._boxPointer._dtpGetPreferredHeightId) { + pmb.menu._boxPointer._container.disconnect(pmb.menu._boxPointer._dtpGetPreferredHeightId); + } + + pmb.menu._boxPointer.sourceActor = pmb.menu._boxPointer._dtpSourceActor; + delete pmb.menu._boxPointer._dtpSourceActor; + pmb.menu._boxPointer._userArrowSide = St.Side.TOP; + }) + + this._removePanelBarriers(p); + + p.disable(); + + let clipContainer = p.panelBox.get_parent(); + + Main.layoutManager._untrackActor(p.panelBox); + Main.layoutManager.removeChrome(clipContainer); + + if (p.isStandalone) { + p.panelBox.destroy(); + } else { + p.panelBox.remove_child(p); + p.remove_child(p.panel.actor); + p.panelBox.add(p.panel.actor); + + p.panelBox.set_position(clipContainer.x, clipContainer.y); + + clipContainer.remove_child(p.panelBox); + Main.layoutManager.addChrome(p.panelBox, { affectsStruts: true, trackFullscreen: true }); + } + }); + + if (BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height) { + Utils.hookVfunc(BoxPointer.BoxPointer.prototype, 'get_preferred_height', BoxPointer.BoxPointer.prototype.vfunc_get_preferred_height); + } + + delete Main.wm._getPositionForDirection; + + if (Main.layoutManager.primaryMonitor) { + Main.layoutManager.panelBox.set_position(Main.layoutManager.primaryMonitor.x, Main.layoutManager.primaryMonitor.y); + Main.layoutManager.panelBox.set_size(Main.layoutManager.primaryMonitor.width, -1); + } + + if (reset) return; + + this._setKeyBindings(false); + + this._signalsHandler.destroy(); + + Main.layoutManager._updateHotCorners = this._oldUpdateHotCorners; + Main.layoutManager._updateHotCorners(); + + Me.settings.disconnect(this._forceHotCornerId); + + if (this._enableHotCornersId) { + Main.layoutManager._interfaceSettings.disconnect(this._enableHotCornersId); + } + + Main.layoutManager._updatePanelBarrier = this._oldUpdatePanelBarrier; + Main.layoutManager._updatePanelBarrier(); + + Utils.getPanelGhost().set_size(-1, -1); + + if (this._oldDoSpringAnimation) { + AppDisplay.BaseAppView.prototype._doSpringAnimation = this._oldDoSpringAnimation; + } + + if (this._oldAnimateIconPosition) { + IconGrid.animateIconPosition = this._oldAnimateIconPosition; + } + + LookingGlass.LookingGlass.prototype._resize = LookingGlass.LookingGlass.prototype._oldResize; + delete LookingGlass.LookingGlass.prototype._oldResize; + + LookingGlass.LookingGlass.prototype.open = LookingGlass.LookingGlass.prototype._oldOpen; + delete LookingGlass.LookingGlass.prototype._oldOpen + + delete Main.panel.style; + }, + + setFocusedMonitor: function(monitor, ignoreRelayout) { + // todo show overview on non primary monitor is not working right now on gnome40 + + // this._needsIconAllocate = 1; + + // if (!this.checkIfFocusedMonitor(monitor)) { + // Main.overview._overview._controls._workspacesDisplay._primaryIndex = monitor.index; + + // Main.overview._overview.clear_constraints(); + // Main.overview._overview.add_constraint(new Layout.MonitorConstraint({ index: monitor.index })); + // } + }, + + _saveMonitors: function() { + //Mutter meta_monitor_manager_get_primary_monitor (global.display.get_primary_monitor()) doesn't return the same + //monitor as GDK gdk_screen_get_primary_monitor (imports.gi.Gdk.Screen.get_default().get_primary_monitor()). + //Since the Mutter function is what's used in gnome-shell and we can't access it from the settings dialog, store + //the monitors information in a setting so we can use the same monitor indexes as the ones in gnome-shell + let primaryIndex = Main.layoutManager.primaryIndex; + let monitors = [primaryIndex]; + + Main.layoutManager.monitors.filter(m => m.index != primaryIndex).forEach(m => monitors.push(m.index)); + Me.settings.set_value('available-monitors', new GLib.Variant('ai', monitors)); + }, + + checkIfFocusedMonitor: function(monitor) { + return Main.overview._overview._controls._workspacesDisplay._primaryIndex == monitor.index; + }, + + _createPanel: function(monitor, isStandalone) { + let panelBox; + let panel; + let clipContainer = new Clutter.Actor(); + + if (isStandalone) { + panelBox = new St.BoxLayout({ name: 'panelBox' }); + } else { + panelBox = Main.layoutManager.panelBox; + Main.layoutManager._untrackActor(panelBox); + panelBox.remove_child(Main.panel.actor); + Main.layoutManager.removeChrome(panelBox); + } + + Main.layoutManager.addChrome(clipContainer, { affectsInputRegion: false }); + clipContainer.add_child(panelBox); + Main.layoutManager.trackChrome(panelBox, { trackFullscreen: true, affectsStruts: true, affectsInputRegion: true }); + + panel = new Panel.dtpPanel(this, monitor, panelBox, isStandalone); + panelBox.add(panel); + panel.enable(); + + panelBox.visible = true; + if (monitor.inFullscreen) { + panelBox.hide(); + } + panelBox.set_position(0, 0); + + return panel; + }, + + _reset: function() { + this.disable(true); + this.allPanels = []; + this.enable(true); + }, + + _updatePanelElementPositions: function() { + this.panelsElementPositions = PanelSettings.getSettingsJson(Me.settings, 'panel-element-positions'); + this.allPanels.forEach(p => p.updateElementPositions()); + }, + + _adjustPanelMenuButton: function(button, monitor, arrowSide) { + if (button) { + Utils.wrapActor(button); + button.menu._boxPointer._dtpSourceActor = button.menu._boxPointer.sourceActor; + button.menu._boxPointer.sourceActor = button.actor; + button.menu._boxPointer._userArrowSide = arrowSide; + button.menu._boxPointer._dtpInPanel = 1; + + if (!button.menu._boxPointer.vfunc_get_preferred_height) { + button.menu._boxPointer._dtpGetPreferredHeightId = button.menu._boxPointer._container.connect('get-preferred-height', (actor, forWidth, alloc) => { + this._getBoxPointerPreferredHeight(button.menu._boxPointer, alloc, monitor); + }); + } + } + }, + + _getBoxPointerPreferredHeight: function(boxPointer, alloc, monitor) { + if (boxPointer._dtpInPanel && boxPointer.sourceActor && Me.settings.get_boolean('intellihide')) { + monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor); + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor == monitor); + let excess = alloc.natural_size + panel.dtpSize + 10 - monitor.height; // 10 is arbitrary + + if (excess > 0) { + alloc.natural_size -= excess; + } + } + + return [alloc.min_size, alloc.natural_size]; + }, + + _findPanelMenuButtons: function(container) { + let panelMenuButtons = []; + let panelMenuButton; + + let find = parent => parent.get_children().forEach(c => { + if ((panelMenuButton = this._getPanelMenuButton(c))) { + panelMenuButtons.push(panelMenuButton); + } + + find(c); + }); + + find(container); + + return panelMenuButtons; + }, + + _removePanelBarriers: function(panel) { + if (panel.isStandalone && panel._rightPanelBarrier) { + panel._rightPanelBarrier.destroy(); + } + + if (panel._leftPanelBarrier) { + panel._leftPanelBarrier.destroy(); + delete panel._leftPanelBarrier; + } + }, + + _getPanelMenuButton: function(obj) { + return obj._delegate && obj._delegate instanceof PanelMenu.Button ? obj._delegate : 0; + }, + + _setKeyBindings: function(enable) { + let keys = { + 'intellihide-key-toggle': () => this.allPanels.forEach(p => p.intellihide.toggle()) + }; + + Object.keys(keys).forEach(k => { + Utils.removeKeybinding(k); + + if (enable) { + Utils.addKeybinding(k, Me.settings, keys[k], Shell.ActionMode.NORMAL); + } + }); + }, + + _newGetShowAppsButton: function() { + let focusedMonitorIndex = Utils.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor)); + + return this.allPanels[focusedMonitorIndex].taskbar.showAppsButton; + } +}); + +// This class drives long-running icon animations, to keep them running in sync +// with each other. +var IconAnimator = Utils.defineClass({ + Name: 'DashToPanel.IconAnimator', + + _init: function(actor) { + this._count = 0; + this._started = false; + this._animations = { + dance: [], + }; + this._timeline = new Clutter.Timeline({ + duration: 3000, + repeat_count: -1, + }); + + /* Just use the construction property when no need to support 3.36 */ + if (this._timeline.set_actor) + this._timeline.set_actor(actor); + + this._timeline.connect('new-frame', () => { + const progress = this._timeline.get_progress(); + const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0; + const dancers = this._animations.dance; + for (let i = 0, iMax = dancers.length; i < iMax; i++) { + dancers[i].target.rotation_angle_z = danceRotation; + } + }); + }, + + destroy: function() { + this._timeline.stop(); + this._timeline = null; + for (let name in this._animations) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + pair.target.disconnect(pair.targetDestroyId); + } + } + this._animations = null; + }, + + pause: function() { + if (this._started && this._count > 0) { + this._timeline.stop(); + } + this._started = false; + }, + + start: function() { + if (!this._started && this._count > 0) { + this._timeline.start(); + } + this._started = true; + }, + + addAnimation: function(target, name) { + const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name)); + this._animations[name].push({ target: target, targetDestroyId: targetDestroyId }); + if (this._started && this._count === 0) { + this._timeline.start(); + } + this._count++; + }, + + removeAnimation: function(target, name) { + const pairs = this._animations[name]; + for (let i = 0, iMax = pairs.length; i < iMax; i++) { + const pair = pairs[i]; + if (pair.target === target) { + target.disconnect(pair.targetDestroyId); + pairs.splice(i, 1); + this._count--; + if (this._started && this._count === 0) { + this._timeline.stop(); + } + return; + } + } + } +}); + +function newGetPositionForDirection(direction, fromWs, toWs) { + let [xDest, yDest] = WM.WindowManager.prototype._getPositionForDirection(direction, fromWs, toWs); + + if (direction == Meta.MotionDirection.UP || + direction == Meta.MotionDirection.UP_LEFT || + direction == Meta.MotionDirection.UP_RIGHT) { + yDest -= Main.panel.height; + } else if (direction != Meta.MotionDirection.LEFT && + direction != Meta.MotionDirection.RIGHT) { + yDest += Main.panel.height; + } + + return [xDest, yDest]; +} + +function newDoSpringAnimation(animationDirection) { + this._grid.opacity = 255; + this._grid.animateSpring(animationDirection, Main.overview.getShowAppsButton()); +} + +function newAnimateIconPosition(icon, box, flags, nChangedIcons) { + if (this._needsIconAllocate) { + Utils.allocate(icon, box, flags); + return; + } + + return this._oldAnimateIconPosition(icon, box, flags, nChangedIcons);; +} + +function newUpdateHotCorners() { + // destroy old hot corners + this.hotCorners.forEach(function(corner) { + if (corner) + corner.destroy(); + }); + this.hotCorners = []; + + //global.settings is ubuntu specific setting to disable the hot corner (Tweak tool > Top Bar > Activities Overview Hot Corner) + //this._interfaceSettings is for the setting to disable the hot corner introduced in gnome-shell 3.34 + if ((global.settings.list_keys().indexOf('enable-hot-corners') >= 0 && !global.settings.get_boolean('enable-hot-corners')) || + (this._interfaceSettings && !this._interfaceSettings.get_boolean('enable-hot-corners'))) { + this.emit('hot-corners-changed'); + return; + } + + // build new hot corners + for (let i = 0; i < this.monitors.length; i++) { + let panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == i); + let panelPosition = panel ? panel.getPosition() : St.Side.BOTTOM; + let panelTopLeft = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT; + let monitor = this.monitors[i]; + let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; + let cornerY = monitor.y; + + let haveTopLeftCorner = true; + + // If the panel is on the bottom, unless this is explicitly forced, don't add a topleft + // hot corner unless it is actually a top left panel. Otherwise, it stops the mouse + // as you are dragging across. In the future, maybe we will automatically move the + // hotcorner to the bottom when the panel is positioned at the bottom + if (i != this.primaryIndex || (!panelTopLeft && !Me.settings.get_boolean('stockgs-force-hotcorner'))) { + // Check if we have a top left (right for RTL) corner. + // I.e. if there is no monitor directly above or to the left(right) + let besideX = this._rtl ? monitor.x + 1 : cornerX - 1; + let besideY = cornerY; + let aboveX = cornerX; + let aboveY = cornerY - 1; + + for (let j = 0; j < this.monitors.length; j++) { + if (i == j) + continue; + let otherMonitor = this.monitors[j]; + if (besideX >= otherMonitor.x && + besideX < otherMonitor.x + otherMonitor.width && + besideY >= otherMonitor.y && + besideY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + if (aboveX >= otherMonitor.x && + aboveX < otherMonitor.x + otherMonitor.width && + aboveY >= otherMonitor.y && + aboveY < otherMonitor.y + otherMonitor.height) { + haveTopLeftCorner = false; + break; + } + } + } + + if (haveTopLeftCorner) { + let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY); + + corner.setBarrierSize = size => corner.__proto__.setBarrierSize.call(corner, Math.min(size, 32)); + corner.setBarrierSize(panel ? panel.dtpSize : 32); + this.hotCorners.push(corner); + } else { + this.hotCorners.push(null); + } + } + + this.emit('hot-corners-changed'); +} + +function newUpdatePanelBarrier(panel) { + let barriers = { + _rightPanelBarrier: [(panel.isStandalone ? panel : this)], + _leftPanelBarrier: [panel] + }; + + Object.keys(barriers).forEach(k => { + let obj = barriers[k][0]; + + if (obj[k]) { + obj[k].destroy(); + obj[k] = null; + } + }); + + if (!this.primaryMonitor || !panel.panelBox.height) { + return; + } + + let barrierSize = Math.min(10, panel.panelBox.height); + let fixed1 = panel.monitor.y; + let fixed2 = panel.monitor.y + barrierSize; + + if (panel.checkIfVertical()) { + barriers._rightPanelBarrier.push(panel.monitor.y + panel.monitor.height, Meta.BarrierDirection.POSITIVE_Y); + barriers._leftPanelBarrier.push(panel.monitor.y, Meta.BarrierDirection.NEGATIVE_Y); + } else { + barriers._rightPanelBarrier.push(panel.monitor.x + panel.monitor.width, Meta.BarrierDirection.NEGATIVE_X); + barriers._leftPanelBarrier.push(panel.monitor.x, Meta.BarrierDirection.POSITIVE_X); + } + + switch (panel.getPosition()) { + //values are initialized as St.Side.TOP + case St.Side.BOTTOM: + fixed1 = panel.monitor.y + panel.monitor.height - barrierSize; + fixed2 = panel.monitor.y + panel.monitor.height; + break; + case St.Side.LEFT: + fixed1 = panel.monitor.x; + fixed2 = panel.monitor.x + barrierSize; + break; + case St.Side.RIGHT: + fixed1 = panel.monitor.x + panel.monitor.width; + fixed2 = panel.monitor.x + panel.monitor.width - barrierSize; + break; + } + + //remove left barrier if it overlaps one of the hotcorners + for (let k in this.hotCorners) { + let hc = this.hotCorners[k]; + + if (hc && hc._monitor == panel.monitor && + ((fixed1 == hc._x || fixed2 == hc._x) || fixed1 == hc._y || fixed2 == hc._y)) { + delete barriers._leftPanelBarrier; + break; + } + } + + Object.keys(barriers).forEach(k => { + let barrierOptions = { + display: global.display, + directions: barriers[k][2] + }; + + barrierOptions[panel.varCoord.c1] = barrierOptions[panel.varCoord.c2] = barriers[k][1]; + barrierOptions[panel.fixedCoord.c1] = fixed1; + barrierOptions[panel.fixedCoord.c2] = fixed2; + + barriers[k][0][k] = new Meta.Barrier(barrierOptions); + }); +} + +function _newLookingGlassResize() { + let primaryMonitorPanel = Utils.find(global.dashToPanel.panels, p => p.monitor == Main.layoutManager.primaryMonitor); + let topOffset = primaryMonitorPanel.getPosition() == St.Side.TOP ? primaryMonitorPanel.dtpSize + 8 : 32; + + this._oldResize(); + Utils.wrapActor(this); + Utils.wrapActor(this._objInspector); + + this._hiddenY = Main.layoutManager.primaryMonitor.y + topOffset - this.actor.height; + this._targetY = this._hiddenY + this.actor.height; + this.actor.y = this._hiddenY; + + this._objInspector.actor.set_position(this.actor.x + Math.floor(this.actor.width * 0.1), this._targetY + Math.floor(this.actor.height * 0.1)); +} + +function _newLookingGlassOpen() { + if (this._open) + return; + + this._resize(); + this._oldOpen(); +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js new file mode 100644 index 0000000..52458bb --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelPositions.js @@ -0,0 +1,61 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +var SHOW_APPS_BTN = 'showAppsButton'; +var ACTIVITIES_BTN = 'activitiesButton'; +var TASKBAR = 'taskbar'; +var DATE_MENU = 'dateMenu'; +var SYSTEM_MENU = 'systemMenu'; +var LEFT_BOX = 'leftBox'; +var CENTER_BOX = 'centerBox'; +var RIGHT_BOX = 'rightBox'; +var DESKTOP_BTN = 'desktopButton'; + +var STACKED_TL = 'stackedTL'; +var STACKED_BR = 'stackedBR'; +var CENTERED = 'centered'; +var CENTERED_MONITOR = 'centerMonitor'; + +var TOP = 'TOP'; +var BOTTOM = 'BOTTOM'; +var LEFT = 'LEFT'; +var RIGHT = 'RIGHT'; + +var START = 'START'; +var MIDDLE = 'MIDDLE'; +var END = 'END'; + +var defaults = [ + { element: SHOW_APPS_BTN, visible: true, position: STACKED_TL }, + { element: ACTIVITIES_BTN, visible: false, position: STACKED_TL }, + { element: LEFT_BOX, visible: true, position: STACKED_TL }, + { element: TASKBAR, visible: true, position: STACKED_TL }, + { element: CENTER_BOX, visible: true, position: STACKED_BR }, + { element: RIGHT_BOX, visible: true, position: STACKED_BR }, + { element: DATE_MENU, visible: true, position: STACKED_BR }, + { element: SYSTEM_MENU, visible: true, position: STACKED_BR }, + { element: DESKTOP_BTN, visible: true, position: STACKED_BR }, +]; + +var optionDialogFunctions = {}; + +optionDialogFunctions[SHOW_APPS_BTN] = '_showShowAppsButtonOptions'; +optionDialogFunctions[DESKTOP_BTN] = '_showDesktopButtonOptions'; + +function checkIfCentered(position) { + return position == CENTERED || position == CENTERED_MONITOR; +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js new file mode 100644 index 0000000..4feb3fd --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelSettings.js @@ -0,0 +1,112 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Pos = Me.imports.panelPositions; + +/** Return object representing a settings value that is stored as JSON. */ +function getSettingsJson(settings, setting) { + try { + return JSON.parse(settings.get_string(setting)); + } catch(e) { + log('Error parsing positions: ' + e.message); + } +} +/** Write value object as JSON to setting in settings. */ +function setSettingsJson(settings, setting, value) { + try { + const json = JSON.stringify(value); + settings.set_string(setting, json); + } catch(e) { + log('Error serializing setting: ' + e.message); + } +} + +/** Returns size of panel on a specific monitor, in pixels. */ +function getPanelSize(settings, monitorIndex) { + const sizes = getSettingsJson(settings, 'panel-sizes'); + // Pull in deprecated setting if panel-sizes does not have setting for monitor. + const fallbackSize = settings.get_int('panel-size'); + const theDefault = 48; + return sizes[monitorIndex] || fallbackSize || theDefault; +} + +function setPanelSize(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 128 && value >= 16)) { + log('Not setting invalid panel size: ' + value); + return; + } + let sizes = getSettingsJson(settings, 'panel-sizes'); + sizes[monitorIndex] = value; + setSettingsJson(settings, 'panel-sizes', sizes); +} + +/** + * Returns length of panel on a specific monitor, as a whole number percent, + * from settings. e.g. 100 + */ +function getPanelLength(settings, monitorIndex) { + const lengths = getSettingsJson(settings, 'panel-lengths'); + const theDefault = 100; + return lengths[monitorIndex] || theDefault; +} + +function setPanelLength(settings, monitorIndex, value) { + if (!(Number.isInteger(value) && value <= 100 && value >= 0)) { + log('Not setting invalid panel length: ' + value); + return; + } + let lengths = getSettingsJson(settings, 'panel-lengths'); + lengths[monitorIndex] = value; + setSettingsJson(settings, 'panel-lengths', lengths); +} + +/** Returns position of panel on a specific monitor. */ +function getPanelPosition(settings, monitorIndex) { + const positions = getSettingsJson(settings, 'panel-positions'); + const fallbackPosition = settings.get_string('panel-position'); + const theDefault = Pos.BOTTOM; + return positions[monitorIndex] || fallbackPosition || theDefault; +} + +function setPanelPosition(settings, monitorIndex, value) { + if (!(value === Pos.TOP || value === Pos.BOTTOM || value === Pos.LEFT + || value === Pos.RIGHT)) { + log('Not setting invalid panel position: ' + value); + return; + } + const positions = getSettingsJson(settings, 'panel-positions'); + positions[monitorIndex] = value; + setSettingsJson(settings, 'panel-positions', positions); +} + +/** Returns anchor location of panel on a specific monitor. */ +function getPanelAnchor(settings, monitorIndex) { + const anchors = getSettingsJson(settings, 'panel-anchors'); + const theDefault = Pos.MIDDLE; + return anchors[monitorIndex] || theDefault; +} + +function setPanelAnchor(settings, monitorIndex, value) { + if (!(value === Pos.START || value === Pos.MIDDLE || value === Pos.END)) { + log('Not setting invalid panel anchor: ' + value); + return; + } + const anchors = getSettingsJson(settings, 'panel-anchors'); + anchors[monitorIndex] = value; + setSettingsJson(settings, 'panel-anchors', anchors); +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js new file mode 100644 index 0000000..2697ace --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/panelStyle.js @@ -0,0 +1,326 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * Credits: + * Ideas for recursing child actors and assigning inline styles + * are based on code from the StatusAreaHorizontalSpacing extension + * https://bitbucket.org/mathematicalcoffee/status-area-horizontal-spacing-gnome-shell-extension + * mathematical.coffee@gmail.com + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const ExtensionUtils = imports.misc.extensionUtils; +const Lang = imports.lang; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const St = imports.gi.St; +const Shell = imports.gi.Shell; + +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +var dtpPanelStyle = Utils.defineClass({ + Name: 'DashToPanel.PanelStyle', + + _init: function() { + + }, + + enable : function(panel) { + this.panel = panel; + + this._applyStyles(); + + this._bindSettingsChanges(); + }, + + disable: function () { + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { + Me.settings.disconnect(this._dtpSettingsSignalIds[i]); + } + + this._removeStyles(); + }, + + _bindSettingsChanges: function() { + let configKeys = [ + "tray-size", + "leftbox-size", + "tray-padding", + "leftbox-padding", + "status-icon-padding", + ]; + + this._dtpSettingsSignalIds = []; + + for(let i in configKeys) { + this._dtpSettingsSignalIds.push(Me.settings.connect('changed::' + configKeys[i], Lang.bind(this, function () { + this._removeStyles(); + this._applyStyles(); + }))); + } + }, + + _applyStyles: function() { + this._rightBoxOperations = []; + + let trayPadding = Me.settings.get_int('tray-padding'); + let isVertical = this.panel.checkIfVertical(); + let paddingStyle = 'padding: ' + (isVertical ? '%dpx 0' : '0 %dpx'); + + if(trayPadding >= 0) { + let operation = {}; + let trayPaddingStyleLine; + + if (isVertical) { + trayPaddingStyleLine = paddingStyle.format(trayPadding); + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + } else { + trayPaddingStyleLine = '-natural-hpadding: %dpx'.format(trayPadding); + if (trayPadding < 6) { + trayPaddingStyleLine += '; -minimum-hpadding: %dpx'.format(trayPadding); + } + + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('panel-button')); + }; + } + + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayPaddingStyleLine, operationIdx); + this._refreshPanelButton(actor); + }); + this._rightBoxOperations.push(operation); + } + + let statusIconPadding = Me.settings.get_int('status-icon-padding'); + if(statusIconPadding >= 0) { + let statusIconPaddingStyleLine = paddingStyle.format(statusIconPadding) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.has_style_class_name && actor.has_style_class_name('system-status-icon')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, statusIconPaddingStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + } + + let trayContentSize = Me.settings.get_int('tray-size'); + if(trayContentSize > 0) { + let trayIconSizeStyleLine = 'icon-size: %dpx'.format(trayContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayIconSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + let trayContentSizeStyleLine = 'font-size: %dpx'.format(trayContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, trayContentSizeStyleLine, operationIdx); + }); + this._rightBoxOperations.push(operation); + + this._overrideStyle(this.panel._rightBox, trayContentSizeStyleLine, 0); + this._overrideStyle(this.panel._centerBox, trayContentSizeStyleLine, 0); + } + + // center box has been moved next to the right box and will be treated the same + this._centerBoxOperations = this._rightBoxOperations; + + this._leftBoxOperations = []; + + let leftboxPadding = Me.settings.get_int('leftbox-padding'); + if(leftboxPadding >= 0) { + let leftboxPaddingStyleLine = paddingStyle.format(leftboxPadding); + let operation = {}; + operation.compareFn = function (actor) { + let parent = actor.get_parent(); + return (parent && parent.has_style_class_name && parent.has_style_class_name('panel-button')); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxPaddingStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + } + + let leftboxContentSize = Me.settings.get_int('leftbox-size'); + if(leftboxContentSize > 0) { + let leftboxIconSizeStyleLine = 'icon-size: %dpx'.format(leftboxContentSize) + let operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Icon'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxIconSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + let leftboxContentSizeStyleLine = 'font-size: %dpx'.format(leftboxContentSize) + operation = {}; + operation.compareFn = function (actor) { + return (actor.constructor && actor.constructor.name == 'St_Label'); + }; + operation.applyFn = Lang.bind(this, function (actor, operationIdx) { + this._overrideStyle(actor, leftboxContentSizeStyleLine, operationIdx); + }); + this._leftBoxOperations.push(operation); + + this._overrideStyle(this.panel._leftBox, leftboxContentSizeStyleLine, 0); + } + + this._applyStylesRecursively(); + + /* connect signal */ + this._rightBoxActorAddedID = this.panel._rightBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._rightBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._rightBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._centerBoxActorAddedID = this.panel._centerBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._centerBoxOperations.length && !this._ignoreAddedChild) + this._recursiveApply(actor, this._centerBoxOperations); + + this._ignoreAddedChild = 0; + }) + ); + this._leftBoxActorAddedID = this.panel._leftBox.connect('actor-added', + Lang.bind(this, function (container, actor) { + if(this._leftBoxOperations.length) + this._recursiveApply(actor, this._leftBoxOperations); + }) + ); + }, + + _removeStyles: function() { + /* disconnect signal */ + if (this._rightBoxActorAddedID) + this.panel._rightBox.disconnect(this._rightBoxActorAddedID); + if (this._centerBoxActorAddedID) + this.panel._centerBox.disconnect(this._centerBoxActorAddedID); + if (this._leftBoxActorAddedID) + this.panel._leftBox.disconnect(this._leftBoxActorAddedID); + + this._restoreOriginalStyle(this.panel._rightBox); + this._restoreOriginalStyle(this.panel._centerBox); + this._restoreOriginalStyle(this.panel._leftBox); + + this._applyStylesRecursively(true); + }, + + _applyStylesRecursively: function(restore) { + /*recurse actors */ + if(this._rightBoxOperations.length) { + // add the system menu as we move it from the rightbox to the panel to position it independently + let children = this.panel._rightBox.get_children().concat([this.panel.statusArea.aggregateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._rightBoxOperations, restore); + } + + if(this._centerBoxOperations.length) { + // add the date menu as we move it from the centerbox to the panel to position it independently + let children = this.panel._centerBox.get_children().concat([this.panel.statusArea.dateMenu.container]); + for(let i in children) + this._recursiveApply(children[i], this._centerBoxOperations, restore); + } + + if(this._leftBoxOperations.length) { + let children = this.panel._leftBox.get_children(); + for(let i in children) + this._recursiveApply(children[i], this._leftBoxOperations, restore); + } + }, + + _recursiveApply: function(actor, operations, restore) { + for(let i in operations) { + let o = operations[i]; + if(o.compareFn(actor)) + if(restore) + o.restoreFn ? o.restoreFn(actor) : this._restoreOriginalStyle(actor); + else + o.applyFn(actor, i); + } + + if(actor.get_children) { + let children = actor.get_children(); + for(let i in children) { + this._recursiveApply(children[i], operations, restore); + } + } + }, + + _overrideStyle: function(actor, styleLine, operationIdx) { + if (actor._dtp_original_inline_style === undefined) { + actor._dtp_original_inline_style = actor.get_style(); + } + + if(actor._dtp_style_overrides === undefined) { + actor._dtp_style_overrides = {}; + } + + actor._dtp_style_overrides[operationIdx] = styleLine; + let newStyleLine = ''; + for(let i in actor._dtp_style_overrides) + newStyleLine += actor._dtp_style_overrides[i] + '; '; + actor.set_style(newStyleLine + (actor._dtp_original_inline_style || '')); + }, + + _restoreOriginalStyle: function(actor) { + if (actor._dtp_original_inline_style !== undefined) { + actor.set_style(actor._dtp_original_inline_style); + delete actor._dtp_original_inline_style; + delete actor._dtp_style_overrides; + } + + if (actor.has_style_class_name('panel-button')) { + this._refreshPanelButton(actor); + } + }, + + _refreshPanelButton: function(actor) { + if (actor.visible && imports.misc.config.PACKAGE_VERSION >= '3.34.0') { + //force gnome 3.34+ to refresh (having problem with the -natural-hpadding) + let parent = actor.get_parent(); + let children = parent.get_children(); + let actorIndex = 0; + + if (children.length > 1) { + actorIndex = children.indexOf(actor); + } + + this._ignoreAddedChild = [this.panel._centerBox, this.panel._rightBox].indexOf(parent) >= 0; + + parent.remove_child(actor); + parent.insert_child_at_index(actor, actorIndex); + } + } + +}); diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js new file mode 100644 index 0000000..3040787 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/prefs.js @@ -0,0 +1,2468 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg. + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const Lang = imports.lang; +const Mainloop = imports.mainloop; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Me.imports.convenience; +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; +const N_ = function(e) { return e }; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; + +const SCALE_UPDATE_TIMEOUT = 500; +const DEFAULT_PANEL_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; +const DEFAULT_FONT_SIZES = [ 96, 64, 48, 32, 24, 16, 0 ]; +const DEFAULT_MARGIN_SIZES = [ 32, 24, 16, 12, 8, 4, 0 ]; +const DEFAULT_PADDING_SIZES = [ 32, 24, 16, 12, 8, 4, 0, -1 ]; +// Minimum length could be 0, but a higher value may help prevent confusion about where the panel went. +const LENGTH_MARKS = [ 100, 90, 80, 70, 60, 50, 40, 30, 20, 10 ]; +const MAX_WINDOW_INDICATOR = 4; + +const SCHEMA_PATH = '/org/gnome/shell/extensions/dash-to-panel/'; +const GSET = 'gnome-shell-extension-tool'; + +/** + * This function was copied from the activities-config extension + * https://github.com/nls1729/acme-code/tree/master/activities-config + * by Norman L. Smith. + */ +function cssHexString(css) { + let rrggbb = '#'; + let start; + for (let loop = 0; loop < 3; loop++) { + let end = 0; + let xx = ''; + for (let loop = 0; loop < 2; loop++) { + while (true) { + let x = css.slice(end, end + 1); + if ((x == '(') || (x == ',') || (x == ')')) + break; + end++; + } + if (loop == 0) { + end++; + start = end; + } + } + xx = parseInt(css.slice(start, end)).toString(16); + if (xx.length == 1) + xx = '0' + xx; + rrggbb += xx; + css = css.slice(end); + } + return rrggbb; +} + +function setShortcut(settings, shortcutName) { + let shortcut_text = settings.get_string(shortcutName + '-text'); + let [key, mods] = Gtk.accelerator_parse(shortcut_text); + + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + settings.set_strv(shortcutName, [shortcut]); + } + else { + settings.set_strv(shortcutName, []); + } +} + +function checkHotkeyPrefix(settings) { + settings.delay(); + + let hotkeyPrefix = settings.get_string('hotkey-prefix-text'); + if (hotkeyPrefix == 'Super') + hotkeyPrefix = ''; + else if (hotkeyPrefix == 'SuperAlt') + hotkeyPrefix = ''; + let [, mods] = Gtk.accelerator_parse(hotkeyPrefix); + let [, shift_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + let [, ctrl_mods] = Gtk.accelerator_parse('' + hotkeyPrefix); + + let numHotkeys = 10; + for (let i = 1; i <= numHotkeys; i++) { + let number = i; + if (number == 10) + number = 0; + let key = Gdk.keyval_from_name(number.toString()); + let key_kp = Gdk.keyval_from_name('KP_' + number.toString()); + if (Gtk.accelerator_valid(key, mods)) { + let shortcut = Gtk.accelerator_name(key, mods); + let shortcut_kp = Gtk.accelerator_name(key_kp, mods); + + // Setup shortcut strings + settings.set_strv('app-hotkey-' + i, [shortcut]); + settings.set_strv('app-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, shift_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, shift_mods); + settings.set_strv('app-shift-hotkey-' + i, [shortcut]); + settings.set_strv('app-shift-hotkey-kp-' + i, [shortcut_kp]); + + // With + shortcut = Gtk.accelerator_name(key, ctrl_mods); + shortcut_kp = Gtk.accelerator_name(key_kp, ctrl_mods); + settings.set_strv('app-ctrl-hotkey-' + i, [shortcut]); + settings.set_strv('app-ctrl-hotkey-kp-' + i, [shortcut_kp]); + } + else { + // Reset default settings for the relevant keys if the + // accelerators are invalid + let keys = ['app-hotkey-' + i, 'app-shift-hotkey-' + i, 'app-ctrl-hotkey-' + i, // Regular numbers + 'app-hotkey-kp-' + i, 'app-shift-hotkey-kp-' + i, 'app-ctrl-hotkey-kp-' + i]; // Key-pad numbers + keys.forEach(function(val) { + settings.set_value(val, settings.get_default_value(val)); + }, this); + } + } + + settings.apply(); +} + +function mergeObjects(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +const Preferences = new Lang.Class({ + Name: 'DashToPanel.Preferences', + + _init: function() { + this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); + this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); + this._builder = new Gtk.Builder(); + this._builder.set_scope(new BuilderScope(this)); + this._builder.set_translation_domain(Me.metadata['gettext-domain']); + this._builder.add_from_file(Me.path + '/Settings.ui'); + this.notebook = this._builder.get_object('settings_notebook'); + + // Timeout to delay the update of the settings + this._panel_size_timeout = 0; + this._dot_height_timeout = 0; + this._tray_size_timeout = 0; + this._leftbox_size_timeout = 0; + this._appicon_margin_timeout = 0; + this._appicon_padding_timeout = 0; + this._opacity_timeout = 0; + this._tray_padding_timeout = 0; + this._statusicon_padding_timeout = 0; + this._leftbox_padding_timeout = 0; + this._addFormatValueCallbacks(); + this._bindSettings(); + }, + + /** + * Connect signals + */ + _connector: function(builder, object, signal, handler) { + object.connect(signal, Lang.bind(this, this._SignalHandler[handler])); + }, + + _updateVerticalRelatedOptions: function() { + let position = this._getPanelPosition(this._currentMonitorIndex); + let isVertical = position == Pos.LEFT || position == Pos.RIGHT; + let showDesktopWidthLabel = this._builder.get_object('show_showdesktop_width_label'); + + showDesktopWidthLabel.set_text(isVertical ? _('Show Desktop button height (px)') : _('Show Desktop button width (px)')); + + this._displayPanelPositionsForMonitor(this._currentMonitorIndex); + }, + + _maybeDisableTopPosition: function() { + let keepTopPanel = this._settings.get_boolean('stockgs-keep-top-panel'); + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let topAvailable = !keepTopPanel || (!monitorSync && this._currentMonitorIndex != this.monitors[0]); + let topRadio = this._builder.get_object('position_top_button'); + + topRadio.set_sensitive(topAvailable); + topRadio.set_tooltip_text(!topAvailable ? _('Unavailable when gnome-shell top panel is present') : ''); + }, + + _getPanelPosition: function(monitorIndex) { + return PanelSettings.getPanelPosition(this._settings, monitorIndex); + }, + + _setPanelPosition: function(position) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelPosition(this._settings, monitorIndex, position); + }); + this._setAnchorLabels(this._currentMonitorIndex); + }, + + _setPositionRadios: function(position) { + this._ignorePositionRadios = true; + + switch (position) { + case Pos.BOTTOM: + this._builder.get_object('position_bottom_button').set_active(true); + break; + case Pos.TOP: + this._builder.get_object('position_top_button').set_active(true); + break; + case Pos.LEFT: + this._builder.get_object('position_left_button').set_active(true); + break; + case Pos.RIGHT: + this._builder.get_object('position_right_button').set_active(true); + break; + } + + this._ignorePositionRadios = false; + }, + + /** + * Set panel anchor combo labels according to whether the monitor's panel is vertical + * or horizontal, or if all monitors' panels are being configured and they are a mix + * of vertical and horizontal. + */ + _setAnchorLabels: function(currentMonitorIndex) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [currentMonitorIndex]; + const allVertical = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.LEFT || position === Pos.RIGHT + }); + const allHorizontal = monitorsToSetFor.every(i => { + const position = PanelSettings.getPanelPosition(this._settings, i); + return position === Pos.TOP || position === Pos.BOTTOM; + }); + + const anchor_combo = this._builder.get_object('panel_anchor_combo'); + anchor_combo.remove_all(); + + if (allHorizontal) { + anchor_combo.append(Pos.START, _('Left')); + anchor_combo.append(Pos.MIDDLE, _('Center')); + anchor_combo.append(Pos.END, _('Right')); + } else if (allVertical) { + anchor_combo.append(Pos.START, _('Top')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('Bottom')); + } else { + // Setting for a mix of horizontal and vertical panels on different monitors. + anchor_combo.append(Pos.START, _('Start')); + anchor_combo.append(Pos.MIDDLE, _('Middle')); + anchor_combo.append(Pos.END, _('End')); + } + + // Set combo box after re-populating its options. But only if it's for a single-panel + // configuration, or a multi-panel configuration where they all have the same anchor + // setting. So don't set the combo box if there is a multi-panel configuration with + // different anchor settings. + const someAnchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + if (monitorsToSetFor.every(i => + PanelSettings.getPanelAnchor(this._settings, i) === someAnchor)) { + const panel_anchor = PanelSettings.getPanelAnchor(this._settings, currentMonitorIndex); + this._builder.get_object('panel_anchor_combo').set_active_id(panel_anchor); + } + }, + + /** + * When a monitor is selected, update the widgets for panel position, size, anchoring, + * and contents so they accurately show the settings for the panel on that monitor. + */ + _updateWidgetSettingsForMonitor: function(monitorIndex) { + // Update display of panel screen position setting + this._maybeDisableTopPosition(); + const panelPosition = this._getPanelPosition(monitorIndex); + this._setPositionRadios(panelPosition); + + // Update display of thickness, length, and anchor settings + const panel_size_scale = this._builder.get_object('panel_size_scale'); + const size = PanelSettings.getPanelSize(this._settings, monitorIndex); + panel_size_scale.set_value(size); + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + const length = PanelSettings.getPanelLength(this._settings, monitorIndex); + panel_length_scale.set_value(length); + this._setAnchorWidgetSensitivity(length); + + this._setAnchorLabels(monitorIndex); + + // Update display of panel content settings + this._displayPanelPositionsForMonitor(monitorIndex); + }, + + /** + * Anchor is only relevant if panel length is less than 100%. Enable or disable + * anchor widget sensitivity accordingly. + */ + _setAnchorWidgetSensitivity: function(panelLength) { + const isPartialLength = panelLength < 100; + this._builder.get_object('panel_anchor_label').set_sensitive(isPartialLength); + this._builder.get_object('panel_anchor_combo').set_sensitive(isPartialLength); + }, + + _displayPanelPositionsForMonitor: function(monitorIndex) { + let taskbarListBox = this._builder.get_object('taskbar_display_listbox'); + + while(taskbarListBox.get_first_child()) + { + taskbarListBox.remove(taskbarListBox.get_first_child()); + } + + let labels = {}; + let panelPosition = this._getPanelPosition(monitorIndex); + let isVertical = panelPosition == Pos.LEFT || panelPosition == Pos.RIGHT; + let panelElementPositionsSettings = PanelSettings.getSettingsJson(this._settings, 'panel-element-positions'); + let panelElementPositions = panelElementPositionsSettings[monitorIndex] || Pos.defaults; + let updateElementsSettings = () => { + let newPanelElementPositions = []; + let monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + let monitors = monitorSync ? this.monitors : [monitorIndex]; + + let child = taskbarListBox.get_first_child(); + while (child != null) + { + newPanelElementPositions.push({ + element: child.id, + visible: child.visibleToggleBtn.get_active(), + position: child.positionCombo.get_active_id() + }); + child = child.get_next_sibling(); + } + + monitors.forEach(m => panelElementPositionsSettings[m] = newPanelElementPositions); + this._settings.set_string('panel-element-positions', JSON.stringify(panelElementPositionsSettings)); + }; + + + labels[Pos.SHOW_APPS_BTN] = _('Show Applications button'); + labels[Pos.ACTIVITIES_BTN] = _('Activities button'); + labels[Pos.TASKBAR] = _('Taskbar'); + labels[Pos.DATE_MENU] = _('Date menu'); + labels[Pos.SYSTEM_MENU] = _('System menu'); + labels[Pos.LEFT_BOX] = _('Left box'); + labels[Pos.CENTER_BOX] = _('Center box'); + labels[Pos.RIGHT_BOX] = _('Right box'); + labels[Pos.DESKTOP_BTN] = _('Desktop button'); + + panelElementPositions.forEach(el => { + let row = new Gtk.ListBoxRow(); + let grid = new Gtk.Grid({ margin_start: 12, margin_end: 12, column_spacing: 8 }); + let upDownGrid = new Gtk.Grid({ column_spacing: 2 }); + let upBtn = new Gtk.Button({ tooltip_text: _('Move up') }); + let upImg = new Gtk.Image({ icon_name: 'go-up-symbolic', pixel_size: 12 }); + let downBtn = new Gtk.Button({ tooltip_text: _('Move down') }); + let downImg = new Gtk.Image({ icon_name: 'go-down-symbolic', pixel_size: 12 }); + let visibleToggleBtn = new Gtk.ToggleButton({ label: _('Visible'), active: el.visible }); + let positionCombo = new Gtk.ComboBoxText({ tooltip_text: _('Select element position') }); + let upDownClickHandler = limit => { + let index = row.get_index(); + + if (index != limit) { + taskbarListBox.remove(row); + taskbarListBox.insert(row, index + (!limit ? -1 : 1)); + updateElementsSettings(); + } + }; + + positionCombo.append(Pos.STACKED_TL, isVertical ? _('Stacked to top') : _('Stacked to left')); + positionCombo.append(Pos.STACKED_BR, isVertical ? _('Stacked to bottom') :_('Stacked to right')); + positionCombo.append(Pos.CENTERED, _('Centered')); + positionCombo.append(Pos.CENTERED_MONITOR, _('Monitor Center')); + positionCombo.set_active_id(el.position); + + upBtn.connect('clicked', () => upDownClickHandler(0)); + downBtn.connect('clicked', () => upDownClickHandler(panelElementPositions.length - 1)); + visibleToggleBtn.connect('toggled', () => updateElementsSettings()); + positionCombo.connect('changed', () => updateElementsSettings()); + + upBtn.set_child(upImg); + downBtn.set_child(downImg); + + upDownGrid.attach(upBtn, 0, 0, 1, 1); + upDownGrid.attach(downBtn, 1, 0, 1, 1); + + grid.attach(upDownGrid, 0, 0, 1, 1); + grid.attach(new Gtk.Label({ label: labels[el.element], xalign: 0, hexpand: true }), 1, 0, 1, 1); + + if (Pos.optionDialogFunctions[el.element]) { + let cogImg = new Gtk.Image({ icon_name: 'emblem-system-symbolic' }); + let optionsBtn = new Gtk.Button({ tooltip_text: _('More options') }); + + optionsBtn.get_style_context().add_class('circular'); + optionsBtn.set_child(cogImg); + grid.attach(optionsBtn, 2, 0, 1, 1); + + optionsBtn.connect('clicked', () => this[Pos.optionDialogFunctions[el.element]]()); + } + + grid.attach(visibleToggleBtn, 3, 0, 1, 1); + grid.attach(positionCombo, 4, 0, 1, 1); + + row.id = el.element; + row.visibleToggleBtn = visibleToggleBtn; + row.positionCombo = positionCombo; + + row.set_child(grid); + taskbarListBox.insert(row, -1); + }); + }, + + _showShowAppsButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Applications options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('show_applications_options'); + dialog.get_content_area().append(box); + + let fileChooserButton = this._builder.get_object('show_applications_icon_file_filebutton'); + let fileChooser = new Gtk.FileChooserNative({ title: _('Open icon'), transient_for: dialog }); + let fileImage = this._builder.get_object('show_applications_current_icon_image'); + let fileFilter = new Gtk.FileFilter(); + fileFilter.add_pixbuf_formats(); + fileChooser.filter = fileFilter; + + let handleIconChange = function(newIconPath) { + if (newIconPath && GLib.file_test(newIconPath, GLib.FileTest.EXISTS)) { + let file = Gio.File.new_for_path(newIconPath); + let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(file.read(null), 32, 32, true, null); + + fileImage.set_from_pixbuf(pixbuf); + fileChooser.set_file(file); + fileChooserButton.set_label(newIconPath); + } else { + newIconPath = ''; + fileImage.set_from_icon_name('view-app-grid-symbolic'); + let picturesFolder = Gio.File.new_for_path(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)); + fileChooser.set_file(picturesFolder); + fileChooserButton.set_label("(None)"); + } + + this._settings.set_string('show-apps-icon-file', newIconPath || ''); + }; + + fileChooserButton.connect('clicked', Lang.bind(this, function() { + fileChooser.show(); + })); + + fileChooser.connect('response', widget => handleIconChange.call(this, widget.get_file().get_path())); + handleIconChange.call(this, this._settings.get_string('show-apps-icon-file')); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-apps-icon-side-padding', this._settings.get_default_value('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._settings.set_value('show-apps-override-escape', this._settings.get_default_value('show-apps-override-escape')); + handleIconChange.call(this, null); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + fileChooser.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _showDesktopButtonOptions: function() { + let dialog = new Gtk.Dialog({ title: _('Show Desktop options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_show_showdesktop_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('showdesktop-button-width', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-delay', widget.get_value()); + })); + + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-showdesktop-time', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('showdesktop-button-width', this._settings.get_default_value('showdesktop-button-width')); + this._builder.get_object('show_showdesktop_width_spinbutton').set_value(this._settings.get_int('showdesktop-button-width')); + + this._settings.set_value('show-showdesktop-hover', this._settings.get_default_value('show-showdesktop-hover')); + + this._settings.set_value('show-showdesktop-delay', this._settings.get_default_value('show-showdesktop-delay')); + this._builder.get_object('show_showdesktop_delay_spinbutton').set_value(this._settings.get_int('show-showdesktop-delay')); + + this._settings.set_value('show-showdesktop-time', this._settings.get_default_value('show-showdesktop-time')); + this._builder.get_object('show_showdesktop_time_spinbutton').set_value(this._settings.get_int('show-showdesktop-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + }, + + _addFormatValueCallbacks: function() { + // position + this._builder.get_object('panel_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // style + this._builder.get_object('appicon_margin_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('appicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box1 + this._builder.get_object('tray_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_size_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // fine-tune box2 + this._builder.get_object('tray_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('statusicon_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + this._builder.get_object('leftbox_padding_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return value + ' px'; + })); + + // animate hovering app icons dialog + this._builder.get_object('animate_appicon_hover_options_duration_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d ms").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_rotation_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d °").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_travel_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_zoom_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%d %%").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_convexity_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return _("%.1f").format(value); + })); + + this._builder.get_object('animate_appicon_hover_options_extent_scale') + .set_format_value_func(Lang.bind(this, function(scale, value) { + return Gettext.ngettext("%d icon", "%d icons", value).format(value); + })); + }, + + _bindSettings: function() { + // size options + let panel_size_scale = this._builder.get_object('panel_size_scale'); + panel_size_scale.set_range(DEFAULT_PANEL_SIZES[DEFAULT_PANEL_SIZES.length - 1], DEFAULT_PANEL_SIZES[0]); + DEFAULT_PANEL_SIZES.slice(1, -1).forEach(function(val) { + panel_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Correct for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + panel_size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + panel_size_scale.set_flippable(false); + panel_size_scale.set_inverted(true); + } + + // Dots Position option + let dotPosition = this._settings.get_string('dot-position'); + + switch (dotPosition) { + case 'BOTTOM': + this._builder.get_object('dots_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('dots_top_button').set_active(true); + break; + case 'LEFT': + this._builder.get_object('dots_left_button').set_active(true); + break; + case 'RIGHT': + this._builder.get_object('dots_right_button').set_active(true); + break; + } + + this._builder.get_object('dot_style_focused_combo').set_active_id(this._settings.get_string('dot-style-focused')); + this._builder.get_object('dot_style_focused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-focused', widget.get_active_id()); + })); + + this._builder.get_object('dot_style_unfocused_combo').set_active_id(this._settings.get_string('dot-style-unfocused')); + this._builder.get_object('dot_style_unfocused_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('dot-style-unfocused', widget.get_active_id()); + })); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let idx = i; + this._builder.get_object('dot_color_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-' + idx, hexString); + })); + + this._builder.get_object('dot_color_unfocused_' + idx + '_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('dot-color-unfocused-' + idx, hexString); + })); + } + + this._builder.get_object('dot_color_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_value('dot-color-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('dot_color_unfocused_apply_all_button').connect('clicked', Lang.bind(this, function() { + for (let i = 2; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_value('dot-color-unfocused-1')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + })); + + this._builder.get_object('focus_highlight_color_colorbutton').connect('color-set', Lang.bind(this, function(button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('focus-highlight-color', hexString); + })); + + this._builder.get_object('dot_style_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Running Indicator Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dots_options'); + dialog.get_content_area().append(box); + + this._settings.bind('dot-color-dominant', + this._builder.get_object('dot_color_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // when either becomes active, turn the other off + this._builder.get_object('dot_color_dominant_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-override', false); + })); + this._builder.get_object('dot_color_override_switch').connect('state-set', Lang.bind (this, function(widget) { + if (widget.get_active()) this._settings.set_boolean('dot-color-dominant', false); + })); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('dot_color_unfocused_different_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('grid_dot_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-override', + this._builder.get_object('dot_color_unfocused_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('dot-color-unfocused-different', + this._builder.get_object('grid_dot_color_unfocused'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.bind('focus-highlight', + this._builder.get_object('focus_highlight_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight', + this._builder.get_object('grid_focus_highlight_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_dominant_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_label'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('focus-highlight-dominant', + this._builder.get_object('focus_highlight_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('focus-highlight-opacity', widget.get_value()); + })); + + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + this._builder.get_object('dot_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('dot-size', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('dot-color-dominant', this._settings.get_default_value('dot-color-dominant')); + this._settings.set_value('dot-color-override', this._settings.get_default_value('dot-color-override')); + this._settings.set_value('dot-color-unfocused-different', this._settings.get_default_value('dot-color-unfocused-different')); + + this._settings.set_value('focus-highlight-color', this._settings.get_default_value('focus-highlight-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('focus-highlight-color')); + this._builder.get_object('focus_highlight_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('focus-highlight-opacity', this._settings.get_default_value('focus-highlight-opacity')); + this._builder.get_object('focus_highlight_opacity_spinbutton').set_value(this._settings.get_int('focus-highlight-opacity')); + + for (let i = 1; i <= MAX_WINDOW_INDICATOR; i++) { + this._settings.set_value('dot-color-' + i, this._settings.get_default_value('dot-color-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-' + i)); + this._builder.get_object('dot_color_' + i + '_colorbutton').set_rgba(rgba); + + this._settings.set_value('dot-color-unfocused-' + i, this._settings.get_default_value('dot-color-unfocused-' + i)); + rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('dot-color-unfocused-' + i)); + this._builder.get_object('dot_color_unfocused_' + i + '_colorbutton').set_rgba(rgba); + } + + this._settings.set_value('dot-size', this._settings.get_default_value('dot-size')); + this._builder.get_object('dot_size_spinbutton').set_value(this._settings.get_int('dot-size')); + + this._settings.set_value('focus-highlight', this._settings.get_default_value('focus-highlight')); + this._settings.set_value('focus-highlight-dominant', this._settings.get_default_value('focus-highlight-dominant')); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + //multi-monitor + this.monitors = this._settings.get_value('available-monitors').deep_unpack(); + + let dtpPrimaryMonitorIndex = this.monitors.indexOf(this._settings.get_int('primary-monitor')); + + if (dtpPrimaryMonitorIndex < 0) { + dtpPrimaryMonitorIndex = 0; + } + + this._currentMonitorIndex = this.monitors[dtpPrimaryMonitorIndex]; + + this._settings.connect('changed::panel-positions', () => this._updateVerticalRelatedOptions()); + this._updateVerticalRelatedOptions(); + + for (let i = 0; i < this.monitors.length; ++i) { + //the primary index is the first one in the "available-monitors" setting + let label = !i ? _('Primary monitor') : _('Monitor ') + (i + 1); + + this._builder.get_object('multimon_primary_combo').append_text(label); + this._builder.get_object('taskbar_position_monitor_combo').append_text(label); + } + + this._builder.get_object('multimon_primary_combo').set_active(dtpPrimaryMonitorIndex); + this._builder.get_object('taskbar_position_monitor_combo').set_active(dtpPrimaryMonitorIndex); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_sync_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('panel-element-positions-monitors-sync', + this._builder.get_object('taskbar_position_monitor_combo'), + 'sensitive', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.connect('changed::panel-element-positions-monitors-sync', () => { + this._maybeDisableTopPosition(); + // The anchor combo box may has different labels for single- or all-monitor configuration. + this._setAnchorLabels(this._currentMonitorIndex); + }); + + this._builder.get_object('multimon_primary_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('primary-monitor', this.monitors[widget.get_active()]); + })); + + this._builder.get_object('taskbar_position_monitor_combo').connect('changed', Lang.bind (this, function(widget) { + this._currentMonitorIndex = this.monitors[widget.get_active()]; + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + })); + + this._settings.bind('multi-monitors', + this._builder.get_object('multimon_multi_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + if (this.monitors.length === 1) { + this._builder.get_object('multimon_multi_switch').set_sensitive(false); + } + + const panel_length_scale = this._builder.get_object('panel_length_scale'); + panel_length_scale.connect('value-changed', Lang.bind (this, function(widget) { + const value = widget.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelLength(this._settings, monitorIndex, value); + }); + + this._setAnchorWidgetSensitivity(value); + })); + + this._builder.get_object('panel_anchor_combo').connect('changed', Lang.bind (this, function(widget) { + const value = widget.get_active_id(); + // Value can be null while anchor labels are being swapped out + if (value !== null) { + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelAnchor(this._settings, monitorIndex, value); + }); + } + })); + + this._updateWidgetSettingsForMonitor(this._currentMonitorIndex); + + //dynamic opacity + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-bg', + this._builder.get_object('trans_bg_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('trans-bg-color')); + this._builder.get_object('trans_bg_color_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_bg_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-bg-color', hexString); + })); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_override_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-opacity', + this._builder.get_object('trans_opacity_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('trans_opacity_override_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('trans_dyn_switch').set_active(false); + }); + + this._builder.get_object('trans_opacity_spinbutton').set_value(this._settings.get_double('trans-panel-opacity') * 100); + this._builder.get_object('trans_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-panel-opacity', widget.get_value() * 0.01); + })); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-dynamic-opacity', + this._builder.get_object('trans_dyn_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-dynamic-behavior', + this._builder.get_object('trans_options_window_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('trans-use-custom-gradient', + this._builder.get_object('trans_gradient_box'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('trans-gradient-top-color')); + this._builder.get_object('trans_gradient_color1_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color1_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-top-color', hexString); + })); + + this._builder.get_object('trans_gradient_color1_spinbutton').set_value(this._settings.get_double('trans-gradient-top-opacity') * 100); + this._builder.get_object('trans_gradient_color1_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-top-opacity', widget.get_value() * 0.01); + })); + + rgba.parse(this._settings.get_string('trans-gradient-bottom-color')); + this._builder.get_object('trans_gradient_color2_colorbutton').set_rgba(rgba); + + this._builder.get_object('trans_gradient_color2_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('trans-gradient-bottom-color', hexString); + })); + + this._builder.get_object('trans_gradient_color2_spinbutton').set_value(this._settings.get_double('trans-gradient-bottom-opacity') * 100); + this._builder.get_object('trans_gradient_color2_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-gradient-bottom-opacity', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-distance', widget.get_value()); + })); + + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + this._builder.get_object('trans_options_min_opacity_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_double('trans-dynamic-anim-target', widget.get_value() * 0.01); + })); + + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('trans-dynamic-anim-time', widget.get_value()); + })); + + this._builder.get_object('trans_dyn_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Dynamic opacity options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_dynamic_opacity_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('trans-dynamic-behavior', this._settings.get_default_value('trans-dynamic-behavior')); + + this._settings.set_value('trans-dynamic-distance', this._settings.get_default_value('trans-dynamic-distance')); + this._builder.get_object('trans_options_distance_spinbutton').set_value(this._settings.get_int('trans-dynamic-distance')); + + this._settings.set_value('trans-dynamic-anim-target', this._settings.get_default_value('trans-dynamic-anim-target')); + this._builder.get_object('trans_options_min_opacity_spinbutton').set_value(this._settings.get_double('trans-dynamic-anim-target') * 100); + + this._settings.set_value('trans-dynamic-anim-time', this._settings.get_default_value('trans-dynamic-anim-time')); + this._builder.get_object('trans_options_anim_time_spinbutton').set_value(this._settings.get_int('trans-dynamic-anim-time')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('desktop-line-use-custom-color', + this._builder.get_object('override_show_desktop_line_color_colorbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + rgba.parse(this._settings.get_string('desktop-line-custom-color')); + this._builder.get_object('override_show_desktop_line_color_colorbutton').set_rgba(rgba); + this._builder.get_object('override_show_desktop_line_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + this._settings.set_string('desktop-line-custom-color', css); + })); + + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide', + this._builder.get_object('intellihide_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_window_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-hide-from-windows', + this._builder.get_object('intellihide_behaviour_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-behaviour', + this._builder.get_object('intellihide_behaviour_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-use-pressure', + this._builder.get_object('intellihide_use_pressure_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-show-in-fullscreen', + this._builder.get_object('intellihide_show_in_fullscreen_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('intellihide-only-secondary', + this._builder.get_object('intellihide_only_secondary_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('multi-monitors', + this._builder.get_object('grid_intellihide_only_secondary'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('multimon_multi_switch').connect('notify::active', (widget) => { + if (!widget.get_active()) + this._builder.get_object('intellihide_only_secondary_switch').set_active(false); + }); + + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-threshold', widget.get_value()); + })); + + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').connect('value-changed', Lang.bind(this, function (widget) { + this._settings.set_int('intellihide-pressure-time', widget.get_value()); + })); + + this._settings.bind('intellihide-key-toggle-text', + this._builder.get_object('intellihide_toggle_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::intellihide-key-toggle-text', () => setShortcut(this._settings, 'intellihide-key-toggle')); + + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-animation-time', widget.get_value()); + })); + + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-close-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('intellihide-enable-start-delay', widget.get_value()); + })); + + this._builder.get_object('intellihide_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Intellihide options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_intellihide_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('intellihide-hide-from-windows', this._settings.get_default_value('intellihide-hide-from-windows')); + this._settings.set_value('intellihide-behaviour', this._settings.get_default_value('intellihide-behaviour')); + this._settings.set_value('intellihide-use-pressure', this._settings.get_default_value('intellihide-use-pressure')); + this._settings.set_value('intellihide-show-in-fullscreen', this._settings.get_default_value('intellihide-show-in-fullscreen')); + this._settings.set_value('intellihide-only-secondary', this._settings.get_default_value('intellihide-only-secondary')); + + this._settings.set_value('intellihide-pressure-threshold', this._settings.get_default_value('intellihide-pressure-threshold')); + this._builder.get_object('intellihide_pressure_threshold_spinbutton').set_value(this._settings.get_int('intellihide-pressure-threshold')); + + this._settings.set_value('intellihide-pressure-time', this._settings.get_default_value('intellihide-pressure-time')); + this._builder.get_object('intellihide_pressure_time_spinbutton').set_value(this._settings.get_int('intellihide-pressure-time')); + + this._settings.set_value('intellihide-key-toggle-text', this._settings.get_default_value('intellihide-key-toggle-text')); + + this._settings.set_value('intellihide-animation-time', this._settings.get_default_value('intellihide-animation-time')); + this._builder.get_object('intellihide_animation_time_spinbutton').set_value(this._settings.get_int('intellihide-animation-time')); + + this._settings.set_value('intellihide-close-delay', this._settings.get_default_value('intellihide-close-delay')); + this._builder.get_object('intellihide_close_delay_spinbutton').set_value(this._settings.get_int('intellihide-close-delay')); + + this._settings.set_value('intellihide-enable-start-delay', this._settings.get_default_value('intellihide-enable-start-delay')); + this._builder.get_object('intellihide_enable_start_delay_spinbutton').set_value(this._settings.get_int('intellihide-enable-start-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(1, 1); + + })); + + // Behavior panel + + this._builder.get_object('show_applications_side_padding_spinbutton').set_value(this._settings.get_int('show-apps-icon-side-padding')); + this._builder.get_object('show_applications_side_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-apps-icon-side-padding', widget.get_value()); + })); + + this._settings.bind('show-apps-override-escape', + this._builder.get_object('show_applications_esc_key_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('show_showdesktop_hide_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-showdesktop-hover', + this._builder.get_object('grid_show_showdesktop_hide_options'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-appmenu', + this._builder.get_object('show_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-window-previews', + this._builder.get_object('show_window_previews_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-tooltip', + this._builder.get_object('show_tooltip_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('show_favorite_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites-all-monitors', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-favorites', + this._builder.get_object('multimon_multi_show_favorites_switch'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('show-running-apps', + this._builder.get_object('show_runnning_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._setPreviewTitlePosition(); + + this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('window-preview-title-font-color', hexString); + })); + + this._builder.get_object('show_window_previews_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Window preview options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let scrolledWindow = this._builder.get_object('box_window_preview_options'); + + dialog.get_content_area().append(scrolledWindow); + + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('show-window-previews-timeout', widget.get_value()); + })); + + this._settings.bind('preview-middle-click-close', + this._builder.get_object('preview_middle_click_close_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-x', + this._builder.get_object('preview_aspect_ratio_x_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-y', + this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-use-custom-icon-size', + this._builder.get_object('preview_custom_icon_size_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('preview-custom-opacity', widget.get_value()); + })); + + this._settings.bind('peek-mode', + this._builder.get_object('peek_mode_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_enter_peek_mode_timeout'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_peek_mode_opacity'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-show-title', + this._builder.get_object('preview_show_title_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_custom_icon_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_weight'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_font_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('enter-peek-mode-timeout', widget.get_value()); + })); + + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('leave-timeout', widget.get_value()); + })); + + this._settings.bind('window-preview-hide-immediate-click', + this._builder.get_object('preview_immediate_click_button'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-animation-time', widget.get_value()); + })); + + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('peek-mode-opacity', widget.get_value()); + })); + + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-size', widget.get_value()); + })); + + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + this._builder.get_object('preview_aspect_ratio_x_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-x', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + this._builder.get_object('preview_aspect_ratio_y_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-y', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-padding', widget.get_value()); + })); + + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-title-font-size', widget.get_value()); + })); + + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-custom-icon-size', widget.get_value()); + })); + + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('window-preview-title-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('show-window-previews-timeout', this._settings.get_default_value('show-window-previews-timeout')); + this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + + this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + + this._settings.set_value('window-preview-hide-immediate-click', this._settings.get_default_value('window-preview-hide-immediate-click')); + + this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + + this._settings.set_value('preview-use-custom-opacity', this._settings.get_default_value('preview-use-custom-opacity')); + + this._settings.set_value('window-preview-use-custom-icon-size', this._settings.get_default_value('window-preview-use-custom-icon-size')); + + this._settings.set_value('preview-custom-opacity', this._settings.get_default_value('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + + this._settings.set_value('window-preview-title-position', this._settings.get_default_value('window-preview-title-position')); + this._setPreviewTitlePosition(); + + this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); + this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); + this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout')); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity')); + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + + this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + + this._settings.set_value('window-preview-fixed-x', this._settings.get_default_value('window-preview-fixed-x')); + this._settings.set_value('window-preview-fixed-y', this._settings.get_default_value('window-preview-fixed-y')); + + this._settings.set_value('window-preview-aspect-ratio-x', this._settings.get_default_value('window-preview-aspect-ratio-x')); + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + + this._settings.set_value('window-preview-aspect-ratio-y', this._settings.get_default_value('window-preview-aspect-ratio-y')); + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + + this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding')); + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); + + this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); + + this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + + this._settings.set_value('window-preview-custom-icon-size', this._settings.get_default_value('window-preview-custom-icon-size')); + this._builder.get_object('preview_custom_icon_size_spinbutton').set_value(this._settings.get_int('window-preview-custom-icon-size')); + + this._settings.set_value('window-preview-title-font-weight', this._settings.get_default_value('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + + this._settings.set_value('window-preview-title-font-color', this._settings.get_default_value('window-preview-title-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(scrolledWindow); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('isolate-workspaces', + this._builder.get_object('isolate_workspaces_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('isolate-monitors', + this._builder.get_object('multimon_multi_isolate_monitor_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overview-click-to-exit', + this._builder.get_object('clicktoexit_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('hide-overview-on-startup', + this._builder.get_object('hide_overview_on_startup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps', + this._builder.get_object('group_apps_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._settings.bind('group-apps', + this._builder.get_object('show_group_apps_options_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this._builder.get_object('group_apps_label_font_color_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color', hexString); + })); + + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').connect('color-set', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('group-apps-label-font-color-minimized', hexString); + })); + + this._settings.bind('group-apps-use-fixed-width', + this._builder.get_object('group_apps_use_fixed_width_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-underline-unfocused', + this._builder.get_object('group_apps_underline_unfocused_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('group-apps-use-launchers', + this._builder.get_object('group_apps_use_launchers_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('show_group_apps_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Ungrouped application options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_group_apps_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-font-size', widget.get_value()); + })); + + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('group-apps-label-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(rgba); + }).apply(this); + + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('group-apps-label-max-width', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('group-apps-label-font-size', this._settings.get_default_value('group-apps-label-font-size')); + this._builder.get_object('group_apps_label_font_size_spinbutton').set_value(this._settings.get_int('group-apps-label-font-size')); + + this._settings.set_value('group-apps-label-font-weight', this._settings.get_default_value('group-apps-label-font-weight')); + this._builder.get_object('group_apps_label_font_weight_combo').set_active_id(this._settings.get_string('group-apps-label-font-weight')); + + this._settings.set_value('group-apps-label-font-color', this._settings.get_default_value('group-apps-label-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('group-apps-label-font-color')); + this._builder.get_object('group_apps_label_font_color_colorbutton').set_rgba(rgba); + + this._settings.set_value('group-apps-label-font-color-minimized', this._settings.get_default_value('group-apps-label-font-color-minimized')); + let minimizedFontColor = new Gdk.RGBA(); + minimizedFontColor.parse(this._settings.get_string('group-apps-label-font-color-minimized')); + this._builder.get_object('group_apps_label_font_color_minimized_colorbutton').set_rgba(minimizedFontColor); + + this._settings.set_value('group-apps-label-max-width', this._settings.get_default_value('group-apps-label-max-width')); + this._builder.get_object('group_apps_label_max_width_spinbutton').set_value(this._settings.get_int('group-apps-label-max-width')); + + this._settings.set_value('group-apps-use-fixed-width', this._settings.get_default_value('group-apps-use-fixed-width')); + this._settings.set_value('group-apps-underline-unfocused', this._settings.get_default_value('group-apps-underline-unfocused')); + this._settings.set_value('group-apps-use-launchers', this._settings.get_default_value('group-apps-use-launchers')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + this._builder.get_object('click_action_combo').set_active_id(this._settings.get_string('click-action')); + this._builder.get_object('click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('click-action', widget.get_active_id()); + })); + + this._builder.get_object('shift_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-click-action', widget.get_active_id()); + })); + + this._builder.get_object('middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('middle-click-action', widget.get_active_id()); + })); + this._builder.get_object('shift_middle_click_action_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shift-middle-click-action', widget.get_active_id()); + })); + + // Create dialog for middle-click options + this._builder.get_object('middle_click_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Customize middle-click behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_middle_click_options'); + dialog.get_content_area().append(box); + + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + + this._settings.bind('shift-click-action', + this._builder.get_object('shift_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('middle-click-action', + this._builder.get_object('middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('shift-middle-click-action', + this._builder.get_object('shift_middle_click_action_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + this._builder.get_object('shift_click_action_combo').set_active_id(this._settings.get_string('shift-click-action')); + this._builder.get_object('middle_click_action_combo').set_active_id(this._settings.get_string('middle-click-action')); + this._builder.get_object('shift_middle_click_action_combo').set_active_id(this._settings.get_string('shift-middle-click-action')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(700, 1); + + })); + + this._builder.get_object('scroll_panel_combo').set_active_id(this._settings.get_string('scroll-panel-action')); + this._builder.get_object('scroll_panel_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-panel-action', widget.get_active_id()); + })); + + this._builder.get_object('scroll_icon_combo').set_active_id(this._settings.get_string('scroll-icon-action')); + this._builder.get_object('scroll_icon_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('scroll-icon-action', widget.get_active_id()); + })); + + // Create dialog for panel scroll options + this._builder.get_object('scroll_panel_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize panel scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_panel_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-panel-delay', widget.get_value()); + })); + + this._settings.bind('scroll-panel-show-ws-popup', + this._builder.get_object('scroll_panel_options_show_ws_popup_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-panel-delay', this._settings.get_default_value('scroll-panel-delay')); + this._builder.get_object('scroll_panel_options_delay_spinbutton').set_value(this._settings.get_int('scroll-panel-delay')); + + this._settings.set_value('scroll-panel-show-ws-popup', this._settings.get_default_value('scroll-panel-show-ws-popup')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + // Create dialog for icon scroll options + this._builder.get_object('scroll_icon_options_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('Customize icon scroll behavior'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('scroll_icon_options_box'); + dialog.get_content_area().append(box); + + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('scroll-icon-delay', widget.get_value()); + })); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('scroll-icon-delay', this._settings.get_default_value('scroll-icon-delay')); + this._builder.get_object('scroll_icon_options_delay_spinbutton').set_value(this._settings.get_int('scroll-icon-delay')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(640, 1); + + })); + + this._settings.bind('hot-keys', + this._builder.get_object('hot_keys_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('hot-keys', + this._builder.get_object('overlay_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('hotkeys-overlay-combo', widget.get_active_id()); + })); + + this._settings.bind('shortcut-previews', + this._builder.get_object('shortcut_preview_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('shortcut_num_keys_combo').set_active_id(this._settings.get_string('shortcut-num-keys')); + this._builder.get_object('shortcut_num_keys_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('shortcut-num-keys', widget.get_active_id()); + })); + + this._settings.connect('changed::hotkey-prefix-text', Lang.bind(this, function() {checkHotkeyPrefix(this._settings);})); + + this._builder.get_object('hotkey_prefix_combo').set_active_id(this._settings.get_string('hotkey-prefix-text')); + + this._settings.bind('hotkey-prefix-text', + this._builder.get_object('hotkey_prefix_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('overlay_combo').set_active_id(this._settings.get_string('hotkeys-overlay-combo')); + + this._settings.bind('hotkeys-overlay-combo', + this._builder.get_object('overlay_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('overlay-timeout', + this._builder.get_object('timeout_spinbutton'), + 'value', + Gio.SettingsBindFlags.DEFAULT); + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') { + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + } + + this._settings.connect('changed::hotkeys-overlay-combo', Lang.bind(this, function() { + if (this._settings.get_string('hotkeys-overlay-combo') !== 'TEMPORARILY') + this._builder.get_object('timeout_spinbutton').set_sensitive(false); + else + this._builder.get_object('timeout_spinbutton').set_sensitive(true); + })); + + this._settings.bind('shortcut-text', + this._builder.get_object('shortcut_entry'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._settings.connect('changed::shortcut-text', Lang.bind(this, function() {setShortcut(this._settings, 'shortcut');})); + + // Create dialog for number overlay options + this._builder.get_object('overlay_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced hotkeys options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_overlay_shortcut'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings for the relevant keys + let keys = ['hotkey-prefix-text', 'shortcut-text', 'hotkeys-overlay-combo', 'overlay-timeout', 'shortcut-previews']; + keys.forEach(function(val) { + this._settings.set_value(val, this._settings.get_default_value(val)); + }, this); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(600, 1); + + })); + + // setup dialog for secondary menu options + this._builder.get_object('secondarymenu_options_button').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Secondary Menu Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_secondarymenu_options'); + dialog.get_content_area().append(box); + + this._settings.bind('secondarymenu-contains-appmenu', + this._builder.get_object('secondarymenu_appmenu_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('secondarymenu-contains-showdetails', + this._builder.get_object('secondarymenu_showdetails_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('secondarymenu-contains-appmenu', this._settings.get_default_value('secondarymenu-contains-appmenu')); + this._settings.set_value('secondarymenu-contains-showdetails', this._settings.get_default_value('secondarymenu-contains-showdetails')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // setup dialog for advanced options + this._builder.get_object('button_advanced_options').connect('clicked', Lang.bind(this, function() { + + let dialog = new Gtk.Dialog({ title: _('Advanced Options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('box_advanced_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + dialog.set_default_size(480, 1); + + })); + + // Fine-tune panel + + let sizeScales = [ + {objectName: 'tray_size_scale', valueName: 'tray-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'leftbox_size_scale', valueName: 'leftbox-size', range: DEFAULT_FONT_SIZES }, + {objectName: 'appicon_margin_scale', valueName: 'appicon-margin', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'appicon_padding_scale', valueName: 'appicon-padding', range: DEFAULT_MARGIN_SIZES }, + {objectName: 'tray_padding_scale', valueName: 'tray-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'leftbox_padding_scale', valueName: 'leftbox-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'statusicon_padding_scale', valueName: 'status-icon-padding', range: DEFAULT_PADDING_SIZES }, + {objectName: 'panel_length_scale', valueName: '', range: LENGTH_MARKS } + ]; + + for(var idx in sizeScales) { + let size_scale = this._builder.get_object(sizeScales[idx].objectName); + let range = sizeScales[idx].range; + size_scale.set_range(range[range.length - 1], range[0]); + let value; + if (sizeScales[idx].objectName === 'panel_length_scale') { + value = PanelSettings.getPanelLength(this._settings, this._currentMonitorIndex); + } else { + value = this._settings.get_int(sizeScales[idx].valueName); + } + size_scale.set_value(value); + // Add marks from range arrays, omitting the first and last values. + range.slice(1, -1).forEach(function(val) { + size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); + }); + + // Corrent for rtl languages + if (this._rtl) { + // Flip value position: this is not done automatically + size_scale.set_value_pos(Gtk.PositionType.LEFT); + // I suppose due to a bug, having a more than one mark and one above a value of 100 + // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable + // and then manually inverting it + size_scale.set_flippable(false); + size_scale.set_inverted(true); + } + } + + this._settings.bind('animate-app-switch', + this._builder.get_object('animate_app_switch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-window-launch', + this._builder.get_object('animate_window_launch_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('animate-appicon-hover', + this._builder.get_object('animate_appicon_hover_button'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + { + this._settings.bind('animate-appicon-hover-animation-type', + this._builder.get_object('animate_appicon_hover_options_type_combo'), + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + + let scales = [ + ['animate_appicon_hover_options_duration_scale', 'animate-appicon-hover-animation-duration', 1], + ['animate_appicon_hover_options_rotation_scale', 'animate-appicon-hover-animation-rotation', 1], + ['animate_appicon_hover_options_travel_scale', 'animate-appicon-hover-animation-travel', 100], + ['animate_appicon_hover_options_zoom_scale', 'animate-appicon-hover-animation-zoom', 100], + ['animate_appicon_hover_options_convexity_scale', 'animate-appicon-hover-animation-convexity', 1], + ['animate_appicon_hover_options_extent_scale', 'animate-appicon-hover-animation-extent', 1], + ]; + + let updateScale = scale => { + let [id, key, factor] = scale; + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let value = this._settings.get_value(key).deep_unpack()[type]; + let defaultValue = this._settings.get_default_value(key).deep_unpack()[type]; + this._builder.get_object(id).sensitive = defaultValue !== undefined; + this._builder.get_object(id).set_value(value * factor || 0); + this._builder.get_object(id).clear_marks(); + this._builder.get_object(id).add_mark(defaultValue * factor, Gtk.PositionType.TOP, + defaultValue !== undefined ? (defaultValue * factor).toString() : ' '); + }; + + scales.forEach(scale => { + let [id, key, factor] = scale; + this._settings.connect('changed::' + key, () => updateScale(scale)); + this._builder.get_object(id).connect('value-changed', widget => { + let type = this._settings.get_string('animate-appicon-hover-animation-type'); + let variant = this._settings.get_value(key); + let unpacked = variant.deep_unpack(); + if (unpacked[type] != widget.get_value() / factor) { + unpacked[type] = widget.get_value() / factor; + this._settings.set_value(key, new GLib.Variant(variant.get_type_string(), unpacked)); + } + }); + }); + + this._settings.connect('changed::animate-appicon-hover-animation-type', () => scales.forEach(updateScale)); + scales.forEach(updateScale); + } + + this._builder.get_object('animate_appicon_hover_button').connect('clicked', Lang.bind(this, function() { + let dialog = new Gtk.Dialog({ title: _('App icon animation options'), + transient_for: this.notebook.get_root(), + use_header_bar: true, + modal: true }); + + // GTK+ leaves positive values for application-defined response ids. + // Use +1 for the reset action + dialog.add_button(_('Reset to defaults'), 1); + + let box = this._builder.get_object('animate_appicon_hover_options'); + dialog.get_content_area().append(box); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + if (id == 1) { + // restore default settings + this._settings.set_value('animate-appicon-hover-animation-type', this._settings.get_default_value('animate-appicon-hover-animation-type')); + this._settings.set_value('animate-appicon-hover-animation-duration', this._settings.get_default_value('animate-appicon-hover-animation-duration')); + this._settings.set_value('animate-appicon-hover-animation-rotation', this._settings.get_default_value('animate-appicon-hover-animation-rotation')); + this._settings.set_value('animate-appicon-hover-animation-travel', this._settings.get_default_value('animate-appicon-hover-animation-travel')); + this._settings.set_value('animate-appicon-hover-animation-zoom', this._settings.get_default_value('animate-appicon-hover-animation-zoom')); + this._settings.set_value('animate-appicon-hover-animation-convexity', this._settings.get_default_value('animate-appicon-hover-animation-convexity')); + this._settings.set_value('animate-appicon-hover-animation-extent', this._settings.get_default_value('animate-appicon-hover-animation-extent')); + } else { + // remove the settings box so it doesn't get destroyed; + dialog.get_content_area().remove(box); + dialog.destroy(); + } + return; + })); + + dialog.show(); + + })); + + this._settings.bind('stockgs-keep-dash', + this._builder.get_object('stockgs_dash_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-keep-top-panel', + this._builder.get_object('stockgs_top_panel_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + + + this._settings.connect('changed::stockgs-keep-top-panel', () => this._maybeDisableTopPosition()); + + this._maybeDisableTopPosition(); + + this._settings.bind('stockgs-panelbtn-click-only', + this._builder.get_object('stockgs_panelbtn_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('stockgs-force-hotcorner', + this._builder.get_object('stockgs_hotcorner_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + // About Panel + + this._builder.get_object('extension_version').set_label(Me.metadata.version.toString() + (Me.metadata.commit ? ' (' + Me.metadata.commit + ')' : '')); + + this._builder.get_object('importexport_export_button').connect('clicked', widget => { + this._showFileChooser( + _('Export settings'), + { action: Gtk.FileChooserAction.SAVE }, + "Save", + filename => { + let file = Gio.file_new_for_path(filename); + let raw = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let out = Gio.BufferedOutputStream.new_sized(raw, 4096); + + out.write_all(GLib.spawn_command_line_sync('dconf dump ' + SCHEMA_PATH)[1], null); + out.close(null); + } + ); + }); + + this._builder.get_object('importexport_import_button').connect('clicked', widget => { + this._showFileChooser( + _('Import settings'), + { action: Gtk.FileChooserAction.OPEN }, + "Open", + filename => { + if (filename && GLib.file_test(filename, GLib.FileTest.EXISTS)) { + let settingsFile = Gio.File.new_for_path(filename); + let [ , pid, stdin, stdout, stderr] = + GLib.spawn_async_with_pipes( + null, + ['dconf', 'load', SCHEMA_PATH], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, + null + ); + + stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true }); + GLib.close(stdout); + GLib.close(stderr); + + let [ , , , retCode] = GLib.spawn_command_line_sync(GSET + ' -d ' + Me.uuid); + if (retCode == 0) { + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => GLib.spawn_command_line_sync(GSET + ' -e ' + Me.uuid)); + } + + stdin.splice(settingsFile.read(null), Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, null); + } + } + ); + }); + + }, + + _setPreviewTitlePosition: function() { + switch (this._settings.get_string('window-preview-title-position')) { + case 'BOTTOM': + this._builder.get_object('preview_title_position_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('preview_title_position_top_button').set_active(true); + break; + } + }, + + _showFileChooser: function(title, params, acceptBtn, acceptHandler) { + let dialog = new Gtk.FileChooserDialog(mergeObjects({ title: title, transient_for: this.notebook.get_root() }, params)); + + dialog.add_button("Cancel", Gtk.ResponseType.CANCEL); + dialog.add_button(acceptBtn, Gtk.ResponseType.ACCEPT); + + dialog.show(); + + dialog.connect('response', Lang.bind(this, function(dialog, id) { + acceptHandler.call(this, dialog.get_file().get_path()); + dialog.destroy(); + })); + } +}); + + +const BuilderScope = GObject.registerClass({ + Implements: [Gtk.BuilderScope], +}, class BuilderScope extends GObject.Object { + + _init(preferences) { + this._preferences = preferences; + super._init(); + } + + vfunc_create_closure(builder, handlerName, flags, connectObject) { + if (flags & Gtk.BuilderClosureFlags.SWAPPED) + throw new Error('Unsupported template signal flag "swapped"'); + + if (typeof this[handlerName] === 'undefined') + throw new Error(`${handlerName} is undefined`); + + return this[handlerName].bind(connectObject || this); + } + + on_btn_click(connectObject) { + connectObject.set_label("Clicked"); + } + + position_bottom_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.BOTTOM); + } + + position_top_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.TOP); + } + + position_left_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.LEFT); + } + + position_right_button_clicked_cb(button) { + if (!this._preferences._ignorePositionRadios && button.get_active()) this._preferences._setPanelPosition(Pos.RIGHT); + } + + dots_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "BOTTOM"); + } + + dots_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "TOP"); + } + + dots_left_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "LEFT"); + } + + dots_right_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('dot-position', "RIGHT"); + } + + preview_title_position_bottom_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'BOTTOM'); + } + + preview_title_position_top_button_toggled_cb(button) { + if (button.get_active()) + this._preferences._settings.set_string('window-preview-title-position', 'TOP'); + } + + panel_size_scale_value_changed_cb(scale) { + // Avoid settings the size continuously + if (this._preferences._panel_size_timeout > 0) + Mainloop.source_remove(this._preferences._panel_size_timeout); + + this._preferences._panel_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this._preferences, function() { + const value = scale.get_value(); + const monitorSync = this._settings.get_boolean('panel-element-positions-monitors-sync'); + const monitorsToSetFor = monitorSync ? this.monitors : [this._currentMonitorIndex]; + monitorsToSetFor.forEach(monitorIndex => { + PanelSettings.setPanelSize(this._settings, monitorIndex, value); + }); + + this._panel_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_size_timeout > 0) + Mainloop.source_remove(this._preferences._tray_size_timeout); + + this._preferences._tray_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-size', scale.get_value()); + this._preferences._tray_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_size_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_size_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_size_timeout); + + this._preferences._leftbox_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-size', scale.get_value()); + this._preferences._leftbox_size_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_margin_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_margin_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_margin_timeout); + + this._preferences._appicon_margin_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-margin', scale.get_value()); + this._preferences._appicon_margin_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + appicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._appicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._appicon_padding_timeout); + + this._preferences._appicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('appicon-padding', scale.get_value()); + this._preferences._appicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + tray_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._tray_padding_timeout > 0) + Mainloop.source_remove(this._preferences._tray_padding_timeout); + + this._preferences._tray_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('tray-padding', scale.get_value()); + this._preferences._tray_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + statusicon_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._statusicon_padding_timeout > 0) + Mainloop.source_remove(this._preferences._statusicon_padding_timeout); + + this._preferences._statusicon_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('status-icon-padding', scale.get_value()); + this._preferences._statusicon_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } + + leftbox_padding_scale_value_changed_cb(scale) { + // Avoid settings the size consinuosly + if (this._preferences._leftbox_padding_timeout > 0) + Mainloop.source_remove(this._preferences._leftbox_padding_timeout); + + this._preferences._leftbox_padding_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { + this._preferences._settings.set_int('leftbox-padding', scale.get_value()); + this._preferences._leftbox_padding_timeout = 0; + return GLib.SOURCE_REMOVE; + })); + } +}); + +function init() { + Convenience.initTranslations(); +} + +function buildPrefsWidget() { + Gtk.Window.list_toplevels()[0].set_default_size(680, 740); + + let preferences = new Preferences(); + + return preferences.notebook; +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js new file mode 100644 index 0000000..1e84e82 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/progress.js @@ -0,0 +1,598 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + */ + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gio = imports.gi.Gio; +const Cairo = imports.cairo; +const Clutter = imports.gi.Clutter; +const Pango = imports.gi.Pango; +const St = imports.gi.St; +const Signals = imports.signals; +const Utils = Me.imports.utils; + + +var ProgressManager = Utils.defineClass({ + Name: 'DashToPanel.ProgressManager', + + _init: function() { + + this._entriesByDBusName = {}; + + this._launcher_entry_dbus_signal_id = + Gio.DBus.session.signal_subscribe(null, // sender + 'com.canonical.Unity.LauncherEntry', // iface + null, // member + null, // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onEntrySignalReceived.bind(this)); + + this._dbus_name_owner_changed_signal_id = + Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender + 'org.freedesktop.DBus', // interface + 'NameOwnerChanged', // member + '/org/freedesktop/DBus', // path + null, // arg0 + Gio.DBusSignalFlags.NONE, + this._onDBusNameOwnerChanged.bind(this)); + + this._acquireUnityDBus(); + }, + + destroy: function() { + if (this._launcher_entry_dbus_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id); + } + + if (this._dbus_name_owner_changed_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id); + } + + this._releaseUnityDBus(); + }, + + size: function() { + return Object.keys(this._entriesByDBusName).length; + }, + + lookupByDBusName: function(dbusName) { + return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null; + }, + + lookupById: function(appId) { + let ret = []; + for (let dbusName in this._entriesByDBusName) { + let entry = this._entriesByDBusName[dbusName]; + if (entry && entry.appId() == appId) { + ret.push(entry); + } + } + + return ret; + }, + + addEntry: function(entry) { + let existingEntry = this.lookupByDBusName(entry.dbusName()); + if (existingEntry) { + existingEntry.update(entry); + } else { + this._entriesByDBusName[entry.dbusName()] = entry; + this.emit('progress-entry-added', entry); + } + }, + + removeEntry: function(entry) { + delete this._entriesByDBusName[entry.dbusName()] + this.emit('progress-entry-removed', entry); + }, + + _acquireUnityDBus: function() { + if (!this._unity_bus_id) { + Gio.DBus.session.own_name('com.canonical.Unity', + Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); + } + }, + + _releaseUnityDBus: function() { + if (this._unity_bus_id) { + Gio.DBus.session.unown_name(this._unity_bus_id); + this._unity_bus_id = 0; + } + }, + + _onEntrySignalReceived: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !signal_name) + return; + + if (signal_name == 'Update') { + if (!sender_name) { + return; + } + + this._handleUpdateRequest(sender_name, parameters); + } + }, + + _onDBusNameOwnerChanged: function(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !this.size()) + return; + + let [name, before, after] = parameters.deep_unpack(); + + if (!after) { + if (this._entriesByDBusName.hasOwnProperty(before)) { + this.removeEntry(this._entriesByDBusName[before]); + } + } + }, + + _handleUpdateRequest: function(senderName, parameters) { + if (!senderName || !parameters) { + return; + } + + let [appUri, properties] = parameters.deep_unpack(); + let appId = appUri.replace(/(^\w+:|^)\/\//, ''); + let entry = this.lookupByDBusName(senderName); + + if (entry) { + entry.setDBusName(senderName); + entry.update(properties); + } else { + let entry = new AppProgress(senderName, appId, properties); + this.addEntry(entry); + } + } +}); +Signals.addSignalMethods(ProgressManager.prototype); + +var AppProgress = Utils.defineClass({ + Name: 'DashToPanel.AppProgress', + + _init: function(dbusName, appId, properties) { + this._dbusName = dbusName; + this._appId = appId; + this._count = 0; + this._countVisible = false; + this._progress = 0.0; + this._progressVisible = false; + this._urgent = false; + this.update(properties); + }, + + appId: function() { + return this._appId; + }, + + dbusName: function() { + return this._dbusName; + }, + + count: function() { + return this._count; + }, + + setCount: function(count) { + if (this._count != count) { + this._count = count; + this.emit('count-changed', this._count); + } + }, + + countVisible: function() { + return this._countVisible; + }, + + setCountVisible: function(countVisible) { + if (this._countVisible != countVisible) { + this._countVisible = countVisible; + this.emit('count-visible-changed', this._countVisible); + } + }, + + progress: function() { + return this._progress; + }, + + setProgress: function(progress) { + if (this._progress != progress) { + this._progress = progress; + this.emit('progress-changed', this._progress); + } + }, + + progressVisible: function() { + return this._progressVisible; + }, + + setProgressVisible: function(progressVisible) { + if (this._progressVisible != progressVisible) { + this._progressVisible = progressVisible; + this.emit('progress-visible-changed', this._progressVisible); + } + }, + + urgent: function() { + return this._urgent; + }, + + setUrgent: function(urgent) { + if (this._urgent != urgent) { + this._urgent = urgent; + this.emit('urgent-changed', this._urgent); + } + }, + + setDBusName: function(dbusName) { + if (this._dbusName != dbusName) { + let oldName = this._dbusName; + this._dbusName = dbusName; + this.emit('dbus-name-changed', oldName); + } + }, + + update: function(other) { + if (other instanceof AppProgress) { + this.setDBusName(other.dbusName()) + this.setCount(other.count()); + this.setCountVisible(other.countVisible()); + this.setProgress(other.progress()); + this.setProgressVisible(other.progressVisible()) + this.setUrgent(other.urgent()); + } else { + for (let property in other) { + if (other.hasOwnProperty(property)) { + if (property == 'count') { + this.setCount(other[property].get_int64()); + } else if (property == 'count-visible') { + this.setCountVisible(Me.settings.get_boolean('progress-show-count') && other[property].get_boolean()); + } else if (property == 'progress') { + this.setProgress(other[property].get_double()); + } else if (property == 'progress-visible') { + this.setProgressVisible(Me.settings.get_boolean('progress-show-bar') && other[property].get_boolean()); + } else if (property == 'urgent') { + this.setUrgent(other[property].get_boolean()); + } else { + // Not implemented yet + } + } + } + } + } +}); +Signals.addSignalMethods(AppProgress.prototype); + + +var ProgressIndicator = Utils.defineClass({ + Name: 'DashToPanel.ProgressIndicator', + + _init: function(source, progressManager) { + this._source = source; + this._progressManager = progressManager; + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._sourceDestroyId = this._source.actor.connect('destroy', () => { + this._signalsHandler.destroy(); + }); + + this._notificationBadgeLabel = new St.Label({ style_class: 'badge' }); + this._notificationBadgeBin = new St.Bin({ + child: this._notificationBadgeLabel, y: 2, x: 2 + }); + this._notificationBadgeLabel.add_style_class_name('notification-badge'); + this._notificationBadgeCount = 0; + this._notificationBadgeBin.hide(); + + this._source._dtpIconContainer.add_child(this._notificationBadgeBin); + this._source._dtpIconContainer.connect('notify::allocation', this.updateNotificationBadge.bind(this)); + + this._progressManagerEntries = []; + this._progressManager.lookupById(this._source.app.id).forEach( + (entry) => { + this.insertEntry(entry); + } + ); + + this._signalsHandler.add([ + this._progressManager, + 'progress-entry-added', + this._onEntryAdded.bind(this) + ], [ + this._progressManager, + 'progress-entry-removed', + this._onEntryRemoved.bind(this) + ]); + }, + + destroy: function() { + this._source.actor.disconnect(this._sourceDestroyId); + this._signalsHandler.destroy(); + }, + + _onEntryAdded: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.insertEntry(entry); + } + }, + + _onEntryRemoved: function(appProgress, entry) { + if (!entry || !entry.appId()) + return; + + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.removeEntry(entry); + } + }, + + updateNotificationBadge: function() { + this._source.updateNumberOverlay(this._notificationBadgeBin); + this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; + }, + + _notificationBadgeCountToText: function(count) { + if (count <= 9999) { + return count.toString(); + } else if (count < 1e5) { + let thousands = count / 1e3; + return thousands.toFixed(1).toString() + "k"; + } else if (count < 1e6) { + let thousands = count / 1e3; + return thousands.toFixed(0).toString() + "k"; + } else if (count < 1e8) { + let millions = count / 1e6; + return millions.toFixed(1).toString() + "M"; + } else if (count < 1e9) { + let millions = count / 1e6; + return millions.toFixed(0).toString() + "M"; + } else { + let billions = count / 1e9; + return billions.toFixed(1).toString() + "B"; + } + }, + + setNotificationBadge: function(count) { + this._notificationBadgeCount = count; + let text = this._notificationBadgeCountToText(count); + this._notificationBadgeLabel.set_text(text); + }, + + toggleNotificationBadge: function(activate) { + if (activate && this._notificationBadgeCount > 0) { + this.updateNotificationBadge(); + this._notificationBadgeBin.show(); + } + else + this._notificationBadgeBin.hide(); + }, + + _showProgressOverlay: function() { + if (this._progressOverlayArea) { + this._updateProgressOverlay(); + return; + } + + this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); + this._progressOverlayArea.add_style_class_name('progress-bar'); + this._progressOverlayArea.connect('repaint', () => { + this._drawProgressOverlay(this._progressOverlayArea); + }); + + this._source._iconContainer.add_child(this._progressOverlayArea); + let node = this._progressOverlayArea.get_theme_node(); + + let [hasColor, color] = node.lookup_color('-progress-bar-background', false); + if (hasColor) + this._progressbar_background = color + else + this._progressbar_background = new Clutter.Color({red: 204, green: 204, blue: 204, alpha: 255}); + + [hasColor, color] = node.lookup_color('-progress-bar-border', false); + if (hasColor) + this._progressbar_border = color; + else + this._progressbar_border = new Clutter.Color({red: 230, green: 230, blue: 230, alpha: 255}); + + this._updateProgressOverlay(); + }, + + _hideProgressOverlay: function() { + if (this._progressOverlayArea) + this._progressOverlayArea.destroy(); + + this._progressOverlayArea = null; + this._progressbar_background = null; + this._progressbar_border = null; + }, + + _updateProgressOverlay: function() { + + if (this._progressOverlayArea) { + this._progressOverlayArea.queue_repaint(); + } + }, + + _drawProgressOverlay: function(area) { + let scaleFactor = Utils.getScaleFactor(); + let [surfaceWidth, surfaceHeight] = area.get_surface_size(); + let cr = area.get_context(); + + let iconSize = this._source.icon.iconSize * scaleFactor; + + let x = Math.floor((surfaceWidth - iconSize) / 2); + let y = Math.floor((surfaceHeight - iconSize) / 2); + + let lineWidth = Math.floor(1.0 * scaleFactor); + let padding = Math.floor(iconSize * 0.05); + let width = iconSize - 2.0*padding; + let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize)); + x += padding; + y += iconSize - height - padding; + + cr.setLineWidth(lineWidth); + + // Draw the outer stroke + let stroke = new Cairo.LinearGradient(0, y, 0, y + height); + let fill = null; + stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1); + stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the background + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9); + fill = new Cairo.LinearGradient(0, y, 0, y + height); + fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0); + fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0); + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); + + // Draw the finished bar + x += lineWidth; + y += lineWidth; + width -= 2.0*lineWidth; + height -= 2.0*lineWidth; + + let finishedWidth = Math.ceil(this._progress * width); + + let bg = this._progressbar_background; + let bd = this._progressbar_border; + + stroke = Cairo.SolidPattern.createRGBA(bd.red/255, bd.green/255, bd.blue/255, bd.alpha/255); + fill = Cairo.SolidPattern.createRGBA(bg.red/255, bg.green/255, bg.blue/255, bg.alpha/255); + + if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) + Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + else + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + + cr.$dispose(); + }, + + setProgress: function(progress) { + this._progress = Math.min(Math.max(progress, 0.0), 1.0); + this._updateProgressOverlay(); + }, + + toggleProgressOverlay: function(activate) { + if (activate) { + this._showProgressOverlay(); + } + else { + this._hideProgressOverlay(); + } + }, + + insertEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) !== -1) + return; + + this._progressManagerEntries.push(appProgress); + this._selectEntry(appProgress); + }, + + removeEntry: function(appProgress) { + if (!appProgress || this._progressManagerEntries.indexOf(appProgress) == -1) + return; + + this._progressManagerEntries.splice(this._progressManagerEntries.indexOf(appProgress), 1); + + if (this._progressManagerEntries.length > 0) { + this._selectEntry(this._progressManagerEntries[this._progressManagerEntries.length-1]); + } else { + this.setNotificationBadge(0); + this.toggleNotificationBadge(false); + this.setProgress(0); + this.toggleProgressOverlay(false); + this.setUrgent(false); + } + }, + + _selectEntry: function(appProgress) { + if (!appProgress) + return; + + this._signalsHandler.removeWithLabel('progress-entry'); + + this._signalsHandler.addWithLabel('progress-entry', + [ + appProgress, + 'count-changed', + (appProgress, value) => { + this.setNotificationBadge(value); + } + ], [ + appProgress, + 'count-visible-changed', + (appProgress, value) => { + this.toggleNotificationBadge(value); + } + ], [ + appProgress, + 'progress-changed', + (appProgress, value) => { + this.setProgress(value); + } + ], [ + appProgress, + 'progress-visible-changed', + (appProgress, value) => { + this.toggleProgressOverlay(value); + } + ], [ + appProgress, + 'urgent-changed', + (appProgress, value) => { + this.setUrgent(value) + } + ]); + + this.setNotificationBadge(appProgress.count()); + this.toggleNotificationBadge(appProgress.countVisible()); + this.setProgress(appProgress.progress()); + this.toggleProgressOverlay(appProgress.progressVisible()); + + this._isUrgent = false; + }, + + setUrgent: function(urgent) { + const icon = this._source.icon._iconBin; + if (urgent) { + if (!this._isUrgent) { + icon.set_pivot_point(0.5, 0.5); + this._source.iconAnimator.addAnimation(icon, 'dance'); + this._isUrgent = true; + } + } else { + if (this._isUrgent) { + this._source.iconAnimator.removeAnimation(icon, 'dance'); + this._isUrgent = false; + } + icon.rotation_angle_z = 0; + } + } +}); diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js new file mode 100644 index 0000000..c298f84 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/proximity.js @@ -0,0 +1,262 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Lang = imports.lang; +const Meta = imports.gi.Meta; + +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; + +//timeout intervals +const MIN_UPDATE_MS = 200; + +//timeout names +const T1 = 'limitUpdateTimeout'; + +var Mode = { + ALL_WINDOWS: 0, + FOCUSED_WINDOWS: 1, + MAXIMIZED_WINDOWS: 2 +}; + +var ProximityWatch = Utils.defineClass({ + Name: 'DashToPanel.ProximityWatch', + + _init: function(actor, mode, xThreshold, yThreshold, handler) { + this.actor = actor; + this.overlap = 0; + this.mode = mode; + this.threshold = [xThreshold, yThreshold]; + this.handler = handler; + + this._allocationChangedId = actor.connect('notify::allocation', () => this._update()); + + this._update(); + }, + + destroy: function() { + this.actor.disconnect(this._allocationChangedId); + }, + + _update: function() { + this.monitorIndex = Main.layoutManager.findIndexForActor(this.actor); + + this._updateWatchRect(); + }, + + _updateWatchRect: function() { + let [actorX, actorY] = this.actor.get_position(); + + this.rect = new Meta.Rectangle({ + x: actorX - this.threshold[0], + y: actorY - this.threshold[1], + width: this.actor.width + this.threshold[0] * 2, + height: this.actor.height + this.threshold[1] * 2 + }); + }, +}); + +var ProximityManager = Utils.defineClass({ + Name: 'DashToPanel.ProximityManager', + + _init: function() { + this._counter = 1; + this._watches = {}; + this._focusedWindowInfo = null; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this._bindSignals(); + this._setFocusedWindow(); + }, + + createWatch: function(actor, mode, xThreshold, yThreshold, handler) { + let watch = new ProximityWatch(actor, mode, xThreshold, yThreshold, handler); + + this._watches[this._counter] = watch; + this.update(); + + return this._counter++; + }, + + removeWatch: function(id) { + if (this._watches[id]) { + this._watches[id].destroy(); + delete this._watches[id]; + } + }, + + update: function() { + this._queueUpdate(true); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + this._disconnectFocusedWindow(); + Object.keys(this._watches).forEach(id => this.removeWatch(id)); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + global.window_manager, + 'switch-workspace', + () => Object.keys(this._watches).forEach(id => this._watches[id].overlap = 0) + ], + [ + Main.overview, + 'hidden', + () => this._queueUpdate() + ], + [ + global.display, + 'notify::focus-window', + () => { + this._setFocusedWindow(); + this._queueUpdate(); + } + ], + [ + global.window_group, + [ + 'actor-added', + 'actor-removed' + ], + () => this._queueUpdate() + ] + ); + }, + + _setFocusedWindow: function() { + this._disconnectFocusedWindow(); + + let focusedWindow = global.display.focus_window; + + if (focusedWindow) { + let focusedWindowInfo = this._getFocusedWindowInfo(focusedWindow); + + if (focusedWindowInfo && this._checkIfHandledWindowType(focusedWindowInfo.metaWindow)) { + focusedWindowInfo.allocationId = focusedWindowInfo.window.connect('notify::allocation', () => this._queueUpdate()); + focusedWindowInfo.destroyId = focusedWindowInfo.window.connect('destroy', () => this._disconnectFocusedWindow(true)); + + this._focusedWindowInfo = focusedWindowInfo; + } + } + }, + + _getFocusedWindowInfo: function(focusedWindow) { + let window = focusedWindow.get_compositor_private(); + let focusedWindowInfo; + + if (window) { + focusedWindowInfo = { window: window }; + focusedWindowInfo.metaWindow = focusedWindowInfo.window.get_meta_window(); + + if (focusedWindow.is_attached_dialog()) { + let mainMetaWindow = focusedWindow.get_transient_for(); + + if (focusedWindowInfo.metaWindow.get_frame_rect().height < mainMetaWindow.get_frame_rect().height) { + focusedWindowInfo.window = mainMetaWindow.get_compositor_private(); + focusedWindowInfo.metaWindow = mainMetaWindow; + } + } + } + + return focusedWindowInfo; + }, + + _disconnectFocusedWindow: function(destroy) { + if (this._focusedWindowInfo && !destroy) { + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.allocationId); + this._focusedWindowInfo.window.disconnect(this._focusedWindowInfo.destroyId); + } + + this._focusedWindowInfo = null; + }, + + _getHandledWindows: function() { + return global.get_window_actors() + .filter(w => w.visible) + .map(w => w.get_meta_window()) + .filter(mw => this._checkIfHandledWindow(mw)); + }, + + _checkIfHandledWindow: function(metaWindow) { + return metaWindow && !metaWindow.minimized && + this._checkIfHandledWindowType(metaWindow); + }, + + _checkIfHandledWindowType: function(metaWindow) { + let metaWindowType = metaWindow.get_window_type(); + + //https://www.roojs.org/seed/gir-1.2-gtk-3.0/seed/Meta.WindowType.html + return metaWindowType <= Meta.WindowType.SPLASHSCREEN && + metaWindowType != Meta.WindowType.DESKTOP; + }, + + _queueUpdate: function(noDelay) { + if (!noDelay && this._timeoutsHandler.getId(T1)) { + //limit the number of updates + this._pendingUpdate = true; + return; + } + + this._timeoutsHandler.add([T1, MIN_UPDATE_MS, () => this._endLimitUpdate()]); + + let metaWindows = this._getHandledWindows(); + + Object.keys(this._watches).forEach(id => { + let watch = this._watches[id]; + let overlap = this._update(watch, metaWindows); + + if (overlap !== watch.overlap) { + watch.handler(overlap); + watch.overlap = overlap; + } + }); + }, + + _endLimitUpdate: function() { + if (this._pendingUpdate) { + this._pendingUpdate = false; + this._queueUpdate(); + } + }, + + _update: function(watch, metaWindows) { + if (watch.mode === Mode.FOCUSED_WINDOWS) { + return (this._focusedWindowInfo && + this._checkIfHandledWindow(this._focusedWindowInfo.metaWindow) && + this._checkProximity(this._focusedWindowInfo.metaWindow, watch)); + } else if (watch.mode === Mode.MAXIMIZED_WINDOWS) { + return metaWindows.some(mw => mw.maximized_vertically && mw.maximized_horizontally && + mw.get_monitor() == watch.monitorIndex); + } + + //Mode.ALL_WINDOWS + return metaWindows.some(mw => this._checkProximity(mw, watch)); + }, + + _checkProximity: function(metaWindow, watch) { + return metaWindow.get_frame_rect().overlap(watch.rect); + }, +}); \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled new file mode 100644 index 0000000..ef5dc7d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/gschemas.compiled differ diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml new file mode 100644 index 0000000..7e8ea3a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -0,0 +1,1278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'BOTTOM' + Panel position (Deprecated) + Panel is shown on the Bottom or Top of the screen. + + + true + Sync element positions + Sync panel element positions on all monitors. + + + '{}' + Panel positions + Panel positions (JSON). + + + '{}' + Panel element positions + Panel element positions (JSON). + + + '{}' + Percentages of screen edge for panel to span + Length of the panels, in percent (JSON). + + + '{}' + Positions along screen edge + Where to show the panels if it is not the full length of the screen edge (JSON). + + + '{}' + Panel sizes + Sizes of panels, in pixels. + + + 48 + Panel size (Deprecated) + Set the size of the panel. + + + false + Override Show Desktop line color + Replace current Show Desktop button line color + + + "rgba(200,200,200,0.2)" + Custom Show Desktop line color + Custom Show Desktop button line color + + + 'BOTTOM' + Dot position + Running indicators are shown on the Bottom or Top of the screen. + + + 'METRO' + Style of the running indicator (focused) + Style of the running indicator for the icon for the currently focused application + + + 'METRO' + Style of the running indicator (unfocused) + Style of the running indicator for the icon for applications which are not currently focused + + + false + Running indicator dominant color + Whether to use the app icon's dominant color for .app-well-running-dot + + + false + Running indicator color override + Whether to override the theme background color for .app-well-running-dot + + + "#5294e2" + Color of running indicator (1 window) + Customize the color of the running indicator when one window is running for that application + + + "#5294e2" + Color of running indicator (2 windows) + Customize the color of the running indicator when two windows are running for that application + + + "#5294e2" + Color of running indicator (3 windows) + Customize the color of the running indicator when three windows are running for that application + + + "#5294e2" + Color of running indicator (4+ windows) + Customize the color of the running indicator when four or more windows are running for that application + + + false + Unfocused color is different than focused + Whether to apply a 2nd color scheme to the indicator when the app is not focused + + + "#5294e2" + Color of unfocused running indicator (1 window) + Customize the color of the unfocused running indicator when one window is running for that application + + + "#5294e2" + Color of unfocused running indicator (2 windows) + Customize the color of the unfocused running indicator when two windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (3 windows) + Customize the color of the unfocused running indicator when three windows are running for that application + + + "#5294e2" + Color of unfocused running indicator (4+ windows) + Customize the color of the unfocused running indicator when four or more windows are running for that application + + + 3 + Running indicator height + Height of the running indicator line/diameter of window indicator dots + + + true + Highlight icon of focused application + Whether to highlight the background of the currently focused application's icon + + + false + Highlight icon dominant color + Base the active window highlight color on that application's icon + + + "#EEEEEE" + Color of highlight of focused application + Customize the color of the highlight of the focused application + + + 25 + Opacity of highlight of focused application + Customize the opacity of the highlight of the focused application + + + false + Keep dash + Whether to keep the stock gnome-shell dash while in overview + + + false + Keep top panel + Whether to keep the stock gnome-shell top panel + + + false + Panel menu buttons require click + Whether to activate the panel menu buttons on hover or on click + + + false + Force hot corner + Wheter to force having an Activities hot corner on the primary monitor + + + false + Lock the taskbar + Specifies if the user can modify the taskbar + + + false + Override theme background color + Replace current theme background color for the panel + + + "#000" + Custom background color + Custom background color for the panel + + + false + Custom background color + Replace current theme background color for the panel + + + false + Dynamic opacity + Enable dynamic opacity + + + 0.4 + Panel opacity + Custom opacity for the panel + + + 'ALL_WINDOWS' + Dynamic opacity behavior + Dictates which window type affects the panel opacity + + + 20 + Distance to change opacity + The distance a window needs to be from the panel to change opacity + + + 0.8 + Modified panel opacity + Modified opacity for the panel when a window is near + + + 300 + Opacity change duration + The duration of the animation when the opacity changes + + + false + Custom gradient + Replace current theme gradient for the panel + + + "#000" + Custom gradient top color + Custom gradient top color for the panel + + + 0 + Custom gradient top opacity + Custom gradient top opacity for the panel + + + "#000" + Custom gradient bottom color + Custom gradient bottom color for the panel + + + 0.2 + Custom gradient bottom opacity + Custom gradient bottom opacity for the panel + + + false + Intellihide + Whether to intelligently hide the panel + + + false + Only hide from windows + Dictates if the dash should only hide when in conflict with windows + + + 'FOCUSED_WINDOWS' + Intellihide behaviour + Dictates how to intelligently hide the panel + + + false + Intellihide pressure + To reveal the panel, pressure needs to be applied to the edege of the screen + + + 100 + Intellihide pressure threshold + The pressure needed to reveal the panel + + + 1000 + Intellihide pressure time + The numer of milliseconds that the pressure needs to be applied to reveal the panel + + + false + Intellihide pressure + Allow the panel to be revealed while an application is in fullscreen mode + + + false + Intellihide only secondary + Whether to only hide secondary panels + + + 200 + Intellihide animation time + The animation time (ms) to hide and reveal the panel + + + 400 + Intellihide close delay + The delay (ms) before hiding the panel + + + "<Super>i" + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + i']]]> + Keybinding toggle intellihide + Keybinding to reveal the panel while in intellihide mode + + + 2000 + Intellihide enable start delay + The delay before enabling intellihide on start + + + "" + Custom Show Applications icon + Customize the Show Applications icon + + + 8 + Show Applications icon side padding + Customize the Show Applications icon side padding + + + true + Override escape key + Override the escape key to return to the desktop when entering the overview using the Show Applications button + + + [] + Show Apps button context menu commands + Commands to add to the Show Apps button right click menu + + + [] + Show Apps button context menu titles + Titles for commands added to Show Apps button right click menu + + + [] + Panel context menu commands + Commands to add to the panel right click menu + + + [] + Panel context menu titles + Titles for commands added to panel right click menu + + + false + Show activities button + Show activities button on the left hand side of the taskbar + + + 8 + Width of show Desktop button + Customize the width of the show Desktop button + + + false + Show desktop on hover + Show the desktop on mouse hover + + + 1000 + Delay show desktop + Delay before showing the desktop + + + 300 + Show desktop animation time + Window fade animation time when showing the destop + + + false + Show appMenu button + Show appMenu on the right hand side of the panel + + + true + Show window preview + Show preview of running window on hover of app icon + + + true + Show tooltip + Show tooltip on hover of app icon + + + true + Show running apps + Show or hide running application icons in the dash + + + true + Show favorites apps + Show or hide favorite application icons in the dash + + + 400 + Icon enter display time + Amount of time after entering icon to wait before displaying window preview if icon is not clicked or mouse has not left. + + + true + Enable peek mode + Peek a window upon hover for some time + + + true + Display title in preview + Display window title in preview + + + false + Window previews manual styling + This defines if the default window previews styling should be applied + + + 'TOP' + Title position + Position of the window title, close button and icon in preview. + + + "#dddddd" + Window previews title font color + This defines the window preview titles font color. + + + 14 + Window previews title font size + This defines the window preview titles font size. + + + false + Window previews use custom icon size + Window previews use custom application icon size. + + + 16 + Window previews custom icon size + Window previews custom application icon size. + + + 260 + Window previews animation time + This defines the window previews animation time. + + + 'inherit' + Font weight of window preview titles + This defines the font weight of window preview titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + 240 + Window previews size + Preferred window previews size + + + false + Fixed aspect ratio X + This defines if the window previews use a fixed aspect ratio X. + + + true + Fixed aspect ratio Y + This defines if the window previews use a fixed aspect ratio Y. + + + 8 + Window previews padding + The padding of the window previews + + + 16 + Aspect ratio X + The window previews respected aspect ratio X. + + + 9 + Aspect ratio Y + The window previews respected aspect ratio Y. + + + false + Immediate hide on icon click + The window previews immediately hide when an application icon is clicked. + + + false + Provide workspace isolation + Dash shows only windows from the current workspace + + + false + Close overview by clicking in empty space + Close overview or app grid by clicking in empty space + + + false + Hide overview on startup + Hide overview on startup, which would be shown by default at gnome startup. + + + true + Group applications + Dash groups the application instances under the same icon + + + 14 + Application title font size + When the applications are ungrouped, this defines the application titles font size. + + + 'inherit' + Font weight of application titles + When the applications are ungrouped, this defines font weight of application titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + + + "#dddddd" + Application title font color + When the applications are ungrouped, this defines the application titles font color. + + + "#dddddd" + Minimized application title font color + When the applications are ungrouped, this defines the titles font color for minimized applications. + + + 160 + Application title max width + When the applications are ungrouped, this defines the application titles maximum width. + + + true + Use a fixed width for the application titles + The application titles all have the same width, even if their texts are shorter than the maximum width. The maximum width value is used as the fixed width. + + + true + Display running indicators on unfocused applications + When the applications are ungrouped, this defines if running applications should display an indicator. + + + false + Use favorite icons as application launchers + When the applications are ungrouped, this defines if running applications stay separate from the favorite icons. + + + 0 + Primary monitor index + Specifies the index of the primary monitor. + + + true + Display panels on all monitors + Specifies if a panel is shown on every monitors + + + [] + Available monitors + Available gnome-shell (Mutter) monitors, internal use + + + false + Provide monitor isolation + Dash shows only windows from the current monitor + + + true + Display the favorites on all monitors + Specifies if every panel should display the favorite applications. If false, the favorite appplications are only displayed on the primary monitor. + + + true + Customize click behaviour + Customize action on various mouse events + + + true + Minimize on shift+click + + + true + Activate only one window + + + 'CYCLE-MIN' + Action when clicking on a running app + Set the action that is executed when clicking on the icon of a running application + + + 'MINIMIZE' + Action when shift+clicking on a running app + Set the action that is executed when shift+clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when middle-clicking on the icon of a running application + + + 'LAUNCH' + Action when clicking on a running app + Set the action that is executed when shift+middle-clicking on the icon of a running application + + + 'SWITCH_WORKSPACE' + Action when scrolling over the panel + Set the action that is executed when scrolling over the panel + + + 0 + Delay between panel mouse scroll events + Set the minimum delay between panel mouse scroll events + + + true + Show the workspace switch head-up when workspace is changed by scrolling on the panel + + + 'CYCLE_WINDOWS' + Action when scrolling over a running app + Set the action that is executed when scrolling over a running application + + + 0 + Delay between icon mouse scroll events + Set the minimum delay between icon mouse scroll events + + + 100 + Icon leave preview timeout + Amount of time to leave preview windows open when the mouse has left the application's icon. + + + 500 + Enter window peeking mode timeout + Amount of time of inactivity to enter the window peeking mode when the mouse has entered a window preview. + + + 40 + Window peeking mode opacity + All windows except for the peeked one have their opacity set to the same value. + + + true + Middle click preview to close window + Middle click on the window preview to close that window + + + true + Window previews use custom opacity + Window previews background use a different opacity from the panel + + + 80 + Window previews background opacity + Window previews use this custom background opacity. + + + 0 + Tray font size + Set the size of the tray font. (0 for default) + + + 0 + Leftbox font size + Set the size of the leftBox font. (0 for default) + + + 8 + App icon margin + Set the margin for application icons in the embedded dash. + + + 4 + App icon padding + Set the padding for application icons in the embedded dash. + + + -1 + Tray item padding + Set the size of the tray padding. (-1 for default) + + + -1 + Leftbox item padding + Set the size of the leftBox padding. (-1 for default) + + + -1 + Status icon padding + Set the size of the aggregate (status) menu icon padding. (-1 for default) + + + true + Animate running indicator when open/closing/switching applications + + + true + Animate when new window launched + + + false + Animate app icon on hover + + + 'SIMPLE' + App icon hover animation type + + + {'RIPPLE':2,'PLANK':1} + App icon hover animation curve convexity (1 is linear, more is convex, less is concave) + + + {'SIMPLE':160,'RIPPLE':130,'PLANK':100} + App icon hover animation duration in milliseconds + + + {'RIPPLE':4,'PLANK':4} + App icon hover animation extent (maximum number of animated icons) + + + {'SIMPLE':0,'RIPPLE':10,'PLANK':0} + App icon hover animation rotation in degrees + + + {'SIMPLE':0.30,'RIPPLE':0.40,'PLANK':0} + App icon hover animation travel translation in relation to the app icon size + + + {'SIMPLE':1,'RIPPLE':1.25,'PLANK':2} + App icon hover animation zoom scale in relation to the app icon size + + + true + Integrate items from the gnome appmenu into the right click menu + + + false + Display Show Details to open Gnome Software from right click menu + + + "<Super>q" + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + q']]]> + Keybinding to show the dock and the number overlay. + Behavior depends on hotkeys-show-dock and hotkeys-overlay. + + + 2000 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 750 + Timeout to hide the dock, in seconds + Sets the time duration before the dock is hidden again. + + + 'TEMPORARILY' + Transitivity of the number overlay + You can choose between NEVER, TEMPORARILY and ALWAYS. + + + false + Super Hot-Keys + Launch and switch between dash items using Super+(0-9) + + + 'Super' + Prefix to use for hotkeys + You can choose between Super or SuperAlt as the prefix for hotkeys. + + + false + Show window previews + When multiple instances of the application are available, show their window previews + + + 'BOTH' + Hotkeys number keys + Which number keys are used for the hotkeys + + + 1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + 2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + 3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + 4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + 5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + 6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + 7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + 8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + 9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + 0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + 1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + 2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + 3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + 4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + 5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + 6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + 7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + 8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + 9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + 0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + 1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + 2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + 3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + 4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + 5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + 6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + 7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + 8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + 9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + 0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + KP_1']]]> + Keybinding to launch 1st dash app + + Keybinding to launch 1st app. + + + + KP_2']]]> + Keybinding to launch 2nd dash app + + Keybinding to launch 2nd app. + + + + KP_3']]]> + Keybinding to launch 3rd dash app + + Keybinding to launch 3rd app. + + + + KP_4']]]> + Keybinding to launch 4th dash app + + Keybinding to launch 4th app. + + + + KP_5']]]> + Keybinding to launch 5th dash app + + Keybinding to launch 5th app. + + + + KP_6']]]> + Keybinding to launch 6th dash app + + Keybinding to launch 6th app. + + + + KP_7']]]> + Keybinding to launch 7th dash app + + Keybinding to launch 7th app. + + + + KP_8']]]> + Keybinding to launch 8th dash app + + Keybinding to launch 8th app. + + + + KP_9']]]> + Keybinding to launch 9th dash app + + Keybinding to launch 9th app. + + + + KP_0']]]> + Keybinding to launch 10th dash app + + Keybinding to launch 10th app. + + + + KP_1']]]> + Keybinding to trigger 1st dash app with shift behavior + + Keybinding to trigger 1st app with shift behavior. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app with shift behavior + + Keybinding to trigger 2nd app with shift behavior. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app with shift behavior + + Keybinding to trigger 3rd app with shift behavior. + + + + KP_4']]]> + Keybinding to trigger 4th dash app with shift behavior + + Keybinding to trigger 4th app with shift behavior. + + + + KP_5']]]> + Keybinding to trigger 5th dash app with shift behavior + + Keybinding to trigger 5th app with shift behavior. + + + + KP_6']]]> + Keybinding to trigger 6th dash app with shift behavior + + Keybinding to trigger 6th app with shift behavior. + + + + KP_7']]]> + Keybinding to trigger 7th dash app with shift behavior + + Keybinding to trigger 7th app with shift behavior. + + + + KP_8']]]> + Keybinding to trigger 8th dash app with shift behavior + + Keybinding to trigger 8th app with shift behavior. + + + + KP_9']]]> + Keybinding to trigger 9th dash app with shift behavior + + Keybinding to trigger 9th app with shift behavior. + + + + KP_0']]]> + Keybinding to trigger 10th dash app with shift behavior + + Keybinding to trigger 10th app with shift behavior. + + + + KP_1']]]> + Keybinding to trigger 1st dash app + + Keybinding to either show or launch the 1st application in the dash. + + + + KP_2']]]> + Keybinding to trigger 2nd dash app + + Keybinding to either show or launch the 2nd application in the dash. + + + + KP_3']]]> + Keybinding to trigger 3rd dash app + + Keybinding to either show or launch the 3rd application in the dash. + + + + KP_4']]]> + Keybinding to trigger 4th dash app + + Keybinding to either show or launch the 4th application in the dash. + + + + KP_5']]]> + Keybinding to trigger 5th dash app + + Keybinding to either show or launch the 5th application in the dash. + + + + KP_6']]]> + Keybinding to trigger 6th dash app + + Keybinding to either show or launch the 6th application in the dash. + + + + KP_7']]]> + Keybinding to trigger 7th dash app + + Keybinding to either show or launch the 7th application in the dash. + + + + KP_8']]]> + Keybinding to trigger 8th dash app + + Keybinding to either show or launch the 8th application in the dash. + + + + KP_9']]]> + Keybinding to trigger 9th dash app + + Keybinding to either show or launch the 9th application in the dash. + + + + KP_0']]]> + Keybinding to trigger 10th dash app + + Keybinding to either show or launch the 10th application in the dash. + + + + true + Show progress bar on app icon + Whether to show progress bar overlay on app icon, for supported applications. + + + true + Show badge count on app icon + Whether to show badge count overlay on app icon, for supported applications. + + + diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css new file mode 100644 index 0000000..6917e24 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/stylesheet.css @@ -0,0 +1,151 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +#dashtopanelTaskbar .dash-item-container > StWidget { + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-icon, +.dashtopanelMainPanel .show-apps .overview-icon { + background: none; + border: none; + margin: 0; + padding: 0; +} + +#dashtopanelScrollview .app-well-app .overview-label { + /* must match TITLE_RIGHT_PADDING in apppicons.js */ + padding-right: 8px; +} + +#dashtopanelScrollview .app-well-app:hover .overview-icon, +#dashtopanelScrollview .app-well-app:focus .overview-icon { + background: none; +} + +.dashtopanelMainPanel .show-apps:hover .overview-icon, +#dashtopanelScrollview .app-well-app:hover .dtp-container, +#dashtopanelScrollview .app-well-app:focus .dtp-container { + background-color: rgba(238, 238, 236, 0.1); +} + +#dashtopanelScrollview .app-well-app:hover .dtp-container.animate-appicon-hover { + background: none; +} + +#dashtopanelScrollview .app-well-app:active .dtp-container { + background-color: rgba(238, 238, 236, 0.18); +} + +#dashtopanelScrollview .app-well-app .favorite { + background-color: rgba(80, 150, 255, 0.4); +} + +#dashtopanelScrollview .app-well-app-running-dot { + margin-bottom: 0; +} + +#dashtopanelTaskbar .scrollview-fade { + background-gradient-end: rgba(0, 0, 0, 0); +} + +.dashtopanelSecondaryMenu { + max-width: 400px; +} + +.dashtopanelMainPanel.vertical .panel-button { + text-align: center; +} + +.dashtopanelMainPanel.vertical .panel-button.vertical *, +.dashtopanelMainPanel.vertical .panel-button.clock-display * { + padding: 0; + margin: 0; +} + +.dashtopanelMainPanel.vertical .panel-button > *, +.dashtopanelMainPanel.vertical .panel-button.vertical > *, +.dashtopanelMainPanel.vertical .panel-button.clock-display > * { + padding: 8px 0; +} + +#dashtopanelThumbnailList { + spacing: 0em; + padding: 0 1em; +} + +#dashtopanelThumbnailList .popup-menu-item { + padding: 0; + border-radius: 5px; + spacing: 0; +} + +#dashtopanelThumbnailList .window-box { + padding: 0; + spacing: 0; +} + +#dashtopanelThumbnailList .preview-window-title { + padding-top: 1em; +} + +.popup-menu.panel-menu { + margin-bottom: 0; +} + +#panel #panelLeft, #panel #panelCenter { + spacing: 0px; +} + +.showdesktop-button-dark-hovered { + background-color: rgba(200, 200, 200, .4); +} + +.showdesktop-button-light-hovered { + background-color: rgba(55, 55, 55, .4); +} + +.panel-corner.hidden:active, .panel-corner.hidden:overview, .panel-corner.hidden:focus { + -panel-corner-border-color: rgba(0, 0, 0, .001); +} +#dashtopanelScrollview .badge { + color: rgba(255, 255, 255, 1); + font-weight: bold; + text-align: center; +} + +#dashtopanelScrollview .number-overlay { + background-color: rgba(0,0,0,0.8); +} + +#dashtopanelScrollview .notification-badge { + background-color: rgba(255,0,0,0.8); +} + +#dashtopanelScrollview .progress-bar { + /* Customization of the progress bar style, e.g.: + -progress-bar-background: rgba(0.8, 0.8, 0.8, 1); + -progress-bar-border: rgba(0.9, 0.9, 0.9, 1); + */ +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js new file mode 100644 index 0000000..4f74d1e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/taskbar.js @@ -0,0 +1,1557 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; +const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; + +const SearchController = imports.ui.main.overview._overview._controls._searchController; +const AppDisplay = imports.ui.main.overview._overview._controls.appDisplay; +const AppFavorites = imports.ui.appFavorites; +const Dash = imports.ui.dash; +const DND = imports.ui.dnd; +const IconGrid = imports.ui.iconGrid; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const AppIcons = Me.imports.appIcons; +const Panel = Me.imports.panel; +const PanelManager = Me.imports.panelManager; +const PanelSettings = Me.imports.panelSettings; +const Pos = Me.imports.panelPositions; +const Utils = Me.imports.utils; +const WindowPreview = Me.imports.windowPreview; + +var DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME / (Dash.DASH_ANIMATION_TIME > 1 ? 1000 : 1); +var DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; +var MIN_ICON_SIZE = 4; + +/** + * Extend DashItemContainer + * + * - set label position based on taskbar orientation + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this ugly pattern. + */ + +function extendDashItemContainer(dashItemContainer) { + dashItemContainer.showLabel = AppIcons.ItemShowLabel; +}; + +const iconAnimationSettings = { + _getDictValue: function(key) { + let type = Me.settings.get_string('animate-appicon-hover-animation-type'); + return Me.settings.get_value(key).deep_unpack()[type] || 0; + }, + + get type() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return ""; + + return Me.settings.get_string('animate-appicon-hover-animation-type'); + }, + + get convexity() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-convexity')); + }, + + get duration() { + return this._getDictValue('animate-appicon-hover-animation-duration'); + }, + + get extent() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-extent')); + }, + + get rotation() { + return this._getDictValue('animate-appicon-hover-animation-rotation'); + }, + + get travel() { + return Math.max(0, this._getDictValue('animate-appicon-hover-animation-travel')); + }, + + get zoom() { + return Math.max(1, this._getDictValue('animate-appicon-hover-animation-zoom')); + }, +}; + +/* This class is a fork of the upstream DashActor class (ui.dash.js) + * + * Summary of changes: + * - modified chldBox calculations for when 'show-apps-at-top' option is checked + * - handle horizontal dash + */ +var taskbarActor = Utils.defineClass({ + Name: 'DashToPanel-TaskbarActor', + Extends: St.Widget, + + _init: function(delegate) { + this._delegate = delegate; + this._currentBackgroundColor = 0; + this.callParent('_init', { name: 'dashtopanelTaskbar', + layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation[delegate.dtpPanel.getOrientation().toUpperCase()] }), + clip_to_allocation: true }); + }, + + vfunc_allocate: function(box, flags)  { + Utils.setAllocation(this, box, flags); + + let panel = this._delegate.dtpPanel; + let availFixedSize = box[panel.fixedCoord.c2] - box[panel.fixedCoord.c1]; + let availVarSize = box[panel.varCoord.c2] - box[panel.varCoord.c1]; + let [dummy, scrollview, leftFade, rightFade] = this.get_children(); + let [, natSize] = this[panel.sizeFunc](availFixedSize); + let childBox = new Clutter.ActorBox(); + let orientation = panel.getOrientation(); + + Utils.allocate(dummy, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c1]; + childBox[panel.varCoord.c2] = Math.min(availVarSize, natSize); + childBox[panel.fixedCoord.c1] = box[panel.fixedCoord.c1]; + childBox[panel.fixedCoord.c2] = box[panel.fixedCoord.c2]; + + Utils.allocate(scrollview, childBox, flags); + + let [value, , upper, , , pageSize] = scrollview[orientation[0] + 'scroll'].adjustment.get_values(); + upper = Math.floor(upper); + scrollview._dtpFadeSize = upper > pageSize ? this._delegate.iconSize : 0; + + if (this._currentBackgroundColor !== panel.dynamicTransparency.currentBackgroundColor) { + this._currentBackgroundColor = panel.dynamicTransparency.currentBackgroundColor; + let gradientStyle = 'background-gradient-start: ' + this._currentBackgroundColor + + 'background-gradient-direction: ' + orientation; + + leftFade.set_style(gradientStyle); + rightFade.set_style(gradientStyle); + } + + childBox[panel.varCoord.c2] = childBox[panel.varCoord.c1] + (value > 0 ? scrollview._dtpFadeSize : 0); + Utils.allocate(leftFade, childBox, flags); + + childBox[panel.varCoord.c1] = box[panel.varCoord.c2] - (value + pageSize < upper ? scrollview._dtpFadeSize : 0); + childBox[panel.varCoord.c2] = box[panel.varCoord.c2]; + Utils.allocate(rightFade, childBox, flags); + }, + + // We want to request the natural size of all our children + // as our natural width, so we chain up to StWidget (which + // then calls BoxLayout) + vfunc_get_preferred_width: function(forHeight) { + let [, natWidth] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); + + return [0, natWidth]; + }, + + vfunc_get_preferred_height: function(forWidth) { + let [, natHeight] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); + + return [0, natHeight]; + }, +}); + +/* This class is a fork of the upstream dash class (ui.dash.js) + * + * Summary of changes: + * - disconnect global signals adding a destroy method; + * - play animations even when not in overview mode + * - set a maximum icon size + * - show running and/or favorite applications + * - emit a custom signal when an app icon is added + * - Add scrollview + * Ensure actor is visible on keyfocus inside the scrollview + * - add 128px icon size, might be useful for hidpi display + * - Sync minimization application target position. + */ + +var taskbar = Utils.defineClass({ + Name: 'DashToPanel.Taskbar', + + _init : function(panel) { + this.dtpPanel = panel; + + // start at smallest size due to running indicator drawing area expanding but not shrinking + this.iconSize = 16; + + this._shownInitially = false; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + this._showLabelTimeoutId = 0; + this._resetHoverTimeoutId = 0; + this._ensureAppIconVisibilityTimeoutId = 0; + this._labelShowing = false; + this.fullScrollView = 0; + + let isVertical = panel.checkIfVertical(); + + this._box = new St.BoxLayout({ vertical: isVertical, + clip_to_allocation: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START }); + + this._container = new taskbarActor(this); + this._scrollView = new St.ScrollView({ name: 'dashtopanelScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true }); + + this._scrollView.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); + this._scrollView.connect('motion-event', Lang.bind(this, this._onMotionEvent)); + this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); + this._scrollView.add_actor(this._box); + + this._showAppsIconWrapper = panel.showAppsIconWrapper; + this._showAppsIconWrapper.connect('menu-state-changed', Lang.bind(this, function(showAppsIconWrapper, opened) { + this._itemMenuStateChanged(showAppsIconWrapper, opened); + })); + // an instance of the showAppsIcon class is encapsulated in the wrapper + this._showAppsIcon = this._showAppsIconWrapper.realShowAppsIcon; + this.showAppsButton = this._showAppsIcon.toggleButton; + + if (isVertical) { + this.showAppsButton.set_width(panel.geom.w); + } + + this.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); + + this.showAppsButton.checked = (SearchController._showAppsButton) ? SearchController._showAppsButton.checked : false; + + this._showAppsIcon.childScale = 1; + this._showAppsIcon.childOpacity = 255; + this._showAppsIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(this._showAppsIcon, this._showAppsIconWrapper); + + this._container.add_child(new St.Widget({ width: 0, reactive: false })); + this._container.add_actor(this._scrollView); + + let orientation = panel.getOrientation(); + let fadeStyle = 'background-gradient-direction:' + orientation; + let fade1 = new St.Widget({ style_class: 'scrollview-fade', reactive: false }); + let fade2 = new St.Widget({ style_class: 'scrollview-fade', + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: 180 }); + + fade1.set_style(fadeStyle); + fade2.set_style(fadeStyle); + + this._container.add_actor(fade1); + this._container.add_actor(fade2); + + this.previewMenu = new WindowPreview.PreviewMenu(panel); + this.previewMenu.enable(); + + let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + this.actor = new St.Bin({ child: this._container, + y_align: St.Align.START, x_align:rtl?St.Align.END:St.Align.START + }); + + let adjustment = this._scrollView[orientation[0] + 'scroll'].adjustment; + + this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); + + this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' }); + + this._appSystem = Shell.AppSystem.get_default(); + + this.iconAnimator = new PanelManager.IconAnimator(this.dtpPanel.panel.actor); + + this._signalsHandler.add( + [ + this.dtpPanel.panel.actor, + 'notify::height', + () => this._queueRedisplay() + ], + [ + this.dtpPanel.panel.actor, + 'notify::width', + () => this._queueRedisplay() + ], + [ + this._appSystem, + 'installed-changed', + Lang.bind(this, function() { + AppFavorites.getAppFavorites().reload(); + this._queueRedisplay(); + }) + ], + [ + this._appSystem, + 'app-state-changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + AppFavorites.getAppFavorites(), + 'changed', + Lang.bind(this, this._queueRedisplay) + ], + [ + global.window_manager, + 'switch-workspace', + () => this._connectWorkspaceSignals() + ], + [ + Utils.DisplayWrapper.getScreen(), + [ + 'window-entered-monitor', + 'window-left-monitor' + ], + () => { + if (Me.settings.get_boolean('isolate-monitors')) { + this._queueRedisplay(); + } + } + ], + [ + Main.overview, + 'item-drag-begin', + Lang.bind(this, this._onDragBegin) + ], + [ + Main.overview, + 'item-drag-end', + Lang.bind(this, this._onDragEnd) + ], + [ + Main.overview, + 'item-drag-cancelled', + Lang.bind(this, this._onDragCancelled) + ], + [ + // Ensure the ShowAppsButton status is kept in sync + SearchController._showAppsButton, + 'notify::checked', + Lang.bind(this, this._syncShowAppsButtonToggled) + ], + [ + Me.settings, + [ + 'changed::dot-size', + 'changed::show-favorites', + 'changed::show-running-apps', + 'changed::show-favorites-all-monitors' + ], + Lang.bind(this, this._redisplay) + ], + [ + Me.settings, + 'changed::group-apps', + Lang.bind(this, function() { + this.isGroupApps = Me.settings.get_boolean('group-apps'); + this._connectWorkspaceSignals(); + }) + ], + [ + Me.settings, + [ + 'changed::group-apps-use-launchers', + 'changed::taskbar-locked' + ], + () => this.resetAppIcons() + ], + [ + adjustment, + [ + 'notify::upper', + 'notify::pageSize' + ], + () => this._onScrollSizeChange(adjustment) + ] + ); + + this.isGroupApps = Me.settings.get_boolean('group-apps'); + + this._onScrollSizeChange(adjustment); + this._connectWorkspaceSignals(); + }, + + destroy: function() { + this.iconAnimator.destroy(); + + this._signalsHandler.destroy(); + this._signalsHandler = 0; + + this._container.destroy(); + + this.previewMenu.disable(); + this.previewMenu.destroy(); + + this._disconnectWorkspaceSignals(); + }, + + _dropIconAnimations: function() { + this._getTaskbarIcons().forEach(item => { + item.raise(0); + item.stretch(0); + }); + }, + + _updateIconAnimations: function(pointerX, pointerY) { + this._iconAnimationTimestamp = Date.now(); + let type = iconAnimationSettings.type; + + if (!pointerX || !pointerY) + [pointerX, pointerY] = global.get_pointer(); + + this._getTaskbarIcons().forEach(item => { + let [x, y] = item.get_transformed_position(); + let [width, height] = item.get_transformed_size(); + let [centerX, centerY] = [x + width / 2, y + height / 2]; + let size = this._box.vertical ? height : width; + let difference = this._box.vertical ? pointerY - centerY : pointerX - centerX; + let distance = Math.abs(difference); + let maxDistance = (iconAnimationSettings.extent / 2) * size; + + if (type == 'PLANK') { + // Make the position stable for items that are far from the pointer. + let translation = distance <= maxDistance ? + distance / (2 + 8 * distance / maxDistance) : + // the previous expression with distance = maxDistance + maxDistance / 10; + + if (difference > 0) + translation *= -1; + + item.stretch(translation); + } + + if (distance <= maxDistance) { + let level = (maxDistance - distance) / maxDistance; + level = Math.pow(level, iconAnimationSettings.convexity); + item.raise(level); + } else { + item.raise(0); + } + }); + }, + + _onLeaveEvent: function(actor) { + let [stageX, stageY] = global.get_pointer(); + let [success, x, y] = actor.transform_stage_point(stageX, stageY); + if (success && !actor.allocation.contains(x, y) && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._dropIconAnimations(); + + return Clutter.EVENT_PROPAGATE; + }, + + _onMotionEvent: function(actor_, event) { + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + let timestamp = Date.now(); + if (!this._iconAnimationTimestamp || + (timestamp - this._iconAnimationTimestamp >= iconAnimationSettings.duration / 2)) { + let [pointerX, pointerY] = event.get_coords(); + this._updateIconAnimations(pointerX, pointerY); + } + } + + return Clutter.EVENT_PROPAGATE; + }, + + _onScrollEvent: function(actor, event) { + + let orientation = this.dtpPanel.getOrientation(); + + // reset timeout to avid conflicts with the mousehover event + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + // Skip to avoid double events mouse + if (event.is_pointer_emulated()) + return Clutter.EVENT_STOP; + + let adjustment, delta; + + adjustment = this._scrollView[orientation[0] + 'scroll'].get_adjustment(); + + let increment = adjustment.step_increment; + + switch ( event.get_scroll_direction() ) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + delta = -increment; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + delta = +increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy*increment; + delta += dx*increment; + break; + + } + + adjustment.set_value(adjustment.get_value() + delta); + + return Clutter.EVENT_STOP; + + }, + + _onScrollSizeChange: function(adjustment) { + // Update minimization animation target position on scrollview change. + this._updateAppIcons(); + + // When applications are ungrouped and there is some empty space on the horizontal taskbar, + // force a fixed label width to prevent the icons from "wiggling" when an animation runs + // (adding or removing an icon). When the taskbar is full, revert to a dynamic label width + // to allow them to resize and make room for new icons. + if (!this.dtpPanel.checkIfVertical() && !this.isGroupApps) { + let initial = this.fullScrollView; + + if (!this.fullScrollView && Math.floor(adjustment.upper) > adjustment.page_size) { + this.fullScrollView = adjustment.page_size; + } else if (adjustment.page_size < this.fullScrollView) { + this.fullScrollView = 0; + } + + if (initial != this.fullScrollView) { + this._getAppIcons().forEach(a => a.updateTitleStyle()); + } + } + }, + + _onDragBegin: function() { + this._dragCancelled = false; + this._dragMonitor = { + dragMotion: Lang.bind(this, this._onDragMotion) + }; + DND.addDragMonitor(this._dragMonitor); + + if (this._box.get_n_children() == 0) { + this._emptyDropTarget = new Dash.EmptyDropTargetItem(); + this._box.insert_child_at_index(this._emptyDropTarget, 0); + this._emptyDropTarget.show(true); + } + + this._toggleFavortieHighlight(true); + }, + + _onDragCancelled: function() { + this._dragCancelled = true; + + if (this._dragInfo) { + this._box.set_child_at_index(this._dragInfo[1]._dashItemContainer, this._dragInfo[0]); + } + + this._endDrag(); + }, + + _onDragEnd: function() { + if (this._dragCancelled) + return; + + this._endDrag(); + }, + + _endDrag: function() { + if (this._dragInfo && this._dragInfo[1]._dashItemContainer instanceof DragPlaceholderItem) { + this._box.remove_child(this._dragInfo[1]._dashItemContainer); + this._dragInfo[1]._dashItemContainer.destroy(); + delete this._dragInfo[1]._dashItemContainer; + } + + this._dragInfo = null; + this._clearEmptyDropTarget(); + this._showAppsIcon.setDragApp(null); + DND.removeDragMonitor(this._dragMonitor); + + this._toggleFavortieHighlight(); + }, + + _onDragMotion: function(dragEvent) { + let app = Dash.getAppFromSource(dragEvent.source); + if (app == null) + return DND.DragMotionResult.CONTINUE; + + let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor); + + if (showAppsHovered) + this._showAppsIcon.setDragApp(app); + else + this._showAppsIcon.setDragApp(null); + + return DND.DragMotionResult.CONTINUE; + }, + + _toggleFavortieHighlight: function(show) { + let appFavorites = AppFavorites.getAppFavorites(); + let cssFuncName = (show ? 'add' : 'remove') + '_style_class_name'; + + this._getAppIcons().filter(appIcon => appFavorites.isFavorite(appIcon.app.get_id())) + .forEach(fav => fav._container[cssFuncName]('favorite')); + }, + + handleIsolatedWorkspaceSwitch: function() { + this._shownInitially = this.isGroupApps; + this._queueRedisplay(); + }, + + _connectWorkspaceSignals: function() { + this._disconnectWorkspaceSignals(); + + this._lastWorkspace = Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + + this._workspaceWindowAddedId = this._lastWorkspace.connect('window-added', () => this._queueRedisplay()); + this._workspaceWindowRemovedId = this._lastWorkspace.connect('window-removed', () => this._queueRedisplay()); + }, + + _disconnectWorkspaceSignals: function() { + if (this._lastWorkspace) { + this._lastWorkspace.disconnect(this._workspaceWindowAddedId); + this._lastWorkspace.disconnect(this._workspaceWindowRemovedId); + + this._lastWorkspace = null; + } + }, + + _queueRedisplay: function () { + Main.queueDeferredWork(this._workId); + }, + + _hookUpLabel: function(item, syncHandler) { + item.child.connect('notify::hover', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + + syncHandler.connect('sync-tooltip', Lang.bind(this, function() { + this._syncLabel(item, syncHandler); + })); + }, + + _createAppItem: function(app, window, isLauncher) { + let appIcon = new AppIcons.taskbarAppIcon( + { + app: app, + window: window, + isLauncher: isLauncher + }, + this.dtpPanel, + { + setSizeManually: true, + showLabel: false, + isDraggable: !Me.settings.get_boolean('taskbar-locked'), + }, + this.previewMenu, + this.iconAnimator + ); + + if (appIcon._draggable) { + appIcon._draggable.connect('drag-begin', + Lang.bind(this, function() { + appIcon.actor.opacity = 0; + appIcon.isDragged = 1; + this._dropIconAnimations(); + })); + appIcon._draggable.connect('drag-end', + Lang.bind(this, function() { + appIcon.actor.opacity = 255; + delete appIcon.isDragged; + this._updateAppIcons(); + })); + } + + appIcon.connect('menu-state-changed', + Lang.bind(this, function(appIcon, opened) { + this._itemMenuStateChanged(item, opened); + })); + + let item = new TaskbarItemContainer(); + + item._dtpPanel = this.dtpPanel + extendDashItemContainer(item); + + item.setChild(appIcon.actor); + appIcon._dashItemContainer = item; + + appIcon.actor.connect('notify::hover', Lang.bind(this, function() { + if (appIcon.actor.hover){ + this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ + Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize); + this._ensureAppIconVisibilityTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(1); + else if (!appIcon.isDragged && (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK')) + this._updateIconAnimations(); + } else { + if (this._ensureAppIconVisibilityTimeoutId>0) { + Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId); + this._ensureAppIconVisibilityTimeoutId = 0; + } + + if (!appIcon.isDragged && iconAnimationSettings.type == 'SIMPLE') + appIcon.actor.get_parent().raise(0); + } + })); + + appIcon.actor.connect('clicked', + Lang.bind(this, function(actor) { + Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + })); + + appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { + let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); + + // This signal is triggered also by mouse click. The popup menu is opened at the original + // coordinates. Thus correct for the shift which is going to be applied to the scrollview. + if (appIcon._menu) { + appIcon._menu._boxPointer.xOffset = -x_shift; + appIcon._menu._boxPointer.yOffset = -y_shift; + } + })); + + // Override default AppIcon label_actor, now the + // accessible_name is set at DashItemContainer.setLabelText + appIcon.actor.label_actor = null; + item.setLabelText(app.get_name()); + + appIcon.icon.setIconSize(this.iconSize); + this._hookUpLabel(item, appIcon); + + return item; + }, + + // Return an array with the "proper" appIcons currently in the taskbar + _getAppIcons: function() { + // Only consider children which are "proper" icons and which are not + // animating out (which means they will be destroyed at the end of + // the animation) + return this._getTaskbarIcons().map(function(actor){ + return actor.child._delegate; + }); + }, + + _getTaskbarIcons: function(includeAnimated) { + return this._box.get_children().filter(function(actor) { + return actor.child && + actor.child._delegate && + actor.child._delegate.icon && + (includeAnimated || !actor.animatingOut); + }); + }, + + _updateAppIcons: function() { + let appIcons = this._getAppIcons(); + + appIcons.filter(icon => icon.constructor === AppIcons.taskbarAppIcon).forEach(icon => { + icon.updateIcon(); + }); + }, + + _itemMenuStateChanged: function(item, opened) { + // When the menu closes, it calls sync_hover, which means + // that the notify::hover handler does everything we need to. + if (opened) { + if (this._showLabelTimeoutId > 0) { + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + } + + item.hideLabel(); + } else { + // I want to listen from outside when a menu is closed. I used to + // add a custom signal to the appIcon, since gnome 3.8 the signal + // calling this callback was added upstream. + this.emit('menu-closed'); + + // The icon menu grabs the events and, once it is closed, the pointer is maybe + // no longer over the taskbar and the animations are not dropped. + if (iconAnimationSettings.type == 'RIPPLE' || iconAnimationSettings.type == 'PLANK') { + this._scrollView.sync_hover(); + if (!this._scrollView.hover) + this._dropIconAnimations(); + } + } + }, + + _syncLabel: function (item, syncHandler) { + let shouldShow = syncHandler ? syncHandler.shouldShowTooltip() : item.child.get_hover(); + + if (shouldShow) { + if (this._showLabelTimeoutId == 0) { + let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; + this._showLabelTimeoutId = Mainloop.timeout_add(timeout, + Lang.bind(this, function() { + this._labelShowing = true; + item.showLabel(); + this._showLabelTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); + if (this._resetHoverTimeoutId > 0) { + Mainloop.source_remove(this._resetHoverTimeoutId); + this._resetHoverTimeoutId = 0; + } + } + } else { + if (this._showLabelTimeoutId > 0) + Mainloop.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + item.hideLabel(); + if (this._labelShowing) { + this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, + Lang.bind(this, function() { + this._labelShowing = false; + this._resetHoverTimeoutId = 0; + return GLib.SOURCE_REMOVE; + })); + GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing'); + } + } + }, + + _adjustIconSize: function() { + const thisMonitorIndex = this.dtpPanel.monitor.index; + let panelSize = PanelSettings.getPanelSize(Me.settings, thisMonitorIndex); + let availSize = panelSize - Me.settings.get_int('appicon-padding') * 2; + let minIconSize = MIN_ICON_SIZE + panelSize % 2; + + if (availSize == this.iconSize) + return; + + if (availSize < minIconSize) { + availSize = minIconSize; + } + + // For the icon size, we only consider children which are "proper" + // icons and which are not animating out (which means they will be + // destroyed at the end of the animation) + let iconChildren = this._getTaskbarIcons().concat([this._showAppsIcon]); + let scale = this.iconSize / availSize; + + this.iconSize = availSize; + + for (let i = 0; i < iconChildren.length; i++) { + let icon = iconChildren[i].child._delegate.icon; + + // Set the new size immediately, to keep the icons' sizes + // in sync with this.iconSize + icon.setIconSize(this.iconSize); + + // Don't animate the icon size change when the overview + // is transitioning, or when initially filling + // the taskbar + if (Main.overview.animationInProgress || + !this._shownInitially) + continue; + + let [targetWidth, targetHeight] = icon.icon.get_size(); + + // Scale the icon's texture to the previous size and + // tween to the new size + icon.icon.set_size(icon.icon.width * scale, icon.icon.height * scale); + + Utils.animate(icon.icon, + { width: targetWidth, + height: targetHeight, + time: DASH_ANIMATION_TIME, + transition: 'easeOutQuad', + }); + } + }, + + sortAppsCompareFunction: function(appA, appB) { + return getAppStableSequence(appA, this.dtpPanel.monitor) - + getAppStableSequence(appB, this.dtpPanel.monitor); + }, + + getAppInfos: function() { + //get the user's favorite apps + let favoriteApps = this._checkIfShowingFavorites() ? AppFavorites.getAppFavorites().getFavorites() : []; + + //find the apps that should be in the taskbar: the favorites first, then add the running apps + // When using isolation, we filter out apps that have no windows in + // the current workspace (this check is done in AppIcons.getInterestingWindows) + let runningApps = this._checkIfShowingRunningApps() ? this._getRunningApps().sort(this.sortAppsCompareFunction.bind(this)) : []; + + if (!this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers')) { + return this._createAppInfos(favoriteApps, [], true) + .concat(this._createAppInfos(runningApps) + .filter(appInfo => appInfo.windows.length)); + } else { + return this._createAppInfos(favoriteApps.concat(runningApps.filter(app => favoriteApps.indexOf(app) < 0))) + .filter(appInfo => appInfo.windows.length || favoriteApps.indexOf(appInfo.app) >= 0); + } + }, + + _redisplay: function () { + if (!this._signalsHandler) { + return; + } + + //get the currently displayed appIcons + let currentAppIcons = this._getTaskbarIcons(); + let expectedAppInfos = this.getAppInfos(); + + //remove the appIcons which are not in the expected apps list + for (let i = currentAppIcons.length - 1; i > -1; --i) { + let appIcon = currentAppIcons[i].child._delegate; + let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app && + appInfo.isLauncher == appIcon.isLauncher); + + if (appIndex < 0 || + (appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) || + (!appIcon.window && !appIcon.isLauncher && + !this.isGroupApps && expectedAppInfos[appIndex].windows.length)) { + currentAppIcons[i][this._shownInitially ? 'animateOutAndDestroy' : 'destroy'](); + currentAppIcons.splice(i, 1); + } + } + + //if needed, reorder the existing appIcons and create the missing ones + let currentPosition = 0; + for (let i = 0, l = expectedAppInfos.length; i < l; ++i) { + let neededAppIcons = this.isGroupApps || !expectedAppInfos[i].windows.length ? + [{ app: expectedAppInfos[i].app, window: null, isLauncher: expectedAppInfos[i].isLauncher }] : + expectedAppInfos[i].windows.map(window => ({ app: expectedAppInfos[i].app, window: window, isLauncher: false })); + + for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) { + //check if the icon already exists + let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app && + appIcon.child._delegate.window == neededAppIcons[j].window); + + if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) { + //moved icon, reposition it + this._box.remove_child(currentAppIcons[matchingAppIconIndex]); + this._box.insert_child_at_index(currentAppIcons[matchingAppIconIndex], currentPosition); + } else if (matchingAppIconIndex < 0) { + //the icon doesn't exist yet, create a new one + let newAppIcon = this._createAppItem(neededAppIcons[j].app, neededAppIcons[j].window, neededAppIcons[j].isLauncher); + + this._box.insert_child_at_index(newAppIcon, currentPosition); + currentAppIcons.splice(currentPosition, 0, newAppIcon); + + // Skip animations on first run when adding the initial set + // of items, to avoid all items zooming in at once + newAppIcon.show(this._shownInitially); + } + + ++currentPosition; + } + } + + this._adjustIconSize(); + + // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 + // Without it, StBoxLayout may use a stale size cache + this._box.queue_relayout(); + + // This is required for icon reordering when the scrollview is used. + this._updateAppIcons(); + + // This will update the size, and the corresponding number for each icon on the primary panel + if (this.dtpPanel.isPrimary) { + this._updateNumberOverlay(); + } + + this._shownInitially = true; + }, + + _checkIfShowingRunningApps: function() { + return Me.settings.get_boolean('show-running-apps'); + }, + + _checkIfShowingFavorites: function() { + return Me.settings.get_boolean('show-favorites') && + (this.dtpPanel.isPrimary || Me.settings.get_boolean('show-favorites-all-monitors')); + }, + + _getRunningApps: function() { + let tracker = Shell.WindowTracker.get_default(); + let windows = global.get_window_actors(); + let apps = []; + + for (let i = 0, l = windows.length; i < l; ++i) { + let app = tracker.get_window_app(windows[i].metaWindow); + + if (app && apps.indexOf(app) < 0) { + apps.push(app); + } + } + + return apps; + }, + + _createAppInfos: function(apps, defaultWindows, defaultIsLauncher) { + return apps.map(app => ({ + app: app, + isLauncher: defaultIsLauncher || false, + windows: defaultWindows || AppIcons.getInterestingWindows(app, this.dtpPanel.monitor) + .sort(sortWindowsCompareFunction) + })); + }, + + // Reset the displayed apps icon to mantain the correct order + resetAppIcons : function(geometryChange) { + let children = this._getTaskbarIcons(true); + + for (let i = 0; i < children.length; i++) { + let item = children[i]; + item.destroy(); + } + + // to avoid ugly animations, just suppress them like when taskbar is first loaded. + this._shownInitially = false; + this._redisplay(); + + if (geometryChange && this.dtpPanel.checkIfVertical()) { + this.previewMenu._updateClip(); + } + }, + + _updateNumberOverlay: function() { + let seenApps = {}; + let counter = 0; + + this._getAppIcons().forEach(function(icon) { + if (!seenApps[icon.app]) { + seenApps[icon.app] = 1; + counter++; + } + + if (counter <= 10) { + icon.setNumberOverlay(counter == 10 ? 0 : counter); + } else { + // No overlay after 10 + icon.setNumberOverlay(-1); + } + + icon.updateHotkeyNumberOverlay(); + }); + + if (Me.settings.get_boolean('hot-keys') && + Me.settings.get_string('hotkeys-overlay-combo') === 'ALWAYS') + this.toggleNumberOverlay(true); + }, + + toggleNumberOverlay: function(activate) { + let appIcons = this._getAppIcons(); + appIcons.forEach(function(icon) { + icon.toggleNumberOverlay(activate); + }); + }, + + _clearEmptyDropTarget: function() { + if (this._emptyDropTarget) { + this._emptyDropTarget.animateOutAndDestroy(); + this._emptyDropTarget = null; + } + }, + + handleDragOver: function(source, actor, x, y, time) { + if (source == Main.xdndHandler) + return DND.DragMotionResult.CONTINUE; + + // Don't allow favoriting of transient apps + if (source.app == null || source.app.is_window_backed()) + return DND.DragMotionResult.NO_DROP; + + if (!this._settings.is_writable('favorite-apps')) + return DND.DragMotionResult.NO_DROP; + + let sourceActor = source instanceof St.Widget ? source : source.actor; + let isVertical = this.dtpPanel.checkIfVertical(); + + if (!this._box.contains(sourceActor) && !source._dashItemContainer) { + //not an appIcon of the taskbar, probably from the applications view + source._dashItemContainer = new DragPlaceholderItem(source, this.iconSize, isVertical); + this._box.insert_child_above(source._dashItemContainer, null); + } + + let sizeProp = isVertical ? 'height' : 'width'; + let posProp = isVertical ? 'y' : 'x'; + let pos = isVertical ? y : x; + + let currentAppIcons = this._getAppIcons(); + let sourceIndex = currentAppIcons.indexOf(source); + let hoveredIndex = Utils.findIndex(currentAppIcons, + appIcon => pos >= appIcon._dashItemContainer[posProp] && + pos <= (appIcon._dashItemContainer[posProp] + appIcon._dashItemContainer[sizeProp])); + + if (!this._dragInfo) { + this._dragInfo = [sourceIndex, source]; + } + + if (hoveredIndex >= 0) { + let isLeft = pos < currentAppIcons[hoveredIndex]._dashItemContainer[posProp] + currentAppIcons[hoveredIndex]._dashItemContainer[sizeProp] * .5; + + // Don't allow positioning before or after self and between icons of same app + if (!(hoveredIndex === sourceIndex || + (isLeft && hoveredIndex - 1 == sourceIndex) || + (isLeft && hoveredIndex - 1 >= 0 && source.app != currentAppIcons[hoveredIndex - 1].app && + currentAppIcons[hoveredIndex - 1].app == currentAppIcons[hoveredIndex].app) || + (!isLeft && hoveredIndex + 1 == sourceIndex) || + (!isLeft && hoveredIndex + 1 < currentAppIcons.length && source.app != currentAppIcons[hoveredIndex + 1].app && + currentAppIcons[hoveredIndex + 1].app == currentAppIcons[hoveredIndex].app))) { + this._box.set_child_at_index(source._dashItemContainer, hoveredIndex); + + // Ensure the next and previous icon are visible when moving the icon + // (I assume there's room for both of them) + if (hoveredIndex > 1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize); + if (hoveredIndex < this._box.get_children().length-1) + Utils.ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize); + } + } + + return this._dragInfo[0] !== sourceIndex ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.CONTINUE; + }, + + // Draggable target interface + acceptDrop : function(source, actor, x, y, time) { + // Don't allow favoriting of transient apps + if (!source.app || source.app.is_window_backed() || !this._settings.is_writable('favorite-apps')) { + return false; + } + + let appIcons = this._getAppIcons(); + let sourceIndex = appIcons.indexOf(source); + let usingLaunchers = !this.isGroupApps && Me.settings.get_boolean('group-apps-use-launchers'); + + // dragging the icon to its original position + if (this._dragInfo[0] === sourceIndex) { + return true; + } + + let appFavorites = AppFavorites.getAppFavorites(); + let sourceAppId = source.app.get_id(); + let appIsFavorite = appFavorites.isFavorite(sourceAppId); + let replacingIndex = sourceIndex + (sourceIndex > this._dragInfo[0] ? -1 : 1); + let favoriteIndex = replacingIndex >= 0 ? appFavorites.getFavorites().indexOf(appIcons[replacingIndex].app) : 0; + let sameApps = appIcons.filter(a => a != source && a.app == source.app); + let showingFavorites = this._checkIfShowingFavorites(); + let favoritesCount = 0; + let position = 0; + let interestingWindows = {}; + let getAppWindows = app => { + if (!interestingWindows[app]) { + interestingWindows[app] = AppIcons.getInterestingWindows(app, this.dtpPanel.monitor); + } + + let appWindows = interestingWindows[app]; //prevents "reference to undefined property Symbol.toPrimitive" warning + return appWindows; + }; + + if (sameApps.length && + ((!appIcons[sourceIndex - 1] || appIcons[sourceIndex - 1].app !== source.app) && + (!appIcons[sourceIndex + 1] || appIcons[sourceIndex + 1].app !== source.app))) { + appIcons.splice(appIcons.indexOf(sameApps[0]), sameApps.length); + Array.prototype.splice.apply(appIcons, [sourceIndex + 1, 0].concat(sameApps)); + } + + for (let i = 0, l = appIcons.length; i < l; ++i) { + let windows = []; + + if (!usingLaunchers || (!source.isLauncher && !appIcons[i].isLauncher)) { + windows = appIcons[i].window ? [appIcons[i].window] : getAppWindows(appIcons[i].app); + } + + windows.forEach(w => w._dtpPosition = position++); + + if (showingFavorites && + ((usingLaunchers && appIcons[i].isLauncher) || + (!usingLaunchers && appFavorites.isFavorite(appIcons[i].app.get_id())))) { + ++favoritesCount; + } + } + + if (sourceIndex < favoritesCount) { + if (appIsFavorite) { + appFavorites.moveFavoriteToPos(sourceAppId, favoriteIndex); + } else { + appFavorites.addFavoriteAtPos(sourceAppId, favoriteIndex); + } + } else if (appIsFavorite && showingFavorites && (!usingLaunchers || source.isLauncher)) { + appFavorites.removeFavorite(sourceAppId); + } + + appFavorites.emit('changed'); + + return true; + }, + + _onShowAppsButtonToggled: function() { + // Sync the status of the default appButtons. Only if the two statuses are + // different, that means the user interacted with the extension provided + // application button, cutomize the behaviour. Otherwise the shell has changed the + // status (due to the _syncShowAppsButtonToggled function below) and it + // has already performed the desired action. + let selector = SearchController; + + if (selector._showAppsButton && + selector._showAppsButton.checked !== this.showAppsButton.checked) { + // find visible view + + if (this.showAppsButton.checked) { + if (Me.settings.get_boolean('show-apps-override-escape')) { + //override escape key to return to the desktop when entering the overview using the showapps button + SearchController._onStageKeyPress = function(actor, event) { + if (Main.modalCount == 1 && event.get_key_symbol() === Clutter.KEY_Escape) { + this._searchActive ? this.reset() : Main.overview.hide(); + + return Clutter.EVENT_STOP; + } + + return this.__proto__._onStageKeyPress.call(this, actor, event); + }; + } + + // force spring animation triggering.By default the animation only + // runs if we are already inside the overview. + if (!Main.overview._shown) { + this.forcedOverview = true; + let grid = AppDisplay._grid; + let onShownCb; + let overviewSignal = Config.PACKAGE_VERSION > '3.38.1' ? 'showing' : 'shown'; + let overviewShowingId = Main.overview.connect(overviewSignal, () => { + Main.overview.disconnect(overviewShowingId); + onShownCb(); + }); + + onShownCb = () => grid.emit('animation-done'); + } + + //temporarily use as primary the monitor on which the showapps btn was clicked, this is + //restored by the panel when exiting the overview + this.dtpPanel.panelManager.setFocusedMonitor(this.dtpPanel.monitor); + + let overviewHiddenId = Main.overview.connect('hidden', () => { + Main.overview.disconnect(overviewHiddenId); + delete SearchController._onStageKeyPress; + }); + + // Finally show the overview + selector._showAppsButton.checked = true; + Main.overview.show(2 /*APP_GRID*/); + } + else { + if (this.forcedOverview) { + // force exiting overview if needed + + Main.overview.hide(); + this.forcedOverview = false; + } + else { + selector._showAppsButton.checked = false; + this.forcedOverview = false; + } + } + } + }, + + _syncShowAppsButtonToggled: function() { + let status = SearchController._showAppsButton.checked; + if (this.showAppsButton.checked !== status) + this.showAppsButton.checked = status; + }, + + showShowAppsButton: function() { + this.showAppsButton.visible = true; + this.showAppsButton.set_width(-1); + this.showAppsButton.set_height(-1); + }, + + popupFocusedAppSecondaryMenu: function() { + let appIcons = this._getAppIcons(); + let tracker = Shell.WindowTracker.get_default(); + + for(let i in appIcons) { + if(appIcons[i].app == tracker.focus_app) { + let appIcon = appIcons[i]; + if(appIcon._menu && appIcon._menu.isOpen) + appIcon._menu.close(); + else + appIcon.popupMenu(); + + appIcon.sync_hover(); + break; + } + } + }, +}); + +Signals.addSignalMethods(taskbar.prototype); + +const CloneContainerConstraint = Utils.defineClass({ + Name: 'DashToPanel-CloneContainerConstraint', + Extends: Clutter.BindConstraint, + + vfunc_update_allocation: function(actor, actorBox) { + if (!this.source) + return; + + let [stageX, stageY] = this.source.get_transformed_position(); + let [width, height] = this.source.get_transformed_size(); + + actorBox.set_origin(stageX, stageY); + actorBox.set_size(width, height); + }, +}); + +var TaskbarItemContainer = Utils.defineClass({ + Name: 'DashToPanel-TaskbarItemContainer', + Extends: Dash.DashItemContainer, + + vfunc_allocate: function(box, flags) { + if (this.child == null) + return; + + Utils.setAllocation(this, box, flags); + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; + let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = this.child.get_preferred_size(); + let [childScaleX, childScaleY] = this.child.get_scale(); + + let childWidth = Math.min(natChildWidth * childScaleX, availWidth); + let childHeight = Math.min(natChildHeight * childScaleY, availHeight); + let childBox = new Clutter.ActorBox(); + + childBox.x1 = (availWidth - childWidth) / 2; + childBox.y1 = (availHeight - childHeight) / 2; + childBox.x2 = childBox.x1 + childWidth; + childBox.y2 = childBox.y1 + childHeight; + + Utils.allocate(this.child, childBox, flags); + }, + + // In case appIcon is removed from the taskbar while it is hovered, + // restore opacity before dashItemContainer.animateOutAndDestroy does the destroy animation. + animateOutAndDestroy: function() { + if (this._raisedClone) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + } + + this.callParent('animateOutAndDestroy'); + }, + + // For ItemShowLabel + _getIconAnimationOffset: function() { + if (!Me.settings.get_boolean('animate-appicon-hover')) + return 0; + + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + return this._dtpPanel.dtpSize * (travel + (zoom - 1) / 2); + }, + + _updateCloneContainerPosition: function(cloneContainer) { + let [stageX, stageY] = this.get_transformed_position(); + + if (Config.PACKAGE_VERSION >= '3.36') + cloneContainer.set_position(stageX - this.translation_x, stageY - this.translation_y); + else + cloneContainer.set_position(stageX, stageY); + }, + + _createRaisedClone: function() { + let [width, height] = this.get_transformed_size(); + + // "clone" of this child (appIcon actor) + let cloneButton = this.child._delegate.getCloneButton(); + + // "clone" of this (taskbarItemContainer) + let cloneContainer = new St.Bin({ + child: cloneButton, + width: width, height: height, + reactive: false, + }); + + this._updateCloneContainerPosition(cloneContainer); + + // For the stretch animation + if (Config.PACKAGE_VERSION >= '3.36') { + let boundProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + this.bind_property(boundProperty, cloneContainer, boundProperty, GObject.BindingFlags.SYNC_CREATE); + } else { + let constraint = new CloneContainerConstraint({ source: this }); + cloneContainer.add_constraint(constraint); + } + + // The clone follows its source when the taskbar is scrolled. + let taskbarScrollView = this.get_parent().get_parent(); + let adjustment = this._dtpPanel.checkIfVertical() ? taskbarScrollView.vscroll.get_adjustment() : taskbarScrollView.hscroll.get_adjustment(); + let adjustmentChangedId = adjustment.connect('notify::value', () => this._updateCloneContainerPosition(cloneContainer)); + + // Update clone position when an item is added to / removed from the taskbar. + let taskbarBox = this.get_parent(); + let taskbarBoxAllocationChangedId = taskbarBox.connect('notify::allocation', () => this._updateCloneContainerPosition(cloneContainer)); + + // The clone itself + this._raisedClone = cloneButton.child; + this._raisedClone.connect('destroy', () => { + adjustment.disconnect(adjustmentChangedId); + taskbarBox.disconnect(taskbarBoxAllocationChangedId); + Mainloop.idle_add(() => cloneContainer.destroy()); + delete this._raisedClone; + }); + + this._raisedClone.source.opacity = 0; + Main.uiGroup.add_actor(cloneContainer); + }, + + // Animate the clone. + // AppIcon actors cannot go outside the taskbar so the animation is done with a clone. + // If level is zero, the clone is dropped and destroyed. + raise: function(level) { + if (this._raisedClone) + Utils.stopAnimations(this._raisedClone); + else if (level) + this._createRaisedClone(); + else + return; + + let panelPosition = this._dtpPanel.getPosition(); + let panelElementPositions = this._dtpPanel.panelManager.panelsElementPositions[this._dtpPanel.monitor.index] || Pos.defaults; + let taskbarPosition = panelElementPositions.filter(pos => pos.element == 'taskbar')[0].position; + + let vertical = panelPosition == St.Side.LEFT || panelPosition == St.Side.RIGHT; + let translationDirection = panelPosition == St.Side.TOP || panelPosition == St.Side.LEFT ? 1 : -1; + let rotationDirection; + if (panelPosition == St.Side.LEFT || taskbarPosition == Pos.STACKED_TL) + rotationDirection = -1; + else if (panelPosition == St.Side.RIGHT || taskbarPosition == Pos.STACKED_BR) + rotationDirection = 1; + else { + let items = this.get_parent().get_children(); + let index = items.indexOf(this); + rotationDirection = (index - (items.length - 1) / 2) / ((items.length - 1) / 2); + } + + let duration = iconAnimationSettings.duration / 1000; + let rotation = iconAnimationSettings.rotation; + let travel = iconAnimationSettings.travel; + let zoom = iconAnimationSettings.zoom; + + // level is about 1 for the icon that is hovered, less for others. + // time depends on the translation to do. + let [width, height] = this._raisedClone.source.get_transformed_size(); + let translationMax = (vertical ? width : height) * (travel + (zoom - 1) / 2); + let translationEnd = translationMax * level; + let translationDone = vertical ? this._raisedClone.translation_x : this._raisedClone.translation_y; + let translationTodo = Math.abs(translationEnd - translationDone); + let scale = 1 + (zoom - 1) * level; + let rotationAngleZ = rotationDirection * rotation * level; + let time = duration * translationTodo / translationMax; + + let options = { + scale_x: scale, scale_y: scale, + rotation_angle_z: rotationAngleZ, + time: time, + transition: 'easeOutQuad', + onComplete: () => { + if (!level) { + this._raisedClone.source.opacity = 255; + this._raisedClone.destroy(); + delete this._raisedClone; + } + }, + }; + options[vertical ? 'translation_x' : 'translation_y'] = translationDirection * translationEnd; + + Utils.animate(this._raisedClone, options); + }, + + // Animate this and cloneContainer, since cloneContainer translation is bound to this. + stretch: function(translation) { + let duration = iconAnimationSettings.duration / 1000; + let zoom = iconAnimationSettings.zoom; + let animatedProperty = this._dtpPanel.checkIfVertical() ? 'translation_y' : 'translation_x'; + let isShowing = this.opacity != 255 || this.child.opacity != 255; + + if (isShowing) { + // Do no stop the animation initiated in DashItemContainer.show. + this[animatedProperty] = zoom * translation; + } else { + let options = { + time: duration, + transition: 'easeOutQuad', + }; + options[animatedProperty] = zoom * translation; + + Utils.stopAnimations(this); + Utils.animate(this, options); + } + }, +}); + +var DragPlaceholderItem = Utils.defineClass({ + Name: 'DashToPanel-DragPlaceholderItem', + Extends: St.Widget, + + _init: function(appIcon, iconSize, isVertical) { + this.callParent('_init', { style: AppIcons.getIconContainerStyle(isVertical), layout_manager: new Clutter.BinLayout() }); + + this.child = { _delegate: appIcon }; + + this._clone = new Clutter.Clone({ + source: appIcon.icon._iconBin, + width: iconSize, + height: iconSize + }); + + this.add_actor(this._clone); + }, + + destroy: function() { + this._clone.destroy(); + this.callParent('destroy'); + }, +}); + +function getAppStableSequence(app, monitor) { + let windows = AppIcons.getInterestingWindows(app, monitor); + + return windows.reduce((prevWindow, window) => { + return Math.min(prevWindow, getWindowStableSequence(window)); + }, Infinity); +} + +function sortWindowsCompareFunction(windowA, windowB) { + return getWindowStableSequence(windowA) - getWindowStableSequence(windowB); +} + +function getWindowStableSequence(window) { + return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence()); +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js new file mode 100644 index 0000000..aa86d7a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/transparency.js @@ -0,0 +1,269 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Lang = imports.lang; +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const St = imports.gi.St; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Proximity = Me.imports.proximity; +const Utils = Me.imports.utils; + +var DynamicTransparency = Utils.defineClass({ + Name: 'DashToPanel.DynamicTransparency', + + _init: function(dtpPanel) { + this._dtpPanel = dtpPanel; + this._proximityManager = dtpPanel.panelManager.proximityManager; + this._proximityWatchId = 0; + this._windowOverlap = false; + this.currentBackgroundColor = 0; + + this._initialPanelStyle = dtpPanel.panel.actor.get_style(); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._initialPanelCornerStyle = dtpPanel.panel._leftCorner.actor.get_style(); + } + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._bindSignals(); + + this._updateAnimationDuration(); + this._updateAllAndSet(); + this._updateProximityWatch(); + }, + + destroy: function() { + this._signalsHandler.destroy(); + this._proximityManager.removeWatch(this._proximityWatchId); + + this._dtpPanel.panel.actor.set_style(this._initialPanelStyle); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(this._initialPanelCornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(this._initialPanelCornerStyle); + } + }, + + updateExternalStyle: function() { + this._updateComplementaryStyles(); + this._setBackground(); + }, + + _bindSignals: function() { + this._signalsHandler.add( + [ + Utils.getStageTheme(), + 'changed', + () => this._updateAllAndSet() + ], + [ + Main.overview, + [ + 'showing', + 'hiding' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-bg', + 'changed::trans-bg-color' + ], + () => this._updateColorAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-opacity', + 'changed::trans-panel-opacity', + 'changed::trans-bg-color', + 'changed::trans-dynamic-anim-target', + 'changed::trans-use-dynamic-opacity' + ], + () => this._updateAlphaAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-use-custom-gradient', + 'changed::trans-gradient-top-color', + 'changed::trans-gradient-bottom-color', + 'changed::trans-gradient-top-opacity', + 'changed::trans-gradient-bottom-opacity' + ], + () => this._updateGradientAndSet() + ], + [ + Me.settings, + [ + 'changed::trans-dynamic-behavior', + 'changed::trans-use-dynamic-opacity', + 'changed::trans-dynamic-distance' + ], + () => this._updateProximityWatch() + ], + [ + Me.settings, + 'changed::trans-dynamic-anim-time', + () => this._updateAnimationDuration() + ] + ); + }, + + _updateProximityWatch: function() { + this._proximityManager.removeWatch(this._proximityWatchId); + + if (Me.settings.get_boolean('trans-use-dynamic-opacity')) { + let isVertical = this._dtpPanel.checkIfVertical(); + let threshold = Me.settings.get_int('trans-dynamic-distance'); + + this._proximityWatchId = this._proximityManager.createWatch( + this._dtpPanel.panelBox.get_parent(), + Proximity.Mode[Me.settings.get_string('trans-dynamic-behavior')], + isVertical ? threshold : 0, + isVertical ? 0 : threshold, + overlap => { + this._windowOverlap = overlap; + this._updateAlphaAndSet(); + } + ); + } + }, + + _updateAnimationDuration: function() { + this.animationDuration = (Me.settings.get_int('trans-dynamic-anim-time') * 0.001) + 's;'; + }, + + _updateAllAndSet: function() { + let themeBackground = this._getThemeBackground(true); + + this._updateColor(themeBackground); + this._updateAlpha(themeBackground); + this._updateComplementaryStyles(); + this._updateGradient(); + this._setBackground(); + this._setGradient(); + }, + + _updateColorAndSet: function() { + this._updateColor(); + this._setBackground(); + }, + + _updateAlphaAndSet: function() { + this._updateAlpha(); + this._setBackground(); + }, + + _updateGradientAndSet: function() { + this._updateGradient(); + this._setGradient(); + }, + + _updateComplementaryStyles: function() { + let panelThemeNode = this._dtpPanel.panel.actor.get_theme_node(); + + this._complementaryStyles = 'border-radius: ' + panelThemeNode.get_border_radius(0) + 'px;'; + }, + + _updateColor: function(themeBackground) { + this.backgroundColorRgb = Me.settings.get_boolean('trans-use-custom-bg') ? + Me.settings.get_string('trans-bg-color') : + (themeBackground || this._getThemeBackground()); + }, + + _updateAlpha: function(themeBackground) { + if (this._windowOverlap && !Main.overview.visibleTarget && Me.settings.get_boolean('trans-use-dynamic-opacity')) { + this.alpha = Me.settings.get_double('trans-dynamic-anim-target'); + } else { + this.alpha = Me.settings.get_boolean('trans-use-custom-opacity') ? + Me.settings.get_double('trans-panel-opacity') : + (themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569 + } + }, + + _updateGradient: function() { + this._gradientStyle = ''; + + if (Me.settings.get_boolean('trans-use-custom-gradient')) { + this._gradientStyle += 'background-gradient-direction: ' + (this._dtpPanel.checkIfVertical() ? 'horizontal;' : 'vertical;') + + 'background-gradient-start: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-top-color'), + Me.settings.get_double('trans-gradient-top-opacity')) + + 'background-gradient-end: ' + Utils.getrgbaColor(Me.settings.get_string('trans-gradient-bottom-color'), + Me.settings.get_double('trans-gradient-bottom-opacity')); + } + }, + + _setBackground: function() { + this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha); + + let transition = 'transition-duration:' + this.animationDuration; + let cornerStyle = '-panel-corner-background-color: ' + this.currentBackgroundColor + transition; + + this._dtpPanel.set_style('background-color: ' + this.currentBackgroundColor + transition + this._complementaryStyles); + + if (this._dtpPanel.geom.position == St.Side.TOP) { + this._dtpPanel.panel._leftCorner.actor.set_style(cornerStyle); + this._dtpPanel.panel._rightCorner.actor.set_style(cornerStyle); + } + }, + + _setGradient: function() { + this._dtpPanel.panel.actor.set_style( + 'background: none; ' + + 'border-image: none; ' + + 'background-image: none; ' + + this._gradientStyle + + 'transition-duration:' + this.animationDuration + ); + }, + + _getThemeBackground: function(reload) { + if (reload || !this._themeBackground) { + let fakePanel = new St.Bin({ name: 'panel' }); + Main.uiGroup.add_child(fakePanel); + let fakeTheme = fakePanel.get_theme_node() + this._themeBackground = this._getBackgroundImageColor(fakeTheme) || fakeTheme.get_background_color(); + Main.uiGroup.remove_child(fakePanel); + } + + return this._themeBackground; + }, + + _getBackgroundImageColor: function(theme) { + let bg = null; + + try { + let imageFile = theme.get_background_image() || theme.get_border_image().get_file(); + + if (imageFile) { + let imageBuf = GdkPixbuf.Pixbuf.new_from_file(imageFile.get_path()); + let pixels = imageBuf.get_pixels(); + + bg = { red: pixels[0], green: pixels[1], blue: pixels[2], alpha: pixels[3] }; + } + } catch (error) {} + + return bg; + } +}); \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js new file mode 100644 index 0000000..d90d2cc --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/utils.js @@ -0,0 +1,1040 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + * + * + * Credits: + * This file is based on code from the Dash to Dock extension by micheleg + * and code from the Taskbar extension by Zorin OS + * Some code was also adapted from the upstream Gnome Shell source code. + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GdkPixbuf = imports.gi.GdkPixbuf; +const Gi = imports._gi; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const Main = imports.ui.main; +const MessageTray = imports.ui.messageTray; +const Util = imports.misc.util; + +var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain']; +var SCROLL_TIME = Util.SCROLL_TIME / (Util.SCROLL_TIME > 1 ? 1000 : 1); + +//Clutter implicit animations are available since 3.34 +//prefer those over Tweener if available +if (Config.PACKAGE_VERSION < '3.34') { + var Tweener = imports.ui.tweener; +} + +var defineClass = function (classDef) { + let parentProto = classDef.Extends ? classDef.Extends.prototype : null; + + if (Config.PACKAGE_VERSION < '3.31.9') { + if (parentProto && (classDef.Extends.name || classDef.Extends.toString()).indexOf('DashToPanel.') < 0) { + classDef.callParent = function() { + let args = Array.prototype.slice.call(arguments); + let func = args.shift(); + + classDef.Extends.prototype[func].apply(this, args); + }; + } + + return new imports.lang.Class(classDef); + } + + let isGObject = parentProto instanceof GObject.Object; + let needsSuper = parentProto && !isGObject; + let getParentArgs = function(args) { + let parentArgs = []; + + (classDef.ParentConstrParams || parentArgs).forEach(p => { + if (p.constructor === Array) { + let param = args[p[0]]; + + parentArgs.push(p[1] ? param[p[1]] : param); + } else { + parentArgs.push(p); + } + }); + + return parentArgs; + }; + + let C = eval( + '(class C ' + (needsSuper ? 'extends Object' : '') + ' { ' + + ' constructor(...args) { ' + + (needsSuper ? 'super(...getParentArgs(args));' : '') + + (needsSuper || !parentProto ? 'this._init(...args);' : '') + + ' }' + + ' callParent(...args) { ' + + ' let func = args.shift(); ' + + ' if (!(func === \'_init\' && needsSuper))' + + ' super[func](...args); ' + + ' }' + + '})' + ); + + if (parentProto) { + Object.setPrototypeOf(C.prototype, parentProto); + Object.setPrototypeOf(C, classDef.Extends); + } + + Object.defineProperty(C, 'name', { value: classDef.Name }); + Object.keys(classDef) + .filter(k => classDef.hasOwnProperty(k) && classDef[k] instanceof Function) + .forEach(k => C.prototype[k] = classDef[k]); + + if (isGObject) { + C = GObject.registerClass({ Signals: classDef.Signals || {} }, C); + } + + return C; +}; + +// simplify global signals and function injections handling +// abstract class +var BasicHandler = defineClass({ + Name: 'DashToPanel.BasicHandler', + + _init: function(){ + this._storage = new Object(); + }, + + add: function(/*unlimited 3-long array arguments*/){ + + // convert arguments object to array, concatenate with generic + let args = [].concat('generic', [].slice.call(arguments)); + // call addWithLabel with ags as if they were passed arguments + this.addWithLabel.apply(this, args); + }, + + destroy: function() { + for( let label in this._storage ) + this.removeWithLabel(label); + }, + + addWithLabel: function( label /* plus unlimited 3-long array arguments*/) { + + if(this._storage[label] == undefined) + this._storage[label] = new Array(); + + // skip first element of the arguments + for( let i = 1; i < arguments.length; i++ ) { + let item = this._storage[label]; + let handlers = this._create(arguments[i]); + + for (let j = 0, l = handlers.length; j < l; ++j) { + item.push(handlers[j]); + } + } + + }, + + removeWithLabel: function(label){ + + if(this._storage[label]) { + for( let i = 0; i < this._storage[label].length; i++ ) { + this._remove(this._storage[label][i]); + } + + delete this._storage[label]; + } + }, + + /* Virtual methods to be implemented by subclass */ + // create single element to be stored in the storage structure + _create: function(item){ + throw new Error('no implementation of _create in ' + this); + }, + + // correctly delete single element + _remove: function(item){ + throw new Error('no implementation of _remove in ' + this); + } +}); + +// Manage global signals +var GlobalSignalsHandler = defineClass({ + Name: 'DashToPanel.GlobalSignalsHandler', + Extends: BasicHandler, + + _create: function(item) { + let handlers = []; + + item[1] = [].concat(item[1]); + + for (let i = 0, l = item[1].length; i < l; ++i) { + let object = item[0]; + let event = item[1][i]; + let callback = item[2] + try { + let id = object.connect(event, callback); + + handlers.push([object, id]); + } catch (e) + { + + } + } + + return handlers; + }, + + _remove: function(item){ + item[0].disconnect(item[1]); + } +}); + +/** + * Manage function injection: both instances and prototype can be overridden + * and restored + */ +var InjectionsHandler = defineClass({ + Name: 'DashToPanel.InjectionsHandler', + Extends: BasicHandler, + + _create: function(item) { + let object = item[0]; + let name = item[1]; + let injectedFunction = item[2]; + let original = object[name]; + + object[name] = injectedFunction; + return [[object, name, injectedFunction, original]]; + }, + + _remove: function(item) { + let object = item[0]; + let name = item[1]; + let original = item[3]; + object[name] = original; + } +}); + +/** + * Manage timeouts: the added timeouts have their id reset on completion + */ +var TimeoutsHandler = defineClass({ + Name: 'DashToPanel.TimeoutsHandler', + Extends: BasicHandler, + + _create: function(item) { + let name = item[0]; + let delay = item[1]; + let timeoutHandler = item[2]; + + this._remove(item); + + this[name] = Mainloop.timeout_add(delay, () => { + this[name] = 0; + timeoutHandler(); + }); + + return [[name]]; + }, + + remove: function(name) { + this._remove([name]) + }, + + _remove: function(item) { + let name = item[0]; + + if (this[name]) { + Mainloop.source_remove(this[name]); + this[name] = 0; + } + }, + + getId: function(name) { + return this[name] ? this[name] : 0; + } +}); + +// This is wrapper to maintain compatibility with GNOME-Shell 3.30+ as well as +// previous versions. +var DisplayWrapper = { + getScreen: function() { + return global.screen || global.display; + }, + + getWorkspaceManager: function() { + return global.screen || global.workspace_manager; + }, + + getMonitorManager: function() { + return global.screen || Meta.MonitorManager.get(); + } +}; + +var getCurrentWorkspace = function() { + return DisplayWrapper.getWorkspaceManager().get_active_workspace(); +}; + +var getWorkspaceByIndex = function(index) { + return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index); +}; + +var getWorkspaceCount = function() { + return DisplayWrapper.getWorkspaceManager().n_workspaces; +}; + +var getStageTheme = function() { + return St.ThemeContext.get_for_stage(global.stage); +}; + +var getScaleFactor = function() { + return getStageTheme().scale_factor || 1; +}; + +var getAppDisplayViews = function() { + //gnome-shell 3.38 only has one view and it is now the appDisplay + return imports.ui.appDisplay._views || [{ view: imports.ui.appDisplay }]; +}; + +var findIndex = function(array, predicate) { + if (Array.prototype.findIndex) { + return array.findIndex(predicate); + } + + for (let i = 0, l = array.length; i < l; ++i) { + if (predicate(array[i])) { + return i; + } + } + + return -1; +}; + +var find = function(array, predicate) { + let index = findIndex(array, predicate); + + if (index > -1) { + return array[index]; + } +}; + +var mergeObjects = function(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + +var hookVfunc = function(proto, symbol, func) { + if (Gi.hook_up_vfunc_symbol && func) { + //gjs > 1.53.3 + proto[Gi.hook_up_vfunc_symbol](symbol, func); + } else { + //On older gjs, this is how to hook vfunc. It is buggy and can't be used reliably to replace + //already hooked functions. Since it's our only use for it, disabled for now (and probably forever) + //Gi.hook_up_vfunc(proto, symbol, func); + } +}; + +var wrapActor = function(actor) { + if (actor) { + Object.defineProperty(actor, 'actor', { + value: actor instanceof Clutter.Actor ? actor : actor.actor + }); + } +}; + +var getTransformedAllocation = function(actor) { + if (Config.PACKAGE_VERSION < '3.37') { + return Shell.util_get_transformed_allocation(actor); + } + + let extents = actor.get_transformed_extents(); + let topLeft = extents.get_top_left(); + let bottomRight = extents.get_bottom_right(); + + return { x1: topLeft.x, x2: bottomRight.x, y1: topLeft.y, y2: bottomRight.y }; +}; + +var allocate = function(actor, box, flags, useParent) { + let allocateObj = useParent ? actor.__proto__ : actor; + + allocateObj.allocate.apply(actor, getAllocationParams(box, flags)); +}; + +var setAllocation = function(actor, box, flags) { + actor.set_allocation.apply(actor, getAllocationParams(box, flags)); +}; + +var getAllocationParams = function(box, flags) { + let params = [box]; + + if (Config.PACKAGE_VERSION < '3.37') { + params.push(flags); + } + + return params; +}; + +var setClip = function(actor, x, y, width, height) { + actor.set_clip(0, 0, width, height); + actor.set_position(x, y); + actor.set_size(width, height); +}; + +var addKeybinding = function(key, settings, handler, modes) { + if (!Main.wm._allowedKeybindings[key]) { + Main.wm.addKeybinding( + key, + settings, + Meta.KeyBindingFlags.NONE, + modes || (Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW), + handler + ); + } +}; + +var removeKeybinding = function(key) { + if (Main.wm._allowedKeybindings[key]) { + Main.wm.removeKeybinding(key); + } +}; + +var getrgbColor = function(color) { + color = typeof color === 'string' ? Clutter.color_from_string(color)[1] : color; + + return { red: color.red, green: color.green, blue: color.blue }; +}; + +var getrgbaColor = function(color, alpha, offset) { + if (alpha <= 0) { + return 'transparent; '; + } + + let rgb = getrgbColor(color); + + if (offset) { + ['red', 'green', 'blue'].forEach(k => { + rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset)); + + if (rgb[k] == color[k]) { + rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset)); + } + }); + } + + return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; +}; + +var checkIfColorIsBright = function(color) { + let rgb = getrgbColor(color); + let brightness = 0.2126 * rgb.red + 0.7152 * rgb.green + 0.0722 * rgb.blue; + + return brightness > 128; +}; + +var getMouseScrollDirection = function(event) { + let direction; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + case Clutter.ScrollDirection.LEFT: + direction = 'up'; + break; + case Clutter.ScrollDirection.DOWN: + case Clutter.ScrollDirection.RIGHT: + direction = 'down'; + break; + } + + return direction; +}; + +var checkIfWindowHasTransient = function(window) { + let hasTransient; + + window.foreach_transient(t => !(hasTransient = true)); + + return hasTransient; +}; + +var activateSiblingWindow = function(windows, direction, startWindow) { + let windowIndex = windows.indexOf(global.display.focus_window); + let nextWindowIndex = windowIndex < 0 ? + startWindow ? windows.indexOf(startWindow) : 0 : + windowIndex + (direction == 'up' ? 1 : -1); + + if (nextWindowIndex == windows.length) { + nextWindowIndex = 0; + } else if (nextWindowIndex < 0) { + nextWindowIndex = windows.length - 1; + } + + if (windowIndex != nextWindowIndex) { + Main.activateWindow(windows[nextWindowIndex]); + } +}; + +var animateWindowOpacity = function(window, tweenOpts) { + //there currently is a mutter bug with the windowactor opacity, starting with 3.34 + //https://gitlab.gnome.org/GNOME/mutter/issues/836 + + if (Config.PACKAGE_VERSION > '3.35') { + //on 3.36, a workaround is to use the windowactor's child for the fade animation + //this leaves a "shadow" on the desktop, so the windowactor needs to be hidden + //when the animation is complete + let visible = tweenOpts.opacity > 0; + let windowActor = window; + + window = windowActor.get_first_child() || windowActor; + + if (!windowActor.visible && visible) { + window.opacity = 0; + windowActor.visible = visible; + } + + if (!visible) { + let initialOpacity = window.opacity; + + tweenOpts.onComplete = () => { + windowActor.visible = visible; + window.opacity = initialOpacity; + }; + } + } else if (Config.PACKAGE_VERSION > '3.33') { + //the workaround only works on 3.35+, so on 3.34, let's just hide the + //window without animation + return window.visible = (tweenOpts.opacity == 255); + } + + animate(window, tweenOpts); +}; + +var animate = function(actor, options) { + if (Tweener) { + return Tweener.addTween(actor, options); + } + + //to support both Tweener and Clutter animations, we use Tweener "time" + //and "delay" properties defined in seconds, as opposed to Clutter animations + //"duration" and "delay" which are defined in milliseconds + if (options.delay) { + options.delay = options.delay * 1000; + } + + options.duration = options.time * 1000; + delete options.time; + + if (options.transition) { + //map Tweener easing equations to Clutter animation modes + options.mode = { + 'easeInCubic': Clutter.AnimationMode.EASE_IN_CUBIC, + 'easeInOutCubic': Clutter.AnimationMode.EASE_IN_OUT_CUBIC, + 'easeInOutQuad': Clutter.AnimationMode.EASE_IN_OUT_QUAD, + 'easeOutQuad': Clutter.AnimationMode.EASE_OUT_QUAD + }[options.transition] || Clutter.AnimationMode.LINEAR; + + delete options.transition; + } + + let params = [options]; + + if ('value' in options && actor instanceof St.Adjustment) { + params.unshift(options.value); + delete options.value; + } + + actor.ease.apply(actor, params); +} + +var isAnimating = function(actor, prop) { + if (Tweener) { + return Tweener.isTweening(actor); + } + + return !!actor.get_transition(prop); +} + +var stopAnimations = function(actor) { + if (Tweener) { + return Tweener.removeTweens(actor); + } + + actor.remove_all_transitions(); +} + +var getIndicators = function(delegate) { + if (delegate instanceof St.BoxLayout) { + return delegate; + } + + return delegate.indicators; +} + +var getPoint = function(coords) { + if (Config.PACKAGE_VERSION > '3.35.1') { + return new imports.gi.Graphene.Point(coords); + } + + return new Clutter.Point(coords); +} + +var getPanelGhost = function() { + if (!Main.overview._panelGhost) { + return Main.overview._overview.get_first_child(); + } + + return Main.overview._panelGhost; +} + +var notify = function(text, iconName, action, isTransient) { + let source = new MessageTray.SystemNotificationSource(); + let notification = new MessageTray.Notification(source, 'Dash to Panel', text); + let notifyFunc = source.showNotification || source.notify; + + if (iconName) { + source.createIcon = function() { + return new St.Icon({ icon_name: iconName }); + }; + } + + if (action) { + if (!(action instanceof Array)) { + action = [action]; + } + + action.forEach(a => notification.addAction(a.text, a.func)); + } + + Main.messageTray.add(source); + + notification.setTransient(isTransient); + notifyFunc.call(source, notification); +}; + +/* + * This is a copy of the same function in utils.js, but also adjust horizontal scrolling + * and perform few further cheks on the current value to avoid changing the values when + * it would be clamp to the current one in any case. + * Return the amount of shift applied +*/ +var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) { + let vadjustment = scrollView.vscroll.adjustment; + let hadjustment = scrollView.hscroll.adjustment; + let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values(); + let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values(); + + let [hvalue0, vvalue0] = [hvalue, vvalue]; + + let voffset = fadeSize; + let hoffset = fadeSize; + + let box = actor.get_allocation_box(); + let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2; + + let parent = actor.get_parent(); + while (parent != scrollView) { + if (!parent) + throw new Error("actor not in scroll view"); + + let box = parent.get_allocation_box(); + y1 += box.y1; + y2 += box.y1; + x1 += box.x1; + x2 += box.x1; + parent = parent.get_parent(); + } + + if (y1 < vvalue + voffset) + vvalue = Math.max(0, y1 - voffset); + else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset) + vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize); + + if (x1 < hvalue + hoffset) + hvalue = Math.max(0, x1 - hoffset); + else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset) + hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize); + + let tweenOpts = { + time: SCROLL_TIME, + onComplete: onComplete || (() => {}), + transition: 'easeOutQuad' + }; + + if (vvalue !== vvalue0) { + animate(vadjustment, mergeObjects(tweenOpts, { value: vvalue })); + } + + if (hvalue !== hvalue0) { + animate(hadjustment, mergeObjects(tweenOpts, { value: hvalue })); + } + + return [hvalue- hvalue0, vvalue - vvalue0]; +} + +/** + * ColorUtils is adapted from https://github.com/micheleg/dash-to-dock + */ +var ColorUtils = { + colorLuminance: function(r, g, b, dlum) { + // Darken or brighten color by a fraction dlum + // Each rgb value is modified by the same fraction. + // Return "#rrggbb" strin + + let rgbString = '#'; + + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2); + rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2); + + return rgbString; + }, + + _decimalToHex: function(d, padding) { + // Convert decimal to an hexadecimal string adding the desired padding + + let hex = d.toString(16); + while (hex.length < padding) + hex = '0'+ hex; + return hex; + }, + + HSVtoRGB: function(h, s, v) { + // Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (h,s,v) independently or {h:h, s:s, v:v} object. + // Return {r:r, g:g, b:b} object. + + if (arguments.length === 1) { + s = h.s; + v = h.v; + h = h.h; + } + + let r,g,b; + let c = v*s; + let h1 = h*6; + let x = c*(1 - Math.abs(h1 % 2 - 1)); + let m = v - c; + + if (h1 <=1) + r = c + m, g = x + m, b = m; + else if (h1 <=2) + r = x + m, g = c + m, b = m; + else if (h1 <=3) + r = m, g = c + m, b = x + m; + else if (h1 <=4) + r = m, g = x + m, b = c + m; + else if (h1 <=5) + r = x + m, g = m, b = c + m; + else + r = c + m, g = m, b = x + m; + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; + }, + + RGBtoHSV: function(r, g, b) { + // Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]). + // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV + // here with h = [0,1] instead of [0, 360] + // Accept either (r,g,b) independently or {r:r, g:g, b:b} object. + // Return {h:h, s:s, v:v} object. + + if (arguments.length === 1) { + r = r.r; + g = r.g; + b = r.b; + } + + let h,s,v; + + let M = Math.max(r, g, b); + let m = Math.min(r, g, b); + let c = M - m; + + if (c == 0) + h = 0; + else if (M == r) + h = ((g-b)/c) % 6; + else if (M == g) + h = (b-r)/c + 2; + else + h = (r-g)/c + 4; + + h = h/6; + v = M/255; + if (M !== 0) + s = c/M; + else + s = 0; + + return {h: h, s: s, v: v}; + } +}; + +/** + * DominantColorExtractor is adapted from https://github.com/micheleg/dash-to-dock + */ +let themeLoader = null; +let iconCacheMap = new Map(); +const MAX_CACHED_ITEMS = 1000; +const BATCH_SIZE_TO_DELETE = 50; +const DOMINANT_COLOR_ICON_SIZE = 64; + +var DominantColorExtractor = defineClass({ + Name: 'DashToPanel.DominantColorExtractor', + + _init: function(app){ + this._app = app; + }, + + /** + * Try to get the pixel buffer for the current icon, if not fail gracefully + */ + _getIconPixBuf: function() { + let iconTexture = this._app.create_icon_texture(16); + + if (themeLoader === null) { + let ifaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" }); + + themeLoader = new Gtk.IconTheme(), + themeLoader.set_custom_theme(ifaceSettings.get_string('icon-theme')); // Make sure the correct theme is loaded + } + + // Unable to load the icon texture, use fallback + if (iconTexture instanceof St.Icon === false) { + return null; + } + + iconTexture = iconTexture.get_gicon(); + + // Unable to load the icon texture, use fallback + if (iconTexture === null) { + return null; + } + + if (iconTexture instanceof Gio.FileIcon) { + // Use GdkPixBuf to load the pixel buffer from the provided file path + return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path()); + } + + // Get the pixel buffer from the icon theme + let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0); + if (icon_info !== null) + return icon_info.load_icon(); + else + return null; + }, + + /** + * The backlight color choosing algorithm was mostly ported to javascript from the + * Unity7 C++ source of Canonicals: + * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp + * so it more or less works the same way. + */ + _getColorPalette: function() { + if (iconCacheMap.get(this._app.get_id())) { + // We already know the answer + return iconCacheMap.get(this._app.get_id()); + } + + let pixBuf = this._getIconPixBuf(); + if (pixBuf == null) + return null; + + let pixels = pixBuf.get_pixels(), + offset = 0; + + let total = 0, + rTotal = 0, + gTotal = 0, + bTotal = 0; + + let resample_y = 1, + resample_x = 1; + + // Resampling of large icons + // We resample icons larger than twice the desired size, as the resampling + // to a size s + // DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE, + // most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally + // a multiple of it. + let width = pixBuf.get_width(); + let height = pixBuf.get_height(); + + // Resample + if (height >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE); + + if (width >= 2* DOMINANT_COLOR_ICON_SIZE) + resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE); + + if (resample_x !==1 || resample_y !== 1) + pixels = this._resamplePixels(pixels, resample_x, resample_y); + + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length; + for (let offset = 0; offset < limit; offset+=4) { + let r = pixels[offset], + g = pixels[offset + 1], + b = pixels[offset + 2], + a = pixels[offset + 3]; + + let saturation = (Math.max(r,g, b) - Math.min(r,g, b)); + let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation; + + rTotal += r * relevance; + gTotal += g * relevance; + bTotal += b * relevance; + + total += relevance; + } + + total = total * 255; + + let r = rTotal / total, + g = gTotal / total, + b = bTotal / total; + + let hsv = ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255); + + if (hsv.s > 0.15) + hsv.s = 0.65; + hsv.v = 0.90; + + let rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v); + + // Cache the result. + let backgroundColor = { + lighter: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0.2), + original: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, 0), + darker: ColorUtils.colorLuminance(rgb.r, rgb.g, rgb.b, -0.5) + }; + + if (iconCacheMap.size >= MAX_CACHED_ITEMS) { + //delete oldest cached values (which are in order of insertions) + let ctr=0; + for (let key of iconCacheMap.keys()) { + if (++ctr > BATCH_SIZE_TO_DELETE) + break; + iconCacheMap.delete(key); + } + } + + iconCacheMap.set(this._app.get_id(), backgroundColor); + + return backgroundColor; + }, + + /** + * Downsample large icons before scanning for the backlight color to + * improve performance. + * + * @param pixBuf + * @param pixels + * @param resampleX + * @param resampleY + * + * @return []; + */ + _resamplePixels: function (pixels, resampleX, resampleY) { + let resampledPixels = []; + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons + let limit = pixels.length / (resampleX * resampleY) / 4; + for (let i = 0; i < limit; i++) { + let pixel = i * resampleX * resampleY; + + resampledPixels.push(pixels[pixel * 4]); + resampledPixels.push(pixels[pixel * 4 + 1]); + resampledPixels.push(pixels[pixel * 4 + 2]); + resampledPixels.push(pixels[pixel * 4 + 3]); + } + + return resampledPixels; + } + +}); + +var drawRoundedLine = function(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { + if (height > width) { + y += Math.floor((height - width) / 2.0); + height = width; + } + + height = 2.0 * Math.floor(height / 2.0); + + var leftRadius = isRoundLeft ? height / 2.0 : 0.0; + var rightRadius = isRoundRight ? height / 2.0 : 0.0; + + cr.moveTo(x + width - rightRadius, y); + cr.lineTo(x + leftRadius, y); + if (isRoundLeft) + cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2); + else + cr.lineTo(x, y + height); + cr.lineTo(x + width - rightRadius, y + height); + if (isRoundRight) + cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2); + else + cr.lineTo(x + width, y); + cr.closePath(); + + if (fill != null) { + cr.setSource(fill); + cr.fillPreserve(); + } + if (stroke != null) + cr.setSource(stroke); + cr.stroke(); +} + +/** + * Check if an app exists in the system. + */ +var checkedCommandsMap = new Map(); + +function checkIfCommandExists(app) { + let answer = checkedCommandsMap.get(app); + if (answer === undefined) { + // Command is a shell built in, use shell to call it. + // Quotes around app value are important. They let command operate + // on the whole value, instead of having shell interpret it. + let cmd = "sh -c 'command -v \"" + app + "\"'"; + try { + let out = GLib.spawn_command_line_sync(cmd); + // out contains 1: stdout, 2: stderr, 3: exit code + answer = out[3] == 0; + } catch (ex) { + answer = false; + } + + checkedCommandsMap.set(app, answer); + } + return answer; +} diff --git a/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js new file mode 100644 index 0000000..45d08a0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/dash-to-panel@jderose9.github.com/windowPreview.js @@ -0,0 +1,1145 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * 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 2 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 . + */ + +const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Main = imports.ui.main; +const Mainloop = imports.mainloop; +const Meta = imports.gi.Meta; +const PopupMenu = imports.ui.popupMenu; +const Signals = imports.signals; +const St = imports.gi.St; +const WindowManager = imports.ui.windowManager; +const Workspace = imports.ui.workspace; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Panel = Me.imports.panel; +const Taskbar = Me.imports.taskbar; +const Utils = Me.imports.utils; + +//timeout intervals +const ENSURE_VISIBLE_MS = 200; + +//timeout names +const T1 = 'openMenuTimeout'; +const T2 = 'closeMenuTimeout'; +const T3 = 'peekTimeout'; +const T4 = 'ensureVisibleTimeout'; + +const MAX_TRANSLATION = 40; +const HEADER_HEIGHT = 38; +const MAX_CLOSE_BUTTON_SIZE = 30; +const MIN_DIMENSION = 100; +const FOCUSED_COLOR_OFFSET = 24; +const HEADER_COLOR_OFFSET = -12; +const FADE_SIZE = 36; +const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; + +let headerHeight = 0; +let alphaBg = 0; +let isLeftButtons = false; +let isTopHeader = true; +let isManualStyling = false; +let scaleFactor = 1; +let animationTime = 0; +let aspectRatio = {}; + +var PreviewMenu = Utils.defineClass({ + Name: 'DashToPanel-PreviewMenu', + Extends: St.Widget, + Signals: { 'open-state-changed': {} }, + + _init: function(panel) { + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); + + let geom = panel.geom; + this.panel = panel; + this.currentAppIcon = null; + this._focusedPreview = null; + this._peekedWindow = null; + this.peekInitialWorkspaceIndex = -1; + this.opened = false; + this.isVertical = geom.position == St.Side.LEFT || geom.position == St.Side.RIGHT; + this._translationProp = 'translation_' + (this.isVertical ? 'x' : 'y'); + this._translationDirection = (geom.position == St.Side.TOP || geom.position == St.Side.LEFT ? -1 : 1); + this._translationOffset = Math.min(panel.dtpSize, MAX_TRANSLATION) * this._translationDirection; + + this.menu = new St.Widget({ + name: 'preview-menu', + layout_manager: new Clutter.BinLayout(), + reactive: true, + track_hover: true, + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign[geom.position != St.Side.RIGHT ? 'START' : 'END'], + y_align: Clutter.ActorAlign[geom.position != St.Side.BOTTOM ? 'START' : 'END'] + }); + this._box = new St.BoxLayout({ vertical: this.isVertical }); + this._scrollView = new St.ScrollView({ + name: 'dashtopanelPreviewScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true, + y_expand: !this.isVertical + }); + + this._scrollView.add_actor(this._box); + this.menu.add_child(this._scrollView); + this.add_child(this.menu); + }, + + enable: function() { + this._timeoutsHandler = new Utils.TimeoutsHandler(); + this._signalsHandler = new Utils.GlobalSignalsHandler(); + + Main.layoutManager.addChrome(this, { affectsInputRegion: false }); + Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); + + this._resetHiddenState(); + this._refreshGlobals(); + this._updateClip(); + this.menu.set_position(1, 1); + + this._signalsHandler.add( + [ + this.menu, + 'notify::hover', + () => this._onHoverChanged() + ], + [ + this._scrollView, + 'scroll-event', + this._onScrollEvent.bind(this) + ], + [ + this.panel.panelBox, + 'style-changed', + () => this._updateClip() + ], + [ + Utils.DisplayWrapper.getScreen(), + 'in-fullscreen-changed', + () => { + if (global.display.focus_window && global.display.focus_window.is_fullscreen()) { + this.close(true); + } + } + ], + [ + Me.settings, + [ + 'changed::panel-sizes', + 'changed::window-preview-size', + 'changed::window-preview-padding', + 'changed::window-preview-show-title' + ], + () => { + this._refreshGlobals(); + this._updateClip(); + } + ] + ); + }, + + disable: function() { + this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); + + this.close(true); + + Main.layoutManager.untrackChrome(this.menu); + Main.layoutManager.removeChrome(this); + }, + + requestOpen: function(appIcon) { + let timeout = Me.settings.get_int('show-window-previews-timeout'); + + if (this.opened) { + timeout = Math.min(100, timeout); + } + + this._endOpenCloseTimeouts(); + this._timeoutsHandler.add([T1, timeout, () => this.open(appIcon)]); + }, + + requestClose: function() { + this._endOpenCloseTimeouts(); + this._addCloseTimeout(); + }, + + open: function(appIcon) { + if (this.currentAppIcon != appIcon) { + this.currentAppIcon = appIcon; + + if (!this.opened) { + this._refreshGlobals(); + + this.set_height(this.clipHeight); + this.menu.show(); + + setStyle(this.menu, 'background: ' + Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, alphaBg)); + } + + this._mergeWindows(appIcon); + this._updatePosition(); + this._animateOpenOrClose(true); + + this._setReactive(true); + this._setOpenedState(true); + } + }, + + close: function(immediate) { + this._endOpenCloseTimeouts(); + this._removeFocus(); + this._endPeek(); + + if (immediate) { + Utils.stopAnimations(this.menu); + this._resetHiddenState(); + } else { + this._animateOpenOrClose(false, () => this._resetHiddenState()); + } + + this._setReactive(false); + this.currentAppIcon = null; + }, + + update: function(appIcon, windows) { + if (this.currentAppIcon == appIcon) { + if (windows && !windows.length) { + this.close(); + } else { + this._addAndRemoveWindows(windows); + this._updatePosition(); + } + } + }, + + updatePosition: function() { + this._updatePosition(); + }, + + focusNext: function() { + let previews = this._box.get_children(); + let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1; + let nextIndex = currentIndex + 1; + + nextIndex = previews[nextIndex] ? nextIndex : 0; + + if (previews[nextIndex]) { + this._removeFocus(); + previews[nextIndex].setFocus(true); + this._focusedPreview = previews[nextIndex]; + } + + return nextIndex; + }, + + activateFocused: function() { + if (this.opened && this._focusedPreview) { + this._focusedPreview.activate(); + } + }, + + requestPeek: function(window) { + this._timeoutsHandler.remove(T3); + + if (Me.settings.get_boolean('peek-mode')) { + if (this.peekInitialWorkspaceIndex < 0) { + this._timeoutsHandler.add([T3, Me.settings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]); + } else { + this._peek(window); + } + } + }, + + endPeekHere: function() { + this._endPeek(true); + }, + + ensureVisible: function(preview) { + let [ , upper, pageSize] = this._getScrollAdjustmentValues(); + + if (upper > pageSize) { + this._timeoutsHandler.add([ + T4, + ENSURE_VISIBLE_MS, + () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION, () => this._updateScrollFade()) + ]); + } + }, + + getCurrentAppIcon: function() { + return this.currentAppIcon; + }, + + _setReactive: function(reactive) {  + this._box.get_children().forEach(c => c.reactive = reactive); + this.menu.reactive = reactive; + }, + + _setOpenedState: function(opened) { + this.opened = opened; + this.emit('open-state-changed'); + }, + + _resetHiddenState: function() { + this.menu.hide(); + this.set_height(0); + this._setOpenedState(false); + this.menu.opacity = 0; + this.menu[this._translationProp] = this._translationOffset; + this._box.get_children().forEach(c => c.destroy()); + }, + + _removeFocus: function() { + if (this._focusedPreview) { + this._focusedPreview.setFocus(false); + this._focusedPreview = null; + } + }, + + _mergeWindows: function(appIcon, windows) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + windows.sort(Taskbar.sortWindowsCompareFunction); + + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); + + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i]) { + currentPreviews[i].assignWindow(windows[i], this.opened); + } else if (!currentPreviews[i]) { + this._addNewPreview(windows[i]); + } else if (!windows[i]) { + currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); + } + } + }, + + _addAndRemoveWindows: function(windows) { + let currentPreviews = this._box.get_children(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + + for (let i = 0, l = windows.length; i < l; ++i) { + let currentIndex = Utils.findIndex(currentPreviews, c => c.window == windows[i]); + + if (currentIndex < 0) { + this._addNewPreview(windows[i]); + } else { + currentPreviews[currentIndex].assignWindow(windows[i]); + currentPreviews.splice(currentIndex, 1); + + if (this._peekedWindow && this._peekedWindow == windows[i]) { + this.requestPeek(windows[i]); + } + } + } + + currentPreviews.forEach(c => c.animateOut()); + }, + + _addNewPreview: function(window) { + let preview = new Preview(this); + + this._box.add_child(preview); + preview.adjustOnStage(); + preview.assignWindow(window, this.opened); + }, + + _addCloseTimeout: function() { + this._timeoutsHandler.add([T2, Me.settings.get_int('leave-timeout'), () => this.close()]); + }, + + _onHoverChanged: function() { + this._endOpenCloseTimeouts(); + + if (this.currentAppIcon && !this.menu.hover) { + this._addCloseTimeout(); + this._endPeek(); + } + }, + + _onScrollEvent: function(actor, event) { + if (!event.is_pointer_emulated()) { + let vOrh = this.isVertical ? 'v' : 'h'; + let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment(); + let increment = adjustment.step_increment; + let delta = increment; + + switch (event.get_scroll_direction()) { + case Clutter.ScrollDirection.UP: + delta = -increment; + break; + case Clutter.ScrollDirection.SMOOTH: + let [dx, dy] = event.get_scroll_delta(); + delta = dy * increment; + delta += dx * increment; + break; + } + + adjustment.set_value(adjustment.get_value() + delta); + this._updateScrollFade(); + } + + return Clutter.EVENT_STOP; + }, + + _endOpenCloseTimeouts: function() { + this._timeoutsHandler.remove(T1); + this._timeoutsHandler.remove(T2); + this._timeoutsHandler.remove(T4); + }, + + _refreshGlobals: function() { + isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + isTopHeader = Me.settings.get_string('window-preview-title-position') == 'TOP'; + isManualStyling = Me.settings.get_boolean('window-preview-manual-styling'); + scaleFactor = Utils.getScaleFactor(); + headerHeight = Me.settings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; + animationTime = Me.settings.get_int('window-preview-animation-time') * .001; + aspectRatio.x = { + size: Me.settings.get_int('window-preview-aspect-ratio-x'), + fixed: Me.settings.get_boolean('window-preview-fixed-x') + }; + aspectRatio.y = { + size: Me.settings.get_int('window-preview-aspect-ratio-y'), + fixed: Me.settings.get_boolean('window-preview-fixed-y') + }; + + alphaBg = Me.settings.get_boolean('preview-use-custom-opacity') ? + Me.settings.get_int('preview-custom-opacity') * .01 : + this.panel.dynamicTransparency.alpha; + }, + + _updateClip: function() { + let x, y, w; + let geom = this.panel.getGeometry(); + let panelBoxTheme = this.panel.panelBox.get_theme_node(); + let previewSize = (Me.settings.get_int('window-preview-size') + + Me.settings.get_int('window-preview-padding') * 2) * scaleFactor; + + if (this.isVertical) { + w = previewSize; + this.clipHeight = this.panel.monitor.height; + y = this.panel.monitor.y; + } else { + w = this.panel.monitor.width; + this.clipHeight = (previewSize + headerHeight); + x = this.panel.monitor.x; + } + + if (geom.position == St.Side.LEFT) { + x = this.panel.monitor.x + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.LEFT); + } else if (geom.position == St.Side.RIGHT) { + x = this.panel.monitor.x + this.panel.monitor.width - (this.panel.dtpSize + previewSize) - panelBoxTheme.get_padding(St.Side.RIGHT); + } else if (geom.position == St.Side.TOP) { + y = this.panel.monitor.y + this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.TOP); + } else { //St.Side.BOTTOM + y = this.panel.monitor.y + this.panel.monitor.height - (this.panel.dtpSize + panelBoxTheme.get_padding(St.Side.BOTTOM) + previewSize + headerHeight); + } + + Utils.setClip(this, x, y, w, this.clipHeight); + }, + + _updatePosition: function() { + let sourceNode = this.currentAppIcon.actor.get_theme_node(); + let sourceContentBox = sourceNode.get_content_box(this.currentAppIcon.actor.get_allocation_box()); + let sourceAllocation = Utils.getTransformedAllocation(this.currentAppIcon.actor); + let [previewsWidth, previewsHeight] = this._getPreviewsSize(); + let appIconMargin = Me.settings.get_int('appicon-margin') / scaleFactor; + let x = 0, y = 0; + + previewsWidth = Math.min(previewsWidth, this.panel.monitor.width); + previewsHeight = Math.min(previewsHeight, this.panel.monitor.height); + this._updateScrollFade(previewsWidth < this.panel.monitor.width && previewsHeight < this.panel.monitor.height); + + if (this.isVertical) { + y = sourceAllocation.y1 + appIconMargin - this.panel.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; + y = Math.max(y, 0); + y = Math.min(y, this.panel.monitor.height - previewsHeight); + } else { + x = sourceAllocation.x1 + appIconMargin - this.panel.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; + x = Math.max(x, 0); + x = Math.min(x, this.panel.monitor.width - previewsWidth); + } + + if (!this.opened) { + this.menu.set_position(x, y); + this.menu.set_size(previewsWidth, previewsHeight); + } else { + Utils.animate(this.menu, getTweenOpts({ x: x, y: y, width: previewsWidth, height: previewsHeight })); + } + }, + + _updateScrollFade: function(remove) { + let [value, upper, pageSize] = this._getScrollAdjustmentValues(); + let needsFade = Math.round(upper) > Math.round(pageSize); + let fadeWidgets = this.menu.get_children().filter(c => c != this._scrollView); + + if (!remove && needsFade) { + if (!fadeWidgets.length) { + fadeWidgets.push(this._getFadeWidget()); + fadeWidgets.push(this._getFadeWidget(true)); + + this.menu.add_child(fadeWidgets[0]); + this.menu.add_child(fadeWidgets[1]); + } + + fadeWidgets[0].visible = value > 0; + fadeWidgets[1].visible = value + pageSize < upper; + } else if (remove || (!needsFade && fadeWidgets.length)) { + fadeWidgets.forEach(fw => fw.destroy()); + } + }, + + _getScrollAdjustmentValues: function() { + let [value , , upper, , , pageSize] = this._scrollView[(this.isVertical ? 'v' : 'h') + 'scroll'].adjustment.get_values(); + + return [value, upper, pageSize]; + }, + + _getFadeWidget: function(end) { + let x = 0, y = 0; + let startBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, Math.min(alphaBg + .1, 1)); + let endBg = Utils.getrgbaColor(this.panel.dynamicTransparency.backgroundColorRgb, 0) + let fadeStyle = 'background-gradient-start:' + startBg + + 'background-gradient-end:' + endBg + + 'background-gradient-direction:' + this.panel.getOrientation(); + + if (this.isVertical) { + y = end ? this.panel.monitor.height - FADE_SIZE : 0; + } else { + x = end ? this.panel.monitor.width - FADE_SIZE : 0; + } + + let fadeWidget = new St.Widget({ + reactive: false, + pivot_point: Utils.getPoint({ x: .5, y: .5 }), + rotation_angle_z: end ? 180 : 0, + style: fadeStyle, + x: x, y: y, + width: this.isVertical ? this.width : FADE_SIZE, + height: this.isVertical ? FADE_SIZE : this.height + }); + + return fadeWidget; + }, + + _getPreviewsSize: function() { + let previewsWidth = 0; + let previewsHeight = 0; + + this._box.get_children().forEach(c => { + if (!c.animatingOut) { + let [width, height] = c.getSize(); + + if (this.isVertical) { + previewsWidth = Math.max(width, previewsWidth); + previewsHeight += height; + } else { + previewsWidth += width; + previewsHeight = Math.max(height, previewsHeight); + } + } + }); + + return [previewsWidth, previewsHeight]; + }, + + _animateOpenOrClose: function(show, onComplete) { + let isTranslationAnimation = this.menu[this._translationProp] != 0; + let tweenOpts = { + opacity: show ? 255 : 0, + transition: show ? 'easeInOutQuad' : 'easeInCubic', + onComplete: () => { + if (isTranslationAnimation) { + Main.layoutManager._queueUpdateRegions(); + } + + (onComplete || (() => {}))(); + } + }; + + tweenOpts[this._translationProp] = show ? this._translationDirection : this._translationOffset; + + Utils.animate(this.menu, getTweenOpts(tweenOpts)); + }, + + _peek: function(window) { + let currentWorkspace = Utils.getCurrentWorkspace(); + let windowWorkspace = window.get_workspace(); + let focusWindow = () => this._focusMetaWindow(Me.settings.get_int('peek-mode-opacity'), window); + + this._restorePeekedWindowStack(); + this._peekedWindow = window; + + if (currentWorkspace != windowWorkspace) { + this._switchToWorkspaceImmediate(windowWorkspace.index()); + this._timeoutsHandler.add([T3, 100, focusWindow]); + } else { + focusWindow(); + } + + if (this.peekInitialWorkspaceIndex < 0) { + this.peekInitialWorkspaceIndex = currentWorkspace.index(); + } + }, + + _endPeek: function(stayHere) { + this._timeoutsHandler.remove(T3); + + if (this._peekedWindow) { + let immediate = !stayHere && this.peekInitialWorkspaceIndex != Utils.getCurrentWorkspace().index(); + + this._restorePeekedWindowStack(); + this._focusMetaWindow(255, this._peekedWindow, immediate, true); + this._peekedWindow = null; + + if (!stayHere) { + this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); + } + + this.peekInitialWorkspaceIndex = -1; + } + }, + + _switchToWorkspaceImmediate: function(workspaceIndex) { + let workspace = Utils.getWorkspaceByIndex(workspaceIndex); + let shouldAnimate = Main.wm._shouldAnimate; + + if (!workspace || (!workspace.list_windows().length && + workspaceIndex < Utils.getWorkspaceCount() - 1)) { + workspace = Utils.getCurrentWorkspace(); + } + + Main.wm._shouldAnimate = () => false; + workspace.activate(global.display.get_current_time_roundtrip()); + Main.wm._shouldAnimate = shouldAnimate; + }, + + _focusMetaWindow: function(dimOpacity, window, immediate, ignoreFocus) { + window.get_workspace().list_windows().forEach(mw => { + let wa = mw.get_compositor_private(); + let isFocused = !ignoreFocus && mw == window; + + if (wa) { + if (isFocused) { + mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa); + wa.get_parent().set_child_above_sibling(wa, null); + } + + if (isFocused && mw.minimized) { + wa.show(); + } + + if (!mw.minimized) { + let tweenOpts = getTweenOpts({ opacity: isFocused ? 255 : dimOpacity }); + + if (immediate && !mw.is_on_all_workspaces()) { + tweenOpts.time = 0; + } + + Utils.animateWindowOpacity(wa, tweenOpts); + } + } + }); + }, + + _restorePeekedWindowStack: function() { + let windowActor = this._peekedWindow ? this._peekedWindow.get_compositor_private() : null; + + if (windowActor) { + if (this._peekedWindow.hasOwnProperty(PEEK_INDEX_PROP)) { + windowActor.get_parent().set_child_at_index(windowActor, this._peekedWindow[PEEK_INDEX_PROP]); + delete this._peekedWindow[PEEK_INDEX_PROP]; + } + + if (this._peekedWindow.minimized) { + windowActor.hide(); + } + } + }, +}); + +var Preview = Utils.defineClass({ + Name: 'DashToPanel-Preview', + Extends: St.Widget, + + _init: function(previewMenu) { + this.callParent('_init', { + style_class: 'preview-container', + reactive: true, + track_hover: true, + layout_manager: new Clutter.BinLayout() + }); + + this.window = null; + this._waitWindowId = 0; + this._needsCloseButton = true; + this.cloneWidth = this.cloneHeight = 0; + this._previewMenu = previewMenu; + this._padding = Me.settings.get_int('window-preview-padding') * scaleFactor; + this._previewDimensions = this._getPreviewDimensions(); + this.animatingOut = false; + + let box = new St.Widget({ layout_manager: new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL }), y_expand: true }); + let [previewBinWidth, previewBinHeight] = this._getBinSize(); + let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); + + if (Config.PACKAGE_VERSION >= '3.31.9') { + closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); + } + + this._closeButtonBin = new St.Widget({ + style_class: 'preview-close-btn-container', + layout_manager: new Clutter.BinLayout(), + opacity: 0, + x_expand: true, y_expand: true, + x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + this._closeButtonBin.add_child(closeButton); + + this._previewBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + style: 'padding: ' + this._padding / scaleFactor + 'px;' + }); + + this._previewBin.set_size(previewBinWidth, previewBinHeight); + + box.add_child(this._previewBin); + + if (headerHeight) { + let headerBox = new St.Widget({ + style_class: 'preview-header-box', + layout_manager: new Clutter.BoxLayout(), + x_expand: true, + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] + }); + + setStyle(headerBox, this._getBackgroundColor(HEADER_COLOR_OFFSET, 1)); + this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); + this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); + + this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._iconBin.set_size(headerHeight, headerHeight); + + headerBox.add_child(this._iconBin); + headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1); + headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); + + box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1); + } + + this.add_child(box); + this.add_child(this._closeButtonBin); + + closeButton.connect('clicked', () => this._onCloseBtnClick()); + this.connect('notify::hover', () => this._onHoverChanged()); + this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); + this.connect('destroy', () => this._onDestroy()); + }, + + adjustOnStage: function() { + let closeButton = this._closeButtonBin.get_first_child(); + let closeButtonHeight = closeButton.height; + let maxCloseButtonSize = MAX_CLOSE_BUTTON_SIZE * scaleFactor; + let closeButtonBorderRadius = ''; + + if (closeButtonHeight > maxCloseButtonSize) { + closeButtonHeight = maxCloseButtonSize; + closeButton.set_size(closeButtonHeight, closeButtonHeight); + } + + if (!headerHeight) { + closeButtonBorderRadius = 'border-radius: '; + + if (isTopHeader) { + closeButtonBorderRadius += (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + } else { + closeButtonBorderRadius += (isLeftButtons ? '0 4px 0 0;' : '4px 0 0 0;'); + } + } + + setStyle( + this._closeButtonBin, + 'padding: ' + (headerHeight ? Math.round((headerHeight - closeButtonHeight) * .5 / scaleFactor) : 4) + 'px;' + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + + closeButtonBorderRadius + ); + }, + + assignWindow: function(window, animateSize) { + if (this.window != window) { + let _assignWindowClone = () => { + if (window.get_compositor_private()) { + let cloneBin = this._getWindowCloneBin(window); + + this._resizeClone(cloneBin, window); + this._addClone(cloneBin, animateSize); + this._previewMenu.updatePosition(); + } else if (!this._waitWindowId) { + this._waitWindowId = Mainloop.idle_add(() => { + this._waitWindowId = 0; + + if (this._previewMenu.opened) { + _assignWindowClone(); + } + }); + } + }; + + _assignWindowClone(); + } + + this._cancelAnimateOut(); + this._removeWindowSignals(); + this.window = window; + this._needsCloseButton = window.can_close() && !Utils.checkIfWindowHasTransient(window); + this._updateHeader(); + }, + + animateOut: function() { + if (!this.animatingOut) { + let tweenOpts = getTweenOpts({ opacity: 0, width: 0, height: 0, onComplete: () => this.destroy() }); + + this.animatingOut = true; + + Utils.stopAnimations(this); + Utils.animate(this, tweenOpts); + } + }, + + getSize: function() { + let [binWidth, binHeight] = this._getBinSize(); + + binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2); + binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight; + + return [binWidth, binHeight]; + }, + + setFocus: function(focused) { + this._hideOrShowCloseButton(!focused); + setStyle(this, this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); + + if (focused) { + this._previewMenu.ensureVisible(this); + this._previewMenu.requestPeek(this.window); + } + }, + + activate: function() { + this._previewMenu.endPeekHere(); + this._previewMenu.close(); + Main.activateWindow(this.window); + }, + + _onDestroy: function() { + if (this._waitWindowId) { + GLib.source_remove(this._waitWindowId); + this._waitWindowId = 0; + } + + this._removeWindowSignals(); + }, + + _onHoverChanged: function() { + this.setFocus(this.hover); + }, + + _onCloseBtnClick: function() { + this._hideOrShowCloseButton(true); + this.reactive = false; + + if (!Me.settings.get_boolean('group-apps')) { + this._previewMenu.close(); + } else { + this._previewMenu.endPeekHere(); + } + + this.window.delete(global.get_current_time()); + }, + + _onButtonReleaseEvent: function(e) { + switch (e.get_button()) { + case 1: // Left click + this.activate(); + break; + case 2: // Middle click + if (Me.settings.get_boolean('preview-middle-click-close')) { + this._onCloseBtnClick(); + } + break; + case 3: // Right click + this._showContextMenu(e); + break; + } + + return Clutter.EVENT_STOP; + }, + + _cancelAnimateOut: function() { + if (this.animatingOut) { + this.animatingOut = false; + + Utils.stopAnimations(this); + Utils.animate(this, getTweenOpts({ opacity: 255, width: this.cloneWidth, height: this.cloneHeight })); + } + }, + + _showContextMenu: function(e) { + let coords = e.get_coords(); + let currentWorkspace = this._previewMenu.peekInitialWorkspaceIndex < 0 ? + Utils.getCurrentWorkspace() : + Utils.getWorkspaceByIndex(this._previewMenu.peekInitialWorkspaceIndex); + + Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, { + x: coords[0], + y: coords[1], + width: 0, + height: 0 + }); + + let ctxMenuData = Main.wm._windowMenuManager._manager._menus[0]; + + ctxMenuData.menu.connect('open-state-changed', () => this._previewMenu.menu.sync_hover()); + + if (this.window.get_workspace() != currentWorkspace) { + let menuItem = new PopupMenu.PopupMenuItem(_('Move to current Workspace') + ' [' + (currentWorkspace.index() + 1) + ']'); + let menuItems = ctxMenuData.menu.box.get_children(); + let insertIndex = Utils.findIndex(menuItems, c => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem); + + insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1; + ctxMenuData.menu.addMenuItem(menuItem, insertIndex); + menuItem.connect('activate', () => this.window.change_workspace(currentWorkspace)); + } + }, + + _removeWindowSignals: function() { + if (this._titleWindowChangeId) { + this.window.disconnect(this._titleWindowChangeId); + this._titleWindowChangeId = 0; + } + }, + + _updateHeader: function() { + if (headerHeight) { + let iconTextureSize = Me.settings.get_boolean('window-preview-use-custom-icon-size') ? + Me.settings.get_int('window-preview-custom-icon-size') : + headerHeight / scaleFactor * .6; + let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize); + let workspaceIndex = ''; + let workspaceStyle = null; + let fontScale = Me.desktopSettings.get_double('text-scaling-factor'); + let commonTitleStyles = 'color: ' + Me.settings.get_string('window-preview-title-font-color') + ';' + + 'font-size: ' + Me.settings.get_int('window-preview-title-font-size') * fontScale + 'px;' + + 'font-weight: ' + Me.settings.get_string('window-preview-title-font-weight') + ';'; + + this._iconBin.destroy_all_children(); + this._iconBin.add_child(icon); + + if (!Me.settings.get_boolean('isolate-workspaces')) { + workspaceIndex = (this.window.get_workspace().index() + 1).toString(); + workspaceStyle = 'margin: 0 4px 0 ' + (isLeftButtons ? Math.round((headerHeight - icon.width) * .5) + 'px' : '0') + '; padding: 0 4px;' + + 'border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px;' + commonTitleStyles; + } + + this._workspaceIndicator.text = workspaceIndex; + setStyle(this._workspaceIndicator, workspaceStyle); + + this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle()); + setStyle(this._windowTitle, 'max-width: 0px; padding-right: 4px;' + commonTitleStyles); + this._updateWindowTitle(); + } + }, + + _updateWindowTitle: function() { + this._windowTitle.text = this.window.title; + }, + + _hideOrShowCloseButton: function(hide) { + if (this._needsCloseButton) { + Utils.animate(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + } + }, + + _getBackgroundColor: function(offset, alpha) { + return 'background-color: ' + this._getRgbaColor(offset, alpha) + + 'transition-duration:' + this._previewMenu.panel.dynamicTransparency.animationDuration; + }, + + _getRgbaColor: function(offset, alpha) { + alpha = Math.abs(alpha); + + if (isNaN(alpha)) { + alpha = alphaBg; + } + + return Utils.getrgbaColor(this._previewMenu.panel.dynamicTransparency.backgroundColorRgb, alpha, offset); + }, + + _addClone: function(newCloneBin, animateSize) { + let currentClones = this._previewBin.get_children(); + let newCloneOpts = getTweenOpts({ opacity: 255 }); + + this._previewBin.add_child(newCloneBin); + + if (currentClones.length) { + let currentCloneBin = currentClones.pop(); + let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentCloneBin.destroy() }); + + if (newCloneBin.width > currentCloneBin.width) { + newCloneOpts.width = newCloneBin.width; + newCloneBin.width = currentCloneBin.width; + } else { + currentCloneOpts.width = newCloneBin.width; + } + + if (newCloneBin.height > currentCloneBin.height) { + newCloneOpts.height = newCloneBin.height; + newCloneBin.height = currentCloneBin.height; + } else { + currentCloneOpts.height = newCloneBin.height; + } + + currentClones.forEach(c => c.destroy()); + Utils.animate(currentCloneBin, currentCloneOpts); + } else if (animateSize) { + newCloneBin.width = 0; + newCloneBin.height = 0; + newCloneOpts.width = this.cloneWidth; + newCloneOpts.height = this.cloneHeight; + } + + Utils.animate(newCloneBin, newCloneOpts); + }, + + _getWindowCloneBin: function(window) { + let frameRect = window.get_frame_rect(); + let bufferRect = window.get_buffer_rect(); + let clone = new Clutter.Clone({ source: window.get_compositor_private() }); + let cloneBin = new St.Widget({ + opacity: 0, + layout_manager: frameRect.width != bufferRect.width || + frameRect.height != bufferRect.height ? + new WindowCloneLayout(frameRect, bufferRect) : + new Clutter.BinLayout() + }); + + cloneBin.add_child(clone); + + return cloneBin; + }, + + _getBinSize: function() { + let [fixedWidth, fixedHeight] = this._previewDimensions; + + return [ + aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1, + aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1 + ]; + }, + + _resizeClone: function(cloneBin, window) { + let frameRect = cloneBin.layout_manager.frameRect || window.get_frame_rect(); + let [fixedWidth, fixedHeight] = this._previewDimensions; + let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1); + let cloneWidth = frameRect.width * ratio; + let cloneHeight = frameRect.height * ratio; + + let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; + let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0; + let clonePaddingTop = clonePaddingTB * .5; + let clonePaddingLeft = clonePaddingLR * .5; + + this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor; + this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor; + + cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;'); + cloneBin.layout_manager.ratio = ratio; + cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor]; + + cloneBin.get_first_child().set_size(cloneWidth, cloneHeight); + }, + + _getPreviewDimensions: function() { + let size = Me.settings.get_int('window-preview-size') * scaleFactor; + let w, h; + + if (this._previewMenu.isVertical) { + w = size; + h = w * aspectRatio.y.size / aspectRatio.x.size; + } else { + h = size; + w = h * aspectRatio.x.size / aspectRatio.y.size; + } + + return [w, h]; + } +}); + +var WindowCloneLayout = Utils.defineClass({ + Name: 'DashToPanel-WindowCloneLayout', + Extends: Clutter.BinLayout, + + _init: function(frameRect, bufferRect) { + this.callParent('_init'); + + //the buffer_rect contains the transparent padding that must be removed + this.frameRect = frameRect; + this.bufferRect = bufferRect; + }, + + vfunc_allocate: function(actor, box, flags) { + let [width, height] = box.get_size(); + + box.set_origin( + (this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0], + (this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1] + ); + + box.set_size( + width + (this.bufferRect.width - this.frameRect.width) * this.ratio, + height + (this.bufferRect.height - this.frameRect.height) * this.ratio + ); + + Utils.allocate(actor.get_first_child(), box, flags); + } +}); + +function setStyle(actor, style) { + if (!isManualStyling) { + actor.set_style(style); + } +} + +function getTweenOpts(opts) { + let defaults = { + time: animationTime, + transition: 'easeInOutQuad' + }; + + return Utils.mergeObjects(opts || {}, defaults); +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/LICENSE @@ -0,0 +1,674 @@ + 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 +. diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js new file mode 100644 index 0000000..904c7de --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/extension.js @@ -0,0 +1,52 @@ +/* exported init */ + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils + +class Extension { + constructor() { + this.available_mods = Self.imports.src.modsList.get() + } + + _refresh_mod(name) { + if (!this.available_mods[name]) return + + if (this.settings.get_boolean(name)) { // enable + if (this.mods[name]) return + + const mod = new this.available_mods[name]() + mod.enable() + this.mods[name] = mod + } else if (this.mods[name]) { //disable + this.mods[name].disable() + delete this.mods[name] + } + } + + enable() { + this.mods = {} + + this.settings = extensionUtils.getSettings() + + Object.keys(this.available_mods).forEach(name => { + this.settings.connect('changed::' + name, () => { + this._refresh_mod(name) + }); + this._refresh_mod(name) + }) + } + + disable() { + for (const key in this.mods) { + if (!this.mods.hasOwnProperty(key)) continue; + this.mods[key].disable() + } + + delete this.mods + delete this.settings + } +} + +function init() { + return new Extension(); +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..a042c9c Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ar/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..5791425 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/en/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..985e2ef Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/fr/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0c2d259 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ja/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..9f6dc63 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ko/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..f657030 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/nl/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..0bcf35d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/ru/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo new file mode 100644 index 0000000..74449f3 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/locale/sv/LC_MESSAGES/gnome-ui-tune@itstime.tech.mo differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json new file mode 100644 index 0000000..326c5f5 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/metadata.json @@ -0,0 +1,14 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Tunes gnome 40-43 Overview UI to make it more usable.\n\nChanges:\n- Search textbox is hidden by default and shown only when user begins to type-to-search\n- Scale of workspaces' thumbnails increased 2x\n- Restores wallpaper on workspaces' thumbnails. No more gray background\n- Show workspaces' thumbnails even when there is only one workspace\n- Firefox's PIP (picture in picture) window is now displayed on the overview screen\n\nAll modifications can be disabled in the extension's settings.\n\nATTENTION!\nAfter extension update, gnome-shell restart is required:\nX11: Alt+F2 => r\nWayland: logout => login", + "name": "Gnome 4x UI Improvements", + "settings-schema": "org.gnome.shell.extensions.gnome-ui-tune", + "shell-version": [ + "40", + "41", + "42" + ], + "url": "https://github.com/axxapy/gnome-ui-tune", + "uuid": "gnome-ui-tune@itstime.tech", + "version": 13 +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js new file mode 100644 index 0000000..f7b8669 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/prefs.js @@ -0,0 +1,55 @@ +'use strict'; + +const Gio = imports.gi.Gio; +const Gtk = imports.gi.Gtk; + +const Self = imports.misc.extensionUtils.getCurrentExtension() +const extensionUtils = imports.misc.extensionUtils +const _ = imports.gettext.domain(Self.metadata.uuid).gettext + + +function init() { +} + +function buildPrefsWidget() { + extensionUtils.initTranslations(Self.metadata.uuid); + + const settings = extensionUtils.getSettings() + + let prefsWidget = new Gtk.Grid({ + margin_top: 18, + margin_bottom: 18, + margin_start: 18, + margin_end: 18, + column_spacing: 12, + row_spacing: 22, + visible: true + }); + + let title = new Gtk.Label({ + label: `${_('settings-mods-list')}`, + halign: Gtk.Align.START, + use_markup: true, + visible: true + }); + prefsWidget.attach(title, 0, 0, 2, 1); + + const mods = Self.imports.src.modsList.getNames() + + for (let modNum = 0; modNum < mods.length; modNum++) { + const key = mods[modNum] + + const row = modNum + 1 + + const label = new Gtk.Label({label: _(key), halign: Gtk.Align.START}) + const toggle = new Gtk.Switch({halign: Gtk.Align.END, active: settings.get_boolean(key)}) + + prefsWidget.attach(label, 0, row, 1, 1); + prefsWidget.attach(toggle, 1, row, 1, 1); + + settings.bind(key, toggle, 'active', Gio.SettingsBindFlags.DEFAULT) + } + + + return prefsWidget +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled new file mode 100644 index 0000000..86313cb Binary files /dev/null and b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/gschemas.compiled differ diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml new file mode 100644 index 0000000..659d656 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/schemas/org.gnome.shell.extensions.gnome-ui-tune.gschema.xml @@ -0,0 +1,30 @@ + + + + + true + Hide search input + Hide search input on overview screen. Search input will be shown when user starts to type-to-search. + + + true + Increase thumbnails size + Increases thumbnails size twice to make them actually usable. + + + true + Restore thumbnails background + Use desktop wallpaper for thumbnails background instead of solid grey color. + + + true + Always show thumbnails + Show workspaces' thumbnails even when there is only single workspace. + + + true + Show firefox's Picture-In-Picture window in desktop overview + By default, firefox's PiP window (for instance, extracted media player) is not displayed in overview. Fix it. + + + diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js new file mode 100644 index 0000000..7dc6b77 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/mod.js @@ -0,0 +1,8 @@ + +var Base = /*abstract*/ class { + constructor() { + //this.enable() + } + enable() {} + disable() {} +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js new file mode 100644 index 0000000..26c30c0 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modAlwaysShowThumbnails.js @@ -0,0 +1,21 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const ThumbnailsBox = imports.ui.workspaceThumbnail.ThumbnailsBox + +var Mod = class extends mod.Base { + enable() { + this.bkp = ThumbnailsBox.prototype._updateShouldShow + ThumbnailsBox.prototype._updateShouldShow = function() { + if (!this._shouldShow) { + this._shouldShow = true; + this.notify('should-show'); + } + } + } + + disable() { + if (this.bkp) { + ThumbnailsBox.prototype._updateShouldShow = this.bkp + } + } +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js new file mode 100644 index 0000000..f79bd5c --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modFirefoxPipInOverview.js @@ -0,0 +1,22 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Workspace = imports.ui.workspace.Workspace + +var Mod = class extends mod.Base { + enable() { + this.bkp_isOverviewWindow = Workspace.prototype._isOverviewWindow + const _isOverviewWindow = this.bkp_isOverviewWindow + Workspace.prototype._isOverviewWindow = function(win) { + if (win.title && win.title === 'Picture-in-Picture') { + if (win.get_wm_class && win.get_wm_class().includes("firefox")) return true; + } + return _isOverviewWindow.call(this, win); + } + } + + disable() { + if (this.bkp_isOverviewWindow) { + Workspace.prototype._isOverviewWindow = this.bkp_isOverviewWindow + } + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js new file mode 100644 index 0000000..1b56a12 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modHideSearchInput.js @@ -0,0 +1,30 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main + +var Mod = class extends mod.Base { + enable() { + this.c = { + searchEntry: Main.overview.searchEntry, + searchController: Main.overview._overview.controls._searchController, + } + + this.c.searchEntry.hide() + + this.connectedId = this.c.searchController.connect('notify::search-active', () => { + if (this.c.searchController.searchActive) { + this.c.searchEntry.show(); + } else { + this.c.searchEntry.hide(); + } + }) + } + + disable() { + if (this.connectedId) { + this.c.searchController.disconnect(this.connectedId) + } + + this.c.searchEntry.show() + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js new file mode 100644 index 0000000..693ba74 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modRestoreThumbnailsBackground.js @@ -0,0 +1,73 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const Main = imports.ui.main +const workspaceThumbnail = imports.ui.workspaceThumbnail +const BackgroundManager = imports.ui.background.BackgroundManager + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_thumb_init = workspaceThumbnail.WorkspaceThumbnail.prototype._init; + const _init = this.bkp_thumb_init + workspaceThumbnail.WorkspaceThumbnail.prototype._init = function(metaWorkspace, monitorIndex) { + _init.call(this, metaWorkspace, monitorIndex) + this._bgManager = new BackgroundManager({ + monitorIndex: monitorIndex, + container: this._contents, + vignette: false + }); + } + + this.bkp_thumb_onDestroy = workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy; + const _onDestroy = this.bkp_thumb_onDestroy + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = function() { + _onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + + // Thumbnails on second monitor + if (!imports.ui.workspacesView.ThumbnailsBox) return; // gnome 42 does not require this hack + this.bkp_layoutManager_thumbnailsBox_updateStates = imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates + const layoutManager_thumbnailsBox_updateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = function() { + layoutManager_thumbnailsBox_updateStates.call(this) + + this._thumbnails.forEach(thumbnail => { + if (thumbnail._bgManager && thumbnail._bgManager.HACKED) { + return + } + thumbnail._bgManager = new BackgroundManager({ + monitorIndex: this._monitorIndex, + container: thumbnail._contents, + vignette: false + }); + thumbnail._bgManager.HACKED = true + const onDestroy = this._thumbnails[0]._onDestroy + thumbnail._onDestroy = function() { + onDestroy.call(this) + if (this._bgManager) { + this._bgManager.destroy(); + this._bgManager = null; + } + } + }) + } + } + + disable() { + if (this.bkp_thumb_init) { + workspaceThumbnail.WorkspaceThumbnail.prototype._init = this.bkp_thumb_init + } + + if (this.bkp_thumb_onDestroy) { + workspaceThumbnail.WorkspaceThumbnail.prototype._onDestroy = this.bkp_thumb_onDestroy + } + + if (this.bkp_layoutManager_thumbnailsBox_updateStates) { + imports.ui.workspacesView.ThumbnailsBox.prototype._queueUpdateStates = this.bkp_layoutManager_thumbnailsBox_updateStates + } + } +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js new file mode 100644 index 0000000..04dea1b --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modScaleThumbnails.js @@ -0,0 +1,40 @@ +const mod = imports.misc.extensionUtils.getCurrentExtension().imports.src.mod + +const workspaceThumbnail = imports.ui.workspaceThumbnail +let SecondaryMonitorDisplay = imports.ui.workspacesView.SecondaryMonitorDisplay + +var Mod = class extends mod.Base { + enable() { + // Thumbnails on main monitor + this.bkp_MAX_THUMBNAIL_SCALE = workspaceThumbnail.MAX_THUMBNAIL_SCALE + workspaceThumbnail.MAX_THUMBNAIL_SCALE = 0.1 + + // Thumbnails on second monitor + + // for gnome 42: SecondaryMonitorDisplay may get initialized after extension code is loaded => import above will not work + SecondaryMonitorDisplay = SecondaryMonitorDisplay ?? imports.ui.workspacesView.SecondaryMonitorDisplay + + this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight = SecondaryMonitorDisplay.prototype._getThumbnailsHeight + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = function(box) { + if (!this._thumbnails.visible) + return 0; + + const [width, height] = box.get_size(); + const { expandFraction } = this._thumbnails; + const [thumbnailsHeight] = this._thumbnails.get_preferred_height(width); + return Math.min( + thumbnailsHeight * expandFraction, + height * workspaceThumbnail.MAX_THUMBNAIL_SCALE); + } + } + + disable() { + if (this.bkp_MAX_THUMBNAIL_SCALE) { + workspaceThumbnail.MAX_THUMBNAIL_SCALE = this.bkp_MAX_THUMBNAIL_SCALE + } + + if (this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight) { + SecondaryMonitorDisplay.prototype._getThumbnailsHeight = this.bkp_SecondaryMonitorDisplay_getThumbnailsHeight + } + } +} diff --git a/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js new file mode 100644 index 0000000..f5d7203 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/gnome-ui-tune@itstime.tech/src/modsList.js @@ -0,0 +1,23 @@ + +// This func can not be used from prefs.js due to mods being actually loaded when they're imported +function get() { + const src = imports.misc.extensionUtils.getCurrentExtension().imports.src + return { + 'hide-search': src.modHideSearchInput.Mod, + 'increase-thumbnails-size': src.modScaleThumbnails.Mod, + 'restore-thumbnails-background': src.modRestoreThumbnailsBackground.Mod, + 'always-show-thumbnails': src.modAlwaysShowThumbnails.Mod, + 'overview-firefox-pip': src.modFirefoxPipInOverview.Mod, + } +} + +// This func is safe to use from prefs.js as it has no external dependencies +function getNames() { + return [ + 'hide-search', + 'increase-thumbnails-size', + 'restore-thumbnails-background', + 'always-show-thumbnails', + 'overview-firefox-pip', + ]; +} diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README new file mode 100644 index 0000000..1f14023 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/README @@ -0,0 +1,6 @@ +Dependencies: +libclutter, libgtop and NetworkManager gir bindings, and gnome-system-monitor + on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gnome-system-monitor + on Fedora: libgtop2-devel NetworkManager-libnm-devel, gnome-system-monitor + on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor + on Arch Linux: libgtop, networkmanager, gnome-system-monitor diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js new file mode 100644 index 0000000..2e1be07 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js @@ -0,0 +1,51 @@ +const Config = imports.misc.config; +const Clutter = imports.gi.Clutter; + +/** Compare two dotted version strings (like '10.2.3'). + * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2 + */ +function versionCompare(v1, v2) { + let v1parts = ('' + v1).split('.') + let v2parts = ('' + v2).split('.') + let minLength = Math.min(v1parts.length, v2parts.length) + let i, p1, p2; + // Compare tuple pair-by-pair. + for (i = 0; i < minLength; i++) { + // Convert to integer if possible, because "8" > "10". + p1 = parseInt(v1parts[i], 10); + p2 = parseInt(v2parts[i], 10); + if (isNaN(p1)) { + p1 = v1parts[i]; + } + if (isNaN(p2)) { + p2 = v2parts[i]; + } + if (p1 === p2) { + continue; + } else if (p1 > p2) { + return 1; + } else if (p1 < p2) { + return -1; + } + // one operand is NaN + return NaN; + } + // The longer tuple is always considered 'greater' + if (v1parts.length === v2parts.length) { + return 0; + } + return (v1parts.length < v2parts.length) ? -1 : 1; +} + +function color_from_string(color) { + let clutterColor, res; + + if (!Clutter.Color.from_string) { + clutterColor = new Clutter.Color(); + clutterColor.from_string(color); + } else { + [res, clutterColor] = Clutter.Color.from_string(color); + } + + return clutterColor; +} diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js new file mode 100644 index 0000000..79b85c1 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js @@ -0,0 +1,94 @@ +/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (c) 2011-2012, Giovanni Campagna + + 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 the GNOME 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 HOLDER 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. +*/ + +const Gettext = imports.gettext; +const Gio = imports.gi.Gio; + +const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; + +/** + * initTranslations: + * @domain: (optional): the gettext domain to use + * + * Initialize Gettext to load translations from extensionsdir/locale. + * If @domain is not provided, it will be taken from metadata['gettext-domain'] + */ +function initTranslations(domain) { + let extension = ExtensionUtils.getCurrentExtension(); + + domain = domain || extension.metadata['gettext-domain']; + + // check if this extension was built with "make zip-file", and thus + // has the locale files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell + let localeDir = extension.dir.get_child('locale'); + if (localeDir.query_exists(null)) { + Gettext.bindtextdomain(domain, localeDir.get_path()); + } else { + Gettext.bindtextdomain(domain, Config.LOCALEDIR); + } +} + +/** + * getSettings: + * @schema: (optional): the GSettings schema id + * + * Builds and return a GSettings schema for @schema, using schema files + * in extensionsdir/schemas. If @schema is not provided, it is taken from + * metadata['settings-schema']. + */ +function getSettings(schema) { + let extension = ExtensionUtils.getCurrentExtension(); + + schema = schema || extension.metadata['settings-schema']; + + const GioSSS = Gio.SettingsSchemaSource; + + // check if this extension was built with "make zip-file", and thus + // has the schema files in a subfolder + // otherwise assume that extension has been installed in the + // same prefix as gnome-shell (and therefore schemas are available + // in the standard folders) + let schemaDir = extension.dir.get_child('schemas'); + let schemaSource; + if (schemaDir.query_exists(null)) { + schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), + GioSSS.get_default(), + false); + } else { + schemaSource = GioSSS.get_default(); + } + + let schemaObj = schemaSource.lookup(schema, true); + if (!schemaObj) { + throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); + } + + return new Gio.Settings({settings_schema: schemaObj}); +} diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js new file mode 100644 index 0000000..1c56f0d --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js @@ -0,0 +1,2592 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +// system-monitor: Gnome shell extension displaying system informations in gnome shell status bar, such as memory usage, cpu usage, network rates… +// Copyright (C) 2011 Florian Mounier aka paradoxxxzero + +// 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 . + +// Author: Florian Mounier aka paradoxxxzero + +/* Ugly. This is here so that we don't crash old libnm-glib based shells unnecessarily + * by loading the new libnm.so. Should go away eventually */ + +var libnm_glib = imports.gi.GIRepository.Repository.get_default().is_registered('NMClient', '1.0'); + +var smDepsGtop = true; +var smDepsNM = true; + +var Config = imports.misc.config; +var Clutter = imports.gi.Clutter; +var GLib = imports.gi.GLib; +var GObject = imports.gi.GObject; +var Lang = imports.lang; + +var Gio = imports.gi.Gio; +var Shell = imports.gi.Shell; +var St = imports.gi.St; +const UPower = imports.gi.UPowerGlib; + +// const System = imports.system; +var ModalDialog = imports.ui.modalDialog; + +var ByteArray = imports.byteArray; + +var ExtensionSystem = imports.ui.extensionSystem; +var ExtensionUtils = imports.misc.extensionUtils; + +var Me = ExtensionUtils.getCurrentExtension(); +var Convenience = Me.imports.convenience; +var Compat = Me.imports.compat; + +var Background, GTop, IconSize, Locale, MountsMonitor, NM, NetworkManager, Schema, StatusArea, Style, gc_timeout, menu_timeout; + +try { + GTop = imports.gi.GTop; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsGtop = false; +} + +try { + NM = libnm_glib ? imports.gi.NMClient : imports.gi.NM; + NetworkManager = libnm_glib ? imports.gi.NetworkManager : NM; +} catch (e) { + log('[System monitor] catched error: ' + e); + smDepsNM = false; +} + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const Gettext = imports.gettext.domain('system-monitor'); +const Mainloop = imports.mainloop; +const Util = imports.misc.util; +const _ = Gettext.gettext; + +const MESSAGE = _('Dependencies Missing\n\ +Please install: \n\ +gnome-system-monitor and libgtop, clutter and Network Manager gir bindings \n\ +\t on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gir1.2-clutter-1.0, gnome-system-monitor \n\ +\t on Fedora: libgtop2-devel, NetworkManager-libnm-devel, gnome-system-monitor \n\ +\t on Arch: libgtop, networkmanager, gnome-system-monitor\n\ +\t on openSUSE: typelib-1_0-GTop-2_0, typelib-1_0-NetworkManager-1_0, gnome-system-monitor \n\ +\t on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor\n'); + +// stale network shares will cause the shell to freeze, enable this with caution +const ENABLE_NETWORK_DISK_USAGE = false; + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let metadata = extension.metadata; +let shell_Version = Config.PACKAGE_VERSION; + +Clutter.Actor.prototype.raise_top = function raise_top() { + const parent = this.get_parent(); + if (!parent) { + return; + } + parent.set_child_above_sibling(this, null); +} +Clutter.Actor.prototype.reparent = function reparent(newParent) { + const parent = this.get_parent(); + if (parent) { + parent.remove_child(this); + } + newParent.add_child(this); +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function l_limit(t) { + return (t > 0) ? t : 1000; +} + +function change_text() { + this.label.visible = Schema.get_boolean(this.elt + '-show-text'); +} + +function change_style() { + let style = Schema.get_string(this.elt + '-style'); + this.text_box.visible = style === 'digit' || style === 'both'; + this.chart.actor.visible = style === 'graph' || style === 'both'; +} + +function build_menu_info() { + let elts = Main.__sm.elts; + let tray_menu = Main.__sm.tray.menu; + + if (tray_menu._getMenuItems().length && + typeof tray_menu._getMenuItems()[0].actor.get_last_child() !== 'undefined') { + tray_menu._getMenuItems()[0].actor.get_last_child().destroy_all_children(); + for (let elt in elts) { + elts[elt].menu_items = elts[elt].create_menu_items(); + } + } else { + return; + } + + let menu_info_box_table = new St.Widget({ + style: 'padding: 10px 0px 10px 0px; spacing-rows: 10px; spacing-columns: 15px;', + layout_manager: new Clutter.GridLayout({orientation: Clutter.Orientation.VERTICAL}) + }); + let menu_info_box_table_layout = menu_info_box_table.layout_manager; + + // Populate Table + let row_index = 0; + for (let elt in elts) { + if (!elts[elt].menu_visible) { + continue; + } + + // Add item name to table + menu_info_box_table_layout.attach( + new St.Label({ + text: elts[elt].item_name, + style_class: Style.get('sm-title'), + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.CENTER + }), 0, row_index, 1, 1); + + // Add item data to table + let col_index = 1; + for (let item in elts[elt].menu_items) { + menu_info_box_table_layout.attach( + elts[elt].menu_items[item], col_index, row_index, 1, 1); + + col_index++; + } + + row_index++; + } + if (shell_Version < '3.36') { + tray_menu._getMenuItems()[0].actor.get_last_child().add(menu_info_box_table, {expand: true}); + } else { + tray_menu._getMenuItems()[0].actor.get_last_child().add_child(menu_info_box_table); + } +} + +function change_menu() { + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + build_menu_info(); +} + +function change_usage() { + let usage = Schema.get_string('disk-usage-style'); + Main.__sm.pie.show(usage === 'pie'); + Main.__sm.bar.show(usage === 'bar'); +} +let color_from_string = Compat.color_from_string; + +function interesting_mountpoint(mount) { + if (mount.length < 3) { + return false; + } + + return ((mount[0].indexOf('/dev/') === 0 || mount[2].toLowerCase() === 'nfs') && mount[2].toLowerCase() !== 'udf'); +} + + +const smStyleManager = class SystemMonitor_smStyleManager { + constructor() { + this._extension = ''; + this._iconsize = 1; + this._diskunits = _('MiB/s'); + this._netunits_kbytes = _('KiB/s'); + this._netunits_mbytes = _('MiB/s'); + this._netunits_gbytes = _('GiB/s'); + this._netunits_kbits = _('kbit/s'); + this._netunits_mbits = _('Mbit/s'); + this._netunits_gbits = _('Gbit/s'); + this._pie_size = 300; + this._pie_fontsize = 14; + this._bar_width = 300; + this._bar_thickness = 15; + this._bar_fontsize = 14; + this._compact = Schema.get_boolean('compact-display'); + + if (this._compact) { + this._extension = '-compact'; + this._iconsize = 3 / 5; + this._diskunits = _('MB'); + this._netunits_kbytes = _('kB'); + this._netunits_mbytes = _('MB'); + this._netunits_gbytes = _('GB'); + this._netunits_kbits = 'kb'; + this._netunits_mbits = 'Mb'; + this._netunits_gbits = 'Gb'; + this._pie_size *= 4 / 5; + this._pie_fontsize = 12; + this._bar_width *= 3 / 5; + this._bar_thickness = 12; + this._bar_fontsize = 12; + } + } + get(style) { + return style + this._extension; + } + iconsize() { + return this._iconsize; + } + diskunits() { + return this._diskunits; + } + netunits_kbytes() { + return this._netunits_kbytes; + } + netunits_mbytes() { + return this._netunits_mbytes; + } + netunits_gbytes() { + return this._netunits_gbytes; + } + netunits_kbits() { + return this._netunits_kbits; + } + netunits_mbits() { + return this._netunits_mbits; + } + netunits_gbits() { + return this._netunits_gbits; + } + pie_size() { + return this._pie_size; + } + pie_fontsize() { + return this._pie_fontsize; + } + bar_width() { + return this._bar_width; + } + bar_thickness() { + return this._bar_thickness; + } + bar_fontsize() { + return this._bar_fontsize; + } +} + +const smDialog = class SystemMonitor_smDialog extends ModalDialog.ModalDialog { + constructor() { + super({styleClass: 'prompt-dialog'}); + let mainContentBox = new St.BoxLayout({style_class: 'prompt-dialog-main-layout', + vertical: false}); + this.contentLayout.add(mainContentBox, + {x_fill: true, + y_fill: true}); + + let messageBox = new St.BoxLayout({style_class: 'prompt-dialog-message-layout', + vertical: true}); + mainContentBox.add(messageBox, + {y_align: St.Align.START}); + + this._subjectLabel = new St.Label({style_class: 'prompt-dialog-headline', + text: _('System Monitor Extension')}); + + messageBox.add(this._subjectLabel, + {y_fill: false, + y_align: St.Align.START}); + + this._descriptionLabel = new St.Label({style_class: 'prompt-dialog-description', + text: MESSAGE}); + + messageBox.add(this._descriptionLabel, + {y_fill: true, + y_align: St.Align.START}); + + + this.setButtons([ + { + label: _('Cancel'), + action: () => { + this.close(); + }, + key: Clutter.Escape + } + ]); + } +} + +const Chart = class SystemMonitor_Chart { + constructor(width, height, parent) { + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.parentC = parent; + this.width = width; + let themeContext = St.ThemeContext.get_for_stage(global.stage); + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); + this.actor.set_height(height); + this.data = []; + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = []; + } + themeContext.connect('notify::scale-factor', this.rescale.bind(this)); + this.actor.connect('repaint', this._draw.bind(this)); + } + update() { + let data_a = this.parentC.vals; + if (data_a.length !== this.parentC.colors.length) { + return; + } + let accdata = []; + for (let l = 0; l < data_a.length; l++) { + accdata[l] = (l === 0) ? data_a[0] : accdata[l - 1] + ((data_a[l] > 0) ? data_a[l] : 0); + this.data[l].push(accdata[l]); + if (this.data[l].length > this.width) { + this.data[l].shift(); + } + } + if (!this.actor.visible) { + return; + } + this.actor.queue_repaint(); + } + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let max; + if (this.parentC.max) { + max = this.parentC.max; + } else { + max = Math.max.apply(this, this.data[this.data.length - 1]); + max = Math.max(1, Math.pow(2, Math.ceil(Math.log(max) / Math.log(2)))); + } + Clutter.cairo_set_source_color(cr, Background); + cr.rectangle(0, 0, width, height); + cr.fill(); + for (let i = this.parentC.colors.length - 1; i >= 0; i--) { + let samples = this.data[i].length - 1; + if (samples > 0) { + cr.moveTo(width, height); // bottom right + let x = width - 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][samples] / max) * height); + x -= 0.5 * this.scale_factor; + for (let j = samples; j >= 0; j--) { + let y = (1 - this.data[i][j] / max) * height; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + cr.lineTo(x, y); + x -= 0.5 * this.scale_factor; + } + x += 0.25 * this.scale_factor; + cr.lineTo(x, (1 - this.data[i][0] / max) * height); + cr.lineTo(x, height); + cr.closePath(); + Clutter.cairo_set_source_color(cr, this.parentC.colors[i]); + cr.fill(); + } + } + cr.$dispose(); + } + resize(width) { + if (this.width === width) { + return; + } + this.width = width; + if (this.width < this.data[0].length) { + for (let i = 0; i < this.parentC.colors.length; i++) { + this.data[i] = this.data[i].slice(-this.width); + } + } + this.actor.set_width(this.width * this.scale_factor); // repaints + } + rescale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor); // repaints + } +} + +// Class to deal with volumes insertion / ejection +const smMountsMonitor = class SystemMonitor_smMountsMonitor { + constructor() { + this.files = []; + this.num_mounts = -1; + this.listeners = []; + this.connected = false; + + this._volumeMonitor = Gio.VolumeMonitor.get(); + let sys_mounts = ['/home', '/tmp', '/boot', '/usr', '/usr/local']; + this.base_mounts = ['/']; + sys_mounts.forEach((sMount) => { + if (this.is_sys_mount(sMount + '/')) { + this.base_mounts.push(sMount); + } + }); + this.connect(); + } + refresh() { + // try check that number of volumes has changed + // try { + // let num_mounts = this.manager.getMounts().length; + // if (num_mounts == this.num_mounts) + // return; + // this.num_mounts = num_mounts; + // } catch (e) {}; + + // Can't get mountlist: + // GTop.glibtop_get_mountlist + // Error: No symbol 'glibtop_get_mountlist' in namespace 'GTop' + // Getting it with mtab + // let mount_lines = Shell.get_file_contents_utf8_sync('/etc/mtab').split("\n"); + // this.mounts = []; + // for(let mount_line in mount_lines) { + // let mount = mount_lines[mount_line].split(" "); + // if(interesting_mountpoint(mount) && this.mounts.indexOf(mount[1]) < 0) { + // this.mounts.push(mount[1]); + // } + // } + // log("[System monitor] old mounts: " + this.mounts); + this.mounts = []; + for (let base in this.base_mounts) { + // log("[System monitor] " + this.base_mounts[base]); + this.mounts.push(this.base_mounts[base]); + } + let mount_lines = this._volumeMonitor.get_mounts(); + mount_lines.forEach((mount) => { + if ((!this.is_net_mount(mount) || ENABLE_NETWORK_DISK_USAGE) && + !this.is_ro_mount(mount)) { + let mpath = mount.get_root().get_path() || mount.get_default_location().get_path(); + if (mpath) { + this.mounts.push(mpath); + } + } + }); + // log("[System monitor] base: " + this.base_mounts); + // log("[System monitor] mounts: " + this.mounts); + for (let i in this.listeners) { + this.listeners[i](this.mounts); + } + } + add_listener(cb) { + this.listeners.push(cb); + } + remove_listener(cb) { + this.listeners.pop(cb); + } + get_mounts() { + return this.mounts; + } + is_sys_mount(mpath) { + let file = Gio.file_new_for_path(mpath); + let info = file.query_info(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT, + Gio.FileQueryInfoFlags.NONE, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT); + } + is_ro_mount(mount) { + // FIXME: running this function after "login after waking from suspend" + // can make login hang. Actual issue seems to occur when a former net + // mount got broken (e.g. due to a VPN connection terminated or + // otherwise broken connection) + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY, null); + return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY); + } catch (e) { + return false; + } + } + is_net_mount(mount) { + try { + let file = mount.get_default_location(); + let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE, null); + let result = info.get_attribute_string(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE); + let net_fs = ['nfs', 'smbfs', 'cifs', 'ftp', 'sshfs', 'sftp', 'mtp', 'mtpfs']; + return !file.is_native() || net_fs.indexOf(result) > -1; + } catch (e) { + return false; + } + } + connect() { + if (this.connected) { + return; + } + try { + this.manager = this._volumeMonitor; + this.mount_added_id = this.manager.connect('mount-added', this.refresh.bind(this)); + this.mount_removed_id = this.manager.connect('mount-removed', this.refresh.bind(this)); + // need to add the other signals here + this.connected = true; + } catch (e) { + log('[System monitor] Failed to register on placesManager notifications'); + log('[System monitor] Got exception : ' + e); + } + this.refresh(); + } + disconnect() { + if (!this.connected) { + return; + } + this.manager.disconnect(this.mount_added_id); + this.manager.disconnect(this.mount_removed_id); + this.connected = false; + } + destroy() { + this.disconnect(); + } +} + +const Graph = class SystemMonitor_Graph { + constructor(width, height) { + this.menu_item = ''; + this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); + this.width = width; + this.height = height; + this.gtop = new GTop.glibtop_fsusage(); + this.colors = ['#888', '#aaa', '#ccc']; + for (let color in this.colors) { + this.colors[color] = color_from_string(this.colors[color]); + } + + let themeContext = St.ThemeContext.get_for_stage(global.stage); + themeContext.connect('notify::scale-factor', this.set_scale.bind(this)); + this.scale_factor = themeContext.scale_factor; + let interfaceSettings = new Gio.Settings({ + schema: 'org.gnome.desktop.interface' + }); + interfaceSettings.connect('changed', this.set_text_scaling.bind(this)); + this.text_scaling = interfaceSettings.get_double('text-scaling-factor'); + if (!this.text_scaling) { + this.text_scaling = 1; + } + + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + this.actor.connect('repaint', this._draw.bind(this)); + } + create_menu_item() { + this.menu_item = new PopupMenu.PopupBaseMenuItem({reactive: false}); + if (shell_Version < '3.36') { + this.menu_item.actor.add(this.actor, {span: -1, expand: true}); + } else { + this.menu_item.actor.add_child(this.actor); + } + // tray.menu.addMenuItem(this.menu_item); + } + show(visible) { + this.menu_item.actor.visible = visible; + } + set_scale(themeContext) { + this.scale_factor = themeContext.scale_factor; + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } + set_text_scaling(interfaceSettings, key) { + // FIXME: for some reason we only get this signal once, not on later + // changes to the setting + //log('[System monitor] got text scaling signal'); + this.text_scaling = interfaceSettings.get_double(key); + this.actor.set_width(this.width * this.scale_factor * this.text_scaling); + this.actor.set_height(this.height * this.scale_factor * this.text_scaling); + } +} + +const Bar = class SystemMonitor_Bar extends Graph { + constructor() { + // Height doesn't matter, it gets set on every draw. + super(Style.bar_width(), 100); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + _draw() { + if (!this.actor.visible) { + return; + } + let thickness = Style.bar_thickness() * this.scale_factor * this.text_scaling; + let fontsize = Style.bar_fontsize() * this.scale_factor * this.text_scaling; + this.actor.set_height(this.mounts.length * (3 * thickness)); + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + + let x0 = width / 8; + let y0 = thickness / 2; + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + let perc_full = (this.gtop.blocks - this.gtop.bfree) / this.gtop.blocks; + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y0 + thickness / 3); + cr.showText(text); + cr.moveTo(width - x0, y0 + thickness / 3); + cr.showText(Math.round(perc_full * 100).toString() + '%'); + y0 += (5 * thickness) / 4; + + cr.moveTo(0, y0); + cr.relLineTo(perc_full * width, 0); + cr.stroke(); + y0 += (7 * thickness) / 4; + } + cr.$dispose(); + } + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +const Pie = class SystemMonitor_Pie extends Graph { + constructor() { + super(Style.pie_size(), Style.pie_size()); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + } + + _draw() { + if (!this.actor.visible) { + return; + } + let [width, height] = this.actor.get_surface_size(); + let cr = this.actor.get_context(); + let xc = width / 2; + let yc = height / 2; + let pi = Math.PI; + function arc(r, value, max, angle) { + if (max === 0) { + return angle; + } + let new_angle = angle + (value * 2 * pi / max); + cr.arc(xc, yc, r, angle, new_angle); + return new_angle; + } + + // Set the ring thickness so that at least 7 rings can be displayed. If + // there are more mounts, make the rings thinner. If the rings are too + // thin to have a line height of 1.2 for the labels, shrink the labels. + let rings = Math.max(this.mounts.length, 7); + let ring_width = width / (2 * rings); + let fontsize = Style.pie_fontsize() * this.scale_factor * this.text_scaling; + if (ring_width < 1.2 * fontsize) { + fontsize = ring_width / 1.2; + } + let thickness = ring_width / 1.5; + + cr.setLineWidth(thickness); + cr.setFontSize(fontsize); + let r = (height - ring_width) / 2; + for (let mount in this.mounts) { + GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); + Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); + arc(r, this.gtop.blocks - this.gtop.bfree, this.gtop.blocks, -pi / 2); + cr.stroke(); + r -= ring_width; + } + let y = (ring_width + fontsize) / 2; + for (let mount in this.mounts) { + var text = this.mounts[mount]; + if (text.length > 10) { + text = text.split('/').pop(); + } + cr.moveTo(0, y); + cr.showText(text); + y += ring_width; + } + cr.$dispose(); + } + + update_mounts(mounts) { + this.mounts = mounts; + this.actor.queue_repaint(); + } +} + +var TipItem = null; + +if (shell_Version < '3.36') { + TipItem = class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + constructor() { + super(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } +} else { + TipItem = GObject.registerClass( + { + GTypeName: 'TipItem' + }, + class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { + _init() { + super._init(); + // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); + this.actor.remove_style_class_name('popup-menu-item'); + this.actor.add_style_class_name('sm-tooltip-item'); + } + } + ); +} +const TipMenu = class SystemMonitor_TipMenu extends PopupMenu.PopupMenuBase { + constructor(sourceActor) { + // PopupMenu.PopupMenuBase.prototype._init.call(this, sourceActor, 'sm-tooltip-box'); + super(sourceActor, 'sm-tooltip-box'); + this.actor = new Clutter.Actor(); + // this.actor.connect('get-preferred-width', + // this._boxGetPreferredWidth).bind(this); + // this.actor.connect('get-preferred-height', + // this._boxGetPreferredHeight.bind(this)); + this.actor.add_actor(this.box); + } + // _boxGetPreferredWidth (actor, forHeight, alloc) { + // // let columnWidths = this.getColumnWidths(); + // // this.setColumnWidths(columnWidths); + // + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_width(forHeight); + // } + // _boxGetPreferredHeight (actor, forWidth, alloc) { + // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_height(forWidth); + // } + // _boxAllocate (actor, box, flags) { + // this.box.allocate(box, flags); + // } + _shift() { + // Probably old but works + let node = this.sourceActor.get_theme_node(); + let contentbox = node.get_content_box(this.sourceActor.get_allocation_box()); + + let sourceTopLeftX = 0; + let sourceTopLeftY = 0; + if (typeof this.sourceActor.get_transformed_extents === 'function') { + let extents = this.sourceActor.get_transformed_extents(); + let sourceTopLeft = extents.get_top_left(); + sourceTopLeftY = sourceTopLeft.y; + sourceTopLeftX = sourceTopLeft.x; + } else { + let allocation = Shell.util_get_transformed_allocation(this.sourceActor); + sourceTopLeftY = allocation.y1; + sourceTopLeftX = allocation.x1; + } + let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); + let [x, y] = [sourceTopLeftX + contentbox.x1, + sourceTopLeftY + contentbox.y1]; + let [cx, cy] = [sourceTopLeftX + (contentbox.x1 + contentbox.x2) / 2, + sourceTopLeftY + (contentbox.y1 + contentbox.y2) / 2]; + let [xm, ym] = [sourceTopLeftX + contentbox.x2, + sourceTopLeftY + contentbox.y2]; + let [width, height] = this.actor.get_size(); + let tipx = cx - width / 2; + tipx = Math.max(tipx, monitor.x); + tipx = Math.min(tipx, monitor.x + monitor.width - width); + let tipy = Math.floor(ym); + // Hacky condition to determine if the status bar is at the top or at the bottom of the screen + if (sourceTopLeftY / monitor.height > 0.3) { + tipy = sourceTopLeftY - height; // If it is at the bottom, place the tooltip above instead of below + } + this.actor.set_position(tipx, tipy); + } + open(animate) { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this.actor.show(); + this._shift(); + this.actor.raise_top(); + this.emit('open-state-changed', true); + } + close(animate) { + this.isOpen = false; + this.actor.hide(); + this.emit('open-state-changed', false); + } +} + +const TipBox = class SystemMonitor_TipBox { + constructor() { + this.actor = new St.BoxLayout({reactive: true}); + this.actor._delegate = this; + this.set_tip(new TipMenu(this.actor)); + this.in_to = this.out_to = 0; + this.actor.connect('enter-event', this.on_enter.bind(this)); + this.actor.connect('leave-event', this.on_leave.bind(this)); + } + set_tip(tipmenu) { + if (this.tipmenu) { + this.tipmenu.destroy(); + } + this.tipmenu = tipmenu; + if (this.tipmenu) { + Main.uiGroup.add_actor(this.tipmenu.actor); + this.hide_tip(); + } + } + show_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.open(); + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + hide_tip() { + if (!this.tipmenu) { + return; + } + this.tipmenu.close(); + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + } + on_enter() { + let show_tooltip = Schema.get_boolean('show-tooltip'); + + if (!show_tooltip) { + return; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + if (!this.in_to) { + this.in_to = Mainloop.timeout_add(500, + this.show_tip.bind(this)); + } + } + on_leave() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + if (!this.out_to) { + this.out_to = Mainloop.timeout_add(500, + this.hide_tip.bind(this)); + } + } + destroy() { + if (this.in_to) { + Mainloop.source_remove(this.in_to); + this.in_to = 0; + } + + if (this.out_to) { + Mainloop.source_remove(this.out_to); + this.out_to = 0; + } + + this.actor.destroy(); + } +} + +const ElementBase = class SystemMonitor_ElementBase extends TipBox { + constructor(properties) { + super(); + this.elt = ''; + this.item_name = _(''); + this.color_name = []; + this.text_items = []; + this.menu_items = []; + this.menu_visible = true; + + Object.assign(this, properties); + + // TipBox.prototype._init.apply(this, arguments); + this.vals = []; + this.tip_labels = []; + this.tip_vals = []; + this.tip_unit_labels = []; + + this.colors = []; + for (let color in this.color_name) { + let name = this.elt + '-' + this.color_name[color] + '-color'; + let clutterColor = color_from_string(Schema.get_string(name)); + Schema.connect('changed::' + name, (schema, key) => { + this.clutterColor = color_from_string(Schema.get_string(key)); + }); + Schema.connect('changed::' + name, () => { + this.chart.actor.queue_repaint(); + }); + this.colors.push(clutterColor); + } + + let element_width = Schema.get_int(this.elt + '-graph-width'); + if (Style.get('') === '-compact') { + element_width = Math.round(element_width / 1.5); + } + this.chart = new Chart(element_width, IconSize, this); + + Schema.connect('changed::background', () => { + this.chart.actor.queue_repaint(); + }); + + this.actor.visible = Schema.get_boolean(this.elt + '-display'); + Schema.connect( + 'changed::' + this.elt + '-display', (schema, key) => { + this.actor.visible = Schema.get_boolean(key); + }); + + this.interval = l_limit(Schema.get_int(this.elt + '-refresh-time')); + this.timeout = Mainloop.timeout_add( + this.interval, + this.update.bind(this), + GLib.PRIORITY_DEFAULT_IDLE + ); + + Schema.connect( + 'changed::' + this.elt + '-refresh-time', + (schema, key) => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.interval = l_limit(Schema.get_int(key)); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + Schema.connect('changed::' + this.elt + '-graph-width', this.resize.bind(this)); + + if (this.elt === 'thermal') { + Schema.connect('changed::thermal-threshold', + () => { + Mainloop.source_remove(this.timeout); + this.timeout = null; + this.reset_style(); + this.timeout = Mainloop.timeout_add( + this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); + }); + } + + this.label = new St.Label({text: this.elt === 'memory' ? _('mem') : _(this.elt), + style_class: Style.get('sm-status-label')}); + change_text.call(this); + Schema.connect('changed::' + this.elt + '-show-text', change_text.bind(this)); + + this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); + Schema.connect('changed::' + this.elt + '-show-menu', change_menu.bind(this)); + + this.actor.add_actor(this.label); + this.text_box = new St.BoxLayout(); + + this.actor.add_actor(this.text_box); + this.text_items = this.create_text_items(); + for (let item in this.text_items) { + this.text_box.add_actor(this.text_items[item]); + } + this.actor.add_actor(this.chart.actor); + change_style.call(this); + Schema.connect('changed::' + this.elt + '-style', change_style.bind(this)); + this.menu_items = this.create_menu_items(); + } + tip_format(unit) { + if (typeof (unit) === 'undefined') { + unit = '%'; + } + if (typeof (unit) === 'string') { + let all_unit = unit; + unit = []; + for (let i = 0; i < this.color_name.length; i++) { + unit.push(all_unit); + } + } + for (let i = 0; i < this.color_name.length; i++) { + let tipline = new TipItem(); + this.tipmenu.addMenuItem(tipline); + tipline.actor.add(new St.Label({text: _(this.color_name[i])})); + this.tip_labels[i] = new St.Label({text: ''}); + tipline.actor.add(this.tip_labels[i]); + + this.tip_unit_labels[i] = new St.Label({text: unit[i]}); + tipline.actor.add(this.tip_unit_labels[i]); + this.tip_vals[i] = 0; + } + } + // set_tip_unit: function(unit) { + // for (let i = 0;i < this.tip_unit_labels.length;i++) { + // this.tip_unit_labels[i].text = unit[i]; + // } + // } + update() { + if (!this.menu_visible && !this.actor.visible) { + return false; + } + this.refresh(); + this._apply(); + if (this.elt === 'thermal') { + this.threshold(); + } + this.chart.update(); + for (let i = 0; i < this.tip_vals.length; i++) { + if (this.tip_labels[i]) { + this.tip_labels[i].text = this.tip_vals[i].toString(); + } + } + return true; + } + reset_style() { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + threshold() { + if (Schema.get_int('thermal-threshold')) { + if (this.temp_over_threshold) { + this.text_items[0].set_style('color: rgba(255, 0, 0, 1)'); + } else { + this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); + } + } + } + resize(schema, key) { + let width = Schema.get_int(key); + if (Style.get('') === '-compact') { + width = Math.round(width / 1.5); + } + this.chart.resize(width); + } + destroy() { + TipBox.prototype.destroy.call(this); + if (this.timeout) { + Mainloop.source_remove(this.timeout); + this.timeout = null; + } + } +} + +const Battery = class SystemMonitor_Battery extends ElementBase { + constructor() { + super({ + elt: 'battery', + item_name: _('Battery'), + color_name: ['batt0'], + icon: '. GThemedIcon battery-good-symbolic battery-good' + }); + + this.max = 100; + this.icon_hidden = false; + this.percentage = 0; + this.timeString = '-- '; + this._proxy = StatusArea.aggregateMenu._power._proxy; + if (typeof (this._proxy) === 'undefined') { + this._proxy = StatusArea.battery._proxy; + } + this.powerSigID = this._proxy.connect('g-properties-changed', this.update_battery.bind(this)); + + // need to specify a default icon, since the contructor completes before UPower callback + this.gicon = Gio.icon_new_for_string(this.icon); + + this.tip_format('%'); + + this.update_battery(); + this.update_tips(); + // this.hide_system_icon(); + this.update(); + + // Schema.connect('changed::' + this.elt + '-hidesystem', this.hide_system_icon.bind(this)); + Schema.connect('changed::' + this.elt + '-time', this.update_tips.bind(this)); + } + refresh() { + // do nothing here? + } + update_battery() { + // callback function for when battery stats updated. + let battery_found = false; + let isBattery = false; + if (typeof (this._proxy.GetDevicesRemote) === 'undefined') { + let device_type = this._proxy.Type; + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + let icon = this._proxy.IconName; + let percentage = this._proxy.Percentage; + let seconds = this._proxy.TimeToEmpty; + this.update_battery_value(seconds, percentage, icon); + } else { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + } else { + this._proxy.GetDevicesRemote((devices, error) => { + if (error) { + log('[System monitor] Power proxy error: ' + error); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + return; + } + + let [result] = devices; + for (let i = 0; i < result.length; i++) { + let [device_id, device_type, icon, percentage, state, seconds] = result[i]; + + isBattery = (device_type === UPower.DeviceKind.BATTERY); + if (isBattery) { + battery_found = true; + this.update_battery_value(seconds, percentage, icon); + break; + } + } + + if (!battery_found) { + // log("[System monitor] No battery found"); + this.actor.hide(); + this.menu_visible = false; + build_menu_info(); + } + }); + } + } + update_battery_value(seconds, percentage, icon) { + if (seconds > 60) { + let time = Math.round(seconds / 60); + let minutes = time % 60; + let hours = Math.floor(time / 60); + this.timeString = C_('battery time remaining', '%d:%02d').format(hours, minutes); + } else { + this.timeString = '-- '; + } + this.percentage = Math.ceil(percentage); + this.gicon = Gio.icon_new_for_string(icon); + + if (Schema.get_boolean(this.elt + '-display')) { + this.actor.show() + } + if (Schema.get_boolean(this.elt + '-show-menu') && !this.menu_visible) { + this.menu_visible = true; + build_menu_info(); + } + } + hide_system_icon(override) { + let value = Schema.get_boolean(this.elt + '-hidesystem'); + if (!override) { + value = false; + } + if (value && Schema.get_boolean(this.elt + '-display')) { + if (shell_Version > '3.5') { + if (StatusArea.battery.actor.visible) { + StatusArea.battery.destroy(); + this.icon_hidden = true; + } + } else { + for (let Index = 0; Index < Main.panel._rightBox.get_children().length; Index++) { + if (StatusArea.battery === Main.panel._rightBox.get_children()[Index]._delegate) { + Main.panel._rightBox.get_children()[Index].destroy(); + StatusArea.battery = null; + this.icon_hidden = true; + break; + } + } + } + } else if (this.icon_hidden) { + if (shell_Version < '3.5') { + let Indicator = new Panel.STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION.battery(); + Main.panel.addToStatusArea('battery', Indicator, Panel.STANDARD_STATUS_AREA_ORDER.indexOf('battery')); + } else { + let Indicator = new Panel.PANEL_ITEM_IMPLEMENTATIONS.battery(); + Main.panel.addToStatusArea('battery', Indicator, Main.sessionMode.panel.right.indexOf('battery'), 'right'); + } + this.icon_hidden = false; + // Main.panel._updatePanel('right'); + } + } + get_battery_unit() { + let unitString; + let value = Schema.get_boolean(this.elt + '-time'); + + if (value) { + unitString = 'h'; + } else { + unitString = '%'; + } + + return unitString; + } + update_tips() { + let unitString = this.get_battery_unit(); + + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[2].text = unitString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[1].text = unitString; + } + + this.update(); + } + _apply() { + let displayString; + let value = Schema.get_boolean(this.elt + '-time'); + if (value) { + displayString = this.timeString; + } else { + displayString = this.percentage.toString() + } + if (Schema.get_boolean(this.elt + '-display')) { + this.text_items[0].gicon = this.gicon; + this.text_items[1].text = displayString; + } + if (Schema.get_boolean(this.elt + '-show-menu')) { + this.menu_items[0].text = displayString; + } + this.vals = [this.percentage]; + this.tip_vals[0] = Math.round(this.percentage); + } + create_text_items() { + return [ + new St.Icon({ + gicon: Gio.icon_new_for_string(this.icon), + style_class: Style.get('sm-status-icon')}), + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.get_battery_unit(), + style_class: Style.get('sm-label')}) + ]; + } + destroy() { + ElementBase.prototype.destroy.call(this); + this._proxy.disconnect(this.powerSigID); + } +} + +const Cpu = class SystemMonitor_Cpu extends ElementBase { + constructor(cpuid) { + super({ + elt: 'cpu', + item_name: _('CPU'), + color_name: ['user', 'system', 'nice', 'iowait', 'other'], + cpuid: -1 // cpuid is -1 when all cores are displayed in the same graph + }); + this.max = 100; + + this.cpuid = cpuid; + this.gtop = new GTop.glibtop_cpu(); + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + try { + this.total_cores = GTop.glibtop_get_sysinfo().ncpu; + if (cpuid === -1) { + this.max *= this.total_cores; + } + } catch (e) { + this.total_cores = this.get_cores(); + global.logError(e) + } + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + this.item_name = _('Cpu'); + if (cpuid !== -1) { + this.item_name += ' ' + (cpuid + 1); + } // append cpu number to cpu name in popup + // ElementBase.prototype._init.call(this); + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_cpu(this.gtop); + // display global cpu usage on 1 graph + if (this.cpuid === -1) { + this.current[0] = this.gtop.user; + this.current[1] = this.gtop.sys; + this.current[2] = this.gtop.nice; + this.current[3] = this.gtop.idle; + this.current[4] = this.gtop.iowait; + let delta = (this.gtop.total - this.last_total) / (100 * this.total_cores); + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.total; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } else { + // display per cpu data + this.current[0] = this.gtop.xcpu_user[this.cpuid]; + this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + let delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total) / 100; + + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); + this.last[i] = this.current[i]; + } + this.last_total = this.gtop.xcpu_total[this.cpuid]; + } else if (delta < 0) { + this.last = [0, 0, 0, 0, 0]; + this.current = [0, 0, 0, 0, 0]; + this.last_total = 0; + this.usage = [0, 0, 0, 1, 0]; + } + } + + // GTop.glibtop_get_cpu(this.gtop); + // // display global cpu usage on 1 graph + // if (this.cpuid == -1) { + // this.current[0] = this.gtop.user; + // this.current[1] = this.gtop.sys; + // this.current[2] = this.gtop.nice; + // this.current[3] = this.gtop.idle; + // this.current[4] = this.gtop.iowait; + // } else { + // // display cpu usage for given core + // this.current[0] = this.gtop.xcpu_user[this.cpuid]; + // this.current[1] = this.gtop.xcpu_sys[this.cpuid]; + // this.current[2] = this.gtop.xcpu_nice[this.cpuid]; + // this.current[3] = this.gtop.xcpu_idle[this.cpuid]; + // this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; + // } + // + // let delta = 0; + // if (this.cpuid == -1) + // delta = (this.gtop.total - this.last_total)/(100*this.total_cores); + // else + // delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total)/100; + // + // if (delta > 0) { + // for (let i = 0;i < 5;i++) { + // this.usage[i] = Math.round((this.current[i] - this.last[i])/delta); + // this.last[i] = this.current[i]; + // } + // if (this.cpuid == -1) + // this.last_total = this.gtop.total; + // else + // this.last_total = this.gtop.xcpu_total[this.cpuid]; + // } + } + _apply() { + let percent = 0; + if (this.cpuid === -1) { + percent = Math.round(((100 * this.total_cores) - this.usage[3]) / + this.total_cores); + } else { + percent = Math.round((100 - this.usage[3])); + } + + this.text_items[0].text = this.menu_items[0].text = percent.toString(); + let other = 100; + for (let i = 0; i < this.usage.length; i++) { + other -= this.usage[i]; + } + // Not to be confusing + other = Math.max(0, other); + this.vals = [this.usage[0], this.usage[1], + this.usage[2], this.usage[4], other]; + for (let i = 0; i < 5; i++) { + this.tip_vals[i] = Math.round(this.vals[i]); + } + } + + get_cores() { + // Getting xcpu_total makes gjs 1.29.18 segfault + // let cores = 0; + // GTop.glibtop_get_cpu(this.gtop); + // let gtop_total = this.gtop.xcpu_total + // for (let i = 0; i < gtop_total.length;i++) { + // if (gtop_total[i] > 0) + // cores++; + // } + // return cores; + return 1; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}) + ]; + } +} + +// Check if one graph per core must be displayed and create the +// appropriate number of cpu items +function createCpus() { + let array = []; + let numcores = 1; + + if (Schema.get_boolean('cpu-individual-cores')) { + // get number of cores + let gtop = new GTop.glibtop_cpu(); + try { + numcores = GTop.glibtop_get_sysinfo().ncpu; + } catch (e) { + global.logError(e); + numcores = 1; + } + } + + // there are several cores to display, + // instantiate each cpu + if (numcores > 1) { + for (let i = 0; i < numcores; i++) { + array.push(new Cpu(i)); + } + } else { + // individual cores option is not set or we failed to + // get the number of cores, create a global cpu item + array.push(new Cpu(-1)); + } + + return array; +} + +const Disk = class SystemMonitor_Disk extends ElementBase { + constructor() { + super({ + elt: 'disk', + item_name: _('Disk'), + color_name: ['read', 'write'] + }); + this.mounts = MountsMonitor.get_mounts(); + MountsMonitor.add_listener(this.update_mounts.bind(this)); + this.last = [0, 0]; + this.usage = [0, 0]; + this.last_time = 0; + this.tip_format(_('MiB/s')); + this.update(); + } + update_mounts(mounts) { + this.mounts = mounts; + } + refresh() { + let accum = [0, 0]; + + let file = Gio.file_new_for_path('/proc/diskstats'); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result); + let lines = parse_bytearray(as_r[1]).toString().split('\n'); + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + let entry = line.trim().split(/[\s]+/); + if (typeof (entry[1]) === 'undefined') { + break; + } + accum[0] += parseInt(entry[5]); + accum[1] += parseInt(entry[9]); + } + + let time = GLib.get_monotonic_time() / 1000; + let delta = (time - this.last_time) / 1000; + if (delta > 0) { + for (let i = 0; i < 2; i++) { + this.usage[i] = ((accum[i] - this.last[i]) / delta / 1024 / 8); + this.last[i] = accum[i]; + } + } + this.last_time = time; + }); + } + _apply() { + this.vals = this.usage.slice(); + for (let i = 0; i < 2; i++) { + if (this.usage[i] < 10) { + this.usage[i] = Math.round(10 * this.usage[i]) / 10; + } else { + this.usage[i] = Math.round(this.usage[i]); + } + } + this.tip_vals = [this.usage[0], this.usage[1]]; + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toLocaleString(Locale); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[1].toLocaleString(Locale); + } + create_text_items() { + return [ + new St.Label({ + text: _('R'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('W'), + style_class: Style.get('sm-status-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-disk-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-disk-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _('R'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: Style.diskunits(), + style_class: Style.get('sm-label')}), + new St.Label({ + text: ' ' + _('W'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Freq = class SystemMonitor_Freq extends ElementBase { + constructor() { + super({ + elt: 'freq', + item_name: _('Freq'), + color_name: ['freq'] + }); + this.freq = 0; + this.tip_format('MHz'); + this.update(); + } + refresh() { + let total_frequency = 0; + let num_cpus = GTop.glibtop_get_sysinfo().ncpu; + let i = 0; + let file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + var that = this; + file.load_contents_async(null, function cb(source, result) { + let as_r = source.load_contents_finish(result); + total_frequency += parseInt(parse_bytearray(as_r[1])); + + if (++i >= num_cpus) { + that.freq = Math.round(total_frequency / num_cpus / 1000); + } else { + file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); + file.load_contents_async(null, cb.bind(that)); + } + }); + } + _apply() { + let value = this.freq.toString(); + this.text_items[0].text = value + ' '; + this.vals[0] = value; + this.tip_vals[0] = value; + if (Style.get('') !== '-compact') { + this.menu_items[0].text = value; + } else { + this.menu_items[0].text = this._pad(value, 4); + } + } + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-big-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: 'MHz', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: 'MHz', + style_class: Style.get('sm-label')}) + ]; + } +} + +const Mem = class SystemMonitor_Mem extends ElementBase { + constructor() { + super({ + elt: 'memory', + item_name: _('Memory'), + color_name: ['program', 'buffer', 'cache'] + }); + this.max = 1; + + this.gtop = new GTop.glibtop_mem(); + this.mem = [0, 0, 0]; + + GTop.glibtop_get_mem(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_mem(this.gtop); + if (this.useGiB) { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[0] /= this._decimals; + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[1] /= this._decimals; + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.mem[2] /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem[0] = Math.round(this.gtop.user / this._unitConversion); + this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); + this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0, 0, 0]; + } else { + for (let i = 0; i < 3; i++) { + this.vals[i] = this.mem[i] / this.total; + this.tip_vals[i] = Math.round(this.vals[i] * 100); + } + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem[0]) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.mem[0]) + + '/' + this._pad(this.total); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Net = class SystemMonitor_Net extends ElementBase { + constructor() { + super({ + elt: 'net', + item_name: _('Net'), + color_name: ['down', 'downerrors', 'up', 'uperrors', 'collisions'] + }); + this.speed_in_bits = false; + this.ifs = []; + this.client = libnm_glib ? NM.Client.new() : NM.Client.new(null); + this.update_iface_list(); + + if (!this.ifs.length) { + let net_lines = Shell.get_file_contents_utf8_sync('/proc/net/dev').split('\n'); + for (let i = 2; i < net_lines.length - 1; i++) { + let ifc = net_lines[i].replace(/^\s+/g, '').split(':')[0]; + if (Shell.get_file_contents_utf8_sync('/sys/class/net/' + ifc + '/operstate') + .replace(/\s/g, '') === 'up' && + ifc.indexOf('br') < 0 && + ifc.indexOf('lo') < 0) { + this.ifs.push(ifc); + } + } + } + this.gtop = new GTop.glibtop_netload(); + this.last = [0, 0, 0, 0, 0]; + this.usage = [0, 0, 0, 0, 0]; + this.last_time = 0; + this.tip_format([_('KiB/s'), '/s', _('KiB/s'), '/s', '/s']); + this.update_units(); + Schema.connect('changed::' + this.elt + '-speed-in-bits', this.update_units.bind(this)); + try { + let iface_list = this.client.get_devices(); + this.NMsigID = []; + for (let j = 0; j < iface_list.length; j++) { + this.NMsigID[j] = iface_list[j].connect('state-changed', this.update_iface_list.bind(this)); + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings: ' + e); + } + this.update(); + } + update_units() { + this.speed_in_bits = Schema.get_boolean(this.elt + '-speed-in-bits'); + } + update_iface_list() { + try { + this.ifs = []; + let iface_list = this.client.get_devices(); + for (let j = 0; j < iface_list.length; j++) { + if (iface_list[j].state === NetworkManager.DeviceState.ACTIVATED) { + this.ifs.push(iface_list[j].get_ip_iface() || iface_list[j].get_iface()); + } + } + } catch (e) { + global.logError('Please install Network Manager Gobject Introspection Bindings'); + } + } + refresh() { + let accum = [0, 0, 0, 0, 0]; + + for (let ifn in this.ifs) { + GTop.glibtop_get_netload(this.gtop, this.ifs[ifn]); + accum[0] += this.gtop.bytes_in; + accum[1] += this.gtop.errors_in; + accum[2] += this.gtop.bytes_out; + accum[3] += this.gtop.errors_out; + accum[4] += this.gtop.collisions; + } + + let time = GLib.get_monotonic_time() * 0.001024; + let delta = time - this.last_time; + if (delta > 0) { + for (let i = 0; i < 5; i++) { + this.usage[i] = Math.round((accum[i] - this.last[i]) / delta); + this.last[i] = accum[i]; + this.vals[i] = this.usage[i]; + } + } + this.last_time = time; + } + + // pad a string with leading spaces + _pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = ' ' + str; + } + return str; + } + + _apply() { + this.tip_vals = this.usage; + if (this.speed_in_bits) { + this.tip_vals[0] = Math.round(this.tip_vals[0] * 8.192); + this.tip_vals[2] = Math.round(this.tip_vals[2] * 8.192); + if (this.tip_vals[0] < 1000) { + this.text_items[2].text = Style.netunits_kbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('kbit/s'); + } else if (this.tip_vals[0] < 1000000) { + this.text_items[2].text = Style.netunits_mbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Mbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbits(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('Gbit/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1000000).toPrecision(3); + } + if (this.tip_vals[2] < 1000) { + this.text_items[5].text = Style.netunits_kbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('kbit/s'); + } else if (this.tip_vals[2] < 1000000) { + this.text_items[5].text = Style.netunits_mbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Mbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbits(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('Gbit/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1000000).toPrecision(3); + } + } else { + if (this.tip_vals[0] < 1024) { + this.text_items[2].text = Style.netunits_kbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('KiB/s'); + } else if (this.tip_vals[0] < 1048576) { + this.text_items[2].text = Style.netunits_mbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('MiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1024).toPrecision(3); + } else { + this.text_items[2].text = Style.netunits_gbytes(); + this.menu_items[1].text = this.tip_unit_labels[0].text = _('GiB/s'); + this.tip_vals[0] = (this.tip_vals[0] / 1048576).toPrecision(3); + } + if (this.tip_vals[2] < 1024) { + this.text_items[5].text = Style.netunits_kbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('KiB/s'); + } else if (this.tip_vals[2] < 1048576) { + this.text_items[5].text = Style.netunits_mbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('MiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1024).toPrecision(3); + } else { + this.text_items[5].text = Style.netunits_gbytes(); + this.menu_items[4].text = this.tip_unit_labels[2].text = _('GiB/s'); + this.tip_vals[2] = (this.tip_vals[2] / 1048576).toPrecision(3); + } + } + + if (Style.get('') !== '-compact') { + this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toString(); + this.menu_items[3].text = this.text_items[4].text = this.tip_vals[2].toString(); + } else { + this.menu_items[0].text = this.text_items[1].text = this._pad(this.tip_vals[0].toString(), 4); + this.menu_items[3].text = this.text_items[4].text = this._pad(this.tip_vals[2].toString(), 4); + } + } + create_text_items() { + return [ + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-down-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Icon({ + icon_size: 2 * IconSize / 3 * Style.iconsize(), + icon_name: 'go-up-symbolic'}), + new St.Label({ + text: '', + style_class: Style.get('sm-net-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-net-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↓'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(' KiB/s'), + style_class: Style.get('sm-label')}), + new St.Label({ + text: _(' ↑'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Swap = class SystemMonitor_Swap extends ElementBase { + constructor() { + super({ + elt: 'swap', + item_name: _('Swap'), + color_name: ['used'] + }); + this.max = 1; + this.gtop = new GTop.glibtop_swap(); + + GTop.glibtop_get_swap(this.gtop); + this.total = Math.round(this.gtop.total / 1024 / 1024); + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1024 * 1024; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + + this.tip_format(); + this.update(); + } + refresh() { + GTop.glibtop_get_swap(this.gtop); + if (this.useGiB) { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.swap /= this._decimals; + this.total = Math.round(this.gtop.total / this._unitConversion); + this.total /= this._decimals; + } else { + this.swap = Math.round(this.gtop.used / this._unitConversion); + this.total = Math.round(this.gtop.total / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + } + // examples: 5.85, 16.0, 128 + return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); + } + + return number.toLocaleString(Locale); + } + _apply() { + if (this.total === 0) { + this.vals = this.tip_vals = [0]; + } else { + this.vals[0] = this.swap / this.total; + this.tip_vals[0] = Math.round(this.vals[0] * 100); + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toString(); + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.swap) + + ' / ' + this._pad(this.total); + } else { + this.menu_items[3].text = this._pad(this.swap) + + '/' + this._pad(this.total); + } + } + + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = 'MiB'; + if (this.useGiB) { + unit = 'GiB'; + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _(unit), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Thermal = class SystemMonitor_Thermal extends ElementBase { + constructor() { + super({ + elt: 'thermal', + item_name: _('Thermal'), + color_name: ['tz0'] + }); + this.max = 100; + + this.item_name = _('Thermal'); + this.temperature = '-- '; + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + this.display_error = true; + this.tip_format(this.temperature_symbol()); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.temperature = Math.round(parseInt(parse_bytearray(as_r[1])) / 1000); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + + this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); + } + _apply() { + this.text_items[0].text = this.menu_items[0].text = this.temperature_text(); + this.temp_over_threshold = this.temperature > Schema.get_int('thermal-threshold'); + this.vals = [this.temperature]; + this.tip_vals[0] = this.temperature_text(); + this.text_items[1].text = this.menu_items[1].text = this.temperature_symbol(); + this.tip_unit_labels[0].text = _(this.temperature_symbol()); + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-temp-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: this.temperature_symbol(), + style_class: Style.get('sm-label')}) + ]; + } + temperature_text() { + let temperature = this.temperature; + if (this.fahrenheit_unit) { + temperature = Math.round(temperature * 1.8 + 32); + } + return temperature.toString(); + } + temperature_symbol() { + return this.fahrenheit_unit ? '°F' : '°C'; + } +} + +const Fan = class SystemMonitor_Fan extends ElementBase { + constructor() { + super({ + elt: 'fan', + item_name: _('Fan'), + color_name: ['fan0'] + }); + this.rpm = 0; + this.display_error = true; + this.tip_format(_('rpm')); + Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); + this.update(); + } + refresh() { + let sfile = Schema.get_string(this.elt + '-sensor-file'); + if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { + let file = Gio.file_new_for_path(sfile); + file.load_contents_async(null, (source, result) => { + let as_r = source.load_contents_finish(result) + this.rpm = parseInt(parse_bytearray(as_r[1])); + }); + } else if (this.display_error) { + global.logError('error reading: ' + sfile); + this.display_error = false; + } + } + _apply() { + this.text_items[0].text = this.rpm.toString(); + this.menu_items[0].text = this.rpm.toString(); + this.vals = [this.rpm / 10]; + this.tip_vals[0] = this.rpm; + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: _('rpm'), style_class: Style.get('sm-unit-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: _('rpm'), + style_class: Style.get('sm-label')}) + ]; + } +} + +const Gpu = class SystemMonitor_Gpu extends ElementBase { + constructor() { + super({ + elt: 'gpu', + item_name: _('GPU'), + color_name: ['used', 'memory'] + }); + this.max = 100; + + this.item_name = _('GPU'); + this.mem = 0; + this.total = 0; + this.tip_format(); + this.update(); + } + _unit(total) { + this.total = total; + let threshold = 4 * 1024; // In MiB + this.useGiB = false; + this._unitConversion = 1; + this._decimals = 100; + if (this.total > threshold) { + this.useGiB = true; + this._unitConversion *= 1024 / this._decimals; + } + } + refresh() { + // Run asynchronously, to avoid shell freeze + try { + let path = Me.dir.get_path(); + let script = ['/bin/bash', path + '/gpu_usage.sh']; + + // Create subprocess and capture STDOUT + let proc = new Gio.Subprocess({argv: script, flags: Gio.SubprocessFlags.STDOUT_PIPE}); + proc.init(null); + // Asynchronously call the output handler when script output is ready + proc.communicate_utf8_async(null, null, Lang.bind(this, this._handleOutput)); + } catch (err) { + global.logError(err.message); + } + } + _handleOutput(proc, result) { + let [ok, output, ] = proc.communicate_utf8_finish(result); + if (ok) { + this._readTemperature(output); + } else { + global.logError('gpu_usage.sh invocation failed'); + } + } + _sanitizeUsageValue(val) { + val = parseInt(val); + if (isNaN(val)) { + val = 0 + } + return val; + } + _readTemperature(procOutput) { + let usage = procOutput.split('\n'); + let memTotal = this._sanitizeUsageValue(usage[0]); + let memUsed = this._sanitizeUsageValue(usage[1]); + this.percentage = this._sanitizeUsageValue(usage[2]); + if (typeof this.useGiB === 'undefined') { + this._unit(memTotal); + this._update_unit(); + } + + if (this.useGiB) { + this.mem = Math.round(memUsed / this._unitConversion); + this.mem /= this._decimals; + this.total = Math.round(memTotal / this._unitConversion); + this.total /= this._decimals; + } else { + this.mem = Math.round(memUsed / this._unitConversion); + this.total = Math.round(memTotal / this._unitConversion); + } + } + _pad(number) { + if (this.useGiB) { + if (number < 1) { + // examples: 0.01, 0.10, 0.88 + return number.toFixed(2); + } + // examples: 5.85, 16.0, 128 + return number.toPrecision(3); + } + + return number; + } + _update_unit() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + this.menu_items[4].text = unit; + } + _apply() { + this.tip_unit_labels[1].text = "/ " + this.total + " " + this.menu_items[4].text; + if (this.total === 0) { + this.vals = [0, 0]; + this.tip_vals = [0, 0]; + } else { + // we subtract percentage from memory because we do not want memory to be + // "accumulated" in the chart with utilization; these two measures should be + // independent + this.vals = [this.percentage, this.mem / this.total * 100 - this.percentage]; + this.tip_vals = [Math.round(this.vals[0]), this.mem]; + } + this.text_items[0].text = this.tip_vals[0].toString(); + this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); + + if (Style.get('') !== '-compact') { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + ' / ' + this._pad(this.total).toLocaleString(Locale); + } else { + this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + + '/' + this._pad(this.total).toLocaleString(Locale); + } + } + create_text_items() { + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-status-value'), + y_align: Clutter.ActorAlign.CENTER}), + new St.Label({ + text: '%', + style_class: Style.get('sm-perc-label'), + y_align: Clutter.ActorAlign.CENTER}) + ]; + } + create_menu_items() { + let unit = _('MiB'); + if (this.useGiB) { + unit = _('GiB'); + } + return [ + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: '%', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-label')}), + new St.Label({ + text: '', + style_class: Style.get('sm-value')}), + new St.Label({ + text: unit, + style_class: Style.get('sm-label')}) + ]; + } +} + +const Icon = class SystemMonitor_Icon { + constructor() { + this.actor = new St.Icon({ + icon_name: 'org.gnome.SystemMonitor-symbolic', + style_class: 'system-status-icon' + }); + this.actor.visible = Schema.get_boolean('icon-display'); + Schema.connect( + 'changed::icon-display', + () => { + this.actor.visible = Schema.get_boolean('icon-display'); + } + ); + } +} + +function init() { + log('[System monitor] applet init from ' + extension.path); + + Convenience.initTranslations(); + // Get locale, needed as an argument for toLocaleString() since GNOME Shell 3.24 + // See: mozjs library bug https://bugzilla.mozilla.org/show_bug.cgi?id=999003 + Locale = GLib.get_language_names()[0]; + if (Locale.indexOf('_') !== -1) { + Locale = Locale.split('_')[0]; + } + + IconSize = Math.round(Panel.PANEL_ICON_SIZE * 4 / 5); +} + +function enable() { + log('[System monitor] applet enabling'); + Schema = Convenience.getSettings(); + + Style = new smStyleManager(); + MountsMonitor = new smMountsMonitor(); + + Background = color_from_string(Schema.get_string('background')); + + if (!(smDepsGtop && smDepsNM)) { + Main.__sm = { + smdialog: new smDialog() + }; + + let dialog_timeout = Mainloop.timeout_add_seconds( + 1, + () => { + Main.__sm.smdialog.open(); + Mainloop.source_remove(dialog_timeout); + return true; + }); + } else { + let panel = Main.panel._rightBox; + StatusArea = Main.panel._statusArea; + if (typeof (StatusArea) === 'undefined') { + StatusArea = Main.panel.statusArea; + } + if (Schema.get_boolean('center-display')) { + panel = Main.panel._centerBox; + } + + MountsMonitor.connect(); + + // Debug + Main.__sm = { + tray: new PanelMenu.Button(0.5), + icon: new Icon(), + pie: new Pie(), + bar: new Bar(), + elts: [], + }; + + // Items to Monitor + Main.__sm.elts = createCpus(); + Main.__sm.elts.push(new Freq()); + Main.__sm.elts.push(new Mem()); + Main.__sm.elts.push(new Swap()); + Main.__sm.elts.push(new Net()); + Main.__sm.elts.push(new Disk()); + Main.__sm.elts.push(new Gpu()); + Main.__sm.elts.push(new Thermal()); + Main.__sm.elts.push(new Fan()); + Main.__sm.elts.push(new Battery()); + + let tray = Main.__sm.tray; + let elts = Main.__sm.elts; + + if (Schema.get_boolean('move-clock')) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._centerBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, -1, Main.panel._rightBox); + tray.clockMoved = true; + } + + Schema.connect('changed::background', (schema, key) => { + Background = color_from_string(Schema.get_string(key)); + }); + Main.panel._addToPanelBox('system-monitor', tray, 1, panel); + + // The spacing adds a distance between the graphs/text on the top bar + let spacing = Schema.get_boolean('compact-display') ? '1' : '4'; + let box = new St.BoxLayout({style: 'spacing: ' + spacing + 'px;'}); + if (shell_Version < '3.36') { + tray.actor.add_actor(box); + } else { + tray.add_actor(box); + } + box.add_actor(Main.__sm.icon.actor); + // Add items to panel box + for (let elt in elts) { + box.add_actor(elts[elt].actor); + } + + // Build Menu Info Box Table + let menu_info = new PopupMenu.PopupBaseMenuItem({reactive: false}); + let menu_info_box = new St.BoxLayout(); + menu_info.actor.add(menu_info_box); + Main.__sm.tray.menu.addMenuItem(menu_info, 0); + + build_menu_info(); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + let pie_item = Main.__sm.pie; + pie_item.create_menu_item(); + tray.menu.addMenuItem(pie_item.menu_item); + + let bar_item = Main.__sm.bar; + bar_item.create_menu_item(); + tray.menu.addMenuItem(bar_item.menu_item); + + change_usage(); + Schema.connect('changed::disk-usage-style', change_usage); + + tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + + tray.menu.connect( + 'open-state-changed', + function (menu, isOpen) { + if (isOpen) { + Main.__sm.pie.actor.queue_repaint(); + + menu_timeout = Mainloop.timeout_add_seconds( + 5, + () => { + Main.__sm.pie.actor.queue_repaint(); + return true; + }); + } else { + Mainloop.source_remove(menu_timeout); + } + } + ); + + let _appSys = Shell.AppSystem.get_default(); + let _gsmApp = _appSys.lookup_app('gnome-system-monitor.desktop'); + let _gsmPrefs = _appSys.lookup_app('gnome-shell-extension-prefs.desktop'); + if (_gsmPrefs === null) { + _gsmPrefs = _appSys.lookup_app('org.gnome.Extensions.desktop'); + } + let item; + item = new PopupMenu.PopupMenuItem(_('System Monitor...')); + item.connect('activate', () => { + _gsmApp.activate(); + }); + tray.menu.addMenuItem(item); + + item = new PopupMenu.PopupMenuItem(_('Preferences...')); + item.connect('activate', () => { + if (typeof ExtensionUtils.openPrefs === 'function') { + ExtensionUtils.openPrefs(); + } else if (_gsmPrefs.get_state() === _gsmPrefs.SHELL_APP_STATE_RUNNING) { + _gsmPrefs.activate(); + } else { + let info = _gsmPrefs.get_app_info(); + let timestamp = global.display.get_current_time_roundtrip(); + info.launch_uris([metadata.uuid], global.create_app_launch_context(timestamp, -1)); + } + }); + tray.menu.addMenuItem(item); + Main.panel.menuManager.addMenu(tray.menu); + } + log('[System monitor] applet enabling done'); +} + +function disable() { + // restore clock + if (Main.__sm.tray.clockMoved) { + let dateMenu = Main.panel.statusArea.dateMenu; + Main.panel._rightBox.remove_actor(dateMenu.container); + Main.panel._addToPanelBox('dateMenu', dateMenu, Main.sessionMode.panel.center.indexOf('dateMenu'), Main.panel._centerBox); + } + // restore system power icon if necessary + // workaround bug introduced by multiple cpus init : + // if (Schema.get_boolean('battery-hidesystem') && Main.__sm.elts.battery.icon_hidden) { + // Main.__sm.elts.battery.hide_system_icon(false); + // } + // for (let i in Main.__sm.elts) { + // if (Main.__sm.elts[i].elt == 'battery') + // Main.__sm.elts[i].hide_system_icon(false); + // } + + if (MountsMonitor) { + MountsMonitor.disconnect(); + MountsMonitor = null; + } + + if (Style) { + Style = null; + } + + Schema.run_dispose(); + for (let eltName in Main.__sm.elts) { + Main.__sm.elts[eltName].destroy(); + } + if (shell_Version < '3.36') { + Main.__sm.tray.actor.destroy(); + } else { + Main.__sm.tray.destroy(); + } + Main.__sm = null; + + log('[System monitor] applet disable'); +} diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh new file mode 100644 index 0000000..de840b9 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh @@ -0,0 +1,49 @@ +#!/bin/sh +################################################################################## +# This file is part of System Monitor Gnome extension. +# System Monitor Gnome extension 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. +# System Monitor Gnome extension 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 System Monitor. If not, see . +# Copyright 2017 Fran Glais, David King, indigohedgehog@github. +################################################################################## + +################################## +# # +# Check for GPU memory usage # +# # +################################## + +checkcommand() +{ + command -v "$1" > /dev/null 2>&1 +} + +# This will print three lines. The first one is the the total vRAM available, +# the second one is the used vRAM and the third on is the GPU usage in %. +if checkcommand nvidia-smi; then + nvidia-smi -i 0 --query-gpu=memory.total,memory.used,utilization.gpu --format=csv,noheader,nounits | while IFS=', ' read -r a b c; do echo "$a"; echo "$b"; echo "$c"; done + +elif lsmod | grep amdgpu > /dev/null; then + total=$(cat /sys/class/drm/card0/device/mem_info_vram_total) + echo $((total / 1024 / 1024)) + + used=$(cat /sys/class/drm/card0/device/mem_info_vram_used) + echo $((used / 1024 / 1024)) + + cat /sys/class/drm/card0/device/gpu_busy_percent + +elif checkcommand glxinfo; then + TOTALVRAM=$(glxinfo | grep -A2 -i GL_NVX_gpu_memory_info | grep -E -i "dedicated" | cut -f2- -d ':' | gawk '{print $1}') + AVAILVRAM=$(glxinfo | grep -A4 -i GL_NVX_gpu_memory_info | grep -E -i "available dedicated" | cut -f2- -d ':' | gawk '{print $1}') + FREEVRAM=$((TOTALVRAM-AVAILVRAM)) + echo "$TOTALVRAM" + echo "$FREEVRAM" + +fi diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ed116be Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..ab48c30 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..be4ab2d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..a14e961 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7302234 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7f3d4b3 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b1ccb17 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7623fac Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..e567368 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..5ffcee0 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..8fb4592 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..4e96e8e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..94c2ce3 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..472482f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9537a6e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..b756a3d Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..7d79d27 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c789c33 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..3bca914 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..c362e0e Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..1d4ff15 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..9169a1f Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo new file mode 100644 index 0000000..09f9162 Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json new file mode 100644 index 0000000..44e737a --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json @@ -0,0 +1,19 @@ +{ + "_generated": "Generated by SweetTooth, do not edit", + "description": "Display system information in GNOME Shell status bar, such as memory, CPU, disk and battery usages, network rates\u2026", + "gettext-domain": "system-monitor", + "name": "system-monitor", + "settings-schema": "org.gnome.shell.extensions.system-monitor", + "shell-version": [ + "3.26", + "3.28", + "3.30", + "3.34", + "3.32", + "3.36", + "40" + ], + "url": "https://github.com/paradoxxxzero/gnome-shell-system-monitor-applet", + "uuid": "system-monitor@paradoxxx.zero.gmail.com", + "version": 40 +} \ No newline at end of file diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js new file mode 100644 index 0000000..388f512 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js @@ -0,0 +1,553 @@ +const Gtk = imports.gi.Gtk; +const Gio = imports.gi.Gio; +const Gdk = imports.gi.Gdk; +const GLib = imports.gi.GLib; +const ByteArray = imports.byteArray; +const Config = imports.misc.config; + +const Gettext = imports.gettext.domain('system-monitor'); + +let extension = imports.misc.extensionUtils.getCurrentExtension(); +let convenience = extension.imports.convenience; + +const _ = Gettext.gettext; +const N_ = function (e) { + return e; +}; + +let Schema; + +const shellMajorVersion = parseInt(Config.PACKAGE_VERSION.split('.')[0]); + +function init() { + convenience.initTranslations(); + Schema = convenience.getSettings(); +} + +String.prototype.capitalize = function () { + return this.replace(/(^|\s)([a-z])/g, function (m, p1, p2) { + return p1 + p2.toUpperCase(); + }); +}; + +function color_to_hex(color) { + var output = N_('#%02x%02x%02x%02x').format( + 255 * color.red, + 255 * color.green, + 255 * color.blue, + 255 * color.alpha); + return output; +} + +function parse_bytearray(bytearray) { + if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { + return ByteArray.toString(bytearray); + } + return bytearray +} + +function check_sensors(sensor_type) { + const hwmon_path = '/sys/class/hwmon/'; + const hwmon_dir = Gio.file_new_for_path(hwmon_path); + + const sensor_files = []; + const sensor_labels = []; + + function get_label_from(file) { + if (file.query_exists(null)) { + // load_contents (and even cat) fails with "Invalid argument" for some label files + try { + let [success, contents] = file.load_contents(null); + if (success) { + return String(parse_bytearray(contents)).split('\n')[0]; + } + } catch (e) { + log('[System monitor] error loading label from file ' + file.get_path() + ': ' + e); + } + } + return null; + } + + function add_sensors_from(chip_dir, chip_label) { + const chip_children = chip_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!chip_children) { + log('[System monitor] error enumerating children of chip ' + chip_dir.get_path()); + return false; + } + + const input_entry_regex = new RegExp('^' + sensor_type + '(\\d+)_input$'); + let info; + let added = false; + while ((info = chip_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.REGULAR) { + continue; + } + const matches = info.get_name().match(input_entry_regex); + if (!matches) { + continue; + } + const input_ordinal = matches[1]; + const input = chip_children.get_child(info); + const input_label = get_label_from(chip_dir.get_child(sensor_type + input_ordinal + '_label')); + + sensor_files.push(input.get_path()); + sensor_labels.push(chip_label + ' - ' + (input_label || input_ordinal)); + added = true; + } + return added; + } + + const hwmon_children = hwmon_dir.enumerate_children( + 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + if (!hwmon_children) { + log('[System monitor] error enumerating hwmon children'); + return [[], []]; + } + + let info; + while ((info = hwmon_children.next_file(null))) { + if (info.get_file_type() !== Gio.FileType.DIRECTORY || !info.get_name().match(/^hwmon\d+$/)) { + continue; + } + const chip = hwmon_children.get_child(info); + const chip_label = get_label_from(chip.get_child('name')) || chip.get_basename(); + + if (!add_sensors_from(chip, chip_label)) { + // This is here to provide compatibility with previous code, but I can't find any + // information about sensors being stored in chip/device directory. Can we delete it? + const chip_device = chip.get_child('device'); + if (chip_device.query_exists(null)) { + add_sensors_from(chip_device, chip_label); + } + } + } + return [sensor_files, sensor_labels]; +} + +/** + * @param args.hasBorder Whether the box has a border (true) or not + * @param args.horizontal Whether the box is horizontal (true) + * or vertical (false) + * @param args.shouldPack Determines whether a horizontal box should have + * uniform spacing for its children. Only applies to horizontal boxes + * @param args.spacing The amount of spacing for a given box + * @returns a new Box with settings specified by args + */ +function box(args = {}) { + const options = { }; + + if (typeof args.spacing !== 'undefined') { + options.spacing = args.spacing; + } + + if (shellMajorVersion < 40) { + if (args.hasBorder) { + options.border_width = 10; + } + + return args.horizontal ? + new Gtk.HBox(options) : new Gtk.VBox(options); + } + + if (args.hasBorder) { + options.margin_top = 10; + options.margin_bottom = 10; + options.margin_start = 10; + options.margin_end = 10; + } + + options.orientation = args.horizontal ? + Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL; + + const aliasBox = new Gtk.Box(options); + + if (args.shouldPack) { + aliasBox.set_homogeneous(true); + } + + + aliasBox.add = aliasBox.append; + aliasBox.pack_start = aliasBox.prepend; + // normally, this would be append; it is aliased to prepend because + // that appears to yield the same behavior as version < 40 + aliasBox.pack_end = aliasBox.prepend; + + return aliasBox; +} + +const ColorSelect = class SystemMonitor_ColorSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.picker = new Gtk.ColorButton(); + this.actor = box({horizontal: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.picker); + this.picker.set_use_alpha(true); + } + set_value(value) { + let color = new Gdk.RGBA(); + + if (Gtk.get_major_version() >= 4) { + // GDK did not support parsing hex colours with alpha before GTK 4. + color.parse(value); + } else { + // Use the Compat only when GTK 4 is not available, + // since it depends on the deprecated Clutter library. + let Compat = extension.imports.compat; + let clutterColor = Compat.color_from_string(value); + let ctemp = [clutterColor.red, clutterColor.green, clutterColor.blue, clutterColor.alpha / 255]; + color.parse('rgba(' + ctemp.join(',') + ')'); + } + + this.picker.set_rgba(color); + } +} + +const IntSelect = class SystemMonitor_IntSelect { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + this.spin = new Gtk.SpinButton(); + this.actor = box({horizontal: true, shouldPack: true, }); + this.actor.add(this.label); + this.actor.add(this.spin); + this.spin.set_numeric(true); + } + set_args(minv, maxv, incre, page) { + this.spin.set_range(minv, maxv); + this.spin.set_increments(incre, page); + } + set_value(value) { + this.spin.set_value(value); + } +} + +const Select = class SystemMonitor_Select { + constructor(name) { + this.label = new Gtk.Label({label: name + _(':')}); + // this.label.set_justify(Gtk.Justification.RIGHT); + this.selector = new Gtk.ComboBoxText(); + this.actor = box({horizontal: true, shouldPack: true, spacing: 5}); + this.actor.add(this.label); + this.actor.add(this.selector); + } + set_value(value) { + this.selector.set_active(value); + } + add(items) { + items.forEach((item) => { + this.selector.append_text(item); + }) + } +} + +function set_enum(combo, schema, name) { + Schema.set_enum(name, combo.get_active()); +} + +function set_color(color, schema, name) { + Schema.set_string(name, color_to_hex(color.get_rgba())) +} + +function set_string(combo, schema, name, _slist) { + Schema.set_string(name, _slist[combo.get_active()]); +} + +const SettingFrame = class SystemMonitor { + constructor(name, schema) { + this.schema = schema; + this.label = new Gtk.Label({label: name}); + + this.vbox = box({horizontal: false, shouldPack: true, spacing: 20}); + this.hbox0 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox1 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox2 = box({horizontal: true, shouldPack: true, spacing: 20}); + this.hbox3 = box({horizontal: true, shouldPack: true, spacing: 20}); + + if (shellMajorVersion < 40) { + this.frame = new Gtk.Frame({border_width: 10}); + this.frame.add(this.vbox); + } else { + this.frame = new Gtk.Frame({ + margin_top: 10, + margin_bottom: 10, + margin_start: 10, + margin_end: 10 + }); + this.frame.set_child(this.vbox); + } + + + if (shellMajorVersion < 40) { + this.vbox.pack_start(this.hbox0, true, false, 0); + this.vbox.pack_start(this.hbox1, true, false, 0); + this.vbox.pack_start(this.hbox2, true, false, 0); + this.vbox.pack_start(this.hbox3, true, false, 0); + } else { + this.vbox.append(this.hbox0); + this.vbox.append(this.hbox1); + this.vbox.append(this.hbox2); + this.vbox.append(this.hbox3); + } + } + + /** Enforces child ordering of first 2 boxes by label */ + _reorder() { + if (shellMajorVersion < 40) { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_children) { + return labelOf(el.get_children()[0]); + } + return el && el.label || ''; + }; + [this.hbox0, this.hbox1].forEach(hbox => { + hbox.get_children() + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))) + .forEach((child, index) => hbox.reorder_child(child, index)); + }); + } else { + /** @return {string} label of/inside component */ + const labelOf = el => { + if (el.get_label) { + return el.get_label(); + } + return labelOf(el.get_first_child()); + } + + [this.hbox0, this.hbox1].forEach(hbox => { + const children = []; + let next = hbox.get_first_child(); + + while (next !== null) { + children.push(next); + next = next.get_next_sibling(); + } + + const sorted = children + .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))); + + sorted + .forEach((child, index) => { + hbox.reorder_child_after(child, sorted[index - 1] || null); + }); + }); + } + } + + add(key) { + const configParent = key.substring(0, key.indexOf('-')); + const config = key.substring(configParent.length + 1); + + // hbox0 + if (config === 'display') { + let item = new Gtk.CheckButton({label: _('Display')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-text') { + let item = new Gtk.CheckButton({label: _('Show Text')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'show-menu') { + let item = new Gtk.CheckButton({label: _('Show In Menu')}); + this.hbox0.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox1 + } else if (config === 'refresh-time') { + let item = new IntSelect(_('Refresh Time')); + item.set_args(50, 100000, 1000, 5000); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'graph-width') { + let item = new IntSelect(_('Graph Width')); + item.set_args(1, 1000, 1, 10); + this.hbox1.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'style') { + let item = new Select(_('Display Style')); + item.add([_('digit'), _('graph'), _('both')]); + item.set_value(this.schema.get_enum(key)); + this.hbox1.add(item.actor); + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + // Schema.bind(key, item.selector, 'active', Gio.SettingsBindFlags.DEFAULT); + // hbox2 + } else if (config.match(/-color$/)) { + let item = new ColorSelect(_(config.split('-')[0].capitalize())); + item.set_value(this.schema.get_string(key)); + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else if (config.match(/sensor/)) { + let sensor_type = configParent === 'fan' ? 'fan' : 'temp'; + let [_slist, _strlist] = check_sensors(sensor_type); + let item = new Select(_('Sensor')); + if (_slist.length === 0) { + item.add([_('Please install lm-sensors')]); + } else if (_slist.length === 1) { + this.schema.set_string(key, _slist[0]); + } + item.add(_strlist); + try { + item.set_value(_slist.indexOf(this.schema.get_string(key))); + } catch (e) { + item.set_value(0); + } + // this.hbox3.add(item.actor); + if (configParent === 'fan') { + if (shellMajorVersion < 40) { + this.hbox2.pack_end(item.actor, true, false, 0); + } else { + this.hbox2.append(item.actor); + } + } else if (shellMajorVersion < 40) { + this.hbox2.pack_start(item.actor, true, false, 0); + } else { + this.hbox2.prepend(item.actor); + } + item.selector.connect('changed', function (combo) { + set_string(combo, Schema, key, _slist); + }); + // hbox3 + } else if (config === 'speed-in-bits') { + let item = new Gtk.CheckButton({label: _('Show network speed in bits')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'individual-cores') { + let item = new Gtk.CheckButton({label: _('Display Individual Cores')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'time') { + let item = new Gtk.CheckButton({label: _('Show Time Remaining')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'hidesystem') { + let item = new Gtk.CheckButton({label: _('Hide System Icon')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'usage-style') { + let item = new Select(_('Usage Style')); + item.add([_('pie'), _('bar'), _('none')]); + item.set_value(this.schema.get_enum(key)); + if (shellMajorVersion < 40) { + this.hbox3.pack_end(item.actor, false, false, 20); + } else { + this.hbox3.append(item.actor); + } + + item.selector.connect('changed', function (style) { + set_enum(style, Schema, key); + }); + } else if (config === 'fahrenheit-unit') { + let item = new Gtk.CheckButton({label: _('Display temperature in Fahrenheit')}); + this.hbox3.add(item); + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (config === 'threshold') { + let item = new IntSelect(_('Temperature threshold (0 to disable)')); + item.set_args(0, 300, 5, 5); + this.hbox3.add(item.actor); + Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); + } + if (configParent.indexOf('gpu') !== -1 && + config === 'display') { + let item = new Gtk.Label({label: _('** Only Nvidia GPUs supported so far **')}); + this.hbox3.add(item); + } + this._reorder(); + } +} + +const App = class SystemMonitor_App { + constructor() { + let setting_items = ['cpu', 'memory', 'swap', 'net', 'disk', 'gpu', 'thermal', 'fan', 'freq', 'battery']; + let keys = Schema.list_keys(); + + this.items = []; + this.settings = []; + + setting_items.forEach((setting) => { + this.settings[setting] = new SettingFrame(_(setting.capitalize()), Schema); + }); + + this.main_vbox = box({ + hasBorder: true, horizontal: false, spacing: 10}); + this.hbox1 = box({ + hasBorder: true, horizontal: true, shouldPack: true, spacing: 20}); + if (shellMajorVersion < 40) { + this.main_vbox.pack_start(this.hbox1, false, false, 0); + } else { + this.main_vbox.prepend(this.hbox1); + } + + keys.forEach((key) => { + if (key === 'icon-display') { + let item = new Gtk.CheckButton({label: _('Display Icon')}); + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'center-display') { + let item = new Gtk.CheckButton({label: _('Display in the Middle')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'compact-display') { + let item = new Gtk.CheckButton({label: _('Compact Display')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'show-tooltip') { + let item = new Gtk.CheckButton({label: _('Show tooltip')}) + item.set_active(Schema.get_boolean(key)) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'move-clock') { + let item = new Gtk.CheckButton({label: _('Move the clock')}) + this.items.push(item) + this.hbox1.add(item) + Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); + } else if (key === 'background') { + let item = new ColorSelect(_('Background Color')) + item.set_value(Schema.get_string(key)) + this.items.push(item) + if (shellMajorVersion < 40) { + this.hbox1.pack_start(item.actor, true, false, 0) + } else { + this.hbox1.prepend(item.actor) + } + item.picker.connect('color-set', function (color) { + set_color(color, Schema, key); + }); + } else { + let sections = key.split('-'); + if (setting_items.indexOf(sections[0]) >= 0) { + this.settings[sections[0]].add(key); + } + } + }); + this.notebook = new Gtk.Notebook() + setting_items.forEach((setting) => { + this.notebook.append_page(this.settings[setting].frame, this.settings[setting].label) + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + this.main_vbox.pack_start(this.notebook, true, true, 0) + } else { + this.main_vbox.append(this.notebook); + } + }); + if (shellMajorVersion < 40) { + this.main_vbox.show_all(); + } + } +} + +function buildPrefsWidget() { + let widget = new App(); + return widget.main_vbox; +} diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled new file mode 100644 index 0000000..aeef9ca Binary files /dev/null and b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled differ diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml new file mode 100644 index 0000000..6247263 --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + true + Display system monitor icon + Set to true to display system monitor icon in status bar.(NOTICE: The icon will be shown when none of the others is shown.) + + + true + Display memory + Set to false to remove memory display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refresh of memory + + + 100 + Memory graph width + Graph width in pixel + + + true + Display 'mem' + Set to true to show 'mem' before memory display + + + true + Display Memory In Menu + Set to true to show memory in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display swap + Set to false to remove swap display in status bar + + + 5000 + Swap refresh time + Time in ms between 2 refresh of swap + + + 100 + Swap graph width + Graph width in pixel + + + true + Display 'swap' + Set to true to show 'swap' before swap display + + + true + Display Swap In Menu + Set to true to show swap in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display cpu + Set to false to remove cpu display in status bar + + + 1500 + Cpu refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu graph width + Graph width in pixel + + + true + Display 'cpu' + Set to true to show 'cpu' before cpu display + + + true + Display Cpu In Menu + Set to true to show cpu in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display one graph per cpu core + Set to true to display one graph per cpu core + + + false + Display GPU usage + Set to false to remove GPU display in status bar + + + 5000 + Memory refresh time + Time in ms between 2 refreshes of GPU usage + + + 100 + GPU usage graph width + Graph width in pixel + + + true + Display 'gpu' + Set to true to show 'gpu' before GPU display + + + false + Display GPU In Menu + Set to true to show GPU in pop-up menu + + + 'graph' + Choose the display style. + + + false + Display freq + Set to false to remove freq display in status bar + + + 1500 + Cpu frequency refresh time + Time in ms between 2 refresh of cpu + + + 100 + Cpu frequency graph width + Graph width in pixel + + + false + Display freq' + Set to true to show 'freq' before cpu frequency display + + + false + Display Freq In Menu + Set to true to show freq in pop-up menu + + + 'graph' + Choose the display style. + + + true + Display net + Set to false to remove net display in status bar + + + 1000 + Net refresh time + Time in ms between 2 refresh of net + + + 100 + Net graph width + Graph width in pixel + + + true + Display 'net' + Set to true to show 'net' before net display + + + true + Display Net In Menu + Set to true to show net in pop-up menu + + + 'graph' + Choose the display style. + + + false + Show network speed in bits/sec + + + false + Display disk io speed + Set to false to remove disk display in status bar + + + 2000 + Disk IO refresh time + Time in ms between 2 refresh of Disk IO + + + 100 + Disk IO graph width + Graph width in pixel + + + true + Display 'disk' + Set to true to show 'disk' before disk io display + + + true + Display Disk In Menu + Set to true to show disk in pop-up menu + + + 'graph' + Choose the display style. + + + 'pie' + Choose the disk usage display style. + + + false + Display thermal + Set to false to remove thermal display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'thermal' + Set to true to show 'thermal' before thermal display + + + true + Display Temps In Menu + Set to true to show thermal in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/thermal_zone0/temp' + Sensor File + Location of the sensor file for cpu temp + + + 0 + Thermal threshold + When the temprature passes the threshold, the text is set to red as an alert. + + + false + Display fan + Set to false to remove fan display in status bar + + + 5000 + fan refresh time + Time in ms between 2 refresh of fan + + + 100 + fan graph width + Graph width in pixel + + + true + Display 'fan' + Set to true to show 'fan' before fan display + + + true + Display Fans In Menu + Set to true to show fan in pop-up menu + + + 'graph' + Choose the display style. + + + '/sys/devices/virtual/thermal/cooling_device0/cur_state' + Sensor File + Location of the sensor file for fan + + + '#f2002e' + Color of fan in the chart + + + false + Display informations next to the clock + True: Set information at the center, False: Set information in status bar (at top right) + + + false + Move the clock to the right when center-display is true + True: Move the clock to the right, False: Keep it in center + + + false + Enable or disable the tooltip + True: show tool tip on mouse hover + + + false + Optimize view for small displays + Optimize texts sizes to fit on a small display + + + '#00b35b' + Color of program memory in the chart + + + '#00ff82' + Color of buffer memory in the chart + + + '#aaf5d0' + Color of cache memory in the chart + + + '#fce94f' + Color of download speed in the chart + + + '#fb74fb' + Color of upload speed in the chart + + + '#ff6e00' + Color of download errors + + + '#e0006e' + Color of upload errors + + + '#ff0000' + Color of collisions + + + '#0072b3' + Color of user cpu in the chart + + + '#0092e6' + Color of system cpu in the chart + + + '#00a3ff' + Color of nice cpu in the chart + + + '#002f3d' + Color of iowait in the chart + + + '#001d26' + Color of other cpu in the chart + + + '#001d26' + Color of freq in the chart + + + '#8b00c3' + Color of used swap in the chart + + + '#c65000' + Color of disk reading speed in the chart + + + '#ff6700' + Color of disk writing speed in the chart + + + '#00b35b' + Color of program GPU usage in the chart + + + '#00ff82' + Color of program GPU memory in the chart + + + '#f2002e' + Color of user thermal in the chart + + + false + Display temperature in Fahrenheit + Set to true to show temperature in Fahrenheit + + + '#ffffff16' + Color of background + + + false + Display battery + Set to false to remove battery display in status bar + + + 5000 + thermal refresh time + Time in ms between 2 refresh of thermal + + + 100 + thermal graph width + Graph width in pixel + + + true + Display 'batt' + Set to true to show 'batt' before net display + + + false + Display 'batt' + Set to true to show battery in pop-up menu + + + 'digit' + Choose the display style. + + + '#f2002e' + Color of battery + + + false + Display battery time remaining rather than percentage + + + false + Hide system battery icon + + + + diff --git a/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css new file mode 100644 index 0000000..5f7120e --- /dev/null +++ b/src/gnome-ui/gnome-extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css @@ -0,0 +1,204 @@ +.sm-title { + font-size: 1em; + padding: 0px 25px 0px 0px; +} + +.sm-label { + color: #bbb; + font-size: 0.75em; + padding-top: 5px; + font-family: monospace; +} + +.sm-label-left { + color: #bbb; + font-size: 0.75em; + padding: 5px 5px 0 0; +} + +.sm-value { + text-align: right; + min-width: 40px; + padding: 2px 5px 0 0; + font-family: monospace; +} + +.sm-status-label { + color: #bbb; + font-size: 0.625em; + padding: 0 2px 0 5px; +} + +.sm-unit-label, +.sm-net-unit-label { + color: #aaa; + font-size: 0.5em; + padding: 0 5px 0 2px; +} + +.sm-disk-unit-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-net-unit-label { + min-width: 25px; +} + +.sm-perc-label { + color: #aaa; + font-size: 0.625em; + padding: 0 5px 0 2px; +} + +.sm-temp-label { + color: #aaa; + font-size: 0.6875em; + padding: 0 5px 0 2px; +} + +.sm-status-value { + min-width: 25px; + text-align: right; +} + +.sm-net-value { + min-width: 40px; + text-align: center; +} + +.sm-disk-value { + min-width: 25px; + text-align: right; +} + +.sm-big-status-value { + min-width: 42px; + text-align: right; +} + +.sm-chart { + padding: 0 2px; +} + +.sm-tooltip-box { + font-size: 0.85em; + font-weight: bold; + color: rgba(255, 255, 255, 0.9); + background-color: rgba(10, 10, 10, 0.7); + border-radius: 5px; + padding: 3px; + border: 1px solid #a5a5a5; +} + +.sm-tooltip-item { + padding: 0px; + spacing: 10px; +} +.sm-status-icon { + padding: 0px 2px; + icon-size: 1.14em; +} + +.sm-popup-menu-item-compact { +} + +/* style definition when 'compact-display' option is activated */ + +.sm-title-compact { + font-size: 0.75em; +} + +.sm-label-compact { + color: #bbb; + font-size: 0.6875em; + font-family: monospace; +} /* Bat, Net... units in menu items */ + +.sm-value-compact { + font-size: 0.6875em; + text-align: right; + font-family: monospace; +} /* Values in menu items */ + +.sm-status-label-compact { + color: #bbb; + font-size: 0.5em; + padding: 2px 0px 0 0px; +} /* names and Disk R and W signs in text items */ + +.sm-unit-label-compact, +.sm-net-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 1px; + text-align: right; + font-size: 0.4375em; +} /* Bat, Net... units in text items */ + +.sm-disk-unit-label-compact { + color: #aaa; + padding: 0 3px 0px 0px; + text-align: right; + font-size: 0.4375em; +} /* Disk units in text items */ + +.sm-perc-label-compact { + padding: 0 3px 0 0px; + color: #aaa; + font-size: 0.5em; +} /* Cpu, Mem ... % sign in text items */ + +.sm-temp-label-compact { + font-size: 0.625em; + color: #aaa; + padding: 0 1px 0 1px; +} /* Thermal °C sign in text items */ + +.sm-status-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:16px; +} /* Cpu, Mem... value in text items */ + +.sm-net-value-compact { + padding:0 0px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width:24px; +} /* Net value in text items */ + +.sm-disk-value-compact { + padding: 0 1px 0 1px; + font-size: 0.6875em; + text-align: right; + min-width: 20px; +} /* Disk value in text items */ + +.sm-big-status-value-compact { + padding: 0 0px 0px 1px; + font-size: 0.6875em; + min-width: 38px; + text-align: right; +} /* freq in text_items */ + +.sm-chart-compact { + padding: 0 2px; +} + +.sm-tooltip-item-compact { + padding: 0px; + spacing: 10px; +} + +.sm-status-icon-compact { + padding: 1px 0 0 2px; + icon-size: 1.00em; +} /* BAT icon in text_items */ + +.sm-popup-menu-item-compact { + font-size: 0.6875em; + width: 20px; + padding: 1px 2px 1px 7px; +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path.py b/src/gnome-ui/nautilus-extensions/nautilus-copy-path.py new file mode 100644 index 0000000..2af9157 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path.py @@ -0,0 +1,4 @@ +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'nautilus-copy-path')) +from nautilus_copy_path import NautilusCopyPath diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/config.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/config.json new file mode 100644 index 0000000..64384f3 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/config.json @@ -0,0 +1,11 @@ +{ + "items": { + "path": true + }, + "selections": { + "clipboard": true, + "primary": true + }, + "language": "auto", + "separator": ", " +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py new file mode 100644 index 0000000..2a0570e --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/nautilus_copy_path.py @@ -0,0 +1,73 @@ +import os +import json +from translation import Translation +from gi.repository import Nautilus, GObject, Gtk, Gdk +from gi import require_version + +require_version('Gtk', '3.0') +require_version('Nautilus', '3.0') + + +class NautilusCopyPath(Nautilus.MenuProvider, GObject.GObject): + + def __init__(self): + self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + self.clipboard_primary = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY) + + self.config = { + "items": { + "path": True, + }, + "selections": { + "clipboard": True, + "primary": True + }, + "language": "auto", + "separator": ", " + } + + with open(os.path.join(os.path.dirname(__file__), "config.json")) as json_file: + try: + self.config.update(json.load(json_file)) + if self.config["language"]: + Translation.select_language(self.config["language"]) + except: + pass + + def get_file_items(self, window, files): + return self._create_menu_items(files, "File") + + def get_background_items(self, window, file): + return self._create_menu_items([file], "Background") + + def _create_menu_items(self, files, group): + plural = len(files) > 1 + config_items = self.config["items"] + active_items = [] + + if config_items["path"]: + item_path = Nautilus.MenuItem( + name="NautilusCopyPath::CopyPath" + group, + label=Translation.t("copy_paths" if plural else "copy_path"), + ) + item_path.connect("activate", self._copy_paths, files) + active_items.append(item_path) + + return active_items + + def _copy_paths(self, menu, files): + self._copy_value(list(map(lambda f: f.get_location().get_path(), files))) + + def _copy_uris(self, menu, files): + self._copy_value(list(map(lambda f: f.get_uri(), files))) + + def _copy_names(self, menu, files): + self._copy_value(list(map(lambda x: os.path.basename(x.get_location().get_path()), files))) + + def _copy_value(self, value): + if len(value) > 0: + new_value = self.config["separator"].join(value) + if self.config["selections"]["clipboard"]: + self.clipboard.set_text(new_value, -1) + if self.config["selections"]["primary"]: + self.clipboard_primary.set_text(new_value, -1) diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translation.py b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translation.py new file mode 100644 index 0000000..6ee1f26 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translation.py @@ -0,0 +1,52 @@ +import locale +import json +import glob +import os + + +class Translation: + _translations_path = os.path.join(os.path.dirname(__file__), 'translations') + _translations = [] + _default_translations = [] + + @staticmethod + def select_language(lang_code="auto"): + if not lang_code or lang_code == "auto": + default_locale = locale.getdefaultlocale()[0] + try: + lang = default_locale.split("_") + lang_code = lang[0] if len(lang) else "en" + except AttributeError: + lang_code = "en" + + if lang_code in Translation.available_languages(): + Translation.lang_code = lang_code + else: + Translation.lang_code = "en" + + Translation._load_lang(Translation.lang_code) + + @staticmethod + def _load_lang(lang_code): + file_path = Translation._translations_path + '/' + lang_code + ".json" + if os.path.isfile(file_path): + with open(file_path) as json_file: + Translation._translations = json.load(json_file) + + file_path_en = Translation._translations_path + "/en.json" + if os.path.isfile(file_path_en): + with open(file_path_en) as json_file: + Translation._default_translations = json.load(json_file) + + @staticmethod + def available_languages(): + return [os.path.splitext(os.path.basename(x))[0] for x in glob.glob(Translation._translations_path + '/*.json')] + + @staticmethod + def t(translation): + if not Translation._translations: + Translation.select_language() + if translation in Translation._translations: + return Translation._translations[translation] + elif translation in Translation._default_translations: + return Translation._default_translations[translation] diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ar.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ar.json new file mode 100644 index 0000000..6bb6c71 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ar.json @@ -0,0 +1,8 @@ +{ + "copy_path": "نسخ مسار الملف", + "copy_paths": "نسخ مسارات الملفات", + "copy_name": "نسخ اسم الملف", + "copy_names": "نسخ اسماء الملفات", + "copy_uri": "نسخ معرّف المصادر الموحد", + "copy_uris": "نسخ معرفي المصادر الموحدة" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/da.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/da.json new file mode 100644 index 0000000..50e3498 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/da.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiér sti", + "copy_paths": "Kopiér stier", + "copy_name": "Kopiér navn", + "copy_names": "Kopiér navne", + "copy_uri": "Kopiér URI", + "copy_uris": "Kopiér URIer" +} \ No newline at end of file diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/de.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/de.json new file mode 100644 index 0000000..1e49c74 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/de.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Pfad kopieren", + "copy_paths": "Pfade kopieren", + "copy_name": "Name kopieren", + "copy_names": "Namen kopieren", + "copy_uri": "URI kopieren", + "copy_uris": "URIs kopieren" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/el.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/el.json new file mode 100644 index 0000000..d11cdbe --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/el.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Αντιγραφή Διαδρομής", + "copy_paths": "Αντιγραφή Διαδρομών", + "copy_name": "Αντιγραφή Ονόματος", + "copy_names": "Αντιγραφή Ονομάτων", + "copy_uri": "Αντιγραφή URI", + "copy_uris": "Αντιγραφή URIs" +} \ No newline at end of file diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/en.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/en.json new file mode 100644 index 0000000..d0b7a3b --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/en.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copy Path", + "copy_paths": "Copy Paths", + "copy_name": "Copy Name", + "copy_names": "Copy Names", + "copy_uri": "Copy URI", + "copy_uris": "Copy URIs" +} \ No newline at end of file diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/es.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/es.json new file mode 100644 index 0000000..5b12ffe --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/es.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiar ruta", + "copy_paths": "Copiar rutas", + "copy_name": "Copiar nombre", + "copy_names": "Copiar nombres" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/fr.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/fr.json new file mode 100644 index 0000000..d98d1ad --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/fr.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copier le chemin", + "copy_paths": "Copier les chemins", + "copy_name": "Copier le nom", + "copy_names": "Copier les noms" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/it.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/it.json new file mode 100644 index 0000000..8a31219 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/it.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copia Percorso", + "copy_paths": "Copia Percorsi", + "copy_name": "Copia Nome", + "copy_names": "Copia Nomi" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ja.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ja.json new file mode 100644 index 0000000..664f124 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ja.json @@ -0,0 +1,8 @@ +{ + "copy_path": "パスをコピー", + "copy_paths": "パスをコピー", + "copy_name": "ファイル名をコピー", + "copy_names": "ファイル名をコピー", + "copy_uri": "URIをコピー", + "copy_uris": "URIをコピー" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/no.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/no.json new file mode 100644 index 0000000..2965771 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/no.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopier sti", + "copy_paths": "Kopier stier", + "copy_name": "Kopier navn", + "copy_names": "Kopier navn", + "copy_uri": "Kopier URI", + "copy_uris": "Kopier URIer" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pl.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pl.json new file mode 100644 index 0000000..45830ad --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pl.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Skopiuj ścieżkę", + "copy_paths": "Skopiuj ścieżki", + "copy_name": "Skopiuj nazwę", + "copy_names": "Skopiuj nazwy", + "copy_uri": "Skopiuj URI", + "copy_uris": "Skopiuj URI" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pt.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pt.json new file mode 100644 index 0000000..dd7aed4 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/pt.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Copiar endereço", + "copy_paths": "Copiar endereços", + "copy_name": "Copiar nome", + "copy_names": "Copiar nomes", + "copy_uri": "Copiar URI", + "copy_uris": "Copiar URIs" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ro.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ro.json new file mode 100644 index 0000000..47327a6 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ro.json @@ -0,0 +1,6 @@ +{ + "copy_path": "Copiază locația", + "copy_paths": "Copiază locațiile", + "copy_name": "Copiază nume", + "copy_names": "Copiază numele" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ru.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ru.json new file mode 100644 index 0000000..7a0ca43 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/ru.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Скопировать путь", + "copy_paths": "Скопировать пути", + "copy_name": "Скопировать имя", + "copy_names": "Скопировать имена", + "copy_uri": "Скопировать URI", + "copy_uris": "Скопировать URIs" +} diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/se.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/se.json new file mode 100644 index 0000000..f9ac706 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/se.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Kopiera stig", + "copy_paths": "Kopiera stigar", + "copy_name": "Kopiera namn", + "copy_names": "Kopiera namn", + "copy_uri": "Kopiera URI", + "copy_uris": "Kopiera URIer" +} \ No newline at end of file diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/tr.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/tr.json new file mode 100644 index 0000000..a0aead1 --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/tr.json @@ -0,0 +1,8 @@ +{ + "copy_path": "Yolu Kopyala", + "copy_paths": "Yolları Kopyala", + "copy_name": "İsmi Kopyala", + "copy_names": "İsimleri Kopyala", + "copy_uri": "URI'yi Kopyala", + "copy_uris": "URI'leri Kopyala" + } \ No newline at end of file diff --git a/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/zh.json b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/zh.json new file mode 100644 index 0000000..a534d3e --- /dev/null +++ b/src/gnome-ui/nautilus-extensions/nautilus-copy-path/translations/zh.json @@ -0,0 +1,8 @@ +{ + "copy_path": "复制路径", + "copy_paths": "复制各个路径", + "copy_name": "复制文件名", + "copy_names": "复制各个文件名", + "copy_uri": "复制URI", + "copy_uris": "复制各个URI" +} diff --git a/src/packaging/almalinux-creative-installer.spec b/src/packaging/almalinux-creative-installer.spec index 678acba..36d2bb4 100644 --- a/src/packaging/almalinux-creative-installer.spec +++ b/src/packaging/almalinux-creative-installer.spec @@ -14,6 +14,9 @@ Requires: python3 Requires: polkit Requires: xdg-utils Requires: rsync +# polkit-gnome provides the authentication agent on X11 GNOME sessions. +# On Wayland, gnome-shell handles polkit natively so this is not strictly required. +Recommends: polkit-gnome # Qt binding — PyQt6 on EL10+, PyQt5 on EL9 %if 0%{?rhel} >= 10 @@ -56,6 +59,11 @@ if [ -d src/icons/apps ]; then %{buildroot}%{_datadir}/%{name}/icons/apps/ fi +# Bundled GNOME UI extensions and dconf profile +if [ -d src/gnome-ui ]; then + cp -a src/gnome-ui %{buildroot}%{_datadir}/%{name}/ +fi + # Polkit policy install -D -m 0644 src/org.almalinux.creativeinstaller.policy \ %{buildroot}%{_datadir}/polkit-1/actions/org.almalinux.creativeinstaller.policy @@ -82,6 +90,8 @@ fi %dir %{_datadir}/%{name}/icons %dir %{_datadir}/%{name}/icons/apps %{_datadir}/%{name}/icons/apps/*.png +%dir %{_datadir}/%{name}/gnome-ui +%{_datadir}/%{name}/gnome-ui/ %{_datadir}/polkit-1/actions/org.almalinux.creativeinstaller.policy %{_datadir}/applications/almalinux-creative-installer.desktop %dir %{_datadir}/licenses/%{name} @@ -89,6 +99,11 @@ fi %{_datadir}/icons/hicolor/*/apps/almalinux-creative-installer.* %changelog +* Thu Jul 10 2026 KernelChief - 2.1.0-1 +- Add Windows-style GNOME UI setup (Dash to Panel, ArcMenu, System Monitor, Blur My Shell, Nautilus copy-path) +- Gate GNOME UI setup to GNOME Desktop sessions only +- Bundle gnome-ui extensions and dconf profile in package +- Remove all SHED/SHED MTL naming from files and scripts * Tue May 26 2026 KernelChief - 2.0.1-1 - Add InstaMaterial (3D, guided RPM install via install.sh) - Add PopcornFX Editor (Animation & Video, Flatpak)