diff options
58 files changed, 7274 insertions, 0 deletions
diff --git a/disable-workspace-switcher/LICENSE b/disable-workspace-switcher/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/disable-workspace-switcher/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/disable-workspace-switcher/README.md b/disable-workspace-switcher/README.md new file mode 100644 index 0000000..bae853f --- /dev/null +++ b/disable-workspace-switcher/README.md @@ -0,0 +1 @@ +GNOME Shell extension that disables the workspace switcher popup diff --git a/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/extension.js b/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/extension.js new file mode 100644 index 0000000..e805c3b --- /dev/null +++ b/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/extension.js @@ -0,0 +1,21 @@ +'use strict' + +const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup.WorkspaceSwitcherPopup; + +class Extension { + constructor() { + this.originalWorkspaceSwitcherPopup_display = WorkspaceSwitcherPopup.prototype.display; + } + + enable() { + WorkspaceSwitcherPopup.prototype.display = () => {}; + } + + disable() { + WorkspaceSwitcherPopup.prototype.display = this.originalWorkspaceSwitcherPopup_display; + } +} + +function init() { + return new Extension(); +} diff --git a/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/metadata.json b/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/metadata.json new file mode 100644 index 0000000..cfbf8e5 --- /dev/null +++ b/disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/metadata.json @@ -0,0 +1,11 @@ +{ + "name": "Disable Workspace Switcher", + "description": "Disable the workspace switcher popup.", + "version": 1, + "uuid": "disable-workspace-switcher@jbradaric.me", + "url": "https://github.com/jbradaric/disable-workspace-switcher", + "shell-version": [ + "42", + "43" + ] +} diff --git a/hibernate-status/.gitignore b/hibernate-status/.gitignore new file mode 100644 index 0000000..68270f9 --- /dev/null +++ b/hibernate-status/.gitignore @@ -0,0 +1,6 @@ +**/*.compiled +*.zip +.~ +*~ +*.mo +locale/hibernate-status-button.pot diff --git a/hibernate-status/LICENSE b/hibernate-status/LICENSE new file mode 100644 index 0000000..d6a9326 --- /dev/null +++ b/hibernate-status/LICENSE @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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 Lesser 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. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + {signature of Ty Coon}, 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 Lesser General +Public License instead of this License. + diff --git a/hibernate-status/Makefile b/hibernate-status/Makefile new file mode 100644 index 0000000..3378024 --- /dev/null +++ b/hibernate-status/Makefile @@ -0,0 +1,77 @@ +# Basic Makefile + +UUID = hibernate-status@dromi +BASE_MODULES = extension.js metadata.json confirmDialog.js LICENSE README.md +EXTRA_MODULES = prefs.js +TOLOCALIZE = confirmDialog.js prefs.js +PO_FILES := $(wildcard ./locale/*/*/*.po) +MO_FILES := $(PO_FILES:.po=.mo) + +ifeq ($(strip $(DESTDIR)),) + INSTALLTYPE = local + INSTALLBASE = $(HOME)/.local/share/gnome-shell/extensions +else + INSTALLTYPE = system + SHARE_PREFIX = $(DESTDIR)/usr/share + INSTALLBASE = $(SHARE_PREFIX)/gnome-shell/extensions +endif +INSTALLNAME = hibernate-status@dromi + +all: extension + +clean: + rm -f ./schemas/gschemas.compiled + rm -f ./**/*~ + rm -f ./locale/*/*/*.mo + rm -f ./locale/hibernate-status-button.pot + +extension: ./schemas/gschemas.compiled $(MO_FILES) + +./schemas/gschemas.compiled: ./schemas/org.gnome.shell.extensions.hibernate-status-button.gschema.xml + glib-compile-schemas ./schemas/ + +potfile: ./locale/hibernate-status-button.pot + +mergepo: potfile + for l in $(PO_FILES); do \ + msgmerge -U $$l ./locale/hibernate-status-button.pot; \ + done; + +./locale/hibernate-status-button.pot: $(TOLOCALIZE) + mkdir -p locale + xgettext -k --keyword=__ --keyword=N__ --add-comments='Translators:' -o locale/hibernate-status-button.pot --package-name "Hibernate Status Button" $(TOLOCALIZE) + +%.mo: %.po + msgfmt -c $< -o $@ + +install: install-local + +install-local: _build + rm -rf $(INSTALLBASE)/$(INSTALLNAME) + mkdir -p $(INSTALLBASE)/$(INSTALLNAME) + cp -r ./_build/* $(INSTALLBASE)/$(INSTALLNAME)/ +ifeq ($(INSTALLTYPE),system) + # system-wide settings and locale files + # rm -r $(INSTALLBASE)/$(INSTALLNAME)/schemas + rm -f $(INSTALLBASE)/$(INSTALLNAME)/schemas/*gschema.xml + rm -r $(INSTALLBASE)/$(INSTALLNAME)/locale + mkdir -p $(SHARE_PREFIX)/glib-2.0/schemas $(SHARE_PREFIX)/locale + cp -r ./schemas/*gschema.* $(SHARE_PREFIX)/glib-2.0/schemas + cp -r ./_build/locale/* $(SHARE_PREFIX)/locale +endif + -rm -fR _build + echo done + +zip-file: _build + cd _build ; zip -qr "$(UUID).zip" . -x '*.po' + mv _build/$(UUID).zip ./ + -rm -fR _build + +_build: all + -rm -fR ./_build + mkdir -p _build + cp $(BASE_MODULES) $(EXTRA_MODULES) _build + mkdir -p _build/schemas + cp schemas/*.xml _build/schemas/ + cp schemas/gschemas.compiled _build/schemas/ + cp -r locale/ _build/locale diff --git a/hibernate-status/README.md b/hibernate-status/README.md new file mode 100644 index 0000000..ff88abd --- /dev/null +++ b/hibernate-status/README.md @@ -0,0 +1,41 @@ +# gnome-shell-extension-hibernate-status + +Gnome Shell extension that adds a hibernate/hybrid suspend button in Status menu. + +Originally developed by [@arelange](https://github.com/arelange); now maintained by [@p91paul](https://github.com/p91paul). + +Supports GNOME 3.36. + +## FAQ + +### Hibernation does not work + +Try launching from your terminal + + systemctl hibernate + +If it doesn't work, it means hibernation is disabled on your system. Please see: + +https://askubuntu.com/questions/1034185/ubuntu-18-04-cant-resume-after-hibernate/1064114#1064114 + +or + +https://help.ubuntu.com/16.04/ubuntu-help/power-hibernate.html + +### Hibernation button does not show up, but systemctl hibernate works + +If you are running Ubuntu, try putting + + [Enable hibernate in upower] + Identity=unix-user:* + Action=org.freedesktop.upower.hibernate + ResultActive=yes + + [Enable hibernate in logind] + Identity=unix-user:* + Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.handle-hibernate-key;org.freedesktop.login1;org.freedesktop.login1.hibernate-multiple-sessions;org.freedesktop.login1.hibernate-ignore-inhibit + ResultActive=yes + +into /etc/polkit-1/localauthority/10-vendor.d/com.ubuntu.desktop.pkla + +Otherwise check for similar settings for your distribution. Credit: https://github.com/arelange/gnome-shell-extension-hibernate-status/issues/41#issuecomment-565883599 diff --git a/hibernate-status/buildforupload.sh b/hibernate-status/buildforupload.sh new file mode 100755 index 0000000..d2c705c --- /dev/null +++ b/hibernate-status/buildforupload.sh @@ -0,0 +1,2 @@ +#!/bin/bash +make zip-file diff --git a/hibernate-status/confirmDialog.js b/hibernate-status/confirmDialog.js new file mode 100644 index 0000000..62069e2 --- /dev/null +++ b/hibernate-status/confirmDialog.js @@ -0,0 +1,193 @@ +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Mainloop = imports.mainloop; + +const LoginManager = imports.misc.loginManager; +const Main = imports.ui.main; +const StatusSystem = imports.ui.status.system; +const PopupMenu = imports.ui.popupMenu; +const ModalDialog = imports.ui.modalDialog; +const CheckBox = imports.ui.checkBox.CheckBox; +const St = imports.gi.St; +const Clutter = imports.gi.Clutter; +const ExtensionUtils = imports.misc.extensionUtils; + +// Use __ () and N__() for the extension gettext domain, and reuse +// the shell domain with the default _() and N_() +const Gettext = imports.gettext.domain('hibernate-status-button'); +const __ = Gettext.gettext; +const N__ = function(e) { return e }; + +ExtensionUtils.initTranslations('hibernate-status-button'); + +var HibernateDialogContent = { + subject: C_("title", __("Hibernate")), + description: __("Do you really want to hibernate the system?"), + confirmButtons: [{ + signal: 'Cancel', + label: C_("button", __("Cancel")), + key: Clutter.Escape + }, + { + signal: 'ConfirmedHibernate', + label: C_("button", __("Hibernate")), + default: true + }], + iconName: 'document-save-symbolic', + iconStyleClass: 'end-session-dialog-shutdown-icon', +}; + +var SystemdMissingDialogContent = { + subject: C_("title", __("Hibernate button: Systemd Missing")), + description: __("Systemd seems to be missing and is required."), + confirmButtons: [{ + signal: 'Cancel', + label: C_("button", __("Cancel")), + key: Clutter.Escape + }, + { + signal: 'DisableExtension', + label: C_("button", __("Disable Extension")), + default: true + }], + iconName: 'document-save-symbolic', + iconStyleClass: 'end-session-dialog-shutdown-icon', +}; + + +var HibernateFailedDialogContent = { + subject: C_("title", __("Hibernate button: Hibernate failed")), + description: __("Looks like hibernation failed.\n" + + "On some linux distributions hibernation is disabled\n" + + "because not all hardware supports it well;\n" + + "please check your distribution documentation\n" + + "on how to enable it."), + checkBox: __("You are wrong, don't check this anymore!"), + confirmButtons: [{ + signal: 'Cancel', + label: C_("button", __("Cancel")), + key: Clutter.Escape + }, + { + signal: 'DisableExtension', + label: C_("button", __("Disable Extension")), + default: true + }], + iconName: 'document-save-symbolic', + iconStyleClass: 'end-session-dialog-shutdown-icon', +}; + +const _DIALOG_ICON_SIZE = 32; + +function _setLabelText(label, text) { + if (text) { + label.set_text(text); + label.show(); + } else { + label.set_text(''); + label.hide(); + } +} + +var ConfirmDialog = GObject.registerClass({ + Signals: { 'ConfirmedHibernate': { param_types: [ GObject.TYPE_BOOLEAN ] }, + 'DisableExtension': { param_types: [ GObject.TYPE_BOOLEAN ] }, + 'Cancel': { param_types: [ GObject.TYPE_BOOLEAN ] } } +}, +class ConfirmDialog extends ModalDialog.ModalDialog { + _init(dialog) { + super._init({ + styleClass: 'end-session-dialog', + destroyOnClose: true + }); + + let mainContentLayout = new St.BoxLayout({ + vertical: false, + x_expand: true , + y_expand: false + }); + this.contentLayout.add(mainContentLayout); + + this._iconBin = new St.Bin({ + x_expand: true, + y_expand: false, + x_align: St.Align.END, + y_align: St.Align.START + }); + mainContentLayout.add(this._iconBin); + + let messageLayout = new St.BoxLayout({ + vertical: true, + y_align: St.Align.START + }); + mainContentLayout.add(messageLayout); + + this._subjectLabel = new St.Label({ + style_class: 'end-session-dialog-subject', + y_expand: false, + y_align: St.Align.START + }); + + messageLayout.add(this._subjectLabel); + + this._descriptionLabel = new St.Label({ + style_class: 'end-session-dialog-description', + y_expand: true, + y_align: St.Align.START + }); + + messageLayout.add(this._descriptionLabel); + + // fill dialog + + _setLabelText(this._descriptionLabel, dialog.description); + _setLabelText(this._subjectLabel, dialog.subject); + + if (dialog.iconName) { + this._iconBin.child = new St.Icon({ + icon_name: dialog.iconName, + icon_size: _DIALOG_ICON_SIZE, + style_class: dialog.iconStyleClass + }); + } + + if (dialog.checkBox) { + this._checkBox = new CheckBox(dialog.checkBox); + mainContentLayout.add(this._checkBox.actor); + } + + let buttons = []; + for (let i = 0; i < dialog.confirmButtons.length; i++) { + let signal = dialog.confirmButtons[i].signal; + let label = dialog.confirmButtons[i].label; + let keys = dialog.confirmButtons[i].key; + buttons.push({ + action: () => { + this.close(); + let signalId = this.connect('closed', + () => { + this.disconnect(signalId); + this._confirm(signal); + }); + }, + label: label, + key: keys + }); + }; + + this.setButtons(buttons); + + } + + _confirm(signal) { + var checked; + if (this._checkBox) + checked = this._checkBox.actor.get_checked() + this.emit(signal, checked); + } + + cancel() { + this.close(); + } +}); diff --git a/hibernate-status/extension.js b/hibernate-status/extension.js new file mode 100644 index 0000000..6e0b248 --- /dev/null +++ b/hibernate-status/extension.js @@ -0,0 +1,248 @@ +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Mainloop = imports.mainloop; + +const ExtensionUtils = imports.misc.extensionUtils; +const LoginManager = imports.misc.loginManager; +const Main = imports.ui.main; +const StatusSystem = imports.ui.status.system; +const PopupMenu = imports.ui.popupMenu; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const ExtensionSystem = imports.ui.extensionSystem; +const ConfirmDialog = Me.imports.confirmDialog; +const Prefs = new Me.imports.prefs.Prefs(); + + +// Use __ () and N__() for the extension gettext domain, and reuse +// the shell domain with the default _() and N_() +const Gettext = imports.gettext.domain('hibernate-status-button'); +const __ = Gettext.gettext; +const N__ = function(e) { return e }; +ExtensionUtils.initTranslations('hibernate-status-button'); + +const HIBERNATE_CHECK_TIMEOUT = 20000; + +class Extension { + _loginManagerCanHibernate(asyncCallback) { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("CanHibernate", + null, + Gio.DBusCallFlags.NONE, + -1, null, function (proxy, asyncResult) { + let result, error; + + try { + result = proxy.call_finish(asyncResult).deep_unpack(); + } catch (e) { + error = e; + } + + if (error) + asyncCallback(false); + else + asyncCallback(result[0] != 'no'); + }); + } else { + Mainloop.idle_add(() => { + asyncCallback(false); + return false; + }); + } + } + + _loginManagerHibernate() { + if (Prefs.getHibernateWorksCheckEnabled()) { + this._hibernateStarted = new Date(); + GLib.timeout_add(GLib.PRIORITY_DEFAULT, HIBERNATE_CHECK_TIMEOUT, + () => this._checkDidHibernate()); + } + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("Hibernate", + GLib.Variant.new('(b)', [true]), + Gio.DBusCallFlags.NONE, + -1, null, null); + } else { + // Can't do in ConsoleKit + this._loginManager.emit('prepare-for-sleep', true); + this._loginManager.emit('prepare-for-sleep', false); + } + } + + _loginManagerCanHybridSleep(asyncCallback) { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("CanHybridSleep", + null, + Gio.DBusCallFlags.NONE, + -1, null, function (proxy, asyncResult) { + let result, error; + + try { + result = proxy.call_finish(asyncResult).deep_unpack(); + } catch (e) { + error = e; + } + + if (error) + asyncCallback(false); + else + asyncCallback(result[0] != 'no'); + }); + } else { + Mainloop.idle_add(() => { + asyncCallback(false); + return false; + }); + } + } + + _loginManagerHybridSleep() { + if (this._loginManager._proxy) { + // systemd path + this._loginManager._proxy.call("HybridSleep", + GLib.Variant.new('(b)', [true]), + Gio.DBusCallFlags.NONE, + -1, null, null); + } else { + // Can't do in ConsoleKit + this._loginManager.emit('prepare-for-sleep', true); + this._loginManager.emit('prepare-for-sleep', false); + } + } + _updateHaveHibernate() { + this._loginManagerCanHibernate((result) => { + log(`have hibernate ${result}`); + this._haveHibernate = result; + this._updateHibernate(); + }); + } + + _updateHibernate() { + this._hibernateMenuItem.visible = this._haveHibernate && !Main.sessionMode.isLocked; + } + + _updateHaveHybridSleep() { + this._loginManagerCanHybridSleep((result) => { + this._haveHybridSleep = result; + this._updateHybridSleep(); + }); + } + + _updateHybridSleep() { + this._hybridSleepMenuItem.visible = this._haveHybridSleep && !Main.sessionMode.isLocked; + } + + _onHibernateClicked() { + this.systemMenu._systemItem.menu.itemActivated(); + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.HibernateDialogContent); + this._dialog.connect('ConfirmedHibernate', () => this._loginManagerHibernate()); + this._dialog.open(); + } + + _onHybridSleepClicked() { + this.systemMenu._systemItem.menu.itemActivated(); + this._loginManagerHybridSleep(); + } + + _disableExtension() { + let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY); + enabledExtensions.splice(enabledExtensions.indexOf(Me.uuid), 1); + global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions); + } + + _cancelDisableExtension(notAgain) { + if (notAgain) + Prefs.setHibernateWorksCheckEnabled(false); + } + + _checkRequirements() { + if (!LoginManager.haveSystemd()) { + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.SystemdMissingDialogContent); + this._dialog.connect('DisableExtension', this._disableExtension); + this._dialog.open(); + } + } + + _checkDidHibernate() { + /* This function is called HIBERNATE_CHECK_TIMEOUT ms after + * hibernate started. If it is successful, at that point the GS + * process is already frozen; so when this function is actually + * called, way more than HIBERNATE_CHECK_TIMEOUT ms are passed*/ + if (new Date() - this._hibernateStarted > HIBERNATE_CHECK_TIMEOUT + 5000) { + // hibernate succeeded + return; + } + // hibernate failed + this._dialog = new ConfirmDialog.ConfirmDialog(ConfirmDialog.HibernateFailedDialogContent); + this._dialog.connect('DisableExtension', this._disableExtension); + this._dialog.connect('Cancel', this._cancelDisableExtension); + this._dialog.open(); + } + + enable() { + this._checkRequirements(); + this._loginManager = LoginManager.getLoginManager(); + this.systemMenu = Main.panel.statusArea.quickSettings._system; + + this._hibernateMenuItem = new PopupMenu.PopupMenuItem(__('Hibernate')); + this._hibernateMenuItemId = this._hibernateMenuItem.connect('activate', () => this._onHibernateClicked()); + + this._hybridSleepMenuItem = new PopupMenu.PopupMenuItem(__('Hybrid Sleep')); + this._hybridSleepMenuItemId = this._hybridSleepMenuItem.connect('activate', () => this._onHybridSleepClicked()); + + let afterSuspendPosition = this.systemMenu._systemItem.menu.numMenuItems - 5; + + this.systemMenu._systemItem.menu.addMenuItem(this._hybridSleepMenuItem, afterSuspendPosition); + this.systemMenu._systemItem.menu.addMenuItem(this._hibernateMenuItem, afterSuspendPosition); + + this._menuOpenStateChangedId = this.systemMenu._systemItem.menu.connect('open-state-changed', + (menu, open) => { + if (!open) + return; + this._updateHaveHibernate(); + this._updateHaveHybridSleep(); + }); + } + + disable() { + if (this._menuOpenStateChangedId) { + this.systemMenu._systemItem.menu.disconnect(this._menuOpenStateChangedId); + this._menuOpenStateChangedId = 0; + } + + if (this._hybridSleepMenuItemId) { + this._hybridSleepMenuItem.disconnect(this._hybridSleepMenuItemId); + this._hybridSleepMenuItemId = 0; + } + + if (this._hibernateMenuItemId) { + this._hibernateMenuItem.disconnect(this._hibernateMenuItemId); + this._hibernateMenuItemId = 0; + } + + if (this._hybridSleepMenuItem) { + this._hybridSleepMenuItem.destroy(); + this._hybridSleepMenuItem = 0; + } + + if (this._hibernateMenuItem) { + this._hibernateMenuItem.destroy(); + this._hibernateMenuItem = 0; + } + } +} + +let extension; +function init() { + extension = new Extension(); +} + +function enable() { + extension.enable(); +} + +function disable() { + extension.disable(); +} diff --git a/hibernate-status/locale/cs/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/cs/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..32e541d --- /dev/null +++ b/hibernate-status/locale/cs/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,66 @@ +# Czech translation of hibernate-status-button +# Copyright (C) 2021 Vojtěch Perník +# This file is distributed under the same license as the hibernate-status-button package. +# Vojtěch Perník <translations@pervoj.cz>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2021-05-06 16:15+0200\n" +"Last-Translator: Vojtěch Perník <translations@pervoj.cz>\n" +"Language-Team: Czech\n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Uspat na disk" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Opravdu chcete systém uspat na disk?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Zrušit" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Hibernate button: Systemd není nainstalován" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Zdá se, že Systemd není nainstalován, ale je vyžadován." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Zakázat rozšíření" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Hibernate button: Uspání na disk se nezdařilo" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Vypadá to, že se uspání na disk nezdařilo.\n" +"U některých linuxových distribucí je uspání na disk\n" +"zakázáno, protože ne všechny hardware ho podporují,\n" +"podívejte se prosím do dokumentace své distribuce, jak ji povolit." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Mýlíte se, už to nekontrolujte!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Toto rozšíření nemá k dispozici žádná nastavení" diff --git a/hibernate-status/locale/de/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/de/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..3fdb8c2 --- /dev/null +++ b/hibernate-status/locale/de/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,72 @@ +# German translation of hibernate-status-button +# Copyright (C) 2022 Oskar Kirmis +# This file is distributed under the same license as the hibernate-status-button package. +# Oskar Kirmis <oskar.kirmis@posteo.de>, 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-28 21:00+0200\n" +"PO-Revision-Date: 2022-10-22 21:30+0200\n" +"Last-Translator: Oskar Kirmis <oskar.kirmis@posteo.de>\n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0.1\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Ruhezustand" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Hybrider Standbymodus" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Wollen Sie das System wirklich in den Ruhezustand versetzen?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Abbrechen" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Hibernate button: Systemd fehlt" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Systemd fehlt offenbar, wird jedoch benötigt." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Erweiterung deaktivieren" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Hibernate button: Versetzen in den Ruhezustand fehlgeschlagen" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Offenbar konnte das System nicht in den Ruhezustand versetzt werden.\n" +"Auf manchen Linuxdistributionen ist der Ruhezustand deaktiviert\n" +"weil nicht jegliche Hardware dies unterstützt;\n" +"bitte schauen Sie in der Dokumentation Ihrer\n" +"Distribution nach, wie Sie ihn aktivieren können." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Das ist falsch, bitte nicht mehr prüfen!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Für diese Erweiterung gibt es keine Einstellungen" diff --git a/hibernate-status/locale/es/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/es/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..92c14bc --- /dev/null +++ b/hibernate-status/locale/es/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# Spanish translation of hibernate-status-button +# Copyright (C) 2022 slaythrax +# This file is distributed under the same license as the hibernate-status-button package. +# slaythrax <jbustamantec@unal.edu.co>, 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2022-10-22 21:30+0200\n" +"Last-Translator: slaythrax <jbustamantec@unal.edu.co>\n" +"Language-Team: Spanish <jbustamantec@unal.edu.co>\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Hibernar" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Suspensión Híbrida" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Desea hibernar el sistema?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Cancelar" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Systemd no está instalado" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Parece que systemd no está instalado. Systemd es necesario" + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Deshabilitar extensión" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Hibernación fallida" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Parece que la hibernación falló\n" +"En algunas distribuciones de linux la hibernación se encuentra deshabilitada\n" +"pues no todo el hardware no la soporta correctamente;\n" +"verifique la documentación de su distribución\n" +"para habilitarla." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "No es necesario hacer esta verificación de nuevo! " + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Esta extensión no tiene ajustes disponibles" diff --git a/hibernate-status/locale/fa/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/fa/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..e4edef0 --- /dev/null +++ b/hibernate-status/locale/fa/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,72 @@ +# Persian translation of hibernate-status-button +# Copyright (C) 2021 MohammadSaleh Kamyab +# This file is distributed under the same license as the hibernate-status-button package. +# MohammadSaleh Kamyab <mskf1383@envs.net>, 2022. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2022-06-21 13:06+0430\n" +"Last-Translator: MohammadSaleh Kamyab <mskf1383@envs.net>\n" +"Language-Team: \n" +"Language: fa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n==0 || n==1);\n" +"X-Generator: Poedit 3.1\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "خواب زمستانی" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "خواب ترکیبی" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "آیا مطمئنید که میخواهید سامانه را به خواب زمستانی ببرید؟" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "لغو" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "دکمهٔ خواب زمستانی: سیستمدی یافت نشد" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "به نظر میرسد سیستمدی که لازم است، وجود ندارد." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "از کار انداختن افزونه" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "دکمهٔ خواب زمستانی: خواب زمستانی شکست خورد" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"به نظر میرسد خواب زمستانی به شکست انجامید.\n" +"در بعضی از توزیعهای گنو/لینوکسی، خواب زمستانی از کار انداخته شده است؛\n" +"زیرا تمامی سختافزارها بهخوبی از آن پشتیبانی نمیکنند.\n" +"لطفاً مستندات توزیع خود را در مورد چگونگی به کار انداختن آن، بررسی کنید." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "اشتباه میکنید، دوباره بررسی نکنید!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "این افزونه هیچ تنظیماتی ندارد" diff --git a/hibernate-status/locale/fr/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/fr/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..9dca80d --- /dev/null +++ b/hibernate-status/locale/fr/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# French translation of hibernate-status-button +# Copyright (C) 2021 Jérôme de Bretagne +# This file is distributed under the same license as the hibernate-status-button package. +# Jérôme de Bretagne <jerome.debretagne@gmail.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2021-11-13 19:34+0200\n" +"Last-Translator: Jérôme de Bretagne <jerome.debretagne@gmail.com>\n" +"Language-Team: French <jerome.debretagne@gmail.com>\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: extension.js:189 confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Mettre en veille prolongée" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Mettre en veille hybride" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Voulez-vous vraiment mettre l'appareil en veille prolongée ?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Annuler" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Extension de mise en veille prolongée : systemd manquant" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "systemd ne semble pas installé et est nécessaire." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Désactiver l'extension" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Extension de mise en veille prolongée : échec" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"La mise en veille prolongée a échoué.\n" +"Sur certaines distributions Linux, la mise en veille prolongée est désactivée\n" +"car elle ne fonctionne pas correctement pour quelques appareils;\n" +"Veuillez vous reporter à la documentation de votre distribution\n" +"pour savoir comment l'activer." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Il n'est pas utile de cocher cette case !" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Cette extension n'a pas de paramètres" diff --git a/hibernate-status/locale/it/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/it/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..a41e5ac --- /dev/null +++ b/hibernate-status/locale/it/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# Italian translation of hibernate-status-button +# Copyright (C) 2021 p91paul +# This file is distributed under the same license as the hibernate-status-button package. +# p91paul <p91paul@gmail.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2022-10-22 21:30+0200\n" +"Last-Translator: p91paul <p91paul@gmail.com>\n" +"Language-Team: Italian <p91paul@gmail.com>\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Iberna" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Sospensione ibrida" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Vuoi davvero ibernare il sistema?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Cancella" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Systemd non installato" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Systemd non è installato ed è necessario" + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Disabilita estensione" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Ibernazione fallita" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Sembra che l'ibernazione sia fallita.\n" +"In alcune distribuzioni Linux l'ibernazione è disabilitata\n" +"perchè non ben supportata da tutte le tipologie di hardware;\n" +"Verifica la documentazione della tua distribuzione\n" +"per abilitarla." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Ti sbagli, va tutto bene, non fare più questa verifica" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Questa estensione non ha impostazioni disponibili" diff --git a/hibernate-status/locale/nl/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/nl/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..6853171 --- /dev/null +++ b/hibernate-status/locale/nl/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,68 @@ +# Nederlands translation of hibernate-status-button
+# Copyright (C) 2021 tebaranowski
+# This file is distributed under the same license as the hibernate-status-button package.
+# tebaranowski <tomasz.baranowski@int.pl>, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Hibernate Status Button\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-04-11 18:31+0200\n"
+"PO-Revision-Date: 2021-09-13 17:56+0200\n"
+"Last-Translator: Heimen Stoffels <vistausss@fastmail.com>\n"
+"Language-Team: Dutch <vistausss@fastmail.com>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
+"X-Generator: Poedit 3.0\n"
+
+#: confirmDialog.js:23 confirmDialog.js:32
+msgid "Hibernate"
+msgstr "Slaapstand"
+
+#: confirmDialog.js:24
+msgid "Do you really want to hibernate the system?"
+msgstr "Weet u zeker dat u het systeem in de slaapstand wilt zetten?"
+
+#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67
+msgid "Cancel"
+msgstr "Annuleren"
+
+#: confirmDialog.js:40
+msgid "Hibernate button: Systemd Missing"
+msgstr "Slaapstandknop: Systemd ontbreekt"
+
+#: confirmDialog.js:41
+msgid "Systemd seems to be missing and is required."
+msgstr "Systemd is vereist, maar niet aangetroffen."
+
+#: confirmDialog.js:49 confirmDialog.js:72
+msgid "Disable Extension"
+msgstr "Uitbreiding uitschakelen"
+
+#: confirmDialog.js:58
+msgid "Hibernate button: Hibernate failed"
+msgstr "Slaapstandknop: slaapstand mislukt"
+
+#: confirmDialog.js:59
+msgid ""
+"Looks like hibernation failed.\n"
+"On some linux distributions hibernation is disabled\n"
+"because not all hardware supports it well;\n"
+"please check your distribution documentation\n"
+"on how to enable it."
+msgstr ""
+"Het lijkt er op dat de slaapstand niet kan worden ingeschakeld.\n"
+"Op sommige distributies is de slaapstand niet beschikbaar.\n"
+"Neem de documentatie van uw distributie door om te\n"
+"zien of u de slaapstand kunt activeren."
+
+#: confirmDialog.js:64
+msgid "You are wrong, don't check this anymore!"
+msgstr "Dit klopt niet - negeer deze controle!"
+
+#: prefs.js:99
+msgid "This extension has no settings available"
+msgstr "Deze uitbreiding bevat geen voorkeurenscherm"
diff --git a/hibernate-status/locale/oc/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/oc/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..25debf8 --- /dev/null +++ b/hibernate-status/locale/oc/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# Occitan translation of hibernate-status-button +# Copyright (C) 2022 Quentin +# This file is distributed under the same license as the hibernate-status-button package. +# Quentin +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2023-01-11 17:19+0200\n" +"Last-Translator: Quentin PAGÈS <>\n" +"Language-Team: Occitan\n" +"Language: oc\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: extension.js:189 confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Metre en velha perlongada" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Metre en velha ibrida" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Volètz vertadièrament metre l'aparelh en velha perlongada ?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Anullar" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Extension de mesa en velha perlongada : systemd mancant" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "systemd sembla pas installat e es necessari." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Desactivar l'extension" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Extension de mesa en velha perlongada : fracàs" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"La mesa en velha perlongada a fracassat.\n" +"Amb d'unas distribucions Linux, la mesa en velha perlongada es desactivada\n" +"pr'amor que fonciona pas coma cal amb d'unes aparelhs ;\n" +"Mercés de consultar la documentacion de la distribucion\n" +"per saber cossí l'activar." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Es pas necessari de marcar aquesta casa !" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Aquesta extension a pas cap de paramètres" diff --git a/hibernate-status/locale/pl/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/pl/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..57b735c --- /dev/null +++ b/hibernate-status/locale/pl/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# Polish translation of hibernate-status-button
+# Copyright (C) 2022 tebaranowski
+# This file is distributed under the same license as the hibernate-status-button package.
+# tebaranowski <tomasz.baranowski@int.pl>, 2022.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Hibernate Status Button\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-04-11 18:31+0200\n"
+"PO-Revision-Date: 2022-11-01 20:31+0200\n"
+"Last-Translator: tebaranowski <tomasz.baranowski@int.pl>\n"
+"Language-Team: Polish <tomasz.baranowski@int.pl>\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: confirmDialog.js:23 confirmDialog.js:32
+msgid "Hibernate"
+msgstr "Hibernacja"
+
+#: extension.js:192
+msgid "Hybrid Sleep"
+msgstr "Uśpienie hybrydowe"
+
+#: confirmDialog.js:24
+msgid "Do you really want to hibernate the system?"
+msgstr "Czy na pewno chcesz zahibernować system?"
+
+#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67
+msgid "Cancel"
+msgstr "Anuluj"
+
+#: confirmDialog.js:40
+msgid "Hibernate button: Systemd Missing"
+msgstr "Nie odnaleziono systemd"
+
+#: confirmDialog.js:41
+msgid "Systemd seems to be missing and is required."
+msgstr "Brak zainstalowanego systemd, wymaganego do hibernacji"
+
+#: confirmDialog.js:49 confirmDialog.js:72
+msgid "Disable Extension"
+msgstr "Wyłącz rozszerzenie"
+
+#: confirmDialog.js:58
+msgid "Hibernate button: Hibernate failed"
+msgstr "Hibernacja nie powiodła się"
+
+#: confirmDialog.js:59
+msgid ""
+"Looks like hibernation failed.\n"
+"On some linux distributions hibernation is disabled\n"
+"because not all hardware supports it well;\n"
+"please check your distribution documentation\n"
+"on how to enable it."
+msgstr ""
+"Wygląda na to, że hibernacja się nie powiodła.\n"
+"W niektórych dystrybucjach Linuksa hibernacja jest wyłączona,\n"
+"ponieważ nie każdy sprzęt poprawnie ją obsługuje.\n"
+"Sprawdź jak ją włączyć w dokumentacji swojej\n"
+"dystrybucji."
+
+#: confirmDialog.js:64
+msgid "You are wrong, don't check this anymore!"
+msgstr "Nie sprawdzaj tego ponownie!"
+
+#: prefs.js:99
+msgid "This extension has no settings available"
+msgstr "To rozszerzenie nie posiada możliwości zmiany ustawień"
diff --git a/hibernate-status/locale/pt/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/pt/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..143129c --- /dev/null +++ b/hibernate-status/locale/pt/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,71 @@ +# Portuguese translation of hibernate-status-button +# Copyright (C) 2021 p91paul +# This file is distributed under the same license as the hibernate-status-button package. +# mantonelli <matheus.antonelli@gmail.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2022-10-22 21:30+0200\n" +"Last-Translator: mantonelli <matheus.antonelli@gmail.com>\n" +"Language-Team: Portuguese <matheus.antonelli@gmail.com>\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Hibernar" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Suspensão Híbrida" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Deseja realmente hibernar o sistema?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Cancelar" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Systemd não está instalado" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Systemd não está instalado e é necessário" + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Desabilitar extensão" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Hibernação falhou" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Parece que a hibernação falhou.\n" +"Em algumas distribuições Linux a hibernação é desabilitada\n" +"já que nem todo hardware oferece suporte adequado à ela;\n" +"Confira a documentação de sua distribuição\n" +"para aprender como habilitá-la." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Você errou! Não selecione isso novamente!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Essa extensão não possui configurações disponíveis" diff --git a/hibernate-status/locale/pt_BR/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/pt_BR/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..326481a --- /dev/null +++ b/hibernate-status/locale/pt_BR/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,73 @@ +# Portuguese translation of hibernate-status-button +# Copyright (C) 2021 p91paul +# This file is distributed under the same license as the hibernate-status-button package. +# mantonelli <matheus.antonelli@gmail.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2022-10-22 21:30+0200\n" +"Last-Translator: Fabrício Müller <fabricio8800@gmail.com>\n" +"Language-Team: Brazilian Portuguese <fabricio8800@gmail.com>\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Poedit 3.0.1\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Hibernar" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Suspensão Híbrida" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Deseja realmente hibernar o sistema?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Cancelar" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Systemd não está instalado" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Systemd não está instalado e é necessário." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Desabilitar extensão" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Hibernação falhou" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Parece que a hibernação falhou.\n" +"Em algumas distribuições Linux a hibernação é desabilitada\n" +"já que nem todo hardware oferece suporte adequado à ela;\n" +"Confira a documentação de sua distribuição\n" +"para aprender como habilitá-la." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Você errou! Não selecione isso novamente!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Essa extensão não possui configurações disponíveis" diff --git a/hibernate-status/locale/ru/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/ru/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..c279315 --- /dev/null +++ b/hibernate-status/locale/ru/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,74 @@ +# Russian translation of hibernate-status-button +# Copyright (C) 2021 Serhii Riznychenko +# This file is distributed under the same license as the hibernate-status-button package. +# Serhii Riznychenko, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2021-11-11 02:00+0200\n" +"Last-Translator: Serhii Riznychenko\n" +"Language-Team: Russian\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 3.0\n" +"X-Poedit-Basepath: .\n" + +#: extension.js:189 confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Спящий режим" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Гибридный сон" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Вы действительно хотите перевести систему в спящий режим?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Отмена" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Не обнаружено systemd" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Кажется отсутствует systemd, необходимый для режима сна." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Отключить расширение" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Не удалось перевести систему в сон" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Попытка перевести систему в сон завершилась неудачей.\n" +"На некоторых дистрибутивах режим сна отключен\n" +"так как не каждое оборудование имеет поддержку,\n" +"пожалуйста обратитесь к документации своего дистрибутива\n" +"чтобы узнать как его включить." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Вы ошиблись, пожалуйста не трогайте это!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Это расширение не содержит параметров" diff --git a/hibernate-status/locale/uk/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/uk/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..68c6b8c --- /dev/null +++ b/hibernate-status/locale/uk/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,74 @@ +# Ukrainian translation of hibernate-status-button +# Copyright (C) 2021 Serhii Riznychenko +# This file is distributed under the same license as the hibernate-status-button package. +# Serhii Riznychenko, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-04-11 18:31+0200\n" +"PO-Revision-Date: 2021-11-11 02:00+0200\n" +"Last-Translator: Serhii Riznychenko\n" +"Language-Team: Ukraine\n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"X-Generator: Poedit 3.0\n" +"X-Poedit-Basepath: .\n" + +#: extension.js:189 confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "Перейти в сон" + +#: extension.js:192 +msgid "Hybrid Sleep" +msgstr "Перейти в гібридний сон" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "Ви дійсно хочете перевести систему в режим сну?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "Відміна" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "Не виявлено systemd" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "Здається відсутній systemd, необхідний режиму сну." + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "Вимкнути розширення" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "Не вдалося перевести систему в сон" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "" +"Спроба перевести систему в сон завершилася невдачею.\n" +"На деяких дистрибутивах режим сну вимкнено\n" +"оскільки не кожне обладнання має його підтримку,\n" +"Будь ласка, зверніться до документації свого дистрибутива\n" +"щоб дізнатися, як його включити." + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "Ви помилилися, будь ласка, не чіпайте це!" + +#: prefs.js:99 +msgid "This extension has no settings available" +msgstr "Це розширення не містить параметрів" diff --git a/hibernate-status/locale/zh_CN/LC_MESSAGES/hibernate-status-button.po b/hibernate-status/locale/zh_CN/LC_MESSAGES/hibernate-status-button.po new file mode 100644 index 0000000..be1a6b1 --- /dev/null +++ b/hibernate-status/locale/zh_CN/LC_MESSAGES/hibernate-status-button.po @@ -0,0 +1,59 @@ +# Simplified Chinese translation of hibernate-status-button +# Copyright (C) 2019 zhmars +# This file is distributed under the same license as the hibernate-status-button package. +# zhmars <1403122061@qq.com>, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: Hibernate Status Button\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-11-22 00:08+0800\n" +"PO-Revision-Date: 2019-11-21 20:00+0800\n" +"Last-Translator: zhmars <1403122061@qq.com>\n" +"Language-Team: Chinese (Simplified) <>\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: confirmDialog.js:23 confirmDialog.js:32 +msgid "Hibernate" +msgstr "休眠" + +#: confirmDialog.js:24 +msgid "Do you really want to hibernate the system?" +msgstr "确定要休眠系统吗?" + +#: confirmDialog.js:27 confirmDialog.js:44 confirmDialog.js:67 +msgid "Cancel" +msgstr "取消" + +#: confirmDialog.js:40 +msgid "Hibernate button: Systemd Missing" +msgstr "无法找到 Systemd" + +#: confirmDialog.js:41 +msgid "Systemd seems to be missing and is required." +msgstr "本功能依赖 Systemd,但目前无法找到。" + +#: confirmDialog.js:49 confirmDialog.js:72 +msgid "Disable Extension" +msgstr "禁用扩展" + +#: confirmDialog.js:58 +msgid "Hibernate button: Hibernate failed" +msgstr "休眠失败" + +#: confirmDialog.js:59 +msgid "" +"Looks like hibernation failed.\n" +"On some linux distributions hibernation is disabled\n" +"because not all hardware supports it well;\n" +"please check your distribution documentation\n" +"on how to enable it." +msgstr "休眠好像失败了。由于不是所有硬件都对该功能支持良好," +"某些发行版默认禁用了休眠,关于如何启用请查阅你所用的发行版文档" + +#: confirmDialog.js:64 +msgid "You are wrong, don't check this anymore!" +msgstr "忽略本项检查" diff --git a/hibernate-status/metadata.json b/hibernate-status/metadata.json new file mode 100644 index 0000000..94098fe --- /dev/null +++ b/hibernate-status/metadata.json @@ -0,0 +1,10 @@ +{ + "uuid": "hibernate-status@dromi", + "name": "Hibernate Status Button", + "url": "https://github.com/arelange/gnome-shell-extension-hibernate-status", + "description": "Adds a Hibernate button in Status menu. Using Alt modifier, you can also select Hybrid Sleep instead.", + "shell-version": [ + "43" + ], + "gettext-domain": "hibernate-status-button" +} diff --git a/hibernate-status/prefs.js b/hibernate-status/prefs.js new file mode 100644 index 0000000..cdcd50e --- /dev/null +++ b/hibernate-status/prefs.js @@ -0,0 +1,105 @@ +const Gio = imports.gi.Gio; +const Gtk = imports.gi.Gtk; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +// Use __() and N__() for the extension gettext domain, and reuse +// the shell domain with the default _() and N_() +const Gettext = imports.gettext.domain('hibernate-status-button'); +const __ = Gettext.gettext; +const N__ = function(e) { return e }; +const ExtensionUtils = imports.misc.extensionUtils; + +var Prefs = class Prefs { + /** + * Creates a new Settings-object to access the settings of this extension. + * @private + */ + constructor() { + this.KEY_HIBERNATE_WORKS_CHECK = "hibernate-works-check"; + this._schemaName = "org.gnome.shell.extensions.hibernate-status-button"; + + let schemaDir = Me.dir.get_child('schemas').get_path(); + + let schemaSource = Gio.SettingsSchemaSource.new_from_directory( + schemaDir, Gio.SettingsSchemaSource.get_default(), false + ); + let schema = schemaSource.lookup(this._schemaName, false); + + this._setting = new Gio.Settings({ + settings_schema: schema + }); + } + /** + * <p>Binds the given 'callback'-function to the "changed"-signal on the given + * key.</p> + * <p>The 'callback'-function is passed an argument which holds the new + * value of 'key'. The argument is of type "GLib.Variant". Given that the + * receiver knows the internal type, use one of the get_XX()-methods to get + * it's actual value.</p> + * @see http://www.roojs.com/seed/gir-1.2-gtk-3.0/gjs/GLib.Variant.html + * @param key the key to watch for changes. + * @param callback the callback-function to call. + */ + bindKey(key, callback) { + // Validate: + if (key === undefined || key === null || typeof key !== "string") { + throw TypeError("The 'key' should be a string. Got: '" + key + "'"); + } + if (callback === undefined || callback === null || typeof callback !== "function") { + throw TypeError("'callback' needs to be a function. Got: " + callback); + } + // Bind: + this._setting.connect("changed::" + key, function (source, key) { + callback(source.get_value(key)); + }); + } + /** + * Get if check for working hibernation is enabled. The user might + * choose to disable it if we happen to be wrong. + * + * @returns bool true if we need to check if hibernation works. + */ + getHibernateWorksCheckEnabled() { + return this._setting.get_boolean(this.KEY_HIBERNATE_WORKS_CHECK); + } + /** + * Set if check for working hibernation is enabled. The user might + * choose to disable it if we happen to be wrong. + * + * @returns bool true if we need to check if hibernation works. + */ + setHibernateWorksCheckEnabled(enabled) { + let key = this.KEY_HIBERNATE_WORKS_CHECK; + if (this._setting.is_writable(key)) { + if (this._setting.set_boolean(key, enabled)) { + Gio.Settings.sync(); + } else { + throw this._errorSet(key); + } + } else { + throw this._errorWritable(key); + } + } + _errorWritable(key) { + return "The key '" + key + "' is not writable."; + } + _errorSet(key) { + return "Couldn't set the key '" + key + "'"; + } +} + +// These "preferences" aren't user accessible so define +// init() and buildPrefsWidget() to empty functions +function init() { + ExtensionUtils.initTranslations('hibernate-status-button'); +} +function buildPrefsWidget() { + let frame = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, + 'margin-top': 10, + 'margin-end': 10, + 'margin-bottom': 10, + 'margin-start': 10}); + let setting_label = new Gtk.Label({label: __("This extension has no settings available"), + xalign: 0 }); + frame.append(setting_label); + return frame; +} diff --git a/hibernate-status/schemas/org.gnome.shell.extensions.hibernate-status-button.gschema.xml b/hibernate-status/schemas/org.gnome.shell.extensions.hibernate-status-button.gschema.xml new file mode 100644 index 0000000..f29ec1c --- /dev/null +++ b/hibernate-status/schemas/org.gnome.shell.extensions.hibernate-status-button.gschema.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<schemalist gettext-domain="hibernate-status-button"> + <schema path="/org/gnome/shell/extensions/hibernate-status-button/" id="org.gnome.shell.extensions.hibernate-status-button"> + <key type="b" name="hibernate-works-check"> + <default>true</default> + </key> + </schema> +</schemalist> diff --git a/multi-monitors-add-on/.project b/multi-monitors-add-on/.project new file mode 100644 index 0000000..58f94f4 --- /dev/null +++ b/multi-monitors-add-on/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>multi-monitors-add-on</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/multi-monitors-add-on/LICENSE b/multi-monitors-add-on/LICENSE new file mode 100644 index 0000000..d6a9326 --- /dev/null +++ b/multi-monitors-add-on/LICENSE @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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 Lesser 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. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + {signature of Ty Coon}, 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 Lesser General +Public License instead of this License. + diff --git a/multi-monitors-add-on/README.md b/multi-monitors-add-on/README.md new file mode 100644 index 0000000..4aaa45a --- /dev/null +++ b/multi-monitors-add-on/README.md @@ -0,0 +1,33 @@ +Multi Monitors Add-On +===================== + +Extension inspired by https://github.com/darkxst/multiple-monitor-panels +and rewritten from scratch for gnome-shell version 3.10.4. Adds panels +and thumbnails for additional monitors. Settings changes are applied +in dynamic fashion, no restart needed. + +Versions +======== + +* Branch [master](https://github.com/realh/multi-monitors-add-on/tree/master) contains extension for GNOME 42 +* Branch [gnome-3-32_3-36](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-32_3-36) contains extension for GNOME 3.32, 3.34 and 3.36 +* Branch [gnome-3-24_3-30](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-24_3-30) contains extension for GNOME 3.24, 3.26, 3.28 and 3.30 +* Branch [gnome-3-20_3-22](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-20_3-22) contains extension for GNOME 3.20 and 3.22 +* Branch [gnome-3-16_3-18](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-16_3-18) contains extension for GNOME 3.16 and 3.18 +* Branch [gnome-3-14](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-14) contains extension for GNOME 3.14 +* Branch [gnome-3-10](https://github.com/spin83/multi-monitors-add-on/tree/gnome-3-10) contains extension for GNOME 3.10 + +Installation from git +===================== + + git clone git://github.com/realh/multi-monitors-add-on.git + cd multi-monitors-add-on + cp -r multi-monitors-add-on@spin83 ~/.local/share/gnome-shell/extensions/ + +Restart the shell and then enable the extension. + +License +======= + +Multi Monitors Add-On extension is distributed under the terms of the +GNU General Public License, version 2 or later. See the LICENSE file for details. diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/convenience.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/convenience.js new file mode 100644 index 0000000..bbc8608 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/convenience.js @@ -0,0 +1,93 @@ +/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (c) 2011-2012, Giovanni Campagna <scampa.giovanni@gmail.com> + + 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/multi-monitors-add-on/multi-monitors-add-on@spin83/extension.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/extension.js new file mode 100644 index 0000000..092d828 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/extension.js @@ -0,0 +1,289 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const { Clutter, Gio } = imports.gi; + +const Main = imports.ui.main; +var { ANIMATION_TIME } = imports.ui.overview; + +const Config = imports.misc.config; +const GNOME_SHELL_VERSION = Config.PACKAGE_VERSION.split('.'); + +const ExtensionUtils = imports.misc.extensionUtils; +const MultiMonitors = ExtensionUtils.getCurrentExtension(); +const Convenience = MultiMonitors.imports.convenience; + +const MMLayout = MultiMonitors.imports.mmlayout; +const MMOverview = MultiMonitors.imports.mmoverview; +const MMIndicator = MultiMonitors.imports.indicator; + +const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; +const MUTTER_SCHEMA = 'org.gnome.mutter'; +const WORKSPACES_ONLY_ON_PRIMARY_ID = 'workspaces-only-on-primary'; + +const SHOW_INDICATOR_ID = 'show-indicator'; +const THUMBNAILS_SLIDER_POSITION_ID = 'thumbnails-slider-position'; + +function copyClass (s, d) { +// global.log(s.name +" > "+ d.name); + if (!s) throw Error(`copyClass s undefined for d ${d.name}`) + let propertyNames = Reflect.ownKeys(s.prototype); + for (let pName of propertyNames.values()) { + +// global.log(" ) "+pName.toString()); + if (typeof pName === "symbol") continue; + if (d.prototype.hasOwnProperty(pName)) continue; + if (pName === "prototype") continue; + if (pName === "constructor") continue; +// global.log(pName); + let pDesc = Reflect.getOwnPropertyDescriptor(s.prototype, pName); +// global.log(typeof pDesc); + if (typeof pDesc !== 'object') continue; + Reflect.defineProperty(d.prototype, pName, pDesc); + } +}; + +function gnomeShellVersion() { + return GNOME_SHELL_VERSION; +} + +class MultiMonitorsAddOn { + + constructor() { + this._settings = Convenience.getSettings(); + this._ov_settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA }); + this._mu_settings = new Gio.Settings({ schema: MUTTER_SCHEMA }); + + this.mmIndicator = null; + Main.mmOverview = null; + Main.mmLayoutManager = null; + + this._mmMonitors = 0; + this.syncWorkspacesActualGeometry = null; + } + + _showIndicator() { + if(this._settings.get_boolean(SHOW_INDICATOR_ID)) { + if(!this.mmIndicator) { + this.mmIndicator = Main.panel.addToStatusArea('MultiMonitorsAddOn', new MMIndicator.MultiMonitorsIndicator()); + } + } + else { + this._hideIndicator(); + } + } + + _hideIndicator() { + if(this.mmIndicator) { + this.mmIndicator.destroy(); + this.mmIndicator = null; + } + } + + _showThumbnailsSlider() { + if (this._settings.get_string(THUMBNAILS_SLIDER_POSITION_ID) === 'none') { + this._hideThumbnailsSlider(); + return; + } + + if(this._ov_settings.get_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID)) + this._ov_settings.set_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID, false); + if(this._mu_settings.get_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID)) + this._mu_settings.set_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID, false); + + if (Main.mmOverview) + return; + + Main.mmOverview = []; + for (let idx = 0; idx < Main.layoutManager.monitors.length; idx++) { + if (idx != Main.layoutManager.primaryIndex) { + Main.mmOverview[idx] = new MMOverview.MultiMonitorsOverview(idx); + } + } + + this.syncWorkspacesActualGeometry = Main.overview.searchController._workspacesDisplay._syncWorkspacesActualGeometry; + Main.overview.searchController._workspacesDisplay._syncWorkspacesActualGeometry = function() { + if (this._inWindowFade) + return; + + const primaryView = this._getPrimaryView(); + if (primaryView) { + primaryView.ease({ + ...this._actualGeometry, + duration: Main.overview.animationInProgress ? ANIMATION_TIME : 0, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + for (let idx = 0; idx < Main.mmOverview.length; idx++) { + if (!Main.mmOverview[idx]) + continue; + if (!Main.mmOverview[idx]._overview) + continue; + const mmView = Main.mmOverview[idx]._overview._controls._workspacesViews; + if (!mmView) + continue; + + const mmGeometry = Main.mmOverview[idx].getWorkspacesActualGeometry(); + mmView.ease({ + ...mmGeometry, + duration: Main.overview.animationInProgress ? ANIMATION_TIME : 0, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + } + } + + _hideThumbnailsSlider() { + if (!Main.mmOverview) + return; + + for (let idx = 0; idx < Main.mmOverview.length; idx++) { + if (Main.mmOverview[idx]) + Main.mmOverview[idx].destroy(); + } + Main.mmOverview = null; + Main.overview.searchController._workspacesDisplay._syncWorkspacesActualGeometry = this.syncWorkspacesActualGeometry; + } + + _relayout() { + if(this._mmMonitors!=Main.layoutManager.monitors.length){ + this._mmMonitors = Main.layoutManager.monitors.length; + global.log("pi:"+Main.layoutManager.primaryIndex); + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + let monitor = Main.layoutManager.monitors[i]; + global.log("i:"+i+" x:"+monitor.x+" y:"+monitor.y+" w:"+monitor.width+" h:"+monitor.height); + } + this._hideThumbnailsSlider(); + this._showThumbnailsSlider(); + } + } + + _switchOffThumbnails() { + if (this._ov_settings.get_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID) || this._mu_settings.get_boolean(WORKSPACES_ONLY_ON_PRIMARY_ID)) { + this._settings.set_string(THUMBNAILS_SLIDER_POSITION_ID, 'none'); + } + } + + enable(version) { + global.log("Enable Multi Monitors Add-On ("+version+")...") + + if(Main.panel.statusArea.MultiMonitorsAddOn) + disable(); + + this._mmMonitors = 0; + + this._switchOffThumbnailsOvId = this._ov_settings.connect('changed::'+WORKSPACES_ONLY_ON_PRIMARY_ID, + this._switchOffThumbnails.bind(this)); + this._switchOffThumbnailsMuId = this._mu_settings.connect('changed::'+WORKSPACES_ONLY_ON_PRIMARY_ID, + this._switchOffThumbnails.bind(this)); + + this._showIndicatorId = this._settings.connect('changed::'+SHOW_INDICATOR_ID, this._showIndicator.bind(this)); + this._showIndicator(); + + Main.mmLayoutManager = new MMLayout.MultiMonitorsLayoutManager(); + this._showPanelId = this._settings.connect('changed::'+MMLayout.SHOW_PANEL_ID, Main.mmLayoutManager.showPanel.bind(Main.mmLayoutManager)); + Main.mmLayoutManager.showPanel(); + + this._thumbnailsSliderPositionId = this._settings.connect('changed::'+THUMBNAILS_SLIDER_POSITION_ID, this._showThumbnailsSlider.bind(this)); + this._relayoutId = Main.layoutManager.connect('monitors-changed', this._relayout.bind(this)); + this._relayout(); + } + + disable() { + Main.layoutManager.disconnect(this._relayoutId); + this._ov_settings.disconnect(this._switchOffThumbnailsOvId); + this._mu_settings.disconnect(this._switchOffThumbnailsMuId); + + this._settings.disconnect(this._showPanelId); + this._settings.disconnect(this._thumbnailsSliderPositionId); + this._settings.disconnect(this._showIndicatorId); + + + this._hideIndicator(); + + Main.mmLayoutManager.hidePanel(); + Main.mmLayoutManager = null; + + this._hideThumbnailsSlider(); + this._mmMonitors = 0; + + global.log("Disable Multi Monitors Add-On ...") + } +} + +var multiMonitorsAddOn = null; +var version = null; + +function init() { + Convenience.initTranslations(); + + // fix bug in panel: Destroy function many time added to this same indicator. + Main.panel._ensureIndicator = function(role) { + let indicator = this.statusArea[role]; + if (indicator) { + indicator.container.show(); + return null; + } + else { + let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + }; + + const metaVersion = MultiMonitors.metadata['version']; + if (Number.isFinite(metaVersion)) { + version = 'v'+Math.trunc(metaVersion); + switch(Math.round((metaVersion%1)*10)) { + case 0: + break; + case 1: + version += '+bugfix'; + break; + case 2: + version += '+develop'; + break; + default: + version += '+modified'; + break; + } + } + else + version = metaVersion; +} + +function enable() { + if (multiMonitorsAddOn !== null) + return; + + multiMonitorsAddOn = new MultiMonitorsAddOn(); + multiMonitorsAddOn.enable(version); +} + +function disable() { + if (multiMonitorsAddOn == null) + return; + + multiMonitorsAddOn.disable(); + multiMonitorsAddOn = null; +} diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-l-symbolic.svg b/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-l-symbolic.svg new file mode 100644 index 0000000..6341c21 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-l-symbolic.svg @@ -0,0 +1,392 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="multi-monitor-symbolic.svg" + height="16" + id="svg7384" + inkscape:version="0.48.5 r10040" + version="1.1" + width="16"> + <metadata + id="metadata90"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Gnome Symbolic Icon Theme</dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:bbox-paths="false" + bordercolor="#666666" + borderopacity="1" + inkscape:current-layer="layer11" + inkscape:cx="3.128503" + inkscape:cy="7.3630629" + gridtolerance="10" + inkscape:guide-bbox="true" + guidetolerance="10" + id="namedview88" + inkscape:object-nodes="false" + inkscape:object-paths="false" + objecttolerance="10" + pagecolor="#555753" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + showborder="false" + showgrid="true" + showguides="true" + inkscape:snap-bbox="true" + inkscape:snap-bbox-midpoints="false" + inkscape:snap-global="true" + inkscape:snap-grids="true" + inkscape:snap-nodes="false" + inkscape:snap-others="false" + inkscape:snap-to-guides="true" + inkscape:window-height="1014" + inkscape:window-maximized="1" + inkscape:window-width="1920" + inkscape:window-x="0" + inkscape:window-y="27" + inkscape:zoom="32"> + <inkscape:grid + empspacing="2" + enabled="true" + id="grid4866" + originx="-42.000009px" + originy="412px" + snapvisiblegridlinesonly="true" + spacingx="1px" + spacingy="1px" + type="xygrid" + visible="true" /> + <sodipodi:guide + orientation="0,1" + position="3.4692426,9.4354561" + id="guide4029" /> + </sodipodi:namedview> + <title + id="title9167">Gnome Symbolic Icon Theme</title> + <defs + id="defs7386"> + <linearGradient + id="linearGradient5351" + osb:paint="solid"> + <stop + style="stop-color:#00a600;stop-opacity:1;" + offset="0" + id="stop5353" /> + </linearGradient> + <marker + inkscape:stockid="EmptyTriangleOutS" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutS" + style="overflow:visible"> + <path + id="path4013" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.2,0,0,0.2,-0.6,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Legs" + orient="auto" + refY="0" + refX="0" + id="Legs" + style="overflow:visible"> + <g + id="g4046" + transform="scale(-0.7,-0.7)"> + <g + id="g4048" + transform="matrix(0,-1,-1,0,20.70862,21.31391)"> + <path + id="path4050" + d="m 21.22125,20.67536 c -6.910151,4.721157 -2.454525,6.606844 -5.841071,13.443235" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4052" + d="m 21.39811,20.54812 c -1.360509,8.347524 3.536072,8.76994 4.505041,13.824958" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + <path + id="path4054" + d="m -14.09007,-6.7318716 -0.922168,4.043383 3.962751,-1.22307 -3.040583,-2.820313 z" + style="fill:#030300;fill-rule:evenodd;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4056" + d="m -15.215679,4.5567534 1.874127,3.699613 2.266874,-3.472855 -4.141001,-0.226758 z" + style="fill:#030300;fill-rule:evenodd;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="Torso" + orient="auto" + refY="0" + refX="0" + id="Torso" + style="overflow:visible"> + <g + id="g4059" + transform="scale(0.7,0.7)"> + <path + id="path4061" + d="m -4.7792281,-3.239542 c 2.350374,0.3659393 5.30026732,1.9375477 5.03715532,3.62748546 C -0.00518779,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 -6.9134221,1.8857769 -8.521035,0.75201414 -8.257922,-0.93792336 -7.994809,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.239542 z" + style="fill:none;stroke:#000000;stroke-width:1.25" + inkscape:connector-curvature="0" /> + <path + id="path4063" + d="M 4.4598789,0.08866574 C -2.5564571,-4.378332 5.2248769,-3.9061806 -0.84829578,-8.7197331" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4065" + d="M 4.9298719,0.05752074 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <rect + id="rect4067" + transform="matrix(0.527536,-0.849533,0.887668,0.460484,0,0)" + y="-1.7408575" + x="-10.391706" + height="2.7608147" + width="2.6366582" + style="fill-rule:evenodd;stroke-width:1pt" /> + <rect + id="rect4069" + transform="matrix(0.671205,-0.741272,0.790802,0.612072,0,0)" + y="-7.9629307" + x="4.9587269" + height="2.8614161" + width="2.7327356" + style="fill-rule:evenodd;stroke-width:1pt" /> + <path + id="path4071" + transform="matrix(0,-1.109517,1.109517,0,25.96648,19.71619)" + d="m 16.779951,-28.685045 a 0.60731727,0.60731727 0 1 0 -1.214634,0 0.60731727,0.60731727 0 1 0 1.214634,0 z" + style="fill:#ff0000;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4073" + transform="matrix(0,-1.109517,1.109517,0,26.8245,16.99126)" + d="m 16.779951,-28.685045 a 0.60731727,0.60731727 0 1 0 -1.214634,0 0.60731727,0.60731727 0 1 0 1.214634,0 z" + style="fill:#ff0000;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="EmptyDiamondLstart" + orient="auto" + refY="0" + refX="0" + id="EmptyDiamondLstart" + style="overflow:visible"> + <path + id="path3962" + d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,5.6,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DiamondSend" + orient="auto" + refY="0" + refX="0" + id="DiamondSend" + style="overflow:visible"> + <path + id="path3950" + d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.2,0,0,0.2,-1.2,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Mend" + style="overflow:visible"> + <path + id="path3856" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(-0.4,0,0,-0.4,-4,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Tail" + orient="auto" + refY="0" + refX="0" + id="Tail" + style="overflow:visible"> + <g + id="g3883" + transform="scale(-1.2,-1.2)"> + <path + id="path3885" + d="M -3.8048674,-3.9585227 0.54352094,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3887" + d="M -1.2866832,-3.9585227 3.0617053,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3889" + d="M 1.3053582,-3.9585227 5.6537466,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3891" + d="M -3.8048674,4.1775838 0.54352094,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3893" + d="M -1.2866832,4.1775838 3.0617053,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3895" + d="M 1.3053582,4.1775838 5.6537466,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="Arrow2Sstart" + orient="auto" + refY="0" + refX="0" + id="Arrow2Sstart" + style="overflow:visible"> + <path + id="path3877" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="matrix(0.3,0,0,0.3,-0.69,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DotL" + orient="auto" + refY="0" + refX="0" + id="DotL" + style="overflow:visible"> + <path + id="path3908" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,5.92,0.8)" + inkscape:connector-curvature="0" /> + </marker> + </defs> + <g + inkscape:groupmode="layer" + id="layer9" + inkscape:label="status" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer10" + inkscape:label="devices" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer11" + inkscape:label="apps" + style="display:inline" + transform="translate(-283.00021,-629)"> + <g + id="g3040"> + <path + id="path3795-3" + d="m 283.60374,629.58458 0,12.86095 14.78834,-1.16918 0,-10.5226 -14.78834,-1.16917 z m 0.73172,0.65766 13.28639,1.05957 0,9.46303 -13.32491,1.02303 0.0385,-11.54563 z" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:1.20035386;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path3839-5" + d="m 290.99791,641.86094 -2e-5,2.33836" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:3.60105371;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path3841-2" + d="m 295.34001,643.66019 -8.13359,0.64305" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:1.32038927;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;display:inline" /> + </g> + </g> + <g + inkscape:groupmode="layer" + id="layer1" + inkscape:label="on" + style="display:inline" /> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="off" + style="display:inline" /> + <g + inkscape:groupmode="layer" + id="layer13" + inkscape:label="places" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer14" + inkscape:label="mimetypes" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer15" + inkscape:label="emblems" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="g71291" + inkscape:label="emotes" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="g4953" + inkscape:label="categories" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer12" + inkscape:label="actions" + style="display:inline" + transform="translate(-283.00021,-629)" /> +</svg> diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-r-symbolic.svg b/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-r-symbolic.svg new file mode 100644 index 0000000..6bf4651 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-r-symbolic.svg @@ -0,0 +1,393 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="multi-monitor-l-symbolic.svg" + height="16" + id="svg7384" + inkscape:version="0.48.5 r10040" + version="1.1" + width="16"> + <metadata + id="metadata90"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Gnome Symbolic Icon Theme</dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:bbox-paths="false" + bordercolor="#666666" + borderopacity="1" + inkscape:current-layer="layer11" + inkscape:cx="3.191003" + inkscape:cy="7.3005629" + gridtolerance="10" + inkscape:guide-bbox="true" + guidetolerance="10" + id="namedview88" + inkscape:object-nodes="false" + inkscape:object-paths="false" + objecttolerance="10" + pagecolor="#555753" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + showborder="false" + showgrid="true" + showguides="true" + inkscape:snap-bbox="true" + inkscape:snap-bbox-midpoints="false" + inkscape:snap-global="true" + inkscape:snap-grids="true" + inkscape:snap-nodes="false" + inkscape:snap-others="false" + inkscape:snap-to-guides="true" + inkscape:window-height="958" + inkscape:window-maximized="1" + inkscape:window-width="1280" + inkscape:window-x="1920" + inkscape:window-y="27" + inkscape:zoom="32"> + <inkscape:grid + empspacing="2" + enabled="true" + id="grid4866" + originx="-42.000009px" + originy="412px" + snapvisiblegridlinesonly="true" + spacingx="1px" + spacingy="1px" + type="xygrid" + visible="true" /> + <sodipodi:guide + orientation="0,1" + position="3.4692426,9.4354561" + id="guide4029" /> + </sodipodi:namedview> + <title + id="title9167">Gnome Symbolic Icon Theme</title> + <defs + id="defs7386"> + <linearGradient + id="linearGradient5351" + osb:paint="solid"> + <stop + style="stop-color:#00a600;stop-opacity:1;" + offset="0" + id="stop5353" /> + </linearGradient> + <marker + inkscape:stockid="EmptyTriangleOutS" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleOutS" + style="overflow:visible"> + <path + id="path4013" + d="m 5.77,0 -8.65,5 0,-10 8.65,5 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.2,0,0,0.2,-0.6,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Legs" + orient="auto" + refY="0" + refX="0" + id="Legs" + style="overflow:visible"> + <g + id="g4046" + transform="scale(-0.7,-0.7)"> + <g + id="g4048" + transform="matrix(0,-1,-1,0,20.70862,21.31391)"> + <path + id="path4050" + d="m 21.22125,20.67536 c -6.910151,4.721157 -2.454525,6.606844 -5.841071,13.443235" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4052" + d="m 21.39811,20.54812 c -1.360509,8.347524 3.536072,8.76994 4.505041,13.824958" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + <path + id="path4054" + d="m -14.09007,-6.7318716 -0.922168,4.043383 3.962751,-1.22307 -3.040583,-2.820313 z" + style="fill:#030300;fill-rule:evenodd;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4056" + d="m -15.215679,4.5567534 1.874127,3.699613 2.266874,-3.472855 -4.141001,-0.226758 z" + style="fill:#030300;fill-rule:evenodd;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="Torso" + orient="auto" + refY="0" + refX="0" + id="Torso" + style="overflow:visible"> + <g + id="g4059" + transform="scale(0.7,0.7)"> + <path + id="path4061" + d="m -4.7792281,-3.239542 c 2.350374,0.3659393 5.30026732,1.9375477 5.03715532,3.62748546 C -0.00518779,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 -6.9134221,1.8857769 -8.521035,0.75201414 -8.257922,-0.93792336 -7.994809,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.239542 z" + style="fill:none;stroke:#000000;stroke-width:1.25" + inkscape:connector-curvature="0" /> + <path + id="path4063" + d="M 4.4598789,0.08866574 C -2.5564571,-4.378332 5.2248769,-3.9061806 -0.84829578,-8.7197331" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4065" + d="M 4.9298719,0.05752074 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725" + style="fill:none;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <rect + id="rect4067" + transform="matrix(0.527536,-0.849533,0.887668,0.460484,0,0)" + y="-1.7408575" + x="-10.391706" + height="2.7608147" + width="2.6366582" + style="fill-rule:evenodd;stroke-width:1pt" /> + <rect + id="rect4069" + transform="matrix(0.671205,-0.741272,0.790802,0.612072,0,0)" + y="-7.9629307" + x="4.9587269" + height="2.8614161" + width="2.7327356" + style="fill-rule:evenodd;stroke-width:1pt" /> + <path + id="path4071" + transform="matrix(0,-1.109517,1.109517,0,25.96648,19.71619)" + d="m 16.779951,-28.685045 a 0.60731727,0.60731727 0 1 0 -1.214634,0 0.60731727,0.60731727 0 1 0 1.214634,0 z" + style="fill:#ff0000;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + <path + id="path4073" + transform="matrix(0,-1.109517,1.109517,0,26.8245,16.99126)" + d="m 16.779951,-28.685045 a 0.60731727,0.60731727 0 1 0 -1.214634,0 0.60731727,0.60731727 0 1 0 1.214634,0 z" + style="fill:#ff0000;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="EmptyDiamondLstart" + orient="auto" + refY="0" + refX="0" + id="EmptyDiamondLstart" + style="overflow:visible"> + <path + id="path3962" + d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,5.6,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DiamondSend" + orient="auto" + refY="0" + refX="0" + id="DiamondSend" + style="overflow:visible"> + <path + id="path3950" + d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.2,0,0,0.2,-1.2,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Mend" + style="overflow:visible"> + <path + id="path3856" + d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(-0.4,0,0,-0.4,-4,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Tail" + orient="auto" + refY="0" + refX="0" + id="Tail" + style="overflow:visible"> + <g + id="g3883" + transform="scale(-1.2,-1.2)"> + <path + id="path3885" + d="M -3.8048674,-3.9585227 0.54352094,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3887" + d="M -1.2866832,-3.9585227 3.0617053,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3889" + d="M 1.3053582,-3.9585227 5.6537466,0" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3891" + d="M -3.8048674,4.1775838 0.54352094,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3893" + d="M -1.2866832,4.1775838 3.0617053,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + <path + id="path3895" + d="M 1.3053582,4.1775838 5.6537466,0.21974226" + style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round" + inkscape:connector-curvature="0" /> + </g> + </marker> + <marker + inkscape:stockid="Arrow2Sstart" + orient="auto" + refY="0" + refX="0" + id="Arrow2Sstart" + style="overflow:visible"> + <path + id="path3877" + style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" + transform="matrix(0.3,0,0,0.3,-0.69,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="DotL" + orient="auto" + refY="0" + refX="0" + id="DotL" + style="overflow:visible"> + <path + id="path3908" + d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" + transform="matrix(0.8,0,0,0.8,5.92,0.8)" + inkscape:connector-curvature="0" /> + </marker> + </defs> + <g + inkscape:groupmode="layer" + id="layer9" + inkscape:label="status" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer10" + inkscape:label="devices" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer11" + inkscape:label="apps" + style="display:inline" + transform="translate(-283.00021,-629)"> + <g + id="g3040" + transform="matrix(-1,0,0,1,581.99582,0)"> + <path + id="path3795-3" + d="m 283.60374,629.58458 0,12.86095 14.78834,-1.16918 0,-10.5226 -14.78834,-1.16917 z m 0.73172,0.65766 13.28639,1.05957 0,9.46303 -13.32491,1.02303 0.0385,-11.54563 z" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:1.20035386;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path3839-5" + d="m 290.99791,641.86094 -2e-5,2.33836" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:3.60105371;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path3841-2" + d="m 295.34001,643.66019 -8.13359,0.64305" + style="fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:#bebebe;stroke-width:1.32038927;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;display:inline" /> + </g> + </g> + <g + inkscape:groupmode="layer" + id="layer1" + inkscape:label="on" + style="display:inline" /> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="off" + style="display:inline" /> + <g + inkscape:groupmode="layer" + id="layer13" + inkscape:label="places" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer14" + inkscape:label="mimetypes" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer15" + inkscape:label="emblems" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="g71291" + inkscape:label="emotes" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="g4953" + inkscape:label="categories" + style="display:inline" + transform="translate(-283.00021,-629)" /> + <g + inkscape:groupmode="layer" + id="layer12" + inkscape:label="actions" + style="display:inline" + transform="translate(-283.00021,-629)" /> +</svg> diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/indicator.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/indicator.js new file mode 100644 index 0000000..8b500ee --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/indicator.js @@ -0,0 +1,109 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const { St, Gio, GLib, GObject } = imports.gi; + +const Util = imports.misc.util; +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; + +const Gettext = imports.gettext.domain('multi-monitors-add-on'); +const _ = Gettext.gettext; +const CE = imports.misc.extensionUtils.getCurrentExtension(); +const MultiMonitors = CE.imports.extension; +const Convenience = CE.imports.convenience; +const extensionPath = CE.path; + +var MultiMonitorsIndicator = (() => { + let MultiMonitorsIndicator = class MultiMonitorsIndicator extends PanelMenu.Button { + _init() { + super._init(0.0, "MultiMonitorsAddOn", false); + + Convenience.initTranslations(); + + this.text = null; + this._mmStatusIcon = new St.BoxLayout({ style_class: 'multimonitor-status-indicators-box' }); + this._mmStatusIcon.hide(); + this.add_child(this._mmStatusIcon); + this._leftRightIcon = true; + this.menu.addAction(_("Preferences"), this._onPreferences.bind(this)); + this._viewMonitorsId = Main.layoutManager.connect('monitors-changed', this._viewMonitors.bind(this)); + this._viewMonitors(); + } + + _onDestroy() { + Main.layoutManager.disconnect(this._viewMonitorsId); + super._onDestroy(); + } + + _syncIndicatorsVisible() { + this._mmStatusIcon.visible = this._mmStatusIcon.get_children().some(a => a.visible); + } + + _icon_name (icon, iconName) { + icon.set_gicon(Gio.icon_new_for_string(extensionPath+"/icons/"+iconName+".svg")); + } + + _viewMonitors() { + let monitors = this._mmStatusIcon.get_children(); + + let monitorChange = Main.layoutManager.monitors.length - monitors.length; + if(monitorChange>0){ + global.log("Add Monitors ..."); + for(let idx = 0; idx<monitorChange; idx++){ + let icon; + icon = new St.Icon({style_class: 'system-status-icon multimonitor-status-icon'}); + this._mmStatusIcon.add_child(icon); + icon.connect('notify::visible', this._syncIndicatorsVisible.bind(this)); + + if (this._leftRightIcon) + this._icon_name(icon, 'multi-monitors-l-symbolic'); + else + this._icon_name(icon, 'multi-monitors-r-symbolic'); + this._leftRightIcon = !this._leftRightIcon; + } + this._syncIndicatorsVisible(); + } + else if(monitorChange<0){ + global.log("Remove Monitors ..."); + monitorChange = -monitorChange; + + for(let idx = 0; idx<monitorChange; idx++){ + let icon = this._mmStatusIcon.get_last_child(); + this._mmStatusIcon.remove_child(icon); + icon.destroy(); + this._leftRightIcon = !this._leftRightIcon; + } + } + } + + _onPreferences() { + const uuid = "multi-monitors-add-on@spin83"; + Gio.DBus.session.call( + 'org.gnome.Shell.Extensions', + '/org/gnome/Shell/Extensions', + 'org.gnome.Shell.Extensions', + 'OpenExtensionPrefs', + new GLib.Variant('(ssa{sv})', [uuid, '', {}]), + null, + Gio.DBusCallFlags.NONE, + -1, + null); + } + }; + return GObject.registerClass(MultiMonitorsIndicator); +})(); diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..ce5795c --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..0691ac2 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,95 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Multi Monitors Add On Gnome Shell Extension\n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: 2015-01-23 22:30+0100\n" +"Last-Translator: Jonatan Zeidler <jonatan_zeidler@gmx.de>\n" +"Language-Team: German <jonatan_zeidler@gmx.de>\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "Einstellungen" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "Multimonitor-Erweiterung" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Multimonitor-Indikator in der oberen Leiste anzeigen" + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "Leiste auf zusätzlichen Monitoren anzeigen" + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "Arbeitsflächenübersicht auf zusätzlichen Monitoren anzeigen" + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "Aktivitäten-Schaltfläche auf zusätzlichen Monitoren anzeigen" + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Anwendungsmenü auf zusätzlichen Monitoren anzeigen" + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Datum-Zeit auf zusätzlichen Monitoren anzeigen." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "" + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "" +"Eine Liste von Indikatoren, die auf die zusätzlichen Monitore verschoben " +"werden sollen" + +#: prefs.js:124 +msgid "Select indicator" +msgstr "Indikator auswählen" + +#: prefs.js:127 +msgid "Add" +msgstr "Hinzufügen" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "Indikatoren in der oberen Leiste" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "Monitorindex:" + +#~ msgid "Test" +#~ msgstr "Test" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..0cd6a92 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..6c51dca --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,91 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Alonso Lara <alonso.lara.plana@gmail.com>, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: 2017-03-04 23:59+0100\n" +"Last-Translator: Alonso Lara <alonso.lara.plana@gmail.com>\n" +"Language-Team: Spanish <LL@li.org>\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "Preferencias" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "Accesorio de monitores múltiples" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Mostrar indicador de monitores múltiples en el panel." + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "Mostrar el panel en monitores adicionales." + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "Mostrar las miniaturas en los monitores adicionales." + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "Mostrar las actividades en los monitores adicionales." + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Mostrar el menú de aplicaciones en los monitores adicionales." + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Mostrar la fecha en los monitores adicionales." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "" + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "Un listado de indicadores para transferir a monitores adicionales." + +#: prefs.js:124 +msgid "Select indicator" +msgstr "Seleccione indicador" + +#: prefs.js:127 +msgid "Add" +msgstr "Añadir" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "Indicadores en el panel" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "Monitor número:" + +#~ msgid "Test" +#~ msgstr "Prueba" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..2aefbb2 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..3b207cc --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Multi Monitors Add On Gnome Shell Extension\n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: 2015-12-26 22:30+0100\n" +"Last-Translator: Quentin Daem\n" +"Language-Team: Language: fr_FR\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.4\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "Préférences" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "Multi Moniteurs Add-On" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Afficher l'icone Multi Moniteurs sur la barre du haut" + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "Afficher Menu sur les moniteurs secondaires" + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "" +"Afficher le dock listant les espaces de travail sur les moniteurs secondaires" + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "Afficher le bouton Activités sur les moniteurs secondaires" + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Afficher le bouton du menu Applications sur les moniteurs secondaires" + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Afficher le bouton Date-Heure sur les moniteurs secondaires." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "" + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "Une liste d'indicateurs pour transfert vers les moniteurs secondaires " + +#: prefs.js:124 +msgid "Select indicator" +msgstr "Selectionner indicateur" + +#: prefs.js:127 +msgid "Add" +msgstr "Ajouter" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "Indicateur dans le panneau du haut" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "Index moniteur:" + +#~ msgid "Test" +#~ msgstr "Test" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..14040b3 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..fd41a90 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,93 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: Multi Monitors Add On Gnome Shell Extension\n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: 2019-10-21 14:53+0200\n" +"Last-Translator: Luca Bandini (@Vombato) <luca.vombato@gmail.com>\n" +"Language-Team: ItalianLanguage: it\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.4\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "Preferenze" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "Componente aggiuntivo per più monitor" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "Panoramica" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "Attività" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "Barra Superiore" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Mostra l'icona Multi Monitor sul pannello superiore." + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "Mostra Menu su monitor secondari." + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "Visualizza le aree di lavoro sui monitor secondari." + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "Mostra il Bottone Attività sui monitor secondari." + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Visualizza il pulsante del menu Applicazioni sui monitor secondari." + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Mostra il Bottone Data/Ora sui monitor secondari." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "" + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "Un elenco di indicatori per il trasferimento a monitor secondari." + +#: prefs.js:124 +msgid "Select indicator" +msgstr "Seleziona indicatore" + +#: prefs.js:127 +msgid "Add" +msgstr "Aggiungere" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "Indicatore nel pannello superiore" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "Indice monitor:" + +#~ msgid "Test" +#~ msgstr "Test" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..84f0f8e --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..80116d8 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,94 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: 2016-12-29 14:25+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: pl_PL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.11\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "Ustawienia" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "Multi Monitors Add-On" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Wyświetl wskaźnik rozszerzenia na głównym pasku." + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "Wyświetl główny pasek na dodatkowych monitorach." + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "Wyświetl pasek miniatur na dodatkowych monitorach." + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "Wyświetl przycisk podglądu na dodatkowych monitorach." + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Wyświetl przycisk aplikacji na dodatkowych monitorach." + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Wyświetl przycisk daty i czasu na dodatkowych monitorach." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "Włączenie podglądu po najechaniu rogu ekranu." + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "Lista wskaźników do przesunięcia na dodatkowe monitory." + +#: prefs.js:124 +msgid "Select indicator" +msgstr "Wybierz wskaźnik" + +#: prefs.js:127 +msgid "Add" +msgstr "Dodaj" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "Wskaźniki na głównym panelu" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "Indeks monitora:" + +#~ msgid "Test" +#~ msgstr "Test" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.mo b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.mo Binary files differnew file mode 100644 index 0000000..beae2e9 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.mo diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.po b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.po new file mode 100644 index 0000000..94c370c --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.po @@ -0,0 +1,89 @@ +# Brazilian Portuguese translation for multi-monitors-add-on +# Copyright (C) 2019 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the multi-monitors-add-on package. +# Rafael Fontenelle <rafaelff@gnome.org>, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: Multi Monitors Add On Gnome Shell Extension\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-23 22:29+0100\n" +"PO-Revision-Date: 2019-10-03 06:49-0300\n" +"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n" +"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"X-Generator: Gtranslator 3.32.0\n" +"X-Project-Style: gnome\n" + +#: prefs.js:61 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "Mostrar o indicador do Multi Monitors no painel superior" + +#: prefs.js:62 +msgid "Show Panel on additional monitors." +msgstr "Mostrar o painel em monitores adicionais" + +#: prefs.js:63 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "Mostrar controle deslizante de miniaturas em monitores adicionais" + +#: prefs.js:64 +msgid "Show Activities-Button on additional monitors." +msgstr "Mostrar botão de Atividades em monitores adicionais" + +#: prefs.js:65 +msgid "Show AppMenu-Button on additional monitors." +msgstr "Mostrar botão de menu de aplicativos em monitores adicionais" + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "Mostrar o botão de data e hora em monitores adicionais" + +#: prefs.js:75 +msgid "A list of indicators for transfer to additional monitors." +msgstr "Uma lista de indicadores para transferir para monitores adicionais." + +#: prefs.js:71 +msgid "Enable hot corners." +msgstr "" + +#: prefs.js:122 +msgid "Select indicator" +msgstr "Selecionar indicador" + +#: prefs.js:125 +msgid "Add" +msgstr "Adicionar" + +#: prefs.js:139 +msgid "Indicators on Top Panel" +msgstr "Indicadores no painel superior" + +#: prefs.js:168 +msgid "Monitor index:" +msgstr "Índice do monitor:" + +#: indicator.js:106 +msgid "Preferences" +msgstr "Preferências" + +#: indicator.js:107 +msgid "Test" +msgstr "Testar" + +#: indicator.js:129 +msgid "Multi Monitors Add-On" +msgstr "Multi Monitors Add-On" + +#~ msgid "Overview" +#~ msgstr "Panorama" + +#~ msgid "Activities" +#~ msgstr "Atividades" + +#~ msgid "Top Bar" +#~ msgstr "Barra superior" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/metadata.json b/multi-monitors-add-on/multi-monitors-add-on@spin83/metadata.json new file mode 100644 index 0000000..68b1295 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/metadata.json @@ -0,0 +1,10 @@ +{ + "shell-version": ["40", "41", "42", "43"], + "uuid": "multi-monitors-add-on@spin83", + "name": "Multi Monitors Add-On", + "settings-schema": "org.gnome.shell.extensions.multi-monitors-add-on", + "gettext-domain": "multi-monitors-add-on", + "description": "Add multiple monitors overview and panel for gnome-shell.", + "url": "https://github.com/spin83/multi-monitors-add-on.git", + "version": 25 +} diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/mmcalendar.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmcalendar.js new file mode 100644 index 0000000..66237f4 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmcalendar.js @@ -0,0 +1,412 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const Signals = imports.signals; + +const { St, Gio, Shell, Clutter, GnomeDesktop, Pango, GObject, GLib } = imports.gi; + +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const MessageList = imports.ui.messageList; +const DateMenu = imports.ui.dateMenu; +const Calendar = imports.ui.calendar; +const PopupMenu = imports.ui.popupMenu; + +const ExtensionUtils = imports.misc.extensionUtils; +const CE = ExtensionUtils.getCurrentExtension(); +const MultiMonitors = CE.imports.extension; +const Convenience = CE.imports.convenience; + +// Calendar.DoNotDisturbSwitch is const, so not exported. Either +// <https://gjs.guide/guides/gobject/subclassing.html#gtypename> is untrue, or +// GObject.type_from_name() is broken, so we can't get its constructor via GI +// either. Luckily it's a short class, so we can copy & paste. +const MultiMonitorsDoNotDisturbSwitch = GObject.registerClass( +class MultiMonitorsDoNotDisturbSwitch extends PopupMenu.Switch { + _init() { + this._settings = new Gio.Settings({ + schema_id: 'org.gnome.desktop.notifications', + }); + + super._init(this._settings.get_boolean('show-banners')); + + this._settings.bind('show-banners', + this, 'state', + Gio.SettingsBindFlags.INVERT_BOOLEAN); + + this.connect('destroy', () => { + this._settings.run_dispose(); + this._settings = null; + }); + } +}); + +var MultiMonitorsCalendar = (() => { + let MultiMonitorsCalendar = class MultiMonitorsCalendar extends St.Widget { + _init () { + this._weekStart = Shell.util_get_week_start(); + this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.calendar' }); + + this._showWeekdateKeyId = this._settings.connect('changed::%s'.format(Calendar.SHOW_WEEKDATE_KEY), this._onSettingsChange.bind(this)); + this._useWeekdate = this._settings.get_boolean(Calendar.SHOW_WEEKDATE_KEY); + + this._headerFormatWithoutYear = _('%OB'); + this._headerFormat = _('%OB %Y'); + + // Start off with the current date + this._selectedDate = new Date(); + + this._shouldDateGrabFocus = false; + + super._init({ + style_class: 'calendar', + layout_manager: new Clutter.GridLayout(), + reactive: true, + }); + + this._buildHeader(); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + this._settings.disconnect(this._showWeekdateKeyId); + } + }; + MultiMonitors.copyClass(Calendar.Calendar, MultiMonitorsCalendar); + return GObject.registerClass({ + Signals: { 'selected-date-changed': { param_types: [GLib.DateTime.$gtype] } }, + }, MultiMonitorsCalendar); +})(); + +var MultiMonitorsEventsSection = (() => { + let MultiMonitorsEventsSection = class MultiMonitorsEventsSection extends St.Button { + _init() { + super._init({ + style_class: 'events-button', + can_focus: true, + x_expand: true, + child: new St.BoxLayout({ + style_class: 'events-box', + vertical: true, + x_expand: true, + }), + }); + + this._startDate = null; + this._endDate = null; + + this._eventSource = null; + this._calendarApp = null; + + this._title = new St.Label({ + style_class: 'events-title', + }); + this.child.add_child(this._title); + + this._eventsList = new St.BoxLayout({ + style_class: 'events-list', + vertical: true, + x_expand: true, + }); + this.child.add_child(this._eventsList); + + this._appSys = Shell.AppSystem.get_default(); + this._appInstalledChangedId = this._appSys.connect('installed-changed', + this._appInstalledChanged.bind(this)); + this._appInstalledChanged(); + + this.connect('destroy', this._onDestroy.bind(this)); + this._appInstalledChanged(); + } + + _onDestroy() { + this._appSys.disconnect(this._appInstalledChangedId); + }}; + + MultiMonitors.copyClass(DateMenu.EventsSection, MultiMonitorsEventsSection); + return GObject.registerClass(MultiMonitorsEventsSection); +})(); + +var MultiMonitorsNotificationSection = (() => { + let MultiMonitorsNotificationSection = class MultiMonitorsNotificationSection extends MessageList.MessageListSection { + _init() { + super._init(); + + this._sources = new Map(); + this._nUrgent = 0; + + this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this)); + Main.messageTray.getSources().forEach(source => { + this._sourceAdded(Main.messageTray, source); + }); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + Main.messageTray.disconnect(this._sourceAddedId); + let source, obj; + for ([source, obj] of this._sources.entries()) { + this._onSourceDestroy(source, obj); + } + }}; + + MultiMonitors.copyClass(Calendar.NotificationSection, MultiMonitorsNotificationSection); + return GObject.registerClass(MultiMonitorsNotificationSection); +})(); + +var MultiMonitorsCalendarMessageList = (() => { + let MultiMonitorsCalendarMessageList = class MultiMonitorsCalendarMessageList extends St.Widget { + _init() { + super._init({ + style_class: 'message-list', + layout_manager: new Clutter.BinLayout(), + x_expand: true, + y_expand: true, + }); + + this._sessionModeUpdatedId = 0; + + this._placeholder = new Calendar.Placeholder(); + this.add_actor(this._placeholder); + + let box = new St.BoxLayout({ vertical: true, + x_expand: true, y_expand: true }); + this.add_actor(box); + + this._scrollView = new St.ScrollView({ + style_class: 'vfade', + overlay_scrollbars: true, + x_expand: true, y_expand: true, + }); + this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); + box.add_actor(this._scrollView); + + let hbox = new St.BoxLayout({ style_class: 'message-list-controls' }); + box.add_child(hbox); + + const dndLabel = new St.Label({ + text: _('Do Not Disturb'), + y_align: Clutter.ActorAlign.CENTER, + }); + hbox.add_child(dndLabel); + + this._dndSwitch = new MultiMonitorsDoNotDisturbSwitch(); + this._dndButton = new St.Button({ + can_focus: true, + toggle_mode: true, + child: this._dndSwitch, + label_actor: dndLabel, + }); + + this._dndSwitch.bind_property('state', + this._dndButton, 'checked', + GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE); + + hbox.add_child(this._dndButton); + + this._clearButton = new St.Button({ + style_class: 'message-list-clear-button button', + label: _('Clear'), + can_focus: true, + x_expand: true, + x_align: Clutter.ActorAlign.END, + }); + this._clearButton.connect('clicked', () => { + this._sectionList.get_children().forEach(s => s.clear()); + }); + hbox.add_actor(this._clearButton); + + this._placeholder.bind_property('visible', + this._clearButton, 'visible', + GObject.BindingFlags.INVERT_BOOLEAN); + + this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections', + vertical: true, + x_expand: true, + y_expand: true, + y_align: Clutter.ActorAlign.START }); + this._sectionList.connect('actor-added', this._sync.bind(this)); + this._sectionList.connect('actor-removed', this._sync.bind(this)); + this._scrollView.add_actor(this._sectionList); + + this._notificationSection = new MultiMonitorsNotificationSection(); + this._addSection(this._notificationSection); + + this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._sync.bind(this)); + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + Main.sessionMode.disconnect(this._sessionModeUpdatedId); + this._sessionModeUpdatedId = 0; + } + + _sync() { + if (this._sessionModeUpdatedId === 0) return; + Calendar.CalendarMessageList.prototype._sync.call(this); + }}; + + MultiMonitors.copyClass(Calendar.CalendarMessageList, MultiMonitorsCalendarMessageList); + return GObject.registerClass(MultiMonitorsCalendarMessageList); +})(); + +var MultiMonitorsMessagesIndicator = (() => { + let MultiMonitorsMessagesIndicator = class MultiMonitorsMessagesIndicator extends St.Icon { + _init() { + super._init({ + icon_size: 16, + visible: false, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + + this._sources = []; + this._count = 0; + + this._settings = new Gio.Settings({ + schema_id: 'org.gnome.desktop.notifications', + }); + this._settings.connect('changed::show-banners', this._sync.bind(this)); + + this._sourceAddedId = Main.messageTray.connect('source-added', this._onSourceAdded.bind(this)); + this._sourceRemovedId = Main.messageTray.connect('source-removed', this._onSourceRemoved.bind(this)); + this._queueChangedId = Main.messageTray.connect('queue-changed', this._updateCount.bind(this)); + + let sources = Main.messageTray.getSources(); + sources.forEach(source => this._onSourceAdded(null, source)); + + this._sync(); + + this.connect('destroy', () => { + this._settings.run_dispose(); + this._settings = null; + Main.messageTray.disconnect(this._sourceAddedId); + Main.messageTray.disconnect(this._sourceRemovedId); + Main.messageTray.disconnect(this._queueChangedId); + }); + }}; + + MultiMonitors.copyClass(DateMenu.MessagesIndicator, MultiMonitorsMessagesIndicator); + return GObject.registerClass(MultiMonitorsMessagesIndicator); +})(); + +var MultiMonitorsDateMenuButton = (() => { + let MultiMonitorsDateMenuButton = class MultiMonitorsDateMenuButton extends PanelMenu.Button { + _init() { + let hbox; + let vbox; + + super._init(0.5); + + this._clockDisplay = new St.Label({ style_class: 'clock' }); + this._clockDisplay.clutter_text.y_align = Clutter.ActorAlign.CENTER; + this._clockDisplay.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; + + this._indicator = new MultiMonitorsMessagesIndicator(); + + const indicatorPad = new St.Widget(); + this._indicator.bind_property('visible', + indicatorPad, 'visible', + GObject.BindingFlags.SYNC_CREATE); + indicatorPad.add_constraint(new Clutter.BindConstraint({ + source: this._indicator, + coordinate: Clutter.BindCoordinate.SIZE, + })); + + let box = new St.BoxLayout({ style_class: 'clock-display-box' }); + box.add_actor(indicatorPad); + box.add_actor(this._clockDisplay); + box.add_actor(this._indicator); + + this.label_actor = this._clockDisplay; + this.add_actor(box); + this.add_style_class_name('clock-display'); + + let layout = new DateMenu.FreezableBinLayout(); + let bin = new St.Widget({ layout_manager: layout }); + // For some minimal compatibility with PopupMenuItem + bin._delegate = this; + this.menu.box.add_child(bin); + + hbox = new St.BoxLayout({ name: 'calendarArea' }); + bin.add_actor(hbox); + + this._calendar = new MultiMonitorsCalendar(); + this._calendar.connect('selected-date-changed', (_calendar, datetime) => { + let date = DateMenu._gDateTimeToDate(datetime); + layout.frozen = !DateMenu._isToday(date); + this._eventsItem.setDate(date); + }); + this._date = new DateMenu.TodayButton(this._calendar); + + this.menu.connect('open-state-changed', (menu, isOpen) => { + // Whenever the menu is opened, select today + if (isOpen) { + let now = new Date(); + this._calendar.setDate(now); + this._date.setDate(now); + this._eventsItem.setDate(now); + } + }); + + // Fill up the first column + this._messageList = new MultiMonitorsCalendarMessageList(); + hbox.add_child(this._messageList); + + // Fill up the second column + const boxLayout = new DateMenu.CalendarColumnLayout([this._calendar, this._date]); + vbox = new St.Widget({ style_class: 'datemenu-calendar-column', + layout_manager: boxLayout }); + boxLayout.hookup_style(vbox); + hbox.add(vbox); + + vbox.add_actor(this._date); + vbox.add_actor(this._calendar); + + this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade', + x_expand: true, + overlay_scrollbars: true }); + this._displaysSection.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); + vbox.add_actor(this._displaysSection); + + let displaysBox = new St.BoxLayout({ vertical: true, + x_expand: true, + style_class: 'datemenu-displays-box' }); + this._displaysSection.add_actor(displaysBox); + + this._eventsItem = new MultiMonitorsEventsSection(); + displaysBox.add_child(this._eventsItem); + + this._clock = new GnomeDesktop.WallClock(); + this._clock.bind_property('clock', this._clockDisplay, 'text', GObject.BindingFlags.SYNC_CREATE); + this._clockNotifyTimezoneId = this._clock.connect('notify::timezone', this._updateTimeZone.bind(this)); + + this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); + this._sessionUpdated(); + } + + _onDestroy() { + Main.sessionMode.disconnect(this._sessionModeUpdatedId); + this._clock.disconnect(this._clockNotifyTimezoneId); + super._onDestroy(); + }}; + + MultiMonitors.copyClass(DateMenu.DateMenuButton, MultiMonitorsDateMenuButton); + return GObject.registerClass(MultiMonitorsDateMenuButton); +})(); + diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/mmlayout.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmlayout.js new file mode 100644 index 0000000..a354ec1 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmlayout.js @@ -0,0 +1,251 @@ +/** + * New node file + */ + +const { St, Meta } = imports.gi; + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const Layout = imports.ui.layout; + +const Config = imports.misc.config; + +const ExtensionUtils = imports.misc.extensionUtils; +const CE = ExtensionUtils.getCurrentExtension(); +const Convenience = CE.imports.convenience; +const MultiMonitors = CE.imports.extension; +const MMPanel = CE.imports.mmpanel; + +var SHOW_PANEL_ID = 'show-panel'; +var ENABLE_HOT_CORNERS = 'enable-hot-corners'; + +const MultiMonitorsPanelBox = class MultiMonitorsPanelBox { + constructor(monitor) { + this.panelBox = new St.BoxLayout({ name: 'panelBox', vertical: true, clip_to_allocation: true }); + Main.layoutManager.addChrome(this.panelBox, { affectsStruts: true, trackFullscreen: true }); + this.panelBox.set_position(monitor.x, monitor.y); + this.panelBox.set_size(monitor.width, -1); + Main.uiGroup.set_child_below_sibling(this.panelBox, Main.layoutManager.panelBox); + } + + destroy() { + this.panelBox.destroy(); + } + + updatePanel(monitor) { + this.panelBox.set_position(monitor.x, monitor.y); + this.panelBox.set_size(monitor.width, -1); + } +}; + +var MultiMonitorsLayoutManager = class MultiMonitorsLayoutManager { + constructor() { + this._settings = Convenience.getSettings(); + this._desktopSettings = Convenience.getSettings("org.gnome.desktop.interface"); + + Main.mmPanel = []; + + this._monitorIds = []; + this.mmPanelBox = []; + this.mmappMenu = false; + + this._showAppMenuId = null; + this._monitorsChangedId = null; + + this.statusIndicatorsController = null; + this._layoutManager_updateHotCorners = null; + this._changedEnableHotCornersId = null; + } + + showPanel() { + if (this._settings.get_boolean(SHOW_PANEL_ID)) { + if (!this._monitorsChangedId) { + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', this._monitorsChanged.bind(this)); + this._monitorsChanged(); + } + if (!this._showAppMenuId) { + this._showAppMenuId = this._settings.connect('changed::'+MMPanel.SHOW_APP_MENU_ID, this._showAppMenu.bind(this)); + } + + if (!this.statusIndicatorsController) { + this.statusIndicatorsController = new MMPanel.StatusIndicatorsController(); + } + + if (!this._layoutManager_updateHotCorners) { + this._layoutManager_updateHotCorners = Main.layoutManager._updateHotCorners; + + const _this = this; + Main.layoutManager._updateHotCorners = function() { + this.hotCorners.forEach((corner) => { + if (corner) + corner.destroy(); + }); + this.hotCorners = []; + + if (!_this._desktopSettings.get_boolean(ENABLE_HOT_CORNERS)) { + this.emit('hot-corners-changed'); + return; + } + + let size = this.panelBox.height; + + for (let i = 0; i < this.monitors.length; i++) { + let monitor = this.monitors[i]; + let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; + let cornerY = monitor.y; + + let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY); + corner.setBarrierSize(size); + this.hotCorners.push(corner); + } + + this.emit('hot-corners-changed'); + }; + + if (!this._changedEnableHotCornersId) { + this._changedEnableHotCornersId = this._desktopSettings.connect('changed::'+ENABLE_HOT_CORNERS, + Main.layoutManager._updateHotCorners.bind(Main.layoutManager)); + } + + Main.layoutManager._updateHotCorners(); + } + } + else { + this.hidePanel(); + } + } + + hidePanel() { + if (this._changedEnableHotCornersId) { + global.settings.disconnect(this._changedEnableHotCornersId); + this._changedEnableHotCornersId = null; + } + + if (this._layoutManager_updateHotCorners) { + Main.layoutManager['_updateHotCorners'] = this._layoutManager_updateHotCorners; + this._layoutManager_updateHotCorners = null; + Main.layoutManager._updateHotCorners(); + } + + if (this.statusIndicatorsController) { + this.statusIndicatorsController.destroy(); + this.statusIndicatorsController = null; + } + + if (this._showAppMenuId) { + this._settings.disconnect(this._showAppMenuId); + this._showAppMenuId = null; + } + this._hideAppMenu(); + + if (this._monitorsChangedId) { + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = null; + } + + let panels2remove = this._monitorIds.length; + for (let i = 0; i < panels2remove; i++) { + let monitorId = this._monitorIds.pop(); + this._popPanel(); + global.log("remove: "+monitorId); + } + } + + _monitorsChanged () { + let monitorChange = Main.layoutManager.monitors.length - this._monitorIds.length -1; + if (monitorChange<0) { + for (let idx = 0; idx<-monitorChange; idx++) { + let monitorId = this._monitorIds.pop(); + this._popPanel(); + global.log("remove: "+monitorId); + } + } + + let j = 0; + let tIndicators = false; + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + if (i!=Main.layoutManager.primaryIndex) { + let monitor = Main.layoutManager.monitors[i]; + let monitorId = "i"+i+"x"+monitor.x+"y"+monitor.y+"w"+monitor.width+"h"+monitor.height; + if (monitorChange>0 && j==this._monitorIds.length) { + this._monitorIds.push(monitorId); + this._pushPanel(i, monitor); + global.log("new: "+monitorId); + tIndicators = true; + } + else if (this._monitorIds[j]>monitorId || this._monitorIds[j]<monitorId) { + let oldMonitorId = this._monitorIds[j]; + this._monitorIds[j]=monitorId; + this.mmPanelBox[j].updatePanel(monitor); + global.log("update: "+oldMonitorId+">"+monitorId); + } + j++; + } + } + this._showAppMenu(); + if (tIndicators && this.statusIndicatorsController) { + this.statusIndicatorsController.transferIndicators(); + } + } + + _pushPanel(i, monitor) { + let mmPanelBox = new MultiMonitorsPanelBox(monitor); + let panel = new MMPanel.MultiMonitorsPanel(i, mmPanelBox); + + Main.mmPanel.push(panel); + this.mmPanelBox.push(mmPanelBox); + } + + _popPanel() { + let panel = Main.mmPanel.pop(); + if (this.statusIndicatorsController) { + this.statusIndicatorsController.transferBack(panel); + } + let mmPanelBox = this.mmPanelBox.pop(); + mmPanelBox.destroy(); + } + + _changeMainPanelAppMenuButton(appMenuButton) { + let role = "appMenu"; + let panel = Main.panel; + let indicator = panel.statusArea[role]; + panel.menuManager.removeMenu(indicator.menu); + indicator.destroy(); + if (indicator._actionGroupNotifyId) { + indicator._targetApp.disconnect(indicator._actionGroupNotifyId); + indicator._actionGroupNotifyId = 0; + } + if (indicator._busyNotifyId) { + indicator._targetApp.disconnect(indicator._busyNotifyId); + indicator._busyNotifyId = 0; + } + if (indicator.menu._windowsChangedId) { + indicator.menu._app.disconnect(indicator.menu._windowsChangedId); + indicator.menu._windowsChangedId = 0; + } + indicator = new appMenuButton(panel); + panel.statusArea[role] = indicator; + let box = panel._leftBox; + panel._addToPanelBox(role, indicator, box.get_n_children()+1, box); + } + + _showAppMenu() { + if (this._settings.get_boolean(MMPanel.SHOW_APP_MENU_ID) && Main.mmPanel.length>0) { + if (!this.mmappMenu) { + this._changeMainPanelAppMenuButton(MMPanel.MultiMonitorsAppMenuButton); + this.mmappMenu = true; + } + } + else { + this._hideAppMenu(); + } + } + + _hideAppMenu() { + if (this.mmappMenu) { + this._changeMainPanelAppMenuButton(Panel.AppMenuButton); + this.mmappMenu = false; + Main.panel._updatePanel() + } + } +}; diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/mmoverview.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmoverview.js new file mode 100644 index 0000000..b7555d2 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmoverview.js @@ -0,0 +1,678 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const { Clutter, GObject, St, Shell, GLib, Gio, Meta } = imports.gi; + +const Main = imports.ui.main; +const Params = imports.misc.params; +const WorkspaceThumbnail = imports.ui.workspaceThumbnail; +const OverviewControls = imports.ui.overviewControls; +const Overview = imports.ui.overview; +const SearchController = imports.ui.searchController; +const LayoutManager = imports.ui.layout; +const Background = imports.ui.background; +const WorkspacesView = imports.ui.workspacesView; + +const ExtensionUtils = imports.misc.extensionUtils; +const CE = ExtensionUtils.getCurrentExtension(); +const MultiMonitors = CE.imports.extension; +const Convenience = CE.imports.convenience; + +const THUMBNAILS_SLIDER_POSITION_ID = 'thumbnails-slider-position'; + +var MultiMonitorsWorkspaceThumbnail = (() => { + let MultiMonitorsWorkspaceThumbnail = class MultiMonitorsWorkspaceThumbnail extends St.Widget { + _init(metaWorkspace, monitorIndex) { + super._init({ + clip_to_allocation: true, + style_class: 'workspace-thumbnail', + }); + this._delegate = this; + + this.metaWorkspace = metaWorkspace; + this.monitorIndex = monitorIndex; + + this._removed = false; + + this._contents = new Clutter.Actor(); + this.add_child(this._contents); + + this.connect('destroy', this._onDestroy.bind(this)); + + this._createBackground(); + + let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex); + this.setPorthole(workArea.x, workArea.y, workArea.width, workArea.height); + + let windows = global.get_window_actors().filter(actor => { + let win = actor.meta_window; + return win.located_on_workspace(metaWorkspace); + }); + + // Create clones for windows that should be visible in the Overview + this._windows = []; + this._allWindows = []; + this._minimizedChangedIds = []; + for (let i = 0; i < windows.length; i++) { + let minimizedChangedId = + windows[i].meta_window.connect('notify::minimized', + this._updateMinimized.bind(this)); + this._allWindows.push(windows[i].meta_window); + this._minimizedChangedIds.push(minimizedChangedId); + + if (this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) + this._addWindowClone(windows[i]); + } + + // Track window changes + this._windowAddedId = this.metaWorkspace.connect('window-added', + this._windowAdded.bind(this)); + this._windowRemovedId = this.metaWorkspace.connect('window-removed', + this._windowRemoved.bind(this)); + this._windowEnteredMonitorId = global.display.connect('window-entered-monitor', + this._windowEnteredMonitor.bind(this)); + this._windowLeftMonitorId = global.display.connect('window-left-monitor', + this._windowLeftMonitor.bind(this)); + + this.state = WorkspaceThumbnail.ThumbnailState.NORMAL; + this._slidePosition = 0; // Fully slid in + this._collapseFraction = 0; // Not collapsed + } + + _createBackground() { + this._bgManager = new Background.BackgroundManager({ monitorIndex: this.monitorIndex, + container: this._contents, + vignette: false }); + }}; + + MultiMonitors.copyClass(WorkspaceThumbnail.WorkspaceThumbnail, MultiMonitorsWorkspaceThumbnail); + return GObject.registerClass({ + Properties: { + 'collapse-fraction': GObject.ParamSpec.double( + 'collapse-fraction', 'collapse-fraction', 'collapse-fraction', + GObject.ParamFlags.READWRITE, + 0, 1, 0), + 'slide-position': GObject.ParamSpec.double( + 'slide-position', 'slide-position', 'slide-position', + GObject.ParamFlags.READWRITE, + 0, 1, 0), + }, + }, MultiMonitorsWorkspaceThumbnail); +})(); + +const MultiMonitorsThumbnailsBox = (() => { + let MultiMonitorsThumbnailsBox = class MultiMonitorsThumbnailsBox extends St.Widget { + _init(scrollAdjustment, monitorIndex) { + + super._init({ reactive: true, + style_class: 'workspace-thumbnails', + request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT }); + + this._delegate = this; + this._monitorIndex = monitorIndex; + + let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' }); + + // We don't want the indicator to affect drag-and-drop + Shell.util_set_hidden_from_pick(indicator, true); + + this._indicator = indicator; + this.add_actor(indicator); + + // The porthole is the part of the screen we're showing in the thumbnails + this._porthole = { width: global.stage.width, height: global.stage.height, + x: global.stage.x, y: global.stage.y }; + + this._dropWorkspace = -1; + this._dropPlaceholderPos = -1; + this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' }); + this.add_actor(this._dropPlaceholder); + this._spliceIndex = -1; + + this._targetScale = 0; + this._scale = 0; + this._pendingScaleUpdate = false; + this._stateUpdateQueued = false; + this._animatingIndicator = false; + + this._stateCounts = {}; + for (let key in WorkspaceThumbnail.ThumbnailState) + this._stateCounts[WorkspaceThumbnail.ThumbnailState[key]] = 0; + + this._thumbnails = []; + + this._showingId = Main.overview.connect('showing', + this._createThumbnails.bind(this)); + this._hiddenId = Main.overview.connect('hidden', + this._destroyThumbnails.bind(this)); + + this._itemDragBeginId = Main.overview.connect('item-drag-begin', + this._onDragBegin.bind(this)); + this._itemDragEndId = Main.overview.connect('item-drag-end', + this._onDragEnd.bind(this)); + this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled', + this._onDragCancelled.bind(this)); + this._windowDragBeginId = Main.overview.connect('window-drag-begin', + this._onDragBegin.bind(this)); + this._windowDragEndId = Main.overview.connect('window-drag-end', + this._onDragEnd.bind(this)); + this._windowDragCancelledId = Main.overview.connect('window-drag-cancelled', + this._onDragCancelled.bind(this)); + + this._settings = new Gio.Settings({ schema_id: WorkspaceThumbnail.MUTTER_SCHEMA }); + this._changedDynamicWorkspacesId = this._settings.connect('changed::dynamic-workspaces', + this._updateSwitcherVisibility.bind(this)); + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => { + this._destroyThumbnails(); + if (Main.overview.visible) + this._createThumbnails(); + }); + + this._workareasChangedPortholeId = global.display.connect('workareas-changed', + this._updatePorthole.bind(this)); + + this._switchWorkspaceNotifyId = 0; + this._nWorkspacesNotifyId = 0; + this._syncStackingId = 0; + this._workareasChangedId = 0; + + this._scrollAdjustment = scrollAdjustment; + + this._scrollAdjustmentNotifyValueId = this._scrollAdjustment.connect('notify::value', adj => { + let workspaceManager = global.workspace_manager; + let activeIndex = workspaceManager.get_active_workspace_index(); + + this._animatingIndicator = adj.value !== activeIndex; + + if (!this._animatingIndicator) + this._queueUpdateStates(); + + this.queue_relayout(); + }); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + this._destroyThumbnails(); + this._scrollAdjustment.disconnect(this._scrollAdjustmentNotifyValueId); + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hiddenId); + + Main.overview.disconnect(this._itemDragBeginId); + Main.overview.disconnect(this._itemDragEndId); + Main.overview.disconnect(this._itemDragCancelledId); + Main.overview.disconnect(this._windowDragBeginId); + Main.overview.disconnect(this._windowDragEndId); + Main.overview.disconnect(this._windowDragCancelledId); + + this._settings.disconnect(this._changedDynamicWorkspacesId); + Main.layoutManager.disconnect(this._monitorsChangedId); + global.display.disconnect(this._workareasChangedPortholeId); + } + + addThumbnails(start, count) { + let workspaceManager = global.workspace_manager; + + for (let k = start; k < start + count; k++) { + let metaWorkspace = workspaceManager.get_workspace_by_index(k); + let thumbnail = new MultiMonitorsWorkspaceThumbnail(metaWorkspace, this._monitorIndex); + thumbnail.setPorthole(this._porthole.x, this._porthole.y, + this._porthole.width, this._porthole.height); + this._thumbnails.push(thumbnail); + this.add_actor(thumbnail); + + if (start > 0 && this._spliceIndex == -1) { + // not the initial fill, and not splicing via DND + thumbnail.state = WorkspaceThumbnail.ThumbnailState.NEW; + thumbnail.slide_position = 1; // start slid out + this._haveNewThumbnails = true; + } else { + thumbnail.state = WorkspaceThumbnail.ThumbnailState.NORMAL; + } + + this._stateCounts[thumbnail.state]++; + } + + this._queueUpdateStates(); + + // The thumbnails indicator actually needs to be on top of the thumbnails + this.set_child_above_sibling(this._indicator, null); + + // Clear the splice index, we got the message + this._spliceIndex = -1; + } + + _updatePorthole() { + this._porthole = Main.layoutManager.getWorkAreaForMonitor(this._monitorIndex); + this.queue_relayout(); + }}; + + MultiMonitors.copyClass(WorkspaceThumbnail.ThumbnailsBox, MultiMonitorsThumbnailsBox); + return GObject.registerClass({ + Properties: { + 'indicator-y': GObject.ParamSpec.double( + 'indicator-y', 'indicator-y', 'indicator-y', + GObject.ParamFlags.READWRITE, + 0, Infinity, 0), + 'scale': GObject.ParamSpec.double( + 'scale', 'scale', 'scale', + GObject.ParamFlags.READWRITE, + 0, Infinity, 0), + }, + }, MultiMonitorsThumbnailsBox); +})(); + +/* This isn't compatible with GNOME 40 and i don't know how to fix it -- TH +var MultiMonitorsSlidingControl = (() => { + let MultiMonitorsSlidingControl = class MultiMonitorsSlidingControl extends St.Widget { + _init(params) { + params = Params.parse(params, { slideDirection: OverviewControls.SlideDirection.LEFT }); + + this.layout = new OverviewControls.SlideLayout(); + this.layout.slideDirection = params.slideDirection; + super._init({ + layout_manager: this.layout, + style_class: 'overview-controls', + clip_to_allocation: true, + }); + + this._visible = true; + this._inDrag = false; + + this.connect('destroy', this._onDestroy.bind(this)); + this._hidingId = Main.overview.connect('hiding', this._onOverviewHiding.bind(this)); + + this._itemDragBeginId = Main.overview.connect('item-drag-begin', this._onDragBegin.bind(this)); + this._itemDragEndId = Main.overview.connect('item-drag-end', this._onDragEnd.bind(this)); + this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled', this._onDragEnd.bind(this)); + + this._windowDragBeginId = Main.overview.connect('window-drag-begin', this._onWindowDragBegin.bind(this)); + this._windowDragCancelledId = Main.overview.connect('window-drag-cancelled', this._onWindowDragEnd.bind(this)); + this._windowDragEndId = Main.overview.connect('window-drag-end', this._onWindowDragEnd.bind(this)); + } + + _onDestroy() { + Main.overview.disconnect(this._hidingId); + + Main.overview.disconnect(this._itemDragBeginId); + Main.overview.disconnect(this._itemDragEndId); + Main.overview.disconnect(this._itemDragCancelledId); + + Main.overview.disconnect(this._windowDragBeginId); + Main.overview.disconnect(this._windowDragCancelledId); + Main.overview.disconnect(this._windowDragEndId); + }}; + + MultiMonitors.copyClass(OverviewControls.SlidingControl, MultiMonitorsSlidingControl); + return GObject.registerClass(MultiMonitorsSlidingControl); +})(); + +var MultiMonitorsThumbnailsSlider = (() => { + let MultiMonitorsThumbnailsSlider = class MultiMonitorsThumbnailsSlider extends MultiMonitorsSlidingControl { + _init(thumbnailsBox) { + super._init({ slideDirection: OverviewControls.SlideDirection.RIGHT }); + + this._thumbnailsBox = thumbnailsBox; + + this.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT; + this.reactive = true; + this.track_hover = true; + this.add_actor(this._thumbnailsBox); + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', this._updateSlide.bind(this)); + this._activeWorkspaceChangedId = global.workspace_manager.connect('active-workspace-changed', + this._updateSlide.bind(this)); + this._notifyNWorkspacesId = global.workspace_manager.connect('notify::n-workspaces', + this._updateSlide.bind(this)); + this.connect('notify::hover', this._updateSlide.bind(this)); + this._thumbnailsBox.bind_property('visible', this, 'visible', GObject.BindingFlags.SYNC_CREATE); + } + + _onDestroy() { + global.workspace_manager.disconnect(this._activeWorkspaceChangedId); + global.workspace_manager.disconnect(this._notifyNWorkspacesId); + Main.layoutManager.disconnect(this._monitorsChangedId); + super._onDestroy(); + }}; + + MultiMonitors.copyClass(OverviewControls.ThumbnailsSlider, MultiMonitorsThumbnailsSlider); + return GObject.registerClass(MultiMonitorsThumbnailsSlider); +})(); +*/ + +var MultiMonitorsControlsManager = GObject.registerClass( +class MultiMonitorsControlsManager extends St.Widget { + _init(index) { + this._monitorIndex = index; + this._workspacesViews = null; + this._spacer_height = 0; + this._fixGeometry = 0; + this._visible = false; + + let layout + if (OverviewControls.ControlsManagerLayout) { + layout = new OverviewControls.ControlsManagerLayout(); + } else { + layout = new OverviewControls.ControlsLayout(); + } + super._init({ + layout_manager: layout, + x_expand: true, + y_expand: true, + clip_to_allocation: true, + }); + + this._workspaceAdjustment = Main.overview._overview._controls._workspaceAdjustment; + + this._thumbnailsBox = + new MultiMonitorsThumbnailsBox(this._workspaceAdjustment, this._monitorIndex); + //this._thumbnailsSlider = new MultiMonitorsThumbnailsSlider(this._thumbnailsBox); + + this._searchController = new St.Widget({ visible: false, x_expand: true, y_expand: true, clip_to_allocation: true }); + this._pageChangedId = Main.overview.searchController.connect('page-changed', this._setVisibility.bind(this)); + this._pageEmptyId = Main.overview.searchController.connect('page-empty', this._onPageEmpty.bind(this)); + + this._group = new St.BoxLayout({ name: 'mm-overview-group-'+index, + x_expand: true, y_expand: true }); + this.add_actor(this._group); + + this._group.add_child(this._searchController); + //this._group.add_actor(this._thumbnailsSlider); + + this._settings = Convenience.getSettings(); + + this._monitorsChanged(); + //this._thumbnailsSlider.slideOut(); + this._thumbnailsBox._updatePorthole(); + + this.connect('notify::allocation', this._updateSpacerVisibility.bind(this)); + this.connect('destroy', this._onDestroy.bind(this)); + //this._thumbnailsSelectSideId = this._settings.connect('changed::'+THUMBNAILS_SLIDER_POSITION_ID, + // this._thumbnailsSelectSide.bind(this)); + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', this._monitorsChanged.bind(this)); + } + + _onDestroy() { + Main.overview.searchController.disconnect(this._pageChangedId); + Main.overview.searchController.disconnect(this._pageEmptyId); + this._settings.disconnect(this._thumbnailsSelectSideId); + Main.layoutManager.disconnect(this._monitorsChangedId); + } + + _monitorsChanged() { + this._primaryMonitorOnTheLeft = Main.layoutManager.monitors[this._monitorIndex].x > Main.layoutManager.primaryMonitor.x; + this._thumbnailsSelectSide(); + } + + /* + _thumbnailsSelectSide() { + let thumbnailsSlider; + thumbnailsSlider = this._thumbnailsSlider; + + let sett = this._settings.get_string(THUMBNAILS_SLIDER_POSITION_ID); + let onLeftSide = sett === 'left' || (sett === 'auto' && this._primaryMonitorOnTheLeft); + + if (onLeftSide) { + let first = this._group.get_first_child(); + if (first != thumbnailsSlider) { + this._thumbnailsSlider.layout.slideDirection = OverviewControls.SlideDirection.LEFT; + this._thumbnailsBox.remove_style_class_name('workspace-thumbnails'); + this._thumbnailsBox.set_style_class_name('workspace-thumbnails workspace-thumbnails-left'); + this._group.set_child_below_sibling(thumbnailsSlider, first) + } + } + else { + let last = this._group.get_last_child(); + if (last != thumbnailsSlider) { + this._thumbnailsSlider.layout.slideDirection = OverviewControls.SlideDirection.RIGHT; + this._thumbnailsBox.remove_style_class_name('workspace-thumbnails workspace-thumbnails-left'); + this._thumbnailsBox.set_style_class_name('workspace-thumbnails'); + this._group.set_child_above_sibling(thumbnailsSlider, last); + } + } + this._fixGeometry = 3; + } + */ + + _updateSpacerVisibility() { + if (Main.layoutManager.monitors.length<this._monitorIndex) + return; + + let top_spacer_height = Main.layoutManager.primaryMonitor.height; + + let panelGhost_height = 0; + if (Main.mmOverview[this._monitorIndex]._overview._panelGhost) + panelGhost_height = Main.mmOverview[this._monitorIndex]._overview._panelGhost.get_height(); + + let allocation = Main.overview._overview._controls.allocation; + let primaryControl_height = allocation.get_height(); + let bottom_spacer_height = Main.layoutManager.primaryMonitor.height - allocation.y2; + + top_spacer_height -= primaryControl_height + panelGhost_height + bottom_spacer_height; + top_spacer_height = Math.round(top_spacer_height); + + let spacer = Main.mmOverview[this._monitorIndex]._overview._spacer; + if (spacer.get_height()!=top_spacer_height) { + this._spacer_height = top_spacer_height; + spacer.set_height(top_spacer_height); + } + } + + getWorkspacesActualGeometry() { + let geometry; + if (this._visible) { + const [x, y] = this._searchController.get_transformed_position(); + const width = this._searchController.allocation.get_width(); + const height = this._searchController.allocation.get_height(); + geometry = { x, y, width, height }; + } + else { + let [x, y] = this.get_transformed_position(); + const width = this.allocation.get_width(); + let height = this.allocation.get_height(); + y -= this._spacer_height; + height += this._spacer_height; + geometry = { x, y, width, height }; + } + if (isNaN(geometry.x)) + return null; + //global.log("actualG+ i: "+this._monitorIndex+" x: "+geometry.x+" y: "+geometry.y+" width: "+geometry.width+" height: "+geometry.height); + return geometry; + } + + _setVisibility() { + // Ignore the case when we're leaving the overview, since + // actors will be made visible again when entering the overview + // next time, and animating them while doing so is just + // unnecessary noise + if (!Main.overview.visible || + (Main.overview.animationInProgress && !Main.overview.visibleTarget)) + return; + + let activePage = Main.overview.searchController.getActivePage(); + let thumbnailsVisible = activePage == SearchController.ViewPage.WINDOWS; + + let opacity = null; + if (thumbnailsVisible) { + opacity = 255; + if (this._fixGeometry===1) + this._fixGeometry = 0; + } + else { + opacity = 0; + this._fixGeometry = 1; + } + + if (!this._workspacesViews) + return; + + this._workspacesViews.ease({ + opacity: opacity, + duration: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + _onPageEmpty() { + //this._thumbnailsSlider.pageEmpty(); + } + + show() { + this._searchController.visible = true; + this._workspacesViews = Main.overview.searchController._workspacesDisplay._workspacesViews[this._monitorIndex]; + this._visible = true; + const geometry = this.getWorkspacesActualGeometry(); + + if (!geometry) { + this._fixGeometry = 0; + return; + } + + /* + if (this._fixGeometry) { + const width = this._thumbnailsSlider.get_width(); + if (this._fixGeometry===2) { + geometry.width = geometry.width-width; + if (this._thumbnailsSlider.layout.slideDirection === OverviewControls.SlideDirection.LEFT) + geometry.x = geometry.x + width; + } + else if (this._fixGeometry===3) { + if (this._thumbnailsSlider.layout.slideDirection === OverviewControls.SlideDirection.LEFT) + geometry.x = geometry.x + width; + else + geometry.x = geometry.x - width; + } + this._fixGeometry = 0; + } + */ + + this._workspacesViews.ease({ + ...geometry, + duration: Main.overview.animationInProgress ? Overview.ANIMATION_TIME : 0, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + hide() { + this._visible = false; + this._workspacesViews.opacity = 255; + if (this._fixGeometry===1) + this._fixGeometry = 2; + const geometry = this.getWorkspacesActualGeometry(); + this._workspacesViews.ease({ + ...geometry, + duration: Main.overview.animationInProgress ? Overview.ANIMATION_TIME : 0, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this._searchController.visible = false; + }, + }); + this._workspacesViews = null; + } +}); + +var MultiMonitorsOverviewActor = GObject.registerClass( +class MultiMonitorsOverviewActor extends St.BoxLayout { + _init(index) { + this._monitorIndex = index; + super._init({ + name: 'mm-overview-'+index, + /* Translators: This is the main view to select + activities. See also note for "Activities" string. */ + accessible_name: _("MMOverview@"+index), + vertical: true, + }); + + this.add_constraint(new LayoutManager.MonitorConstraint({ index: this._monitorIndex })); + + this._panelGhost = null; + if (Main.mmPanel) { + for (let idx in Main.mmPanel) { + if (Main.mmPanel[idx].monitorIndex !== this._monitorIndex) + continue + // Add a clone of the panel to the overview so spacing and such is + // automatic + this._panelGhost = new St.Bin({ + child: new Clutter.Clone({ source: Main.mmPanel[idx] }), + reactive: false, + opacity: 0, + }); + this.add_actor(this._panelGhost); + break; + } + } + + this._spacer = new St.Widget(); + this.add_actor(this._spacer); + + this._controls = new MultiMonitorsControlsManager(this._monitorIndex); + + // Add our same-line elements after the search entry + this.add_child(this._controls); + } +}); + + +var MultiMonitorsOverview = class MultiMonitorsOverview { + constructor(index) { + this.monitorIndex = index; + + this._initCalled = true; + this._overview = new MultiMonitorsOverviewActor(this.monitorIndex); + this._overview._delegate = this; + this._overview.connect('destroy', this._onDestroy.bind(this)); + Main.layoutManager.overviewGroup.add_child(this._overview); + + this._showingId = Main.overview.connect('showing', this._show.bind(this)); + this._hidingId = Main.overview.connect('hiding', this._hide.bind(this)); + } + + getWorkspacesActualGeometry() { + return this._overview._controls.getWorkspacesActualGeometry(); + } + + _onDestroy() { + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + + Main.layoutManager.overviewGroup.remove_child(this._overview); + this._overview._delegate = null; + } + + _show() { + this._overview._controls.show(); + } + + _hide() { + this._overview._controls.hide(); + } + + destroy() { + this._overview.destroy(); + } + + addAction(action) { + this._overview.add_action(action); + } + + removeAction(action) { + if (action.get_actor()) + this._overview.remove_action(action); + } +}; diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js new file mode 100644 index 0000000..a381f15 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js @@ -0,0 +1,520 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const { St, Shell, Meta, Atk, Clutter, GObject } = imports.gi; + +const Main = imports.ui.main; +const Panel = imports.ui.panel; +const PopupMenu = imports.ui.popupMenu; +const PanelMenu = imports.ui.panelMenu; +const CtrlAltTab = imports.ui.ctrlAltTab; +const ExtensionSystem = imports.ui.extensionSystem; + +const ExtensionUtils = imports.misc.extensionUtils; +const CE = ExtensionUtils.getCurrentExtension(); +const MultiMonitors = CE.imports.extension; +const Convenience = CE.imports.convenience; +const MMCalendar = CE.imports.mmcalendar; + +const SHOW_ACTIVITIES_ID = 'show-activities'; +var SHOW_APP_MENU_ID = 'show-app-menu'; +const SHOW_DATE_TIME_ID = 'show-date-time'; +const AVAILABLE_INDICATORS_ID = 'available-indicators'; +const TRANSFER_INDICATORS_ID = 'transfer-indicators'; + +var StatusIndicatorsController = class StatusIndicatorsController { + constructor() { + this._transfered_indicators = []; + this._settings = Convenience.getSettings(); + + this._updatedSessionId = Main.sessionMode.connect('updated', this._updateSessionIndicators.bind(this)); + this._updateSessionIndicators(); + this._extensionStateChangedId = Main.extensionManager.connect('extension-state-changed', + this._extensionStateChanged.bind(this)); + + this._transferIndicatorsId = this._settings.connect('changed::'+TRANSFER_INDICATORS_ID, + this.transferIndicators.bind(this)); + } + + destroy() { + this._settings.disconnect(this._transferIndicatorsId); + Main.extensionManager.disconnect(this._extensionStateChangedId); + Main.sessionMode.disconnect(this._updatedSessionId); + this._settings.set_strv(AVAILABLE_INDICATORS_ID, []); + this._transferBack(this._transfered_indicators); + } + + transferBack(panel) { + let transfer_back = this._transfered_indicators.filter((element) => { + return element.monitor==panel.monitorIndex; + }); + + this._transferBack(transfer_back, panel); + } + + transferIndicators() { + let boxs = ['_leftBox', '_centerBox', '_rightBox']; + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).deep_unpack(); + let show_app_menu = this._settings.get_value(SHOW_APP_MENU_ID); + + let transfer_back = this._transfered_indicators.filter((element) => { + return !transfers.hasOwnProperty(element.iname); + }); + + this._transferBack(transfer_back); + + for(let iname in transfers) { + if(transfers.hasOwnProperty(iname) && Main.panel.statusArea[iname]) { + let monitor = transfers[iname]; + + let indicator = Main.panel.statusArea[iname]; + let panel = this._findPanel(monitor); + boxs.forEach((box) => { + if(Main.panel[box].contains(indicator.container) && panel) { + global.log('a '+box+ " > " + iname + " : "+ monitor); + this._transfered_indicators.push({iname:iname, box:box, monitor:monitor}); + Main.panel[box].remove_child(indicator.container); + if (show_app_menu && box === '_leftBox') + panel[box].insert_child_at_index(indicator.container, 1); + else + panel[box].insert_child_at_index(indicator.container, 0); + } + }); + } + } + } + + _findPanel(monitor) { + for (let i = 0; i < Main.mmPanel.length; i++) { + if (Main.mmPanel[i].monitorIndex == monitor) { + return Main.mmPanel[i]; + } + } + return null; + } + + _transferBack(transfer_back, panel) { + transfer_back.forEach((element) => { + this._transfered_indicators.splice(this._transfered_indicators.indexOf(element)); + if(Main.panel.statusArea[element.iname]) { + let indicator = Main.panel.statusArea[element.iname]; + if(!panel) { + panel = this._findPanel(element.monitor); + } + if(panel[element.box].contains(indicator.container)) { + global.log("r "+element.box+ " > " + element.iname + " : "+ element.monitor); + panel[element.box].remove_child(indicator.container); + if (element.box === '_leftBox') + Main.panel[element.box].insert_child_at_index(indicator.container, 1); + else + Main.panel[element.box].insert_child_at_index(indicator.container, 0); + } + } + }); + } + + _extensionStateChanged() { + this._findAvailableIndicators(); + this.transferIndicators(); + } + + _updateSessionIndicators() { + let session_indicators = []; + session_indicators.push('MultiMonitorsAddOn'); + let sessionPanel = Main.sessionMode.panel; + for (let sessionBox in sessionPanel){ + sessionPanel[sessionBox].forEach((sesionIndicator) => { + session_indicators.push(sesionIndicator); + }); + } + this._session_indicators = session_indicators; + this._available_indicators = []; + + this._findAvailableIndicators(); + this.transferIndicators(); + } + + _findAvailableIndicators() { + let available_indicators = []; + let statusArea = Main.panel.statusArea; + for(let indicator in statusArea) { + if(statusArea.hasOwnProperty(indicator) && this._session_indicators.indexOf(indicator)<0){ + available_indicators.push(indicator); + } + } + if(available_indicators.length!=this._available_indicators.length) { + this._available_indicators = available_indicators; +// global.log(this._available_indicators); + this._settings.set_strv(AVAILABLE_INDICATORS_ID, this._available_indicators); + } + } +}; + +var MultiMonitorsAppMenuButton = (() => { + let MultiMonitorsAppMenuButton = class MultiMonitorsAppMenuButton extends PanelMenu.Button { + _init(panel) { + if (panel.monitorIndex==undefined) + this._monitorIndex = Main.layoutManager.primaryIndex; + else + this._monitorIndex = panel.monitorIndex; + this._actionOnWorkspaceGroupNotifyId = 0; + this._targetAppGroup = null; + this._lastFocusedWindow = null; + Panel.AppMenuButton.prototype._init.call(this, panel); + + this._windowEnteredMonitorId = global.display.connect('window-entered-monitor', + this._windowEnteredMonitor.bind(this)); + this._windowLeftMonitorId = global.display.connect('window-left-monitor', + this._windowLeftMonitor.bind(this)); + } + + _windowEnteredMonitor (metaScreen, monitorIndex, metaWin) { + if (monitorIndex == this._monitorIndex) { + switch(metaWin.get_window_type()){ + case Meta.WindowType.NORMAL: + case Meta.WindowType.DIALOG: + case Meta.WindowType.MODAL_DIALOG: + case Meta.WindowType.SPLASHSCREEN: + this._sync(); + break; + } + } + } + + _windowLeftMonitor (metaScreen, monitorIndex, metaWin) { + if (monitorIndex == this._monitorIndex) { + switch(metaWin.get_window_type()){ + case Meta.WindowType.NORMAL: + case Meta.WindowType.DIALOG: + case Meta.WindowType.MODAL_DIALOG: + case Meta.WindowType.SPLASHSCREEN: + this._sync(); + break; + } + } + } + + _findTargetApp() { + + if (this._actionOnWorkspaceGroupNotifyId) { + this._targetAppGroup.disconnect(this._actionOnWorkspaceGroupNotifyId); + this._actionOnWorkspaceGroupNotifyId = 0; + this._targetAppGroup = null; + } + let groupWindow = false; + let groupFocus = false; + + let workspaceManager = global.workspace_manager; + let workspace = workspaceManager.get_active_workspace(); + let tracker = Shell.WindowTracker.get_default(); + let focusedApp = tracker.focus_app; + if (focusedApp && focusedApp.is_on_workspace(workspace)){ + let windows = focusedApp.get_windows(); + for (let i = 0; i < windows.length; i++) { + let win = windows[i]; + if (win.located_on_workspace(workspace)){ + if (win.get_monitor() == this._monitorIndex){ + if (win.has_focus()){ + this._lastFocusedWindow = win; + // global.log(this._monitorIndex+": focus :"+win.get_title()+" : "+win.has_focus()); + return focusedApp; + } + else + groupWindow = true; + } + else { + if(win.has_focus()) + groupFocus = true; + } + if (groupFocus && groupWindow) { + if(focusedApp != this._targetApp){ + this._targetAppGroup = focusedApp; + this._actionOnWorkspaceGroupNotifyId = this._targetAppGroup.connect('notify::action-group', + this._sync.bind(this)); + // global.log(this._monitorIndex+": gConnect :"+win.get_title()+" : "+win.has_focus()); + } + break; + } + } + } + } + + for (let i = 0; i < this._startingApps.length; i++) + if (this._startingApps[i].is_on_workspace(workspace)){ + // global.log(this._monitorIndex+": newAppFocus"); + return this._startingApps[i]; + } + + if (this._lastFocusedWindow && this._lastFocusedWindow.located_on_workspace(workspace) && + this._lastFocusedWindow.get_monitor() == this._monitorIndex){ + // global.log(this._monitorIndex+": lastFocus :"+this._lastFocusedWindow.get_title()); + return tracker.get_window_app(this._lastFocusedWindow); + } + + let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, workspace); + + for (let i = 0; i < windows.length; i++) { + if(windows[i].get_monitor() == this._monitorIndex){ + this._lastFocusedWindow = windows[i]; + // global.log(this._monitorIndex+": appFind :"+windows[i].get_title()); + return tracker.get_window_app(windows[i]); + } + } + + return null; + } + + _sync() { + if (!this._switchWorkspaceNotifyId) + return; + Panel.AppMenuButton.prototype._sync.call(this); + } + + _onDestroy() { + if (this._actionGroupNotifyId) { + this._targetApp.disconnect(this._actionGroupNotifyId); + this._actionGroupNotifyId = 0; + } + + global.display.disconnect(this._windowEnteredMonitorId); + global.display.disconnect(this._windowLeftMonitorId); + + if (this._busyNotifyId) { + this._targetApp.disconnect(this._busyNotifyId); + this._busyNotifyId = 0; + } + + if (this.menu._windowsChangedId) { + this.menu._app.disconnect(this.menu._windowsChangedId); + this.menu._windowsChangedId = 0; + } + Panel.AppMenuButton.prototype._onDestroy.call(this); + } + }; + MultiMonitors.copyClass(Panel.AppMenuButton, MultiMonitorsAppMenuButton); + return GObject.registerClass({Signals: {'changed': {}},}, MultiMonitorsAppMenuButton); +})(); + +var MultiMonitorsActivitiesButton = (() => { + let MultiMonitorsActivitiesButton = class MultiMonitorsActivitiesButton extends PanelMenu.Button { + _init() { + super._init(0.0, null, true); + this.accessible_role = Atk.Role.TOGGLE_BUTTON; + + this.name = 'mmPanelActivities'; + + /* Translators: If there is no suitable word for "Activities" + in your language, you can use the word for "Overview". */ + this._label = new St.Label({ text: _("Activities"), + y_align: Clutter.ActorAlign.CENTER }); + this.add_actor(this._label); + + this.label_actor = this._label; + + this._showingId = Main.overview.connect('showing', () => { + this.add_style_pseudo_class('overview'); + this.add_accessible_state (Atk.StateType.CHECKED); + }); + this._hidingId = Main.overview.connect('hiding', () => { + this.remove_style_pseudo_class('overview'); + this.remove_accessible_state (Atk.StateType.CHECKED); + }); + + this._xdndTimeOut = 0; + } + + _onDestroy() { + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + super._onDestroy(); + } + } + MultiMonitors.copyClass(Panel.ActivitiesButton, MultiMonitorsActivitiesButton); + return GObject.registerClass(MultiMonitorsActivitiesButton); +})(); + +const MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': MultiMonitorsActivitiesButton, + 'appMenu': MultiMonitorsAppMenuButton, + 'dateMenu': MMCalendar.MultiMonitorsDateMenuButton, +}; + +var MultiMonitorsPanel = (() => { + let MultiMonitorsPanel = class MultiMonitorsPanel extends St.Widget { + _init(monitorIndex, mmPanelBox) { + super._init({ name: 'panel', + reactive: true }); + + this.monitorIndex = monitorIndex; + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({ name: 'panelLeft' }); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({ name: 'panelCenter' }); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({ name: 'panelRight' }); + this.add_child(this._rightBox); + + this._showingId = Main.overview.connect('showing', () => { + this.add_style_pseudo_class('overview'); + }); + this._hidingId = Main.overview.connect('hiding', () => { + this.remove_style_pseudo_class('overview'); + }); + + mmPanelBox.panelBox.add(this); + Main.ctrlAltTabManager.addGroup(this, _("Top Bar"), 'focus-top-bar-symbolic', + { sortGroup: CtrlAltTab.SortGroup.TOP }); + + this._updatedId = Main.sessionMode.connect('updated', this._updatePanel.bind(this)); + + this._workareasChangedId = global.display.connect('workareas-changed', () => this.queue_relayout()); + this._updatePanel(); + + this._settings = Convenience.getSettings(); + this._showActivitiesId = this._settings.connect('changed::'+SHOW_ACTIVITIES_ID, + this._showActivities.bind(this)); + this._showActivities(); + + this._showAppMenuId = this._settings.connect('changed::'+SHOW_APP_MENU_ID, + this._showAppMenu.bind(this)); + this._showAppMenu(); + + this._showDateTimeId = this._settings.connect('changed::'+SHOW_DATE_TIME_ID, + this._showDateTime.bind(this)); + this._showDateTime(); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + global.display.disconnect(this._workareasChangedId); + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + + this._settings.disconnect(this._showActivitiesId); + this._settings.disconnect(this._showAppMenuId); + this._settings.disconnect(this._showDateTimeId); + + Main.ctrlAltTabManager.removeGroup(this); + Main.sessionMode.disconnect(this._updatedId); + } + + _showActivities() { + let name = 'activities'; + if (this._settings.get_boolean(SHOW_ACTIVITIES_ID)) { + if (this.statusArea[name]) + this.statusArea[name].visible = true; + } + else { + if (this.statusArea[name]) + this.statusArea[name].visible = false; + } + } + + _showDateTime() { + let name = 'dateMenu'; + if (this._settings.get_boolean(SHOW_DATE_TIME_ID)) { + if (this.statusArea[name]) + this.statusArea[name].visible = true; + } + else { + if (this.statusArea[name]) + this.statusArea[name].visible = false; + } + } + + _showAppMenu() { + let name = 'appMenu'; + if (this._settings.get_boolean(SHOW_APP_MENU_ID)) { + if (!this.statusArea[name]) { + let indicator = new MultiMonitorsAppMenuButton(this); + this.statusArea[name] = indicator; + let box = this._leftBox; + this._addToPanelBox(name, indicator, box.get_n_children()+1, box); + } + } + else { + if (this.statusArea[name]) { + let indicator = this.statusArea[name]; + this.menuManager.removeMenu(indicator.menu); + indicator.destroy(); + delete this.statusArea[name]; + } + } + } + + vfunc_get_preferred_width(forHeight) { + if (Main.layoutManager.monitors.length>this.monitorIndex) + return [0, Main.layoutManager.monitors[this.monitorIndex].width]; + + return [0, 0]; + } + + _hideIndicators() { + for (let role in MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (indicator) { + indicator.container.show(); + return null; + } + else { + let constructor = MULTI_MONITOR_PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + _getDraggableWindowForPosition(stageX) { + let workspaceManager = global.workspace_manager; + const windows = workspaceManager.get_active_workspace().list_windows(); + const allWindowsByStacking = + global.display.sort_windows_by_stacking(windows).reverse(); + + return allWindowsByStacking.find(metaWindow => { + let rect = metaWindow.get_frame_rect(); + return metaWindow.get_monitor() == this.monitorIndex && + metaWindow.showing_on_its_workspace() && + metaWindow.get_window_type() != Meta.WindowType.DESKTOP && + metaWindow.maximized_vertically && + stageX > rect.x && stageX < rect.x + rect.width; + }); + }}; + + MultiMonitors.copyClass(Panel.Panel, MultiMonitorsPanel); + return GObject.registerClass(MultiMonitorsPanel); +})(); diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/multi-monitors-add-on.pot b/multi-monitors-add-on/multi-monitors-add-on@spin83/multi-monitors-add-on.pot new file mode 100644 index 0000000..6b18906 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/multi-monitors-add-on.pot @@ -0,0 +1,89 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the multi-monitors-add-on package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: multi-monitors-add-on\n" +"Report-Msgid-Bugs-To: https://github.com/spin83/multi-monitors-add-on/" +"issues\n" +"POT-Creation-Date: 2019-10-04 04:44-0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: indicator.js:46 +msgid "Preferences" +msgstr "" + +#: indicator.js:115 +msgid "Multi Monitors Add-On" +msgstr "" + +#: mmoverview.js:642 +msgid "Overview" +msgstr "" + +#. Translators: If there is no suitable word for "Activities" +#. in your language, you can use the word for "Overview". +#: mmpanel.js:333 +msgid "Activities" +msgstr "" + +#: mmpanel.js:414 +msgid "Top Bar" +msgstr "" + +#: prefs.js:62 +msgid "Show Multi Monitors indicator on Top Panel." +msgstr "" + +#: prefs.js:63 +msgid "Show Panel on additional monitors." +msgstr "" + +#: prefs.js:64 +msgid "Show Thumbnails-Slider on additional monitors." +msgstr "" + +#: prefs.js:65 +msgid "Show Activities-Button on additional monitors." +msgstr "" + +#: prefs.js:66 +msgid "Show AppMenu-Button on additional monitors." +msgstr "" + +#: prefs.js:67 +msgid "Show DateTime-Button on additional monitors." +msgstr "" + +#: prefs.js:68 +msgid "Show Thumbnails-Slider on left side of additional monitors." +msgstr "" + +#: prefs.js:77 +msgid "A list of indicators for transfer to additional monitors." +msgstr "" + +#: prefs.js:124 +msgid "Select indicator" +msgstr "" + +#: prefs.js:127 +msgid "Add" +msgstr "" + +#: prefs.js:141 +msgid "Indicators on Top Panel" +msgstr "" + +#: prefs.js:170 +msgid "Monitor index:" +msgstr "" diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/prefs.js b/multi-monitors-add-on/multi-monitors-add-on@spin83/prefs.js new file mode 100644 index 0000000..d1ba7ea --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/prefs.js @@ -0,0 +1,289 @@ +/* +Copyright (C) 2014 spin83 + +This program is free software; you can 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, visit https://www.gnu.org/licenses/. +*/ + +const Lang = imports.lang; + +const GObject = imports.gi.GObject; +const Gdk = imports.gi.Gdk; +const Gtk = imports.gi.Gtk; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; + +const Gettext = imports.gettext.domain('multi-monitors-add-on'); +const _ = Gettext.gettext; + +const ExtensionUtils = imports.misc.extensionUtils; +const MultiMonitors = ExtensionUtils.getCurrentExtension(); +const Convenience = MultiMonitors.imports.convenience; + +const SHOW_INDICATOR_ID = 'show-indicator'; +const SHOW_PANEL_ID = 'show-panel'; +const SHOW_ACTIVITIES_ID = 'show-activities'; +const SHOW_APP_MENU_ID = 'show-app-menu'; +const SHOW_DATE_TIME_ID = 'show-date-time'; +const THUMBNAILS_SLIDER_POSITION_ID = 'thumbnails-slider-position'; +const AVAILABLE_INDICATORS_ID = 'available-indicators'; +const TRANSFER_INDICATORS_ID = 'transfer-indicators'; +const ENABLE_HOT_CORNERS = 'enable-hot-corners'; + +const Columns = { + INDICATOR_NAME: 0, + MONITOR_NUMBER: 1 +}; + + +var MultiMonitorsPrefsWidget = GObject.registerClass( +class MultiMonitorsPrefsWidget extends Gtk.Grid { + _init() { + super._init({ + margin_top: 6, margin_end: 6, margin_bottom: 6, margin_start: 6 + }); + + this._numRows = 0; + + this.set_orientation(Gtk.Orientation.VERTICAL); + + this._settings = Convenience.getSettings(); + this._desktopSettings = Convenience.getSettings("org.gnome.desktop.interface"); + + this._display = Gdk.Display.get_default(); + this._monitors = this._display.get_monitors() + + this._addBooleanSwitch(_('Show Multi Monitors indicator on Top Panel.'), SHOW_INDICATOR_ID); + this._addBooleanSwitch(_('Show Panel on additional monitors.'), SHOW_PANEL_ID); + this._addBooleanSwitch(_('Show Activities-Button on additional monitors.'), SHOW_ACTIVITIES_ID); + this._addBooleanSwitch(_('Show AppMenu-Button on additional monitors.'), SHOW_APP_MENU_ID); + this._addBooleanSwitch(_('Show DateTime-Button on additional monitors.'), SHOW_DATE_TIME_ID); + this._addComboBoxSwitch(_('Show Thumbnails-Slider on additional monitors.'), THUMBNAILS_SLIDER_POSITION_ID, { + none: _('No'), + right: _('On the right'), + left: _('On the left'), + auto: _('Auto') + }); + this._addSettingsBooleanSwitch(_('Enable hot corners.'), this._desktopSettings, ENABLE_HOT_CORNERS); + + this._store = new Gtk.ListStore(); + this._store.set_column_types([GObject.TYPE_STRING, GObject.TYPE_INT]); + + this._treeView = new Gtk.TreeView({ model: this._store, hexpand: true, vexpand: true }); + this._treeView.get_selection().set_mode(Gtk.SelectionMode.SINGLE); + + let appColumn = new Gtk.TreeViewColumn({ expand: true, sort_column_id: Columns.INDICATOR_NAME, + title: _("A list of indicators for transfer to additional monitors.") }); + + let nameRenderer = new Gtk.CellRendererText; + appColumn.pack_start(nameRenderer, true); + appColumn.add_attribute(nameRenderer, "text", Columns.INDICATOR_NAME); + + nameRenderer = new Gtk.CellRendererText; + appColumn.pack_start(nameRenderer, true); + appColumn.add_attribute(nameRenderer, "text", Columns.MONITOR_NUMBER); + + this._treeView.append_column(appColumn); + this.add(this._treeView); + + let toolbar = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL}); + toolbar.get_style_context().add_class("inline-toolbar"); + + this._settings.connect('changed::'+TRANSFER_INDICATORS_ID, Lang.bind(this, this._updateIndicators)); + this._updateIndicators(); + + let addTButton = new Gtk.Button({ icon_name: "list-add" }); + addTButton.connect('clicked', Lang.bind(this, this._addIndicator)); + toolbar.append(addTButton); + + let removeTButton = new Gtk.Button({ icon_name: "list-remove" }); + removeTButton.connect('clicked', Lang.bind(this, this._removeIndicator)); + toolbar.append(removeTButton); + + this.add(toolbar); + } + + add(child) { + this.attach(child, 0, this._numRows++, 1, 1); + } + + _updateIndicators() { + this._store.clear(); + + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).deep_unpack(); + + for(let indicator in transfers) { + if(transfers.hasOwnProperty(indicator)){ + let monitor = transfers[indicator]; + let iter = this._store.append(); + this._store.set(iter, [Columns.INDICATOR_NAME, Columns.MONITOR_NUMBER], [indicator, monitor]); + } + } + } + + _addIndicator() { + + let dialog = new Gtk.Dialog({ title: _("Select indicator"), + transient_for: this.get_toplevel(), modal: true }); + dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL); + dialog.add_button(_("Add"), Gtk.ResponseType.OK); + dialog.set_default_response(Gtk.ResponseType.OK); + + let grid = new Gtk.Grid({ column_spacing: 10, row_spacing: 15, + margin_top: 10, margin_end: 10, margin_bottom: 10, margin_start: 10 }); + + grid.set_orientation(Gtk.Orientation.VERTICAL); + + dialog._store = new Gtk.ListStore(); + dialog._store.set_column_types([GObject.TYPE_STRING]); + + dialog._treeView = new Gtk.TreeView({ model: dialog._store, hexpand: true, vexpand: true }); + dialog._treeView.get_selection().set_mode(Gtk.SelectionMode.SINGLE); + + let appColumn = new Gtk.TreeViewColumn({ expand: true, sort_column_id: Columns.INDICATOR_NAME, + title: _("Indicators on Top Panel") }); + + let nameRenderer = new Gtk.CellRendererText; + appColumn.pack_start(nameRenderer, true); + appColumn.add_attribute(nameRenderer, "text", Columns.INDICATOR_NAME); + + dialog._treeView.append_column(appColumn); + + let availableIndicators = () => { + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).unpack(); + dialog._store.clear(); + this._settings.get_strv(AVAILABLE_INDICATORS_ID).forEach((indicator) => { + if(!transfers.hasOwnProperty(indicator)){ + let iter = dialog._store.append(); + dialog._store.set(iter, [Columns.INDICATOR_NAME], [indicator]); + } + }); + }; + + let availableIndicatorsId = this._settings.connect('changed::'+AVAILABLE_INDICATORS_ID, + availableIndicators); + let transferIndicatorsId = this._settings.connect('changed::'+TRANSFER_INDICATORS_ID, + availableIndicators); + + availableIndicators.apply(this); + grid.attach(dialog._treeView, 0, 0, 2, 1); + + let gHBox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 10, margin_end: 10, margin_bottom: 10, margin_start: 10, + spacing: 20, hexpand: true}); + let gLabel = new Gtk.Label({label: _('Monitor index:'), halign: Gtk.Align.START}); + gHBox.append(gLabel); + dialog._adjustment = new Gtk.Adjustment({lower: 0.0, upper: 0.0, step_increment:1.0}); + let spinButton = new Gtk.SpinButton({halign: Gtk.Align.END, adjustment: dialog._adjustment, numeric: 1}); + gHBox.append(spinButton); + + let monitorsChanged = () => { + let n_monitors = this._monitors.get_n_items() -1; + dialog._adjustment.set_upper(n_monitors) + dialog._adjustment.set_value(n_monitors); + }; + + let monitorsChangedId = this._monitors.connect('items-changed', monitorsChanged); + + monitorsChanged.apply(this); + grid.append(gHBox); + + dialog.get_content_area().append(grid); + + dialog.connect('response', (dialog, id) => { + this._monitors.disconnect(monitorsChangedId); + this._settings.disconnect(availableIndicatorsId); + this._settings.disconnect(transferIndicatorsId); + if (id != Gtk.ResponseType.OK) { + dialog.destroy(); + return; + } + + let [any, model, iter] = dialog._treeView.get_selection().get_selected(); + if (any) { + let indicator = model.get_value(iter, Columns.INDICATOR_NAME); + + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).deep_unpack(); + if(!transfers.hasOwnProperty(indicator)){ + transfers[indicator] = dialog._adjustment.get_value(); + this._settings.set_value(TRANSFER_INDICATORS_ID, new GLib.Variant('a{si}', transfers)); + } + } + + dialog.destroy(); + }); + } + + _removeIndicator() { + let [any, model, iter] = this._treeView.get_selection().get_selected(); + if (any) { + let indicator = model.get_value(iter, Columns.INDICATOR_NAME); + + let transfers = this._settings.get_value(TRANSFER_INDICATORS_ID).deep_unpack(); + if(transfers.hasOwnProperty(indicator)){ + delete transfers[indicator]; + this._settings.set_value(TRANSFER_INDICATORS_ID, new GLib.Variant('a{si}', transfers)); + } + } + } + + _addComboBoxSwitch(label, schema_id, options) { + this._addSettingsComboBoxSwitch(label, this._settings, schema_id, options) + } + + _addSettingsComboBoxSwitch(label, settings, schema_id, options) { + let gHBox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 10, margin_end: 10, margin_bottom: 10, margin_start: 10, + spacing: 20, hexpand: true}); + let gLabel = new Gtk.Label({label: _(label), halign: Gtk.Align.START}); + gHBox.append(gLabel); + + let gCBox = new Gtk.ComboBoxText({halign: Gtk.Align.END}); + Object.entries(options).forEach(function(entry) { + const [key, val] = entry; + gCBox.append(key, val); + }); + gHBox.append(gCBox); + + this.add(gHBox); + + settings.bind(schema_id, gCBox, 'active-id', Gio.SettingsBindFlags.DEFAULT); + } + + _addBooleanSwitch(label, schema_id) { + this._addSettingsBooleanSwitch(label, this._settings, schema_id); + } + + _addSettingsBooleanSwitch(label, settings, schema_id) { + let gHBox = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, + margin_top: 10, margin_end: 10, margin_bottom: 10, margin_start: 10, + spacing: 20, hexpand: true}); + let gLabel = new Gtk.Label({label: _(label), halign: Gtk.Align.START}); + gHBox.append(gLabel); + let gSwitch = new Gtk.Switch({halign: Gtk.Align.END}); + gHBox.append(gSwitch); + this.add(gHBox); + + settings.bind(schema_id, gSwitch, 'active', Gio.SettingsBindFlags.DEFAULT); + } +}); + +function init() { + Convenience.initTranslations(); +} + +function buildPrefsWidget() { + let widget = new MultiMonitorsPrefsWidget(); + + return widget; +} diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/gschemas.compiled b/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/gschemas.compiled Binary files differnew file mode 100644 index 0000000..5a9e945 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/gschemas.compiled diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/org.gnome.shell.extensions.multi-monitors-add-on.gschema.xml b/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/org.gnome.shell.extensions.multi-monitors-add-on.gschema.xml new file mode 100644 index 0000000..4a42a23 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/org.gnome.shell.extensions.multi-monitors-add-on.gschema.xml @@ -0,0 +1,59 @@ +<schemalist gettext-domain="gnome-shell-extensions"> + <schema id="org.gnome.shell.extensions.multi-monitors-add-on" path="/org/gnome/shell/extensions/multi-monitors-add-on/"> + + <key name="show-indicator" type="b"> + <default>true</default> + <summary>Show Multi Monitors indicator on Top Panel.</summary> + <description>Add or remove Multi Monitors indicator from Top Panel.</description> + </key> + + <key name="show-panel" type="b"> + <default>true</default> + <summary>Show Panel on additional monitors.</summary> + <description>Add or remove Panel from additional monitors.</description> + </key> + + <key name="show-activities" type="b"> + <default>true</default> + <summary>Show Activities-Button on additional monitors.</summary> + <description>Change visibility of Activities-Button on additional monitors.</description> + </key> + + <key name="show-app-menu" type="b"> + <default>true</default> + <summary>Show AppMenu-Button on additional monitors.</summary> + <description>Change visibility of AppMenu-Button on additional monitors.</description> + </key> + + <key name="show-date-time" type="b"> + <default>true</default> + <summary>Show DateTime-Button on additional monitors.</summary> + <description>Change visibility of DateTime-Button on additional monitors.</description> + </key> + + <key name="thumbnails-slider-position" type="s"> + <choices> + <choice value='none'/> + <choice value='right'/> + <choice value='left'/> + <choice value='auto'/> + </choices> + <default>'auto'</default> + <summary>Show Thumbnails-Slider on additional monitors.</summary> + <description>Select position of Thumbnails-Slider on additional monitors.</description> + </key> + + <key name="available-indicators" type="as"> + <default>[]</default> + <summary>A list of available indicators.</summary> + <description>A list of indicators that are available for transfer. For internal use only.</description> + </key> + + <key name="transfer-indicators" type="a{si}"> + <default>{}</default> + <summary>A list of indicators for transfer.</summary> + <description>A list of indicators selected for transfer to additional Panel.</description> + </key> + + </schema> +</schemalist>
\ No newline at end of file diff --git a/multi-monitors-add-on/multi-monitors-add-on@spin83/stylesheet.css b/multi-monitors-add-on/multi-monitors-add-on@spin83/stylesheet.css new file mode 100644 index 0000000..b1d20c5 --- /dev/null +++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/stylesheet.css @@ -0,0 +1,29 @@ + +.helloworld-label { + font-size: 72px; + font-weight: bold; + color: #ffffff; + background-color: rgba(0,0,0,0.5); + border-radius: 5px; + padding: .5em; +} + +.multimonitor-spacer { + height: 4em; +} + +.multimonitor-status-indicators-box { + spacing: 0px; +} + +.multimonitor-status-icon { + padding: 0 2px; +} + +.workspace-thumbnails-left { + border-radius: 0 9px 9px 0; +} + +.workspace-thumbnails-left:rtl { + border-radius: 9px 0 0 9px; +} |