summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--disable-workspace-switcher/LICENSE674
-rw-r--r--disable-workspace-switcher/README.md1
-rw-r--r--disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/extension.js21
-rw-r--r--disable-workspace-switcher/disable-workspace-switcher@jbradaric.me/metadata.json11
-rw-r--r--hibernate-status/.gitignore6
-rw-r--r--hibernate-status/LICENSE340
-rw-r--r--hibernate-status/Makefile77
-rw-r--r--hibernate-status/README.md41
-rwxr-xr-xhibernate-status/buildforupload.sh2
-rw-r--r--hibernate-status/confirmDialog.js193
-rw-r--r--hibernate-status/extension.js248
-rw-r--r--hibernate-status/locale/cs/LC_MESSAGES/hibernate-status-button.po66
-rw-r--r--hibernate-status/locale/de/LC_MESSAGES/hibernate-status-button.po72
-rw-r--r--hibernate-status/locale/es/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/fa/LC_MESSAGES/hibernate-status-button.po72
-rw-r--r--hibernate-status/locale/fr/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/it/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/nl/LC_MESSAGES/hibernate-status-button.po68
-rw-r--r--hibernate-status/locale/oc/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/pl/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/pt/LC_MESSAGES/hibernate-status-button.po71
-rw-r--r--hibernate-status/locale/pt_BR/LC_MESSAGES/hibernate-status-button.po73
-rw-r--r--hibernate-status/locale/ru/LC_MESSAGES/hibernate-status-button.po74
-rw-r--r--hibernate-status/locale/uk/LC_MESSAGES/hibernate-status-button.po74
-rw-r--r--hibernate-status/locale/zh_CN/LC_MESSAGES/hibernate-status-button.po59
-rw-r--r--hibernate-status/metadata.json10
-rw-r--r--hibernate-status/prefs.js105
-rw-r--r--hibernate-status/schemas/org.gnome.shell.extensions.hibernate-status-button.gschema.xml8
-rw-r--r--multi-monitors-add-on/.project11
-rw-r--r--multi-monitors-add-on/LICENSE340
-rw-r--r--multi-monitors-add-on/README.md33
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/convenience.js93
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/extension.js289
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-l-symbolic.svg392
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/icons/multi-monitors-r-symbolic.svg393
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/indicator.js109
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1722 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/de/LC_MESSAGES/multi-monitors-add-on.po95
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1593 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/es/LC_MESSAGES/multi-monitors-add-on.po91
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1701 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/fr/LC_MESSAGES/multi-monitors-add-on.po94
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1820 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/it/LC_MESSAGES/multi-monitors-add-on.po93
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1743 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pl/LC_MESSAGES/multi-monitors-add-on.po94
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.mobin0 -> 1759 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/locale/pt_BR/LC_MESSAGES/multi-monitors-add-on.po89
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/metadata.json10
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/mmcalendar.js412
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/mmlayout.js251
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/mmoverview.js678
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/mmpanel.js520
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/multi-monitors-add-on.pot89
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/prefs.js289
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/gschemas.compiledbin0 -> 788 bytes
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/org.gnome.shell.extensions.multi-monitors-add-on.gschema.xml59
-rw-r--r--multi-monitors-add-on/multi-monitors-add-on@spin83/stylesheet.css29
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
new 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
Binary files differ
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
new 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
Binary files differ
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
new 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
Binary files differ
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
new 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
Binary files differ
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
new 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
Binary files differ
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
new 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
Binary files differ
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
new file mode 100644
index 0000000..5a9e945
--- /dev/null
+++ b/multi-monitors-add-on/multi-monitors-add-on@spin83/schemas/gschemas.compiled
Binary files differ
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;
+}