diff options
| -rw-r--r-- | .gitignore | 18 | ||||
| -rw-r--r-- | COPYING | 674 | ||||
| -rw-r--r-- | DEPENDENCIES | 1 | ||||
| -rw-r--r-- | LICENSE | 15 | ||||
| -rw-r--r-- | Makefile | 198 | ||||
| -rw-r--r-- | README | 6 | ||||
| -rw-r--r-- | completion (renamed from src/completion) | 18 | ||||
| -rw-r--r-- | config.mk | 3 | ||||
| -rw-r--r-- | dist/archlinux/stable/PKGBUILD | 26 | ||||
| -rw-r--r-- | examples/x-window-focus | 26 | ||||
| -rw-r--r-- | interface.py (renamed from src/interface.py) | 20 | ||||
| -rwxr-xr-x | src/__main__.py | 924 | 
12 files changed, 95 insertions, 1834 deletions
@@ -1,17 +1,13 @@ -_/ -/dist/*/*/* -!/dist/archlinux/*/PKGBUILD -!/dist/archlinux/*/nightshift.install -bin/ -obj/ -__pycache__/ -\#*\# -.* -!.git* +*\#*  *~  *.swp  *.swo  *.bak  *.pyc  *.pyo - +__pycache__/ +/nightshift +/nightshift.zip +/nightshift.bash +/nightshift.fish +/nightshift.zsh diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed0..0000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ -                    GNU GENERAL PUBLIC LICENSE -                       Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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 -<http://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 -<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/DEPENDENCIES b/DEPENDENCIES index 39d4e38..acbabc7 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -10,4 +10,3 @@ MAKE DEPENDENCIES:  	make  	zip  	coreutils - @@ -0,0 +1,15 @@ +ISC License + +© 2014, 2025 Mattias Andrée <m@maandree.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. @@ -1,162 +1,70 @@ -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved.  This file is offered as-is, -# without any warranty. +.POSIX: +CONFIGFILE = config.mk +include $(CONFIGFILE) -# The package path prefix, if you want to install to another root, set DESTDIR to that root -PREFIX = /usr -# The command path excluding prefix -BIN = /bin -# The resource path excluding prefix -DATA = /share -# The documenation path excluding prefix and /share -DOC = /doc -# The command path including prefix -BINDIR = $(PREFIX)$(BIN) -# The resource path including prefix -DATADIR = $(PREFIX)$(DATA) -# The documentation path including prefix and /share -DOCDIR = $(DATADIR)$(DOC) -# The license base path including prefix -LICENSEDIR = $(DATADIR)/licenses -# Python 3 command to use in shebangs -SHEBANG = /usr/bin/env python3 -# The name of the command as it should be installed -COMMAND = nightshift -# The name of the package as it should be installed -PKGNAME = nightshift +PYFILES =\ +	__main__.py\ +	interface.py -# Python source files -PYFILES = __main__.py interface.py +EXAMPLES =\ +	examples/x-window-focus -# Configuration script example files -EXAMPLES = x-window-focus +all: nightshift nightshift.bash nightshift.zsh nightshift.fish -# Build rules +nightshift: nightshift.zip +	printf '#!%s\n' '$(SHEBANG)' | cat - nightshift.zip > $@ +	chmod -- a+x $@ -.PHONY: default -default: command shell +nightshift.zip: $(PYFILES) +	zip $@ $(PYFILES) -.PHONY: all -all: command shell +nightshift.bash: completion +	auto-auto-complete bash --output $@ --source completion -.PHONY: command -command: bin/nightshift +nightshift.zsh: completion +	auto-auto-complete zsh --output $@ --source completion -# Build rules for Python source files +nightshift.fish: completion +	auto-auto-complete fish --output $@ --source completion -bin/nightshift: obj/nightshift.zip -	mkdir -p bin -	echo '#!$(SHEBANG)' > $@ -	cat $< >> $@ -	chmod a+x $@ +install: +	mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/share/licenses" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/share/doc/nightshift/examples" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/share/bash-completion/completions" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/share/zsh/site-functions" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/share/fish/completions" +	test ! -d "$(DESTDIR)$(PREFIX)/share/licenses/nightshift" +	test ! -d "$(DESTDIR)$(PREFIX)/share/bash-completion/completions/nightshift" +	test ! -d "$(DESTDIR)$(PREFIX)/share/zsh/site-functions/_nightshift" +	test ! -d "$(DESTDIR)$(PREFIX)/share/fish/completions/nightshift.fish" +	cp -- nightshift "$(DESTDIR)$(PREFIX)/bin/" +	cp -- LICENSE "$(DESTDIR)$(PREFIX)/share/licenses/nightshift" +	cp -- $(EXAMPLES) "$(DESTDIR)$(PREFIX)/share/doc/nightshift/examples/" +	cp -- nightshift.bash "$(DESTDIR)$(PREFIX)/share/bash-completion/completions/nightshift" +	cp -- nightshift.zsh "$(DESTDIR)$(PREFIX)/share/zsh/site-functions/_nightshift" +	cp -- nightshift.fish "$(DESTDIR)$(PREFIX)/share/fish/completions/nightshift.fish" -obj/nightshift.zip: $(foreach F,$(PYFILES),src/$(F)) -	@mkdir -p obj -	cd src && zip ../$@ $(foreach F,$(PYFILES),$(F)) - -# Build rules for shell auto-completion - -.PHONY: shell -shell: bash zsh fish - -.PHONY: bash -bash: bin/nightshift.bash -bin/nightshift.bash: src/completion -	@mkdir -p bin -	auto-auto-complete bash --output $@ --source $< - -.PHONY: zsh -zsh: bin/nightshift.zsh -bin/nightshift.zsh: src/completion -	@mkdir -p bin -	auto-auto-complete zsh --output $@ --source $< - -.PHONY: fish -fish: bin/nightshift.fish -bin/nightshift.fish: src/completion -	@mkdir -p bin -	auto-auto-complete fish --output $@ --source $< - - -# Install rules - -.PHONY: install -install: install-base install-examples install-shell - -.PHONY: install -install-all: install-base install-examples install-shell - -# Install base - -.PHONY: install-base -install-base: install-command install-license - -.PHONY: install-command -install-command: bin/nightshift -	install -dm755 -- "$(DESTDIR)$(BINDIR)" -	install -m755 $< -- "$(DESTDIR)$(BINDIR)/$(COMMAND)" - -.PHONY: install-license -install-license: -	install -dm755 -- "$(DESTDIR)$(LICENSEDIR)/$(PKGNAME)" -	install -m644 COPYING -- "$(DESTDIR)$(LICENSEDIR)/$(PKGNAME)" - -# Install documentation - -.PHONY: install-examples -install-examples: $(foreach E,$(EXAMPLES),examples/$(E)) -	install -dm755 -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME)/examples" -	install -m644 $^ -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME)/examples" - -# Install shell auto-completion - -.PHONY: install-shell -install-shell: install-bash install-zsh install-fish - -.PHONY: install-bash -install-bash: bin/nightshift.bash -	install -dm755 -- "$(DESTDIR)$(DATADIR)/bash-completion/completions" -	install -m644 $< -- "$(DESTDIR)$(DATADIR)/bash-completion/completions/$(COMMAND)" - -.PHONY: install-zsh -install-zsh: bin/nightshift.zsh -	install -dm755 -- "$(DESTDIR)$(DATADIR)/zsh/site-functions" -	install -m644 $< -- "$(DESTDIR)$(DATADIR)/zsh/site-functions/_$(COMMAND)" - -.PHONY: install-fish -install-fish: bin/nightshift.fish -	install -dm755 -- "$(DESTDIR)$(DATADIR)/fish/completions" -	install -m644 $< -- "$(DESTDIR)$(DATADIR)/fish/completions/$(COMMAND).fish" - - -# Uninstall rules - -.PHONY: uninstall  uninstall: -	-rm -- "$(DESTDIR)$(BINDIR)/$(COMMAND)" -	-rm -- "$(DESTDIR)$(LICENSEDIR)/$(PKGNAME)/COPYING" -	-rmdir -- "$(DESTDIR)$(LICENSEDIR)/$(PKGNAME)" -	-rm -- $(foreach E,$(EXAMPLES),"$(DESTDIR)$(DOCDIR)/$(PKGNAME)/examples/$(E)") -	-rmdir -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME)/examples" -	-rmdir -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME)" -	-rm -- "$(DESTDIR)$(DATADIR)/fish/completions/$(COMMAND).fish" -	-rmdir -- "$(DESTDIR)$(DATADIR)/fish/completions" -	-rmdir -- "$(DESTDIR)$(DATADIR)/fish" -	-rm -- "$(DESTDIR)$(DATADIR)/zsh/site-functions/_$(COMMAND)" -	-rmdir -- "$(DESTDIR)$(DATADIR)/zsh/site-functions" -	-rmdir -- "$(DESTDIR)$(DATADIR)/zsh" -	-rm -- "$(DESTDIR)$(DATADIR)/bash-completion/completions/$(COMMAND)" -	-rmdir -- "$(DESTDIR)$(DATADIR)/bash-completion/completions" -	-rmdir -- "$(DESTDIR)$(DATADIR)/bash-completion" - - -# Clean rules +	-rm -f -- "$(DESTDIR)$(PREFIX)/bin/nightshift" +	-rm -f -- "$(DESTDIR)$(PREFIX)/share/licenses/nightshift" +	-cd -- "$(DESTDIR)$(PREFIX)/share/doc/nightshift/" && rm -f -- $(EXAMPLES) +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/doc/nightshift/examples" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/doc/nightshift" +	-rm -f -- "$(DESTDIR)$(PREFIX)/share/fish/completions/nightshift.fish" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/fish/completions" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/fish" +	-rm -f -- "$(DESTDIR)$(PREFIX)/share/zsh/site-functions/_nightshift" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/zsh/site-functions" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/zsh" +	-rm -f -- "$(DESTDIR)$(PREFIX)/share/bash-completion/completions/nightshift" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/bash-completion/completions" +	-rmdir -- "$(DESTDIR)$(PREFIX)/share/bash-completion" -.PHONY: all  clean: -	-rm -r bin obj +	-rm -f -- nightshift nightshift.zip nightshift.bash nightshift.fish nightshift.zsh +.PHONY: all install uninstall clean @@ -85,11 +85,9 @@ OPTIONS  		Disable temperature transitions.  NOTES -	Apple is using the name of this project for there own +	Apple is using the name of this project for their own  	alternative without my permission and with my express  	opposition.  SEE ALSO -	redshift(1), blueshift(1) - - +	redshift(1), blueshift(1), radharc(1) diff --git a/src/completion b/completion index 7d7200f..234f7d0 100644 --- a/src/completion +++ b/completion @@ -1,19 +1,4 @@ -; nightshift - A terminal user interface for redshift -; Copyright © 2014  Mattias Andrée (m@maandree.se) -;  -; This program is free software: you can 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 <http://www.gnu.org/licenses/>. - +; See LICENSE file for copyright and license details.  (nightshift    (unargumented (options -h --help)          (complete --help)                                            (desc 'Display this help message')) @@ -38,4 +23,3 @@    (argumented   (options -m --method)        (complete --method)        (arg METHOD)           (files -0) (desc 'Method to use to set colour temperature'))    (unargumented (options -r --no-transition) (complete --no-transition)                                   (desc 'Disable temperature transitions'))  ) - diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..8090300 --- /dev/null +++ b/config.mk @@ -0,0 +1,3 @@ +PREFIX = /usr + +SHEBANG = /usr/bin/env python3 diff --git a/dist/archlinux/stable/PKGBUILD b/dist/archlinux/stable/PKGBUILD deleted file mode 100644 index eb0130b..0000000 --- a/dist/archlinux/stable/PKGBUILD +++ /dev/null @@ -1,26 +0,0 @@ -# Maintainer: Mattias Andrée <`base64 -d`(bWFhbmRyZWUK)@member.fsf.org> - -pkgname=nightshift -pkgver=0.6 -pkgrel=1 -pkgdesc="A terminal user interface for redshift" -arch=(any) -url="https://github.com/maandree/nightshift" -license=('GPL3') -depends=(python3 redshift linux) -makedepends=(make coreutils zip auto-auto-complete) -source=($url/archive/$pkgver.tar.gz) -sha256sums=(2e325c337e5ced2e944bd065e2ac323783299362301ec73ca5b5a341e3bb84ec) - - -build() { -  cd "$srcdir/$pkgname-$pkgver" -  make PREFIX=/usr -} - - -package() { -  cd "$srcdir/$pkgname-$pkgver" -  make PREFIX=/usr DESTDIR="$pkgdir" install -} - diff --git a/examples/x-window-focus b/examples/x-window-focus index 930044a..08e058f 100644 --- a/examples/x-window-focus +++ b/examples/x-window-focus @@ -6,20 +6,21 @@  # only been tested on twm and xmonad. -# Copyright © 2014  Mattias Andrée (m@maandree.se) +# ISC License  #  -# This program is free software: you can 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. +# © 2014, 2025 Mattias Andrée <m@maandree.se>  #  -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies.  #  -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  # This requires that python3-xlib is installed. @@ -30,7 +31,7 @@ import threading  import Xlib.display  # TODO: cannot re-exec when this script is used -# TODO: does not wait with toggling of redshift is froozen +# TODO: does not wait with toggling if redshift is frozen  def x_window_focus_thread_function(proc): @@ -124,4 +125,3 @@ def start_daemon_threads(proc, sock):      thread = threading.Thread(target = x_window_focus_thread_function, args = (proc,))      thread.setDaemon(True)      thread.start() - diff --git a/src/interface.py b/interface.py index 53928d6..1a112a5 100644 --- a/src/interface.py +++ b/interface.py @@ -1,22 +1,5 @@  #!/usr/bin/env python3 -# -*- python -*- -''' -nightshift - A terminal user interface for redshift -Copyright © 2014  Mattias Andrée (m@maandree.se) - -This program is free software: you can 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 <http://www.gnu.org/licenses/>. -''' +# See LICENSE file for copyright and license details.  import sys  import fcntl @@ -214,4 +197,3 @@ def daemon_thread(target, **kwargs):      thread = threading.Thread(target = target, **kwargs)      thread.setDaemon(True)      return thread - diff --git a/src/__main__.py b/src/__main__.py deleted file mode 100755 index dbc4623..0000000 --- a/src/__main__.py +++ /dev/null @@ -1,924 +0,0 @@ -#!/usr/bin/env python3 -# -*- python -*- -copyright=''' -nightshift - A terminal user interface for redshift -Copyright © 2014  Mattias Andrée (m@maandree.se) - -This program is free software: you can 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 <http://www.gnu.org/licenses/>. -''' - -import os -import sys -import socket -import signal -import threading -from subprocess import Popen, PIPE - - -PROGRAM_NAME = 'nightshift' -''' -:str  The name of the program -''' - -PROGRAM_VERSION = '0.4' -''' -:str  The version of the program -''' - - -## Set process title -def setproctitle(title): -    ''' -    Set process title -     -    @param  title:str  The title of the process -    ''' -    import ctypes -    try: -        # Remove path, keep only the file, -        # otherwise we get really bad effects, namely -        # the name title is truncates by the number -        # of slashes in the title. At least that is -        # the observed behaviour when using procps-ng. -        title = title.split('/')[-1] -        # Create strng buffer with title -        title = title.encode(sys.getdefaultencoding(), 'replace') -        title = ctypes.create_string_buffer(title) -        if 'linux' in sys.platform: -            # Set process title on Linux -            libc = ctypes.cdll.LoadLibrary('libc.so.6') -            libc.prctl(15, ctypes.byref(title), 0, 0, 0) -        elif 'bsd' in sys.platform: -            # Set process title on at least FreeBSD -            libc = ctypes.cdll.LoadLibrary('libc.so.7') -            libc.setproctitle(ctypes.create_string_buffer(b'-%s'), title) -    except: -        pass -setproctitle(sys.argv[0]) - - -backlog = 5 -''' -:int  The size of the server socket's backlog -''' - -red_args = None -''' -:list<str>?  Raw arguments passed to redshift -''' - -red_opts = ['-v'] -''' -:list<str>  Nightshift parsed options passed to redshift -''' - -daemon = 0 -''' -:int  Whether or not to run as daemon, 2 if revived -''' - -kill = 0 -''' -:int  Whether or not to kill the redshift and the nightshift daemon, -      0 for no, 1 for yes, 2 for immediately -''' - -toggle = False -''' -:bool  Whether or not to toggle redshift -''' - -set_status = None -''' -:bool?  `True` if redshift should be enabled, `False` for disble, otherwise `None` -''' - -set_freeze = None -''' -:bool?  `True` if redshift should be frozen, `False` for thawed, otherwise `None` -''' - -status = False -''' -:bool  Whether or not to get the current status -''' - -conf_opts = [] -''' -:list<str>  This list will always have at least one element. This list is filled -            with options passed to the configurations, with the first element -            being the configuration file -''' - -config_file = None -''' -:str?  The configuration file, same as the first element in `conf_opts` -''' - - -## Parse options -add_to_red_opts = False -reading_conf_opts = False -for arg in sys.argv[1:]: -    if add_to_red_opts: -        red_opts.append(arg) -        add_to_red_opts = False -    elif reading_conf_opts: -        if arg == '}': -            reading_conf_opts = False -        else: -            conf_opts.append(arg) -    elif isinstance(config_file, list): -        config_file = arg -    elif red_args is not None: -        red_args.append(arg) -    elif arg == '{': -        reading_conf_opts = True -    elif arg in ('-V', '--version', '-version'): -        ## Print the version of nightshift and of redshift -        print('%s %s' % (PROGRAM_NAME, PROGRAM_VERSION)) -        Popen(['redshift', '-V'], stdout = sys.stdout, env = redshift_env).wait() -        sys.exit(0) -    elif arg in ('-C', '--copyright', '-copyright'): -        ## Print copyright information -        print(copyright[1 : -1]) -        sys.exit(0) -    elif arg in ('-W', '--warranty', '-warranty'): -        ## Print warranty disclaimer -        print(copyright.split('\n\n')[-2]) -        sys.exit(0) -    elif arg in ('-h', '-?', '--help', '-help'): -        ## Display help message -        text = '''USAGE: nightshift [OPTIONS...] ['{' SCRIPT-OPTIONS... '}'] ['--' REDSHIFT-OPTIONS...] -                   -                  Terminal user interface for redshift, a program for setting the colour -                  temperature of the display according to the time of day. -                   -                    -h --help                       Display this help message -                    -V --version                    Show program version -                    -C --copyright                  Show program copyright information -                    -W --warranty                   Show program warrantly disclaimer -                     -                    -d --daemon                     Start as daemon -                    -x --reset --kill               Remove adjustment from screen -                    +x --toggle                     Temporarily disable or enable adjustments -                    +d --disable                    Temporarily disable adjustments -                    +e --enable                     Re-enable adjustments -                    +f --freeze                     Temporarily freeze the redshift process -                    +t --thaw                       Thaw the redshift process -                    -s --status                     Print status information -                    +c --script         FILE        Load nightshift configuration script from specified file -                     -                    -c --config         FILE        Load redshift settings from specified file -                    -b --brightness     DAY:NIGHT   Screen brightness to set at daytime/night -                    -b --brightness     BRIGHTNESS  Screen brightness to apply -                    -t --temperature    DAY:NIGHT   Colour temperature to set at daytime/night -                    -t --temperature    TEMP        Colour temperature to apply -                    -l --location       LAT:LON     Your current location -                    -l --location       PROVIDER    Select provider for automatic location updates -                                                    (Type `list' to see available providers) -                    -m --method         METHOD      Method to use to set colour temperature -                                                    (Type `list' to see available methods) -                    -r --no-transition              Disable temperature transitions -               ''' -        text = text.split('\n')[:-1] -        indent = min([len(line) - len(line.lstrip()) for line in text if line.rstrip().startswith(' ')]) -        print('\n'.join([line[indent:] if line.startswith(' ') else line for line in text])) -        sys.exit(0) -    elif arg == '--': -        red_args = [] -    else: -        subargs = [arg] -        if   arg.startswith('-') and not arg.startswith('--'):  subargs = ['-' + letter for letter in arg[1:]] -        elif arg.startswith('+') and not arg.startswith('++'):  subargs = ['+' + letter for letter in arg[1:]] -        elif arg.startswith('=') and not arg.startswith('=='):  subargs = ['=' + letter for letter in arg[1:]] -        red_arg = '' -        for arg in subargs: -            if (add_to_red_opts is None) or add_to_red_opts: -                add_to_red_opts = None -                red_arg += arg -            elif isinstance(config_file, list): -                config_file.append(arg) -            elif arg in ('-d', '--daemon'):             daemon = 1 -            elif arg in ('=d', '==daemon'):             daemon = 2 -            elif arg in ('-x', '--reset', '--kill'):    kill += 1 -            elif arg in ('+x', '--toggle'):             toggle = True -            elif arg in ('+d', '--disable'):            set_status = False -            elif arg in ('+e', '--enable'):             set_status = True -            elif arg in ('+f', '--freeze'):             set_freeze = True -            elif arg in ('+t', '--thaw'):               set_freeze = False -            elif arg in ('-s', '--status'):             status = True -            elif arg in ('+c', '--script'):             config_file = [] -            else: -                add_to_red_opts = True -                if   arg in ('-c', '--config'):         red_opts.append('-c') -                elif arg in ('-b', '--brightness'):     red_opts.append('-b') -                elif arg in ('-t', '--temperature'):    red_opts.append('-t') -                elif arg in ('-l', '--location'):       red_opts.append('-l') -                elif arg in ('-m', '--method'):         red_opts.append('-m') -                elif arg in ('-r', '--no-transition'):  red_opts.append('-r') -                else: -                    ## Unrecognised option -                    sys.stderr.write('%s: error: unrecognised option: %s\n' % (sys.argv[0], arg)) -                    sys.exit(1) -        if add_to_red_opts is None: -            red_opts.append(red_arg) -            add_to_red_opts = False -        if isinstance(config_file, list) and (len(config_file) > 0): -            config_file = ''.join(config_file) -if isinstance(config_file, list): -    sys.stderr.write('%s: error: premature end of arguments\n' % sys.argv[0]) -    sys.exit(1) - - -# Parse help request for -l and -m -for opt in ('-l', '-m'): -    i = 0 -    while opt in red_opts[i:]: -        i = red_opts.index(opt) + 1 -        if not i == len(red_opts): -            arg = red_opts[i] -            if (arg == 'list') or ('help' in arg.split(':')): -                proc = ['redshift', opt, arg] -                proc = Popen(proc, stdout = sys.stdout, stderr = sys.stderr, env = redshift_env) -                proc.wait() -                sys.exit(proc.returncode) -# Translate single-parameter -t into dual-parameter -t -i = 0 -while '-t' in red_opts[i:]: -    i = red_opts.index('-t') + 1 -    if not i == len(red_opts): -        if ':' not in red_opts[i]: -            red_opts[i] = '%s:%s' % (red_opts[i], red_opts[i]) - - - -# Construct name of socket -socket_path = '%s.%s~%s' % ('/dev/shm/', PROGRAM_NAME, os.environ['USER']) -''' -The pathname of the interprocess communication socket for nightshift -''' - - -# The status of redshift -red_brightness, red_temperature = 1, 6500 -red_brightnesses, red_temperatures = (1, 1), (5500, 3500) -red_period, red_location = 1, (0, 0) -red_status, red_running, red_dying, red_frozen = True, True, False, False -red_condition, broadcast_condition = None, None - - -## Create locale free environment for redshift -redshift_env = os.environ.copy() -for var in ('LANG', 'LANGUAGE', 'LC_ALL', 'LC_MESSAGES'): -    redshift_env[var] = 'C' - - -def read_status(proc, sock): -    ''' -    Read status from redshift -     -    @param  proc:Popen   The redshift process -    @param  sock:socket  The server socket -    ''' -    global red_brightness, red_temperature -    global red_brightnesses, red_temperatures -    global red_period, red_location -    global red_status, red_running -    released = True -    while True: -        got = proc.stdout.readline() -        if (got is None) or (len(got) == 0): -            if red_frozen: -                proc.wait() -                continue -            break -        got = got.decode('utf-8', 'replace')[:-1] -        if ': 'not in got: -            continue -        (key, value) = got.split(': ') -        if released: -            red_condition.acquire() -        try: -            if key == 'Location': -                def coordcomp(v): -                    v = (v + ' N').split(' ')[:2] -                    return float(v[0]) * (-1 if v[1] in 'SW' else 1) -                red_location = [coordcomp(v) for v in value.split(', ')] -                # Followed by 'Temperatures' -            elif key == 'Temperatures': -                red_temperatures = [float(v.split(' ')[0][:-1]) for v in value.split(', ')] -                # Followed by two parameter 'Brightness' -            elif key == 'Period': -                if value == 'Night': -                    red_period = 0 -                elif value == 'Daytime': -                    red_period = 1 -                else: -                    red_period = float(value.split(' ')[1][1 : -1]) / 100 -                # Followed by 'Color temperature' -            elif key == 'Color temperature': -                red_temperature = float(value[:-1]) -                # Followed by one parameter 'Brightness' -            elif key == 'Brightness': -                if ':' in value: -                    red_brightnesses = [float(v) for v in value.split(':')] -                else: -                    red_brightness = float(value) -                # Neither version is followed by anything, notify and release -                released = True -            elif key == 'Status': -                red_status = value == 'Enabled' -                # Not followed by anything, notify and release -                released = True -            if released: -                red_condition.notify_all() -                red_condition.release() -        except: -            pass -    if released: -        red_condition.acquire() -    red_running = False -    red_condition.notify_all() -    red_condition.release() -    sock.shutdown(socket.SHUT_RDWR) - - -def broadcast_status(sock): -    ''' -    Broadcast status updates -     -    @param  sock:socket  The socket connected to the client -    ''' -    try: -        while True: -            broadcast_condition.acquire() -            try: -                broadcast_condition.wait() -                red_condition.acquire() -                try: -                    message = generate_status_message() -                    sock.sendall((message + '\n').encode('utf-8')) -                finally: -                    red_condition.release() -            finally: -                broadcast_condition.release() -    except: -        pass - - -def generate_status_message(): -    ''' -    Generate message to send to the client to inform about the status -     -    @return  :str  Status message -    ''' -    message =  'Current brightness: %f\n'  % red_brightness -    message += 'Daytime brightness: %f\n'  % red_brightnesses[0] -    message += 'Night brightness: %f\n'    % red_brightnesses[1] -    message += 'Current temperature: %f\n' % red_temperature -    message += 'Daytime temperature: %f\n' % red_temperatures[0] -    message += 'Night temperature: %f\n'   % red_temperatures[1] -    message += 'Dayness: %f\n'             % red_period -    message += 'Latitude: %f\n'            % red_location[0] -    message += 'Longitude: %f\n'           % red_location[1] -    message += 'Enabled: %s\n'             % ('yes' if red_status  else 'no') -    message += 'Running: %s\n'             % ('yes' if red_running else 'no') -    message += 'Dying: %s\n'               % ('yes' if red_dying   else 'no') -    message += 'Frozen: %s\n'              % ('yes' if red_frozen  else 'no') -    return message - - -def use_client(sock, proc): -    ''' -    Communication with client -     -    @param  sock:socket  The socket connected to the client -    @param  proc:Popen   The redshift process -    ''' -    global red_dying, red_frozen -    buf = '' -    closed = False -    while not closed: -        try: -            got = sock.recv(128).decode('utf-8', 'strict') -            if (got is None) or (len(got) == 0): -                break -        except: -            break -        buf += got -        while '\n' in buf: -            buf = buf.split('\n') -            message, buf = buf[0], '\n'.join(buf[1:]) -            if message == 'status': -                red_condition.acquire() -                try: -                    message = generate_status_message() -                    sock.sendall((message + '\n').encode('utf-8')) -                finally: -                    red_condition.release() -            elif message == 'toggle': -                if (not red_dying) and (not red_frozen): -                    proc.send_signal(signal.SIGUSR1) -            elif message == 'disable': -                if (not red_dying) and (not red_frozen): -                    if red_status: -                        proc.send_signal(signal.SIGUSR1) -            elif message == 'enable': -                if (not red_dying) and (not red_frozen): -                    if not red_status: -                        proc.send_signal(signal.SIGUSR1) -            elif message == 'freeze': -                broadcast_condition.acquire() -                try: -                    if not red_frozen: -                        red_frozen = True -                        proc.send_signal(signal.SIGTSTP) -                    broadcast_condition.notify_all() -                finally: -                    broadcast_condition.release() -            elif message == 'thaw': -                broadcast_condition.acquire() -                try: -                    if red_frozen: -                        red_frozen = False -                        proc.send_signal(signal.SIGCONT) -                    broadcast_condition.notify_all() -                finally: -                    broadcast_condition.release() -            elif message == 'kill': -                if red_frozen: -                    red_frozen = False -                    proc.send_signal(signal.SIGCONT) -                red_dying = True -                proc.terminate() -                import time -                time.sleep(0.05) # XXX sometimes redshift is too slow -            elif message == 'close': -                closed = True -            elif message == 'listen': -                def listen(): -                    while True: -                        red_condition.acquire() -                        try: -                            red_condition.wait() -                            message = generate_status_message() -                            sock.sendall((message + '\n').encode('utf-8')) -                        except: -                            break -                        finally: -                            red_condition.release() -                thread = threading.Thread(target = listen) -                thread.setDaemon(True) -                thread.start() -    sock.close() - - -def start_daemon_threads(proc, sock): -    ''' -    Start the threads for the daemon -     -    @param  sock:socket  The server socket -    @param  proc:Popen   The redshift process -    ''' -    pass - - -def run_as_daemon(sock): -    ''' -    Perform daemon logic -     -    @param  sock:socket  The server socket -    ''' -    global red_condition, broadcast_condition, red_pid -     -    # Create status conditions -    red_condition = threading.Condition() -    broadcast_condition = threading.Condition() -     -    # Start redshift -    command = ['redshift'] + red_opts -    if red_args is not None: -        command += red_args -    proc = Popen(command, stdout = PIPE, stderr = open(os.devnull)) -     -    start_daemon_threads(proc, sock) -     -    # Read status from redshift -    thread = threading.Thread(target = read_status, args = (proc, sock)) -    thread.setDaemon(True) -    thread.start() -     -    red_condition.acquire() -    broke = False -    while red_running: -        red_condition.release() -        try: -            (client_sock, _client_address) = sock.accept() -        except: -            broke = True -            break # We have shut down the socket so that accept halts -        client_thread = threading.Thread(target = use_client, args = (client_sock, proc)) -        client_thread.setDaemon(True) -        client_thread.start() -        # Broadcast status from redshift -        broadacast_thread = threading.Thread(target = broadcast_status, args = (client_sock,)) -        broadacast_thread.setDaemon(True) -        broadacast_thread.start() -        red_condition.acquire() -     -    if not broke: -        red_condition.release() -    thread.join() - - -def do_daemon(reexec): -    ''' -    Run actions for --daemon or ==daemon -     -    @param  reexec:bool  Wether to perform actions for ==daemon -    ''' -    if not reexec: -        if (kill > 0) or toggle or (set_status is not None) or (set_freeze is not None) or status: -            disallowed = '-x, +x, +e, +d, +f, +t and -s' -            print('%s: error: %s can be used when running as the daemon' % (disallowed, sys.argv[0])) -            sys.exit(1) -     -    # Create server socket -    try: -        os.unlink(socket_path) -    except: -        pass # The fill does (probably) not exist -    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -    sock.bind(socket_path) -    sock.listen(backlog) -     -    # Signal respawner -    if reexec: -        print() -        sys.stdout.close() -     -    # Perform daemon logic -    run_as_daemon(sock) -     -    # Close socket -    sock.close() - - -def not_running(): -    ''' -    Run actions for --status when the daemon is not running -    ''' -    print('Not running') - - -def do_status(): -    ''' -    Run actions for --status when the daemon is running -    ''' -    sock.sendall('status\n'.encode('utf-8')) -    buf = '' -    while True: -        got = sock.recv(1024) -        if (got is None) or (len(got) == 0): -            break -        buf += got.decode('utf-8', 'replace') -        if '\n\n' in buf: -            break -    buf = buf.split('\n\n')[0] + '\n' -    sys.stdout.buffer.write(buf.encode('utf-8')) -    sys.stdout.buffer.flush() - - -def do_toggle(): -    ''' -    Run actions for --toggle -    ''' -    sock.sendall('toggle\n'.encode('utf-8')) - - -def do_disable(): -    ''' -    Run actions for --disable -    ''' -    sock.sendall('disable\n'.encode('utf-8')) - - -def do_enable(): -    ''' -    Run actions for --enable -    ''' -    sock.sendall('enable\n'.encode('utf-8')) - - -def do_freeze(): -    ''' -    Run actions for --freeze -    ''' -    sock.sendall('freeze\n'.encode('utf-8')) - - -def do_thaw(): -    ''' -    Run actions for --thaw -    ''' -    sock.sendall('thaw\n'.encode('utf-8')) - - -def do_kill(): -    ''' -    Run actions for --kill -    ''' -    sock.sendall('kill\n'.encode('utf-8')) -    if kill > 1: -        sock.sendall('kill\n'.encode('utf-8')) - - -def create_daemon(): -    ''' -    Start daemon when it is required but is not running -    ''' -    ## Server is not running -    # Create pipe for interprocess signal -    (r_end, w_end) = os.pipe() -     -    # Duplicate process -    pid = os.fork() -     -    if pid == 0: -        ## Daemon (child) -        # Close stdin and stdout -        if ('DEBUG' not in os.environ) or (not os.environ['DEBUG'] == 'yes'): -            os.close(sys.stdin.fileno()) -            os.close(sys.stdout.fileno()) -         -        # Create server socket -        try: -            os.unlink(socket_path) -        except: -            pass # The fill does (probably) not exist -        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -        sock.bind(socket_path) -        sock.listen(backlog) -         -        # Send signal -        with os.fdopen(w_end, 'wb') as file: -            file.write(b'\n') -            file.flush() -         -        # Close the pipe -        os.close(r_end) -         -        # Perform daemon logic -        run_as_daemon(sock) -         -        # Close socket -        sock.close() -        # Close process -        sys.exit(0) -    else: -        ## Front-end (parent) -        # Wait for a signal -        rc = None -        with os.fdopen(r_end, 'rb') as file: -            file.read(1) -         -        # Close the pipe -        os.close(w_end) - - -def create_client(): -    ''' -    Create client socket and start daemon if not running -     -    @return  :socket  The client socket -    ''' -    # Create socket -    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -    try: -        # Connect to the server -        sock.connect(socket_path) -    except: -        # The process need separate sockets, lets close it -        # and let both process recreate it -        sock.close() -        sock = None -         -        if status: -            not_running() -            sys.exit(0) -     -    if sock is None: -        # Create daemon and wait for it to start listening for clients -        create_daemon() -         -        # Connect to the server -        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -        sock.connect(socket_path) -     -    return sock - - -def run_as_client(): -    ''' -    Perform client actions -    ''' -    # Temporarily disable or enable redshift -    if set_status is not None: -        if set_status: -            do_enable() -        else: -            do_disable() -    elif toggle: -        do_toggle() -     -    # Freeze or thaw redshift -    if set_freeze is not None: -        if set_freeze: -            do_freeze() -        else: -            do_thaw() -     -    # Kill redshift and the nightshift daemon -    if kill > 0: -        do_kill() -     -    # Get redshift status -    if status: -        do_status() -        sock.close() -     -    # Start user interface -    if (kill == 0) and not (status or toggle or (set_status is not None) or (set_freeze is not None)): -        sock.sendall('listen\n'.encode('utf-8')) -        user_interface() - - -def do_client(): -    ''' -    Do everything that has to do with being a client -    ''' -    global sock -    # Connect to client -    sock = create_client() -     -    # Perform client actions -    run_as_client() -     -    # Close socket -    try: -        sock.sendall('close\n'.encode('utf-8')) -    except: -        pass -    sock.close() - - -def respawn_daemon(): -    ''' -    Restart the nightshift daemon -    ''' -    global sock -     -    # Close old socket -    sock.close() -     -    ## Server is not running -    # Create pipe for interprocess signal -    (r_end, w_end) = os.pipe() -     -    # Duplicate process -    pid = os.fork() -     -    if pid == 0: -        ## Daemon (child) -        # Close stdin and stdout -        os.close(sys.stdin.fileno()) -        os.close(sys.stdout.fileno()) -         -        # Replace stdout with the pipe -        os.dup2(w_end, sys.stdout.fileno()) -        os.close(w_end) -         -        # Reexecute image -        exe = os.readlink('/proc/self/exe') -        os.execl(exe, exe, *(sys.argv + ['==daemon'])) -    else: -        ## Front-end (parent) -        # Wait for a signal -        rc = None -        with os.fdopen(r_end, 'rb') as file: -            file.read(1) -         -        # Close the pipe -        os.close(w_end) -         -        # Connect to the server -        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -        sock.connect(socket_path) - - -def run(): -    ''' -    Run as either the daemon (if --daemon or ==daemon) or as a client (otherwise) -    ''' -    if daemon > 0: -        do_daemon(daemon == 2) -    else: -        do_client() - - -g, l = globals(), dict(locals()) -for key in l: -    g[key] = l[key] - - -## Import interface.py with shared globals -# Get the Python version -v = sys.version_info -if (v.major > 3) or ((v.major == 3) and (v.minor >= 4)): -    # The (new) Python 3.4 way -    import importlib.util -    exec(importlib.util.find_spec('interface').loader.get_code('interface'), g) -else: -    # The deprecated legacy way -    import importlib -    exec(importlib.find_loader('interface').get_code('interface'), g) - - -## Load extension and configurations via nightshiftrc -# No configuration script has been selected explicitly, -# so select one automatically. -if config_file is None: -    # Possible auto-selected configuration scripts, -    # earlier ones have precedence, we can only select one. -    files = [] -    def add_files(var, *ps, multi = False): -        if var == '~': -            try: -                # Get the home (also known as initial) directory of the real user -                import pwd -                var = pwd.getpwuid(os.getuid()).pw_dir -            except: -                return -        else: -            # Resolve environment variable or use empty string if none is selected -            if (var is None) or (var in os.environ) and (not os.environ[var] == ''): -                var = '' if var is None else os.environ[var] -            else: -                return -        paths = [var] -        # Split environment variable value if it is a multi valeu variable -        if multi and os.pathsep in var: -            paths = [v for v in var.split(os.pathsep) if not v == ''] -        # Add files according to patterns -        for p in ps: -            p = p.replace('/', os.sep).replace('%', PROGRAM_NAME) -            for v in paths: -                files.append(v + p) -    add_files('XDG_CONFIG_HOME', '/%/%rc', '/%rc') -    add_files('HOME',            '/.config/%/%rc', '/.config/%rc', '/.%rc') -    add_files('~',               '/.config/%/%rc', '/.config/%rc', '/.%rc') -    add_files('XDG_CONFIG_DIRS', '/%rc', multi = True) -    add_files(None,              '/etc/%rc') -    for file in files: -        # If the file we exists, -        if os.path.exists(file): -            # select it, -            config_file = file -            # and stop trying files with lower precedence. -            break -# As the zeroth argument for the configuration script, -# add the configurion script file. Just like the zeroth -# command line argument is the invoked command. -conf_opts = [config_file] + conf_opts -if config_file is not None: -    code = None -    # Read configuration script file -    with open(config_file, 'rb') as script: -        code = script.read() -    # Decode configurion script file and add a line break -    # at the end to ensure that the last line is empty. -    # If it is not, we will get errors. -    code = code.decode('utf-8', 'strict') + '\n' -    # Compile the configuration script, -    code = compile(code, config_file, 'exec') -    # and run it, with it have the same -    # globals as this module, so that it can -    # not only use want we have defined, but -    # also redefine it for us. -    exec(code, g) - - -run() -  | 
