pax_global_header00006660000000000000000000000064135736661010014522gustar00rootroot0000000000000052 comment=4dffd5edd6f8e560e1b893667c246e1d1e516ddf cinnamon-screensaver-4.4.1/000077500000000000000000000000001357366610100156505ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/.circleci/000077500000000000000000000000001357366610100175035ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/.circleci/config.yml000066400000000000000000000040411357366610100214720ustar00rootroot00000000000000version: 2.0 shared: &shared steps: - checkout - run: name: Prepare environment command: apt-get update - run: name: Install dependencies command: | wget https://github.com/linuxmint/xapps/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O xapps.tar.gz wget https://github.com/linuxmint/cinnamon-desktop/releases/download/master.${CIRCLE_JOB}/packages.tar.gz -O cinnamon-desktop.tar.gz ls *.tar.gz | xargs -i tar zxvf {} apt install --yes --allow-downgrades ./packages/*.deb rm -rf packages - run: name: Build project command: mint-build -i - run: name: Prepare packages command: | if [ -z $CI_PULL_REQUEST ]; then mkdir /packages mv /root/*.deb /packages/ git log > /packages/git.log cd / tar zcvf packages.tar.gz packages fi - run: name: Deploy packages to Github command: | if [ -z $CI_PULL_REQUEST ]; then wget https://github.com/tcnksm/ghr/releases/download/v0.5.4/ghr_v0.5.4_linux_amd64.zip apt-get install --yes unzip unzip ghr_v0.5.4_linux_amd64.zip TAG="master".$CIRCLE_JOB ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -replace $TAG /packages.tar.gz ./ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME -recreate -b "Latest unstable packages" $TAG /packages.tar.gz fi jobs: "mint19": <<: *shared docker: - image: linuxmintd/mint19-amd64 "lmde3": <<: *shared docker: - image: linuxmintd/lmde3-amd64 workflows: version: 2 build: jobs: - "mint19" - "lmde3" cinnamon-screensaver-4.4.1/.github/000077500000000000000000000000001357366610100172105ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000004211357366610100217120ustar00rootroot00000000000000 ``` * Cinnamon-Screensaver version (cinnamon-screensaver --version) * Distribution - (Mint 17.2, Arch, Fedora 25, etc...) * Graphics hardware *and* driver used * 32 or 64 bit ``` **Issue** **Steps to reproduce** **Expected behaviour** **Other information** cinnamon-screensaver-4.4.1/.gitignore000066400000000000000000000015211357366610100176370ustar00rootroot00000000000000INSTALL Makefile Makefile.in aclocal.m4 autom4te.cache/ compile config.guess config.h config.h.in config.log config.status config.sub configure data/Makefile data/Makefile.in data/org.cinnamon.ScreenSaver.service files/Makefile install-sh intltool-extract.in intltool-merge.in intltool-update.in libtool ltmain.sh missing omf.make libcscreensaver/test-passwd po/.intltool-merge-cache po/Makefile po/Makefile.in po/POTFILES po/stamp-it po/cinnamon-screensaver.pot src/.deps/ src/Makefile src/Makefile.in src/config.py src/binfiles/cinnamon-screensaver src/binfiles/cinnamon-screensaver-command src/pamhelper/cinnamon-screensaver-pam-helper data/cinnamon-screensaver.desktop data/cinnamon-screensaver.desktop.in src/__pycache__ stamp-h1 xmldocs.make *.Plo *.lo *.o *.la *proxy.c *proxy.h *.gir *.typelib *.pc .libs debian/files m4 depcomp py-compile cinnamon-screensaver-4.4.1/AUTHORS000066400000000000000000000000511357366610100167140ustar00rootroot00000000000000Michael Webster cinnamon-screensaver-4.4.1/COPYING000066400000000000000000000431131357366610100167050ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street - Suite 500, Boston, MA, 02110-1335, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA, 02110-1335, USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. cinnamon-screensaver-4.4.1/COPYING.LIB000066400000000000000000000613021357366610100173120ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street - Suite 500, Boston, MA, 02110-1335, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Library 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA, 02110-1335, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cinnamon-screensaver-4.4.1/ChangeLog000066400000000000000000000000001357366610100174100ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/HACKING000066400000000000000000000006211357366610100166360ustar00rootroot00000000000000HACKING ======= Cinnamon-Screensaver is normally build using dpkg. If using Linux Mint, Ubuntu, or any other member of the Debian family, install the `devscripts` package with `sudo apt-get install devscripts`. Once you have devscripts, run `debuild -us -uc` to build cinnamon-screensaver (or any other cinnamon package) and `sudo dpkg -i ../cinnamon-screensaver_{version}_{arch}.deb` to install. cinnamon-screensaver-4.4.1/Makefile.am000066400000000000000000000016651357366610100177140ustar00rootroot00000000000000# This file will be processed with automake-1.7 to create Makefile.in srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ AUTOMAKE_OPTIONS = 1.7 DISTCHECK_CONFIGURE_FLAGS = --enable-introspection NULL = SUBDIRS = \ libcscreensaver \ src \ po \ data \ files \ $(NULL) EXTRA_DIST = \ COPYING \ COPYING.LIB \ AUTHORS \ INSTALL \ README \ ChangeLog \ NEWS \ HACKING \ intltool-extract.in \ intltool-merge.in \ intltool-update.in \ $(NULL) DISTCLEANFILES = \ intltool-extract \ intltool-merge \ intltool-update \ ./po/.intltool-merge-cache \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ intltool-*.in \ compile \ configure \ INSTALL \ install-sh \ missing \ mkinstalldirs \ config.guess \ ltmain.sh \ config.sub \ depcomp \ Makefile.in \ config.h.* \ aclocal.m4 \ acinclude.m4 \ $(NULL) -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/NEWS000066400000000000000000001314151357366610100163540ustar00rootroot00000000000000============== Version 3.4.1 ============== - Drop num lock warning - Translation updates (Greek, Marathi, Hindi, Aragonese) ============== Version 3.4.0 ============== - Translations updates (crh) ============== Version 3.3.92 ============== - Fix fade when explicitly locking screen - Translations updates (ko) ============== Version 3.2.2 ============== - Fix --with-systemd=auto configure option - Stop using deprecated GTK+ API - Fix misleading debug messages referring to ConsoleKit - Fix a compile warning when compiled with systemd - Use correct signature for GetActiveTime D-Bus API - Translation updates (Xhosa) - Properly turn off caps lock warning ============== Version 3.2.1 ============== - Optionally use systemd instead of ConsoleKit - Always lock when asked - Fade out quickly on explicit locks - Allow arbitrary long idle times - Fix background scaling on multi-monitor setups - Implement OpenBSD authentication - Translation updates (Burmese, Czech, Norwegian bokmål) ============== Version 3.2.0 ============== - Translation updates (Gujarati, Telugu, Assamese, Lithuanian, Irish) =============== Version 3.1.92 =============== - Use maintainer mode by default - Fix the clock to actually update every minute - Translation updates (Japanese) =============== Version 3.1.91 =============== - Use GnomeWallClock to keep informed about time and timezone changes =============== Version 3.1.90 =============== - Properly set background to black when cancelling unlock - Drop the .pc file ============== Version 3.1.5 ============== - Add back keyboard layout indicator - Detect clock skew when resuming or ntp runs and compensate - Fix crash in user switcher - Drop libgnome-menu dependency - Translation updates (Finnish, Thai, Polish, Turkish, Czech, Esperanto, Belarusian, Catalan (Valencian), Persian) ============== Version 3.0.0 ============== - Remove inihibit APIs from the documentation - Translation updates (Russian, Bulgarian, Vietnamese, Punjabi, Uighur, Brazilian Portuguese, Latvian, Simplified Chinese, Traditional Chinese, Basque, Japanese, Danish, Tamil, Czech, Dutch, Catalan, Bengali) ================ Version 2.91.92 ================ - Store time values in seconds instead of minutes - Don't monitor session settings - Ensure the initial state of the clock is correct - Remove dbus activation - Remove daemonization - Request shell exit overview when locking - Translation updates ((Polish, Vietnamese, Brazilian Portuguese, Arabic, Dutch, Romanian, Africaans, Hungarian, Estonian, Slovenian, Portuguese, Hebrew, Norwegian bokmål, British English, German, Ukrainian, Swedish, Catalan, Serbian, Korean, French, Indonesian, Assamese) ================ Version 2.91.91 ================ - Follow the users clock format preference - Port to GDBus - Build cleanups - Remove --poke option from the commandline tool (didn't work anyway) - Remove unused delay and timeout preferences - Remove inhibit interface (inhibit the session instead) - Remove theme and job support - Update style to match gnome-shell - Use accountsservice to get face - Translation updates (Korean, Simplified Chinese, Norwegian bokmål, Latvian Oriya, Ukrainian, Russian) =============== Version 2.91.90 =============== - Use username in top panel if real name is empty - Various settings fixes - Translation updates =============== Version 2.91.4 =============== - Fix build against recent GTK+ - GNOME 3 style updates - Translation updates =============== Version 2.91.3 =============== - Fix build against recent GTK+ - Use GIO to launch gdmflexiserver - Translation updates =============== Version 2.91.2 =============== - Fix build against recent GTK+ - Port to GSettings =============== Version 2.91.1 =============== - Fix build against recent GTK+ and gnome-desktop - Port background handling to gsettings - Translation updates =============== Version 2.91.0 =============== - Switch to GTK+ 3.0 - Fix crash on systems that lack vidmode and randr extensions - Add session service activation file - Use better unicode symbols in strings - Drop "Leave a message" feature - Drop unlock dialog theme support - Drop support for non-PAM based authentication - Improve aesthetics of unlock dialog - Monitor hotplug fixes - Auto-activate screensaver when needed if not running - Translation updates =============== Version 2.30.0 =============== Translation updates =============== Version 2.29.92 =============== Fixed bugs: - Build fix for systems with x11 < 1.3 =============== Version 2.29.91 =============== Fixed bugs: - #609789 - CVE-2010-0422, handle monitor hotplugging more securely - Fix screen dirt in floaters screensaver =============== Version 2.29.90 =============== Fixed bugs: - #609337, CVE-2010-0414, handle monitor removal more securely =============== Version 2.29.1 =============== Fixed bugs: - #597874, Use xrandr 1.2 gamma fading - RH bug #546656, Fix crash in popsquares - #598476, Don't crash when lock dialog dies during shake - #593616, Fix multi-head issues - #600488, Remove session inhibitors if the originator falls of the bus =============== Version 2.28.0 =============== Fixed bugs: - #444927, get idle time from xorg - #463010, Port cinnamon-screensaver from libglade to gtkbuilder - #564061, Install .desktop file - #570402, screensaver crash if number of screens changes - #570941, String not marked for translation cinnamon-screensaver-command.c - #574896, [Leave message] Cancel button should clean clipboard buffe - #576463, can't unlock screen after upgrade until restarting gnome- screensaver - #581995, Fade out doesn't properly fall back to gamma number if X server only supports 0-size ramp - #586174, Encoding key in desktop files is deprecated - #589728, cinnamon-screensaver: implicit declaration g_printf - #590776, screensaver is never activated - #591193, Update/Create .gitignore - #591194, Add Comment and Icon in cinnamon-screensaver.desktop - #594082, cinnamon-screensaver ignores input when fading to black Translators: - Khaled Hosny (ar) - Amitakhya Phukan (as) - Alexander Shopov (bg) - Runa Bhattacharjee (bn_IN) - Jamil Ahmed (bn) - Denis ARNAUD (br) - Carles Ferrando (ca@valencia) - Petr Kovar (cz) - Ask H. Larsen (da) - Mario Blättermann, Christian Kirbach (de) - Philip Withnall (en_GB) - Jorge González (es) - Ivar Smolin, Mattias Põldaru (et) - Inaki Larranaga Murgoitio (eu) - Tommi Vainikainen (fi) - Claude Paroz (fr) - Seán de Búrca (ga) - Antón Méixome (gl) - Sweta Kothari (gu) - Yaron Shahrabani (he) - Rajesh Ranjan (hi) - Gabor Kelemen (hu) - Luca Ferretti (it) - Shankar Prasad (kn) - Changwoo Ryu (ko) - Gintautas Miliauskas (lt) - Rajesh Ranjan (mai) - Ani (ml) - Sandeep Shedmake (mr) - Kjartan Maraas (nb) - Niels-Christoph Fiedler (nds) - Manoj Kumar Giri (or) - A S Alam (pa) - Tomasz Dominikowski (pl) - Rodrigo L. M. Flores, Krix Apolinário (pt_BR) - Duarte Loreto (pt) - Lucian Adrian Grijincu (ro) - Matej Urbančič (sl) - Miloš Popović (sr@latin) - Miloš Popović (sr) - Daniel Nylander (sv) - ifelix (ta) - krishnababu k (te) - Theppitak Karoonboonyanan (th) - Maxim V. Dziumanenko (uk) - Chao-Hsiung Liao (zh_HK) - Chao-Hsiung Liao (zh_TW) =============== Version 2.27.0 =============== - Add an autostart file for cinnamon-screensaver (#585485) Updated Translations: Telugu, Catalan, zh_CN, Crimean Tatar =============== Version 2.26.1 =============== - Fixed #572955, audit GError usage (William Jon McCann) - Fixed #572956, use g_strerror (William Jon McCann) - Fixed #573495, logout_command setting may be overwritten with keyboard_command value (William Jon McCann) - Fixed #577739, cinnamon-screensaver-gl-helper calls gdk_x11_visual_get_xvisual with NULL visual (William Jon McCann) - Fixed #578669, Screenserver (William Jon McCann) Translations: - Updated crh: Reşat SABIQ - Updated ja: Takeshi AIHANA - Updated kn: Shankar Prasad =============== Version 2.26.0 =============== - Remove power notice signal - Rely on GNOME session idle detection - Proxy g-s inhibitors over to the session - Read status message from session - Accept a full path for theme (Matthias Clasen) =============== Version 2.25.2 =============== - Fix pixmap leak (Matthias Clasen) - Fix dialog border width =============== Version 2.25.1 =============== - Add bevel around dialog - Fixed #444927, get idle time from xorg - Fixed #492949, screensavers-personal-slideshow should not show hidden directories (Jörg) - Fixed #530561, "Random" preview is always the last saver (Maxim Ermilov) - Fixed #561855, Calls wrong slideshow binary if there is one installed in $PATH (Frederic Crozat) Translations: None =============== Version 2.24.1 =============== - Fixed #555701, libgnome-desktop:gnome_bg_create_pixmap() leaks pixmaps and X clients (Scott Remnant) - Fixed #451498, Preview of "Blank screen" is not consistent (Neil Patel) - Fixed #552119, Add GTK and GNOME to screensaver desktop (William Jon McCann) - Fixed #552523, Screensaver suddenly stopped working (William Jon McCann) - Fixed #555254, cinnamon-screensaver-dialog NULL pointer crash (William Jon McCann) - Fixed #555491, cinnamon-screensaver should release mouse/keyboard when failed to grab both of them (Joey Yu Zheng) - Fixed #560456, Cleaning up GTK Includes in cinnamon-screensaver (Maxim Ermilov) Translations: - Updated ar: Djihed Afifi - Updated ast: Andre Klapper, Astur - Updated be@latin: Ihar Hračyška, Ihar Hrachyshka - Updated pt_BR: Leonardo Ferreira Fontenelle, Vladimir Melo =============== Version 2.24.0 =============== - Updated LINGUAS, sr@latin.po, sr@Latn: Arangel Angov - Updated ar: Djihed Afifi, Khaled Hosny - Updated bg: Alexander Shopov - Updated bn_IN: Runa Bhattacharjee - Updated ca: Gil Forcada - Updated da: Kenneth Nielsen - Updated de: Hendrik Richter - Updated dz: Pema Geyleg, Dawa pemo - Updated en_GB: Philip Withnall, David Lodge - Updated et: Ivar Smolin - Updated fr: Claude Paroz - Updated ga: Seán de Búrca - Updated hr: Robert Sedak, Ante Karamatić - Updated hu: Gabor Kelemen - Updated it: Luca Ferretti - Updated kn: Shankar Prasad - Updated ko: Changwoo Ryu - Updated mk: Arangel Angov, Clytie Siddall - Updated ml: Praveen Arimbrathodiyil, പ്രവീണ്‍ അരിമ്പ്രത്തൊടിയില്‍ - Updated mr: Sandeep Shedmake - Updated nl: Wouter Bolsterlee - Updated pl: Wadim Dziedzic, wadim dziedzic - Updated pt_BR: Vladimir Melo - Updated ro: Mugurel Tudor, Mișu Moldovan - Updated sr.po, sr@latin: Goran Rakić - Updated ta: I. Felix - Updated tr: Baris Cicek =============== Version 2.23.90 =============== - use standard icon names (Matthias Clasen) - Paint widget background color as face background color. - Add/remove windows as necessary in response to RANDR 1.2 events - Honor the disable_user_switching lockdown key. - Fixed #547013, The dialog incorrectly tell that the numlock is on (William Jon McCann) Translations: - Updated LINGUAS, sr@latin.po, sr@Latn: Goran Rakic - Updated ar: Khaled Hosny - Updated cs: Petr Kovar - Updated eu: Inaki Larranaga Murgoitio, Iñaki Larrañaga Murgoitio - Updated fi: Ilkka Tuohela, Timo Jyrinki - Updated gu: Daniel Nylander, Sweta Kothari - Updated he: Yair Hershkovitz , Yaniv Abir - Updated ja: Takeshi AIHANA - Updated lt: Gintautas Miliauskas - Updated pt: Duarte Loreto - Updated pt_BR: Vladimir Melo - Updated sv: Daniel Nylander Help Manual Translations: None =============== Version 2.23.3 =============== * Fix build issue (Wouter Bolsterlee) * Add a simple frame around user icon * Add a new child widget to use for themes to draw on =============== Version 2.23.2 =============== * Fix gamma lost during fade * Show default desktop background behind lock dialog * Add reporting of inhibitors to --query command =============== Version 2.22.2 =============== * Add a 160 char limit to the message text box. =============== Version 2.22.1 =============== * Fix for bug 525785 – CVE-2008-0887 =============== Version 2.22.0 =============== Translators - Updated oc: Yannig Marchegay - Updated ca: Gil Forcada - Updated eu: Inaki Larranaga Murgoitio, Djihed Afifi - Updated as: Amitakhya Phukan - Updated ar: Artur Flinta, Djihed Afifi - Updated cs: Petr Kovar, Clytie Siddall - Updated et: Priit Laes - Updated bn_IN: Runa Bhattacharjee - Updated nl: Wouter Bolsterlee - Updated pt: Duarte Loreto - Updated nb: Kjartan Maraas - Updated tr: Baris Cicek - Updated ne: Pawan Chitrakar - Updated lt: Gintautas Miliauskas - Updated th: Theppitak Karoonboonyanan - Updated zh_TW: Taiwan - Updated en_GB: Philip Withnall - Updated be: Alexander Nyakhaychyk - Updated fr: Claude Paroz - Updated zh_HK: Hong Kong - Updated pt_BR: Leonardo Ferreira Fontenelle - Updated de: Andre Klapper - Updated hu: Gabor Kelemen - Updated fi: bug #518255, Ilkka Tuohela - Updated da: Kenneth Nielsen - Updated ja: Takeshi AIHANA - Updated he: Yair Hershkovitz - Updated be@latin: Ihar Hrachyshka - Updated ko: Changwoo Ryu - Updated sv: Daniel Nylander - Updated mk: Arangel Angov, Ignacio Casal Quinteiro , Clytie Siddall - Updated sk: Marcel Telka - Updated pl: Artur Flinta - Updated uk: Maxim Dziumanenko - Updated mr: Rahul Bhalerao, mr =============== Version 2.21.6 =============== * New theme transfer progress dialog. (John Millikin) * Migrate gnome-vfs to GIO (John Millikin) * Set default action after cancelling note. =============== Version 2.20.0 =============== cinnamon-screensaver * Fixed #442853, Unlock dialog shows Switch User button when /apps/cinnamon-screensaver/user_switch_enabled is false (William Jon McCann) Translators * Updated el: Nikos Charonitakis * Updated vi: Clytie Siddall * Updated ca: Gil Forcada * Updated it: Luca Ferretti * Updated ar: Djihed Afifi * Updated et: Priit Laes * Updated ru: Nickolay V. Shmyrev * Updated nl: Wouter Bolsterlee * Updated pt: Duarte Loreto * Updated nb: Kjartan Maraas * Updated tr: Baris Cicek * Updated lt: Gintautas Miliauskas * Updated ro: Mugurel Tudor * Updated ta: I. Felix * Updated fr: Stéphane Raimbault * Updated da: Kenneth Nielsen * Updated hu: Gabor Kelemen * Updated ja: Takeshi AIHANA * Updated ml: Ani Peter * Updated mk: Jovan Naumovski + * Updated sk: Andre Klapper * Updated si: Danishka Navin * Updated uk: Maxim Dziumanenko =============== Version 2.19.7 =============== cinnamon-screensaver * Fixed #437225, Solaris needs additional libs linked with to build (William Jon McCann) * Fixed #463754, remove last dep on libgnome (Jani Monoses) * Initialize XWindowAttributes (Rodrigo Moya) * Improvements to slideshow (Frederic Crozat) Translators * Updated gu: Ankit Patel * Updated be@latin: Ihar Hrachyshka * Updated pt_BR: Leonardo Ferreira Fontenelle * Updated ml: Ani Peter * Updated de: Hendrik Richter * Updated ko: Changwoo Ryu * Updated sv: Daniel Nylander * Updated es: Jorge Gonzalez * Updated th: Theppitak Karoonboonyanan * Updated fi: Ilkka Tuohela * Updated eu: Inaki Larranaga Murgoitio * Updated et: Priit Laes * Updated te: Sunil Mohan Adapa * Updated ja: Takeshi AIHANA * Updated pl: Artur Flinta =============== Version 2.19.6 =============== cinnamon-screensaver * Fixed #327602, cinnamon-screensaver never propagates the environment to its helper dialog (William Jon McCann) * Fixed #456705, useless message on stdout (Bill Nottingham) * Fixed #461028, console-kit ActiveChanged (VC switch) does not trigger unlock request (Ian Jackson) * Fixed #461722, Add support to disable slideshow randomization (Frederic Crozat) * Fixed #461814, Allow to specify background color for image slideshow (Frederic Crozat) * Fixed #461824, remove libexif dependency (Frederic Crozat) Translators * Updated mn: Djihed Afifi * Updated nl: Wouter Bolsterlee * Updated be@latin: Ihar Hrachyshka * Updated vi: Nguyễn Thái Ngọc Duy, Clytie Siddall * Updated nb: Kjartan Maraas * Updated de: Andre Klapper * Updated sv: Daniel Nylander * Updated mk: Daniel Nylander * Updated hu: Gabor Kelemen * Updated lv: Daniel Nylander, Djihed Afifi * Updated si: I. Felix, si * Updated en_GB: David Lodge * Updated dz: Pema Geyleg * Updated pl: Artur Flinta * Updated th: Theppitak Karoonboonyanan * Updated fi: Ilkka Tuohela * Updated et: Priit Laes * Updated ja: Takeshi AIHANA * Updated es: Jorge Gonzalez * Updated ta: I. Felix, I Felix =============== Version 2.19.5 =============== cinnamon-screensaver * Fixed #331515, No translation for themes in command line help (William Jon McCann) * Fixed #354663, lock dialog not visible when using nvidia clone (William Jon McCann) * Fixed #434712, cinnamon-screensaver crashes without dbus system bus (William Jon McCann) * Fixed #436818, replace gnome_help_display (William Jon McCann) * Fixed #445443, Screensaver deactivation is not correct (William Jon McCann) Translators * Updated be@latin: Ihar Hrachyshka * Updated vi: Nguyễn Thái Ngọc Duy, Clytie Siddall * Updated nb: Kjartan Maraas * Updated sv: Daniel Nylander * Updated lv: Daniel Nylander * Updated si: I. Felix, si * Updated en_GB: David Lodge * Updated dz: Pema Geyleg * Updated es: Jorge Gonzalez * Updated th: Theppitak Karoonboonyanan * Updated et: Priit Laes * Updated pl: Artur Flinta * Updated ta: I Felix =============== Version 2.19.1 =============== cinnamon-screensaver * Fixed #384509, cinnamon-screensaver could allow users to leave notes when screen is locked (William Jon McCann) * Fixed #411252, Use xdg-user-dirs to find pictures directory (William Jon McCann) * Fixed #428199, Make fast-user-switching work with gdm configurations involving multiple X servers (William Jon McCann) =============== Version 2.18.1 =============== cinnamon-screensaver * Fixed #424165, power management button should reflect g-p-m status (William Jon McCann) * Fixed #425550, cinnamon-screensaver should probably require mouse grab to lock (Ray Strode) Translators * Updated zh_CN: Funda Wang * Updated ca: Josep Puigdemont i Casamajó * Updated da: Peter Bach * Updated lv: Raivis Dejus * Updated sl: Matic Zgur * Updated eu: Inaki Larranaga Murgoitio * Updated gl: Ignacio Casal Quinteiro =============== Version 2.18.0 =============== cinnamon-screensaver * Fixed #412486, cinnamon-screensaver doesn't work with xnest (William Lachance) * Fixed #412492, cinnamon-screensaver won't build * Fixed #417323, build from trunk fails; undefined reference to pango symbols (Elijah Newren) * Fixed #417538, unapproved change broke theme management (William Jon McCann) Translators * Updated ru: Nickolay V. Shmyrev * Updated gu: Ankit Patel * Updated zh_HK.po, zh_TW: Abel Cheung * Updated it: Luca Ferretti * Updated mk: Jovan Naumovski + * Updated lt: Gintautas Miliauskas * Updated ar: Djihed Afifi * Updated dz: Pema Geyleg * Updated pl: Artur Flinta * Updated he: Yair Hershkovitz =============== Version 2.17.8 =============== cinnamon-screensaver * Fixed #400579, cinnamon-screensaver fails to compile against openpam (Ray Strode) * Fixed #407524, Freeze on unlock screen (William Jon McCann) * Fixed #407964, direct fast user switching (William Jon McCann) * Fixed #411393, 'switch user' button needs to turn inactive on selection (William Jon McCann) * Set ConsoleKit idle-hint state Translators * Updated bg: Alexander Shopov * Updated pt: Duarte Loreto * Updated ko: Changwoo Ryu * Updated hu: Gabor Kelemen * Updated lt: Gintautas Miliauskas * Updated uk: Maxim Dziumanenko * Updated fi: Ilkka Tuohela * Updated ja: Takeshi AIHANA * Updated pl: Artur Flinta =============== Version 2.17.7 =============== cinnamon-screensaver * #402183, use gdm socket command to start a login procedure when available (Matthias Clasen) * #403936, Specifically block shaping the window (William Jon McCann) * Sync FUSA code with upstream Translators * Updated fr: Stéphane Raimbault * Updated nl: Wouter Bolsterlee * Updated ca: Josep Puigdemont i Casamajó * Updated pt_BR: Leonardo Ferreira Fontenelle * Updated da: Lasse Bang Mikkelsen =============== Version 2.17.6 =============== cinnamon-screensaver * Categorize preferences for the control center (Denis Washington) Translators * Updated nb: Kjartan Maraas * Updated ca: Josep Puigdemont i Casamajó =============== Version 2.17.5 =============== cinnamon-screensaver * Fix some PAM threading issues * Fixed #387572, auth hangs when password is expired * Fixed #392780, Pass DBUS_SESSION_BUS_ADDRESS into hack environment Translators * Updated lv: Raivis Dejus * Updated et: Priit Laes * Updated ar: Djihed Afifi * Updated en_GB: British * Updated vi: Clytie Siddall =============== Version 2.17.4 =============== cinnamon-screensaver * Fix non-ramp gamma fading * Add script to help debugging * Be sure to initialize threading Themes * (slideshow) Check for empty file list Translators * Khaled Hosny (ar) * Francisco Javier F. Serrador (es) * Kjartan Maraas (nb) * Theppitak Karoonboonyanan (th) =============== Version 2.17.3 =============== cinnamon-screensaver * Convert PAM messages to UTF-8 (Ray Strode) * Make PAM authentication async (Ray Strode) Translators * Ivar Smolin (et) * Daniel Nylander (sv) =============== Version 2.17.2 =============== cinnamon-screensaver * Remove the pointer polling * Add a keyboard layout indicator (Sergey Udaltsov) * Only notice mouse motion of 10% of screen width (Thomas Andersen) * Add SessionPowerManagementIdleChanged D-Bus signal * Add GetInhibitors D-Bus method cinnamon-screensaver-preferences * Add a button to launch the power management preferences cinnamon-screensaver-command * Add option to how long screensaver was active (Patrick McLean) Translators * Francisco Javier F. Serrador (es) * Ivar Smolin (et) * Ilkka Tuohela (fi) * Ankit Patel (gu) * Jovan Naumovski (mk) * Kjartan Maraas (nb) =============== Version 2.17.1 =============== cinnamon-screensaver * Don't poll in dialog cinnamon-screensaver-preferences * Don't show expander column Translators * Gil Forcada (ca) * Jakub Friedl (cs) * Ivar Smolin (et) * Ignacio Casal Quinteiro (gl) =============== Version 2.16.1 =============== cinnamon-screensaver * Set the correct value of DISPLAY for the gl helper * Don't queue keys that may cause focus navigation (Bruno Boaventura) cinnamon-screensaver-preferences * Don't explicitly set icon sizes in preview bar (Dimitur Kirov) Translators * David Lodge (en_GB) * Ivar Smolin (et) * Rajesh Ranjan (hi) * Luca Ferretti (it) * Satoru SATOH (ja) * Leonardo Ferreira Fontenelle (pt_BR) =============== Version 2.16.0 =============== Translators * Kostas Papadimas (el) * Iñaki Larrañaga Murgoitio (eu) * Meelad Zakaria (fa) * Robert-André Mauchin (fr) * Rajesh Ranjan (hi) * Gabor Kelemen (hu) * Gintautas Miliauskas (lt) * Raivis Dejus (lv) * Jovan Naumovski (mk) * Subhransu Behera (or) * Duarte Loreto (pt) * Matic %GŽ%@gur (sl) * Theppitak Karoonboonyanan (th) * Deniz Koçak (tr) * Ching-Hung Lin (zh_HK) * Ching-Hung Lin (zh_TW) =============== Version 2.15.7 =============== Translators * Rostislav \"zbrox\" Raykov (bg) * Gil Forcada (ca) * Hendrik Richter (de) * Ivar Smolin (et) * Ilkka Tuohela (fi) * Ankit Patel (gu) * Gabor Kelemen (hu) * Satoru SATOH (ja) * Vladimer Sichinava (ka) * Changwoo Ryu (ko) * rizoye-xerzi (ku) * Ani Peter (ml) * Badral (mn) * Wouter Bolsterlee (nl) * Subhransu Behera (or) * Leonid Kanter (ru) * Daniel Nylander (sv) * Maxim V. Dziumanenko (uk) * Clytie Siddall (vi) =============== Version 2.15.6 =============== cinnamon-screensaver * Support drag-n-drop of themes to preferences dialog * Add support for embedding a keyboard in window * More memory usage reduction * Only allow a small number of queued key events Translators * Francisco Javier F. Serrador (es) * Ivar Smolin (et) * Ilkka Tuohela (fi) * Christophe Merlet (RedFox) (fr) * Ankit Patel (gu) * ahmad riza h nst (id) * %GŽ%@ygimantas Beru%Gč%@ka (lt) * Jovan Naumovski (mk) * Kjartan Maraas (nb) * Matic %GŽ%@gur (sl) * Theppitak Karoonboonyanan (th) =============== Version 2.15.5 =============== cinnamon-screensaver * Turn off themes when screen is not visible * Make the unlock dialog show on correct window under Xinerama * Prevent theme flickering from watchdog timer * Listen for HAL coffee key events * Ignore brightness key events cinnamon-screensaver-preferences * Populate themes list in an idle after startup Translators * Mahay Alam Khan (bn_IN) * Gil Forcada (ca) * Jakub Friedl (cs) * Hendrik Richter (de) * Kostas Papadimas (el) * Francisco Javier F. Serrador (es) * Priit Laes (et) * Ankit Patel (gu) * Rajesh Ranjan (hi) * Changwoo Ryu (ko) * Fano Rajaonarisoa (mg) * Daniel Nylander (sv) * Theppitak Karoonboonyanan (th) =============== Version 2.15.4 =============== cinnamon-screensaver * Override gtk+ theme background style * Use helper command to get best GL visual * Add a blocking inhibit option to the command-line tool * Add short options to the command-line tool * Misc memory reduction Translators * Rostislav \"zbrox\" Raykov (bg) * Mahay Alam Khan (bn_IN) * Jakub Friedl (cs) * Hendrik Richter (de) * Francisco Javier F. Serrador (es) * Ilkka Tuohela (fi) * Robert-André Mauchin (fr) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Yaniv Abir (he) * Rajesh Ranjan (hi) * Raivis Dejus (lv) * Jovan Naumovski (mk) * Kjartan Maraas (nb) * Shyam Krishna Bal (ne) * Daniel Nylander (sv) * Felix (ta) * Theppitak Karoonboonyanan (th) =============== Version 2.15.3 =============== cinnamon-screensaver * Fully support PAM driving the unlock dialog * Only support one auth backend configured at build time * Don't try to unlock using root's password * DBUS API changes based on XDG feedback * Add docbook documentation (Richard Hughes) * Use replacable tokens in the lock dialog theme glade file * Set lock flag before activating (Rodrigo Moya) * Fix support for RUNNING_UNDER_GDM environment variable * Increase minimum distance the mouse must move to detect motion * Add theme engine profiling support * Switch user when double clicking in treeview * Don't reset throttle when deactivating * Try to grab keyboard before doing idle notice fade-out * Make activation wait for fade to complete. cinnamon-screensaver-preferences * Print a warning that locking is disabled when running as root Themes * (slideshow) Performance improvements (L. David Baron) Translators * Jakub Friedl (cs) * Francisco Javier F. Serrador (es) * Ankit Patel (gu) * Kjartan Maraas (nb) * Theppitak Karoonboonyanan (th) * Clytie Siddall (vi) =============== Version 2.15.2 =============== cinnamon-screensaver * Sync with FUSA code (fixes GDM configuration) * Make cancel close the unlock dialog * Make button presses and scroll events request an unlock * Send DBUS signals before/after authentication is requested * Various fixes for async fade out * Fix potential crasher when poked while fading * Support short username in themed dialog (Matthias Clasen) Themes * (popsquares) Fix crash when window is NULL (Joe Marcus Clarke) Translators * Francisco Javier F. Serrador (es) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Kjartan Maraas (nb) * Chao-Hsiung Liao (zh_HK) * Chao-Hsiung Liao (zh_TW) =============== Version 2.15.1 =============== cinnamon-screensaver * Add support for theming the lock dialog * Use OpenGL to get the best visual and use it * Shorten mouse poll interval * New DBUS API for throttle and inhibit * Support themes in all XDG dirs (including $HOME) * Make caps-lock warning more accurate cinnamon-screensaver-preferences * Add fullscreen preview * Update wording Translators * Priit Laes (et) * Ilkka Tuohela (fi) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Clytie Siddall (vi) =============== Version 2.14.1 =============== cinnamon-screensaver * Detect button press activity (Ray Strode) * Make operation after system suspend (Ray Strode) * Cygwin build fix * Use GTimer for portability * Obtain new Kerberos credentials when unlocking screen Themes * (floaters) Use the entire screen at start Translators * Lukas Novotny (cs) * Ivar Smolin (et) * Benoît Dejean (fr) * Wouter Bolsterlee (nl) * Andrzej PolatyÅski (pl) * Theppitak Karoonboonyanan (th) * Clytie Siddall (vi) =============== Version 2.14.0 =============== cinnamon-screensaver * Removed unused GConf keys from schemas * Don't queue keypad enter keypresses * Use black circle as invisible character in password entry Translators * Rostislav \"zbrox\" Raykov (bg) * Mahay Alam Khan (bn) * Gil Forcada (ca) * Petr TomeÅ¡ (cs) * Rhys Jones (cy) * David Nielsen (da) * Frank Arnold (de) * Ivar Smolin (et) * Rajesh Ranjan (hi) * Luca Ferretti (it) * Young-Ho Cha (ko) * Kjartan Maraas (nb) * Kjartan Maraas (no) * Raphael Higino (pt_BR) * Duarte Loreto (pt) * Laurent Dhima (sq) * Daniel Nylander (sv) * Maxim V. Dziumanenko (uk) =============== Version 2.13.92 =============== cinnamon-screensaver * Fix problems when some other program has keyboard grabbed * Add a pkg-config file for out of tree themes * Use a black bullet character instead of * for password entry * Capitalize DBUS method names that weren't already cinnamon-screensaver-preferences * Track gconf key changes for themes Translators * Kostas Papadimas (el) * Francisco Javier F. Serrador (es) * Ilkka Tuohela (fi) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Gabor Kelemen (hu) * Luca Ferretti (it) * Satoru SATOH (ja) * Vladimer SIchinava (ka) * Hyun-Jin Moon (ko) * Žygimantas BeruÄka (lt) * Kjartan Maraas (nb) * Tino Meinen (nl) * Kjartan Maraas (no) * Raphael Higino (pt_BR) * Leonid Kanter (ru) * Theppitak Karoonboonyanan (th) * Clytie Siddall (vi) =============== Version 2.13.91 =============== cinnamon-screensaver * Maintain a pointer grab unless the unlock dialog is up * Convert the real and user names to UTF8 * Use G_GUINT32_FORMAT for communicating XID * Start themes after grabbing window * Handle broken grabs * Don't abort when fade isn't available * Display host name in unlock dialog cinnamon-screensaver-preferences * Add help * Don't make heading bold or indent under it Themes * (floaters) More performance work (Ray Strode) Translators * Gil Forcada (ca) * Lukas Novotny (cs) * Žygimantas BeruÄka (lt) * Ãivind Hoel (nb) =============== Version 2.13.90 =============== cinnamon-screensaver * Ignore our windows when watching for map and configure events * Clear window after showing to prevent flashing * Don't start child processes in home directory themes * (floaters) Cap update rate (Ray Strode) Translators * Rostislav \"zbrox\" Raykov (bg) * Hendrik Brandt (de) * Ilkka Tuohela (fi) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Tino Meinen (nl) * Theppitak Karoonboonyanan (th) * Chao-Hsiung Liao (zh_HK) * Chao-Hsiung Liao (zh_TW) ============== Version 2.13.5 ============== cinnamon-screensaver * Move DPMS functionality to gnome-power-manager * Rename the DBUS interface from screensaver to ScreenSaver * Disable the X.org grab smasher * Don't do the slow fade if we are inhibited * Fix screen flashing after idle activation cinnamon-screensaver-preferences * Rework dialog for setting session idle timeout * Remove unused help button Translators * Rostislav \"zbrox\" Raykov (bg) * Adam Weinberger (en_CA) * Francisco Javier F. Serrador (es) * Ilkka Tuohela (fi) * Ignacio Casal Quinteiro (gl) * Takeshi AIHANA (ja) * Tino Meinen (nl) * Clytie Siddall (vi) * Abel Cheung (zh_HK) * Abel Cheung (zh_TW) ============== Version 0.0.24 ============== cinnamon-screensaver * Add proper session idle reporting * Clear all children of toplevel windows Translators * Josep Puigdemont i Casamajó (ca) * Adam Weinberger (en_CA) * Francisco Javier F. Serrador (es) * Ilkka Tuohela (fi) * Ankit Patel (gu) * Žygimantas BeruÄka (lt) * Tino Meinen (nl) * Слободан Ð. СÑедоÑÐµÐ²Ð¸Ñ (sr) * Theppitak Karoonboonyanan (th) * Clytie Siddall (vi) ============== Version 0.0.23 ============== cinnamon-screensaver * Fix idle warning cancellation * Changes to D-Bus API * Add --debug command line option * Build fix when DPMS disabled themes * (floaters) New theme engine (Ray Strode et al) Translators * Francisco Javier F. Serrador (es) * Ignacio Casal Quinteiro (gl) * Ankit Patel (gu) * Takeshi AIHANA (ja) * Theppitak Karoonboonyanan (th) ============== Version 0.0.22 ============== cinnamon-screensaver * Don't mess up event mask for root window. Translators * Miloslav Trmac (cs) * Gabor Kelemen (hu) * Kjartan Maraas (nb) * Kjartan Maraas (no) ============== Version 0.0.21 ============== cinnamon-screensaver * Try to prevent popups over screensaver window * Use an interruptable slow fade before idle activation Translators * Rostislav \"zbrox\" Raykov (bg) * Ilkka Tuohela (fi) * Åygimantas BeruÄka (lt) * Amanpreet Singh Alam (pa) * Marcel Telka (sk) * Theppitak Karoonboonyanan (th) ============== Version 0.0.20 ============== cinnamon-screensaver * Fix blanking when running under Xnest ============== Version 0.0.19 ============== cinnamon-screensaver * Allow trying password after auth failure * Allow more space for user list * Make unlock dialog centered vertically * Use OverrideRedirect windows * Sync with latest FUSA version * Add test for window/dialog subsystem * Fix leaking of signal handlers * Misc correctness fixes Translators * Adam Weinberger (en_CA) * Francisco Javier F. Serrador (es) * Davy Defaud (fr) * Takeshi AIHANA (ja) * Åygimantas Beruka (lt) ============== Version 0.0.18 ============== cinnamon-screensaver * UI tweaks for unlock dialog * Fix Intel compiler warnings (Kjartan Maraas) * Do more error checking of GConf input * Check for command parsing errors * Fix leaks * Redesign the idle watcher and fix leaks * Solaris build fixes (Damien Carbery) cinnamon-screensaver-preferences * Make lock toggle work again Translators * Miloslav Trmac (cs) * Adam Weinberger (en_CA) * Francisco Javier F. Serrador (es) * Davy Defaud (fr) * Gabor Kelemen (hu) * Takeshi AIHANA (ja) * Tino Meinen (nl) ============== Version 0.0.17 ============== cinnamon-screensaver * Restart idle watch if can't grab keyboard * Make timeout in preferences work again * Daemonize process by default * Add option --no-daemon * Don't use any icon if face image is not found Translators * Adam Weinberger (en_CA) * Kjartan Maraas (nb) * Kjartan Maraas (no) ============== Version 0.0.16 ============== cinnamon-screensaver * Shake the dialog when authentication fails * Maintain nicer aspect ratio on unlock dialog * Only notice motion of 10 pixels or more * Periodically raise windows * Don't emit duplicate response signals from dialog * Make dialog buttons insensitive when input isn't allowed * Add a gconf setting for the logout command themes * (slideshow) Skip thumbnail images Translators * Rostislav \"zbrox\" Raykov (bg) * Adam Weinberger (en_CA) * Francisco Javier F. Serrador (es) * Takeshi AIHANA (ja) * Tino Meinen (nl) * Funda Wang (zh_CN) ============== Version 0.0.15 ============== cinnamon-screensaver * First version with working power management * Add Gamma fade out * Don't forward first enter or space to unlock dialog * Make poke command work when screen is blanked * Add getIdleTime dbus method * Translation fixes themes * (slideshow) Optionally use EXIF info to rotate images (torkel@acc.umu.se) Translators * Rostislav \"zbrox\" Raykov (bg) * Miloslav Trmac (cs) * Adam Weinberger (en_CA) * Žygimantas BeruÄka (lt) * Kjartan Maraas (nb) * Tino Meinen (nl) * Kjartan Maraas (no) ============== Version 0.0.14 ============== cinnamon-screensaver * Don't drop keypresses before unlock dialog appears * Use .desktop files and menu spec to find themes * Simplify unlock dialog * Make user switching a gconf option (Matthias Clasen) * Make user switching disabled by default * Fix a crash due to a missing error handler cinnamon-screensaver-preferences * Use new themes API that will theme list to be modified by distro/sysadmin/user. Translators * Ilkka Tuohela (fi) * Luca Ferretti (it) * Takeshi AIHANA (ja) * Tino Meinen (nl) * Clytie Siddall (vi) ============== Version 0.0.13 ============== cinnamon-screensaver * Fix problem when starting GNOME from KDM * Only look for theme files that end in .xml * Look for xscreensaver themes in a few more places ============== Version 0.0.12 ============== cinnamon-screensaver * Fix crasher caused by destroying NULL hash table * Don't activate after last inhibitor is removed Translators * Adam Weinberger (en_CA) ============== Version 0.0.11 ============== cinnamon-screensaver * Make unlock dialog show more quickly * Support the gconf cycle timeout key * Add system name to unlock dialog cinnamon-screensaver-preferences * Add random theme (Rodrigo) Translators * Francisco Javier F. Serrador (es) * Tino Meinen (nl) * Clytie Siddall (vi) ============== Version 0.0.10 ============== cinnamon-screensaver * Fix hang on system resume * Actually use the gconf lock key * Add configure option to look for xscreensaver hacks (Rodrigo) cinnamon-screensaver-preferences * Add checkbox to enable/disable locking (Rodrigo) * Make type ahead find work correctly * HIG fixes (Dennis Cranston) Translators * Adam Weinberger (en_CA) * Eric Maeker (fr) * Takeshi AIHANA (ja) * Clytie Siddall (vi) ============= Version 0.0.9 ============= cinnamon-screensaver * Added slideshow theme engine * Display username if real name is unknown (Rodrigo) themes * Added personal slideshow theme * Added cosmos slideshow theme Translators * Rostislav \"zbrox\" Raykov (bg) * Tommi Vainikainen (fi) * Maxim V. Dziumanenko (uk) ============= Version 0.0.8 ============= cinnamon-screensaver * Add Dbus API for inhibiting the idle activation * Integrate fast-user-switching directly into the unlock dialog. * Restart unlock dialog timer after every keystroke * Fix leaks * Fix xauth problems for some displays Translators * Adam Weinberger (en_CA) * Takeshi AIHANA (ja) * Tino Meinen (nl) * Abel Cheung (zh_TW) ============= Version 0.0.7 ============= cinnamon-screensaver * Fix authentication on SuSE/Novell * Automatically find the SuSE/Novell gdm.conf file * Don't require the gdm.conf file to exist at build time * Actually ship the translations * Fix crash in popsquares * Reset throttle value after deactivation Translators * Hendrik Richter (de) * Adam Weinberger (en_CA) * Takeshi AIHANA (ja) * Christian Rose (sv) ============= Version 0.0.6 ============= cinnamon-screensaver * Added Multi-head/Xinerama support * Added screensaver throttle capability * Depend on dbus >= 0.3 * Use property based dbus methods/signals * Fix Solaris build * Install own PAM configuration instead of relying on xscreensaver * Add ability to disable 'New Login' button cinnamon-screensaver-preferences * Support drag and drop of theme configuration files * Display a nicer form of the activation time value Translators * Frank Arnold (de) * Adam Weinberger (en_CA) * James Ogley (en_GB) * Francisco Javier F. Serrador (es) * Raphael Higino (pt_BR) * Christian Rose (sv) * Funda Wang (zh_CN) ============= Version 0.0.5 ============= cinnamon-screensaver * Support user themes in USER_DATA_DIR/cinnamon-screensaver/themes/ * Send activation/deactivation signals on session message bus * Added DPMS support * Added xscreensaver compatible XML configuration for themes * Add optional logout button after a specified amount of time * Fix leaking of file descriptors cinnamon-screensaver-preferences * Added configuration applet * Use screensaver icon themes * Added version of popsquares that follows GNOME theme cinnamon-screensaver-4.4.1/README000077700000000000000000000000001357366610100200022README.mdustar00rootroot00000000000000cinnamon-screensaver-4.4.1/README.md000066400000000000000000000213361357366610100171340ustar00rootroot00000000000000### To do - ~~Add GdkFilter to prevent new windows raising themselves above the stage~~ - ~~Gtk 3.20.. make a new CSS file, do a check at startup which file to use based on gtk version check~~ - ~~Make styling work at fallback provider priority (1 instead of 600)~~ - ~~clock positioning broken in Gtk 3.20 (widget.queue_resize instead of widget.queue_draw to trigger GtkOverlay~~ ~~redraws, but still issues?)~~ - ~~add music player widget? Next to volume, track info, position (read-only) or time, 3 buttons (pause-forw-back)~~ - security testing... try to break it - add our own flag gsettings key to org.cinnamon.desktop.screensaver, instead of using libgnomekbd? it's a dependency anyhow. Add user setting for this as well? - Evaluate allowed keybindings - add more? Some missing? (keybindings.py) - ~~No boxes around infobar widgets? just a separator maybe, or nothing..~~ - monitor window urgent/demands-attention hints - add to info bar? - ~~Evaluate throttle - it's in the freedesktop spec.. idea being, you don't want a plugin screensaver running while you're on battery. Since we talk to upower, we can implement this ourselves, or let our session manager tell us when to throttle back/throttle forward (plug in, switch back to x plugin or whatever?)~~ - ~~keep track of last keyboard layout used in the unlocker, use that one by default (keeps user from having to switch repeatedly when unlocking, while using a different input layout in general)~~ How does it work? ### Program Entry Main entry is from /usr/bin/cinnamon-screensaver to cinnamon-screensaver-main.py, which launches a dbus service (org.cinnamon.Screensaver) service.py launches the ScreensaverManager (manager.py), which is central command for all things here, as well as a session proxy to listen for idle changes from cinnamon-session, and logind or consolekit proxues. ### Running At this point we're listening, either for a command sent by the user (like via cinnamon-screensaver-command) or from one of our proxies. ### Locking (active) Once a lock command is received, the manager spawns a main window (Stage in stage.py) which covers the entire Gdk screen size (an imaginary rectangle containing all monitors). Think of this overlay as very basic window manager. Into this overlay it places: - MonitorViews (monitorView.py) - one for each monitor, painted with the user's background, placed at the exact location of each window. - A clock widget, which bounces around mostly randomly around all monitors - An unlock widget, which is initially hidden At this point we're also now setup to receive user events like button and key presses, and motion events. This is assisted by the GrabHelper and EventHandler that ensure only those keystrokes we want are allowed, and muffin is blocked from processing global keybindings. - Any motion is a wake event (show the unlock widget or kill the stage if we're not locked) - Any click is a wake event (ditto) - Keypresses are first filtered - media keys are checked, and things like volume, brightness controls will not raise the unlock dialog (for now, only if they're simple key combinations - complex ones with modifiers will still do it) - key strokes for characters will be forwarded to the dialog - if you start typing your password on a blank screensaver screen, it will be forwarded to the password entry. ### Unlocking Once the user types their password and hits enter or clicks unlock, we authenticate via a pam helper in cinnamon-desktop. If the authentication is successful, all widgets are destroyed, all grabs released, and we go back to the idle listening state. Files: application.css: Application priority css, stuff to make the unlock dialog, clock widgets look ok against varying backgrounds cinnamon-screensaver-command.py: Send commands to the screensaver via the command line cinnamon-screensaver-main.py: Main entry point into the program, handles a couple of arguments, adds our css provider, fires up the ScreensaverService. baseWindow.py: A base revealer class that the Clock and Unlock widgets implement - any widget that will move around the Stage should implement this (except the monitorViews) - the revealer base lets you do simple fade-ins and fade-outs. cinnamonProxy.py: Connects to Cinnamon's dbus interface, asks Cinnamon to make sure expo or overview are closed (as they make a server grab that we can't wrest focus from, preventing the screensaver from activating). clock.py (inherits BaseWindow): The clock widget that bounces around the screen, this contains all of that. Positioning is done via a randomizer on a timer that adjusts vertical and horizontal alignment properties (one of start, center, or end) along with current monitor, which is used by the Stage positioning function to tell it where to place the Clock widget. config.py.in (compiles into config.py): Contains system-specific file locations that are used by various files here. consoleKitProxy.py: Listens to commands from consolekit over dbus constants.py: A file containing simply a list of hardcoded screens/values that various files here use. eventHandler.py: Gets forwarded all events received from various sources, and acts on them. Does not propagate except in the case of motion. fader.py: A helper for the Stage that uses a frame tick callback to fade the stage in our out over a specific timeframe. Since it uses the frame clock instead of a GSource, times remain consistent, and only as many frames are drawn as there is time for (a 1 second animation will take one second, but you might not see all 60 frame draws) focusNavigator.py: A helper for navigating focus and performing activation on the navigable widgets on the unlock screen. Since we funnel events so strictly, and don't perform any propagation (to prevent wm or desktop keybindings from triggering) we have to manage the focus ourselves, as well as performing activation on the focused widget when enter or space is pressed. grabHelper.py: A helper for achieving exclusive mouse and key grabs, as well as hiding the mouse pointer when appropriate. keybindings.py: gets fed key events from the EventHandler, and acts on them or not - allows certain media keys, handles escape, enter, space events. logindProxy.py: Listens to commands from logind over dbus manager.py: This is the head honcho, the big cheese, el numero uno. It spawns the GrabHelper, FocusNavigator, along with the session and logind/ck proxies. It acts on commands received from there, as well as our own dbus service (ScreensaverService). It manages all the flags in status.py, spawns and despawns the stage. monitorView.py: This is a widget that gets placed in the stage that provides the backgrounds or screensaver plugin view. There is one per monitor, and they are positioned directly where each monitor is by the Stage positioning function. It handles transitioning between backgrounds (during a slideshow) and transitioning between plugins and wallpaper. service.py: This is our implementation of the dbus service "org.cinnamon.Screensaver" - commands received via this interface are sent to the manager for answers and action. This spawns the manager. sessionProxy.py: Listens to cinnamon-session for idle changes and notifies the manager when they change. settings.py: holds our GSettings instances, as well as getters for each of the different keys. Also takes care of our CinnamonDesktop BG instance, and updates it when settings change. stage.py: This is our toplevel window, a GtkWindow. It is made the size of the GdkScreen (a theoretical rectangle that exactly encompasses all monitors). At its core is a GtkOverlay, which we sort of use like a window manager. The position_overlay_child callback is used to position our children (Clock, UnlockWidget, MonitorView). A forced call to this position function can be done via overlay.queue_resize(). This class talks fairly freely with the manager, even though it is spawned and despawned by the manager repeatedly (when the screensaver is activated/deactivated) status.py: A global state tracker, used by many widgets - Active means the screensaver stage exists, and we're displaying wallpaper or whatever. Locked means we will need to enter our password to unlock. Awake means the unlock dialog is currently shown. focusChain is where a list of focusable widgets should be stored that tab will navigate between. (This is currently done just in the UnlockDialog) trackers.py: A utility for easy tracking of timers and signal connections. It basically performs any cleanup for you, with no need to track source ids or signal ids generally. unlock.py: Provides the unlock dialog, including the user image, name, password entry and buttons utils.py: Various utilities that seem best to keep in one place. x11.py: X11-specific focus helper function - optional, python3-xlib doesn't exist everywhere yet. cinnamon-screensaver-4.4.1/acinclude.m4000066400000000000000000000116401357366610100200430ustar00rootroot00000000000000# Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. # This program is free software; you can 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, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, see . # AM_PATH_PYTHON_VERSION(ABI-VERSION1, [MINIMUM-VERSION1 [, ABI-VERSION2, [MINIMUM-VERSION2 ...]]]) # # An alternative to AM_PATH_PYTHON that checks for specific python ABI/version pairs. # Example: # AM_PATH_PYTHON_VERSION(2.3, 2.3.5, 2.4, 2.4.0) # checks for a python2.3 binary returning python version >= 2.3.5, and # if that fails it looks for python2.4 containing version >= 2.4.0 # It aborts configure with an error if no statisfying version is found. # Env. var. PYTHON can be used to point a specific/laternate version to configure. AC_DEFUN([AM_PATH_PYTHON_VERSION], [ m4_pattern_allow([m4_shift]) _python_save="$PYTHON" dnl Find a Python interpreter with corresponding ABI version. m4_define(PYTHON_var, PYTHON[]m4_translit($1,[.],[_])) if test -z "$PYTHON"; then AC_PATH_PROG(PYTHON_var, python$1, []) else PYTHON_var="$PYTHON" fi PYTHON="$PYTHON_var" AC_SUBST(PYTHON) if test -n "$PYTHON"; then m4_if([$2],[],[ ], [ dnl A version check is needed. AC_MSG_CHECKING([whether $PYTHON version is >= $2]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$2], [AC_MSG_RESULT(yes)], [AC_MSG_RESULT([no]); PYTHON=""]) ]) fi if test -z "$PYTHON"; then dnl if more arguments, shift/recurse, else fail m4_if([$3],[],[ AC_MSG_ERROR([no suitable Python interpreter found]) ], [ PYTHON="$_python_save" AM_PATH_PYTHON_VERSION(m4_shift(m4_shift($@))) ]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; print sys.platform"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [am_cv_python_pythondir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='$PYTHON_PREFIX')" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"`]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [am_cv_python_pyexecdir=`$PYTHON -c "from distutils import sysconfig; print sysconfig.get_python_lib(1,0,prefix='$PYTHON_EXEC_PREFIX')" 2>/dev/null || echo "${PYTHON_EXEC_PREFIX}/lib/python${PYTHON_VERSION}/site-packages"`]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) fi ]) cinnamon-screensaver-4.4.1/autogen.sh000077500000000000000000000017551357366610100176610ustar00rootroot00000000000000#!/bin/sh # Run this to generate all the initial makefiles, etc. test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. olddir=$(pwd) cd $srcdir (test -f configure.ac) || { echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***" exit 1 } # shellcheck disable=SC2016 PKG_NAME=$(autoconf --trace 'AC_INIT:$1' configure.ac) if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then echo "*** WARNING: I am going to run 'configure' with no arguments." >&2 echo "*** If you wish to pass any to it, please specify them on the" >&2 echo "*** '$0' command line." >&2 echo "" >&2 fi mkdir -p m4 intltoolize --force --copy --automake || exit 1 autoreconf --verbose --force --install || exit 1 cd "$olddir" if [ "$NOCONFIGURE" = "" ]; then $srcdir/configure "$@" || exit 1 if [ "$1" = "--help" ]; then exit 0 else echo "Now type 'make' to compile $PKG_NAME" || exit 1 fi else echo "Skipping configure process." fi cinnamon-screensaver-4.4.1/cinnamon-screensaver.pot000066400000000000000000000045051357366610100225200ustar00rootroot00000000000000# 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 , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-23 15:09+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: src/cinnamon-screensaver-command.py:37 msgid "Causes the screensaver to exit gracefully" msgstr "" #: src/cinnamon-screensaver-command.py:39 msgid "Query the state of the screensaver" msgstr "" #: src/cinnamon-screensaver-command.py:41 msgid "Query the length of time the screensaver has been active" msgstr "" #: src/cinnamon-screensaver-command.py:43 msgid "Tells the running screensaver process to lock the screen immediately" msgstr "" #: src/cinnamon-screensaver-command.py:45 msgid "Turn the screensaver on (blank the screen)" msgstr "" #: src/cinnamon-screensaver-command.py:47 msgid "If the screensaver is active then deactivate it (un-blank the screen)" msgstr "" #: src/cinnamon-screensaver-command.py:49 msgid "Version of this application" msgstr "" #: src/cinnamon-screensaver-command.py:51 msgid "Message to be displayed in lock screen" msgstr "" #: src/cinnamon-screensaver-command.py:80 msgid "The screensaver is active\n" msgstr "" #: src/cinnamon-screensaver-command.py:82 msgid "The screensaver is inactive\n" msgstr "" #: src/cinnamon-screensaver-command.py:86 msgid "The screensaver is not currently active.\n" msgstr "" #: src/cinnamon-screensaver-command.py:88 #, python-format msgid "The screensaver has been active for %d second.\n" msgid_plural "The screensaver has been active for %d seconds.\n" msgstr[0] "" msgstr[1] "" #: src/passwordEntry.py:23 src/unlock.py:203 msgid "Please enter your password..." msgstr "" #: src/unlock.py:90 msgid "Unlock" msgstr "" #: src/unlock.py:98 msgid "Switch User" msgstr "" #: src/unlock.py:181 msgid "Incorrect password" msgstr "" #: src/unlock.py:195 msgid "Checking..." msgstr "" #: src/unlock.py:241 msgid "You have the Caps Lock key on." msgstr "" cinnamon-screensaver-4.4.1/configure.ac000066400000000000000000000253731357366610100201500ustar00rootroot00000000000000dnl -*- mode: m4 -*- AC_PREREQ(2.60) AC_INIT([cinnamon-screensaver], [4.4.1], [https://github.com/linuxmint/cinnamon-screensaver/issues]) PKG_PROG_PKG_CONFIG([0.26]) AC_CONFIG_MACRO_DIR([m4]) AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \${ACLOCAL_FLAGS}"]) m4_ifdef([AX_IS_RELEASE], [AX_IS_RELEASE([always])]) AC_CONFIG_SRCDIR(src/cinnamon-screensaver-main.py) AM_INIT_AUTOMAKE([1.7 no-dist-gzip dist-xz]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AX_COMPILER_FLAGS], [AX_COMPILER_FLAGS([WARN_CFLAGS],[WARN_LDFLAGS])]) LT_INIT([disable-static]) AC_CONFIG_HEADERS(config.h) AM_MAINTAINER_MODE([enable]) IT_PROG_INTLTOOL([0.40.0]) AC_CONFIG_MACRO_DIRS([m4]) dnl put the ACLOCAL flags in the makefile ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" AC_CHECK_HEADERS(unistd.h) AC_CHECK_HEADERS(crypt.h sys/select.h) AC_CHECK_FUNCS(select fcntl uname nice setpriority getcwd getwd putenv sbrk) AC_CHECK_FUNCS(sigaction syslog realpath setrlimit) AC_TYPE_UID_T AC_CHECK_FUNCS([setenv unsetenv clearenv]) GETTEXT_PACKAGE=cinnamon-screensaver AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package]) AM_GLIB_GNU_GETTEXT GOBJECT_INTROSPECTION_CHECK([0.9.7]) AC_DEFUN([AC_CHECK_X_HEADER], [ ac_save_CPPFLAGS="$CPPFLAGS" if test \! -z "$includedir" ; then CPPFLAGS="$CPPFLAGS -I$includedir" fi CPPFLAGS="$CPPFLAGS $X_CFLAGS" AC_CHECK_HEADER([$1],[$2],[$3],[$4]) CPPFLAGS="$ac_save_CPPFLAGS"]) # Like AC_TRY_COMPILE, but it uses the already-computed -I directories. # AC_DEFUN([AC_TRY_X_COMPILE], [ ac_save_CPPFLAGS="$CPPFLAGS" if test \! -z "$includedir" ; then CPPFLAGS="$CPPFLAGS -I$includedir" fi CPPFLAGS="$CPPFLAGS $X_CFLAGS" AC_TRY_COMPILE([$1], [$2], [$3], [$4]) CPPFLAGS="$ac_save_CPPFLAGS"]) ALL_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" # Check for Xinerama extension (Solaris impl or Xfree impl) cs_save_cppflags="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X_CFLAGS" AC_ARG_ENABLE(xinerama, AC_HELP_STRING([--disable-xinerama], [disable use of the Xinerama extension]), try_xinerama=$enable_xinerama,try_xinerama=yes) dnl ' use_solaris_xinerama=no use_xfree_xinerama=no if test "${try_xinerama}" != no; then case "$host" in *-*-solaris*) # Check for solaris use_solaris_xinerama=yes AC_CHECK_LIB(Xext, XineramaGetInfo, use_solaris_xinerama=yes, use_solaris_xinerama=no, $ALL_X_LIBS) if test "x$use_solaris_xinerama" = "xyes"; then AC_CHECK_HEADER(X11/extensions/xinerama.h, if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS" fi AC_DEFINE(HAVE_SOLARIS_XINERAMA, , [Have Solaris-style Xinerama]) AC_DEFINE(HAVE_XINERAMA, , [Have some version of Xinerama]), use_solaris_xinerama=no, [#include ]) fi AC_MSG_CHECKING(for Xinerama support on Solaris) AC_MSG_RESULT($use_solaris_xinerama); ;; *) # Check for XFree use_xfree_xinerama=yes AC_CHECK_LIB(Xinerama, XineramaQueryExtension, [AC_CHECK_HEADER(X11/extensions/Xinerama.h, X_EXTRA_LIBS="-lXinerama $X_EXTRA_LIBS" if test -z "`echo $ALL_X_LIBS | grep "\-lXext" 2> /dev/null`"; then X_EXTRA_LIBS="-lXext $X_EXTRA_LIBS" fi AC_DEFINE(HAVE_XFREE_XINERAMA, , [Have XFree86-style Xinerama]) AC_DEFINE(HAVE_XINERAMA,, [Have some version of Xinerama]), use_xfree_xinerama=no, [#include ])], use_xfree_xinerama=no, -lXext $ALL_X_LIBS) AC_MSG_CHECKING(for Xinerama support on XFree86) AC_MSG_RESULT($use_xfree_xinerama); ;; esac fi CPPFLAGS="$cs_save_cppflags" RANDR_LIBS= found_randr=no AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration, [AC_CHECK_HEADER(X11/extensions/Xrandr.h, RANDR_LIBS=-lXrandr found_randr=yes,, [#include ])], , -lXrender -lXext $ALL_X_LIBS) if test "x$found_randr" = "xyes"; then AC_DEFINE(HAVE_RANDR, , [Have the Xrandr extension library]) fi AM_PATH_PYTHON(3.4) PKG_CHECK_MODULES(SCREENSAVER_PAM, gtk+-3.0 glib-2.0) AC_SUBST(SCREENSAVER_PAM_CFLAGS) AC_SUBST(SCREENSAVER_PAM_LIBS) PKG_CHECK_MODULES(CSCREENSAVER, gobject-2.0 gtk+-3.0 gdk-x11-3.0 x11 xext glib-2.0 gio-2.0 gthread-2.0) AC_SUBST(CSCREENSAVER_CFLAGS) AC_SUBST(CSCREENSAVER_LIBS) CSCREENSAVER_LIBS="$CSCREENSAVER_LIBS $RANDR_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lm" dnl --------------------------------------------------------------------------- dnl - The --enable-setres option dnl --------------------------------------------------------------------------- AC_ARG_ENABLE(setres,[ setres option: --enable-setres Use setresuid/setresgid in the setuid.c helper --disable-setres Don't use setresuid/setresgid (this is the default behavior)], [enable_setres="$enableval"],[enable_setres=no]) if test "$enable_setres" = yes; then echo "****************************************" AC_CHECK_FUNC(setresuid, [have_setresuid=yes], [have_setresuid=no]) AC_CHECK_FUNC(setresgid, [have_setresgid=yes], [have_setresgid=no]) if test "x$have_setresuid" = "xyes" -a "x$have_setresgid" = "xyes"; then AC_DEFINE(USE_SETRES, 1, [Define to have the setuid helper use setresuid/setresgid instead of setuid/setgid.]) else AC_MSG_ERROR("setres requested but not available so we are ignoring the option") fi elif test "$enable_setres" = no; then true fi dnl --------------------------------------------------------------------------- dnl - Check for PAM dnl --------------------------------------------------------------------------- withval="" AC_ARG_WITH(pam-prefix, AS_HELP_STRING([--with-pam-prefix=], [specify where pam files go]), [if test x$withval != x; then AC_MSG_RESULT("PAM files will be installed in prefix ${withval}.") fi]) if test x$withval != x; then PAM_PREFIX="$withval" else PAM_PREFIX='${sysconfdir}' fi AC_SUBST(PAM_PREFIX) have_pam=no AC_CHECK_LIB(pam, pam_start, have_pam=yes) if test "x$have_pam" = "xyes"; then AUTH_LIBS="${AUTH_LIBS} -lpam" AUTH_SCHEME=pam # On Linux, sigtimedwait() is in libc; on Solaris, it's in librt. have_timedwait=no AC_CHECK_LIB(c, sigtimedwait, [have_timedwait=yes]) if test "$have_timedwait" = no ; then AC_CHECK_LIB(rt, sigtimedwait, [AUTH_LIBS="${AUTH_LIBS} -lrt"]) fi AC_MSG_CHECKING(how to call pam_strerror) AC_CACHE_VAL(ac_cv_pam_strerror_args, [AC_TRY_COMPILE([#include #include #include ], [pam_handle_t *pamh = 0; char *s = pam_strerror(pamh, PAM_SUCCESS);], [ac_pam_strerror_args=2], [AC_TRY_COMPILE([#include #include #include ], [char *s = pam_strerror(PAM_SUCCESS);], [ac_pam_strerror_args=1], [ac_pam_strerror_args=0])]) ac_cv_pam_strerror_args=$ac_pam_strerror_args]) ac_pam_strerror_args=$ac_cv_pam_strerror_args if test "$ac_pam_strerror_args" = 1 ; then AC_MSG_RESULT(one argument) elif test "$ac_pam_strerror_args" = 2 ; then AC_DEFINE(PAM_STRERROR_TWO_ARGS, 1, [Define if pam_strerror takes two arguments]) AC_MSG_RESULT(two arguments) else AC_MSG_RESULT(unknown) fi else AC_MSG_ERROR("PAM libraries not found") fi AC_SUBST(HAVE_PAM) AC_SUBST(AUTH_LIBS) AC_SUBST(AUTH_SCHEME) if test "x$have_pam" = "xyes"; then AC_CHECK_HEADERS([security/pam_modutil.h security/pam_ext.h]) AC_CHECK_LIB(pam, pam_syslog, [AC_DEFINE(HAVE_PAM_SYSLOG, [], [Define to 1 if you have the pam_syslog function])]) fi dnl test whether struct pam_message is const (Linux) or not (Sun) if test "x$have_pam" = "xyes"; then pam_appl_h="$ac_pam_includes/security/pam_appl.h" AC_MSG_CHECKING(for const pam_message) AC_EGREP_HEADER([struct pam_message], $pam_appl_h, [ AC_EGREP_HEADER([const struct pam_message], $pam_appl_h, [AC_MSG_RESULT(["const: Linux-type PAM"]) ], [AC_MSG_RESULT(["nonconst: Sun-type PAM"]) AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] )], [AC_MSG_RESULT(["not found - assume const, Linux-type PAM"])] ) fi have_shape=no AC_CHECK_X_HEADER(X11/extensions/shape.h, [have_shape=yes],, [#include ]) if test "$have_shape" = yes; then AC_DEFINE(HAVE_SHAPE_EXT, 1, [Define if shape extension is available]) fi # Find out where the session service file goes # The sad sed hack is recommended by section 27.10 of the automake manual. DBUS_SESSION_SERVICE_DIR=`$PKG_CONFIG --variable session_bus_services_dir dbus-1 | sed -e 's,/usr/share,${datarootdir},g'` AC_SUBST(DBUS_SESSION_SERVICE_DIR) REAL_PREFIX= if test "x$prefix" = "xNONE"; then REAL_PREFIX=$ac_default_prefix else REAL_PREFIX=$prefix fi ## temporarily change prefix and exec_prefix old_prefix=$prefix prefix=$REAL_PREFIX if test "x$exec_prefix" = xNONE ; then REAL_EXEC_PREFIX=$REAL_PREFIX else REAL_EXEC_PREFIX=$exec_prefix fi old_exec_prefix=$exec_prefix exec_prefix=$REAL_EXEC_PREFIX BINDIR_TMP="$bindir" EXPANDED_BINDIR=`eval echo $BINDIR_TMP` AC_SUBST(EXPANDED_BINDIR) ## put prefix and exec_prefix back prefix=$old_prefix exec_prefix=$old_exec_prefix AC_SUBST(AUTH_LIBS) AC_SUBST(CSCREENSAVER_LIBS) # Files AC_OUTPUT([ Makefile data/Makefile data/org.cinnamon.ScreenSaver.service data/cinnamon-screensaver.desktop data/icons/Makefile files/Makefile libcscreensaver/Makefile libcscreensaver/cscreensaver.pc libcscreensaver/cscreensaver-uninstalled.pc po/Makefile.in src/Makefile src/binfiles/Makefile src/dbusdepot/Makefile src/widgets/Makefile src/util/Makefile src/pamhelper/Makefile ]) cinnamon-screensaver-4.4.1/data/000077500000000000000000000000001357366610100165615ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/data/Makefile.am000066400000000000000000000042511357366610100206170ustar00rootroot00000000000000NULL = SUBDIRS = icons desktopdir = $(datadir)/applications desktop_DATA = cinnamon-screensaver.desktop dbussessionservicedir = $(DBUS_SESSION_SERVICE_DIR) dbussessionservice_DATA = org.cinnamon.ScreenSaver.service EXTRA_DIST = \ org.cinnamon.ScreenSaver.service.in \ cinnamon-screensaver \ $(NULL) install-data-hook: @system=`uname`; \ if test -f /usr/include/security/pam_appl.h; then \ if test '!' -d $(DESTDIR)$(PAM_PREFIX)/pam.d; then \ $(mkinstalldirs) $(DESTDIR)$(PAM_PREFIX)/pam.d; \ chmod 755 $(DESTDIR)$(PAM_PREFIX)/pam.d; \ fi; \ if test $$system = Linux; then \ if test '!' -f $(DESTDIR)$(PAM_PREFIX)/pam.d/cinnamon-screensaver; then \ $(INSTALL_DATA) cinnamon-screensaver $(DESTDIR)$(PAM_PREFIX)/pam.d/cinnamon-screensaver; \ fi; \ if test "x$(PAM_PREFIX)" != "x/etc/pam.d"; then \ echo "***" ; \ echo "*** Warning: cinnamon-screensaver has been compiled with support for" ; \ echo "*** Pluggable Authentication Modules (PAM). However, you may need to" ; \ echo "*** manually install $(PAM_PREFIX)/pam.d/cinnamon-screensaver" ; \ echo "*** to /etc/pam.d/cinnamon-screensaver. Otherwise, unlocking might" ; \ echo "*** not work." ; \ echo "***" ; \ echo "*** Note: If you are using SuSE/Novell you may have to modify this file." ; \ echo "***" ; \ fi; \ fi; \ if test $$system = SunOS; then \ echo "***" ; \ echo "*** Warning: cinnamon-screensaver has been compiled with support for" ; \ echo "*** Pluggable Authentication Modules (PAM). However, you" ; \ echo "*** need to manually add authentication for cinnamon-screensaver in" ; \ echo "*** $(PAM_PREFIX)/pam.conf or /etc/pam.conf." ; \ echo "*** Otherwise, unlocking might not work." ; \ echo "***" ; \ fi; \ fi MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/data/cinnamon-screensaver000066400000000000000000000007411357366610100226260ustar00rootroot00000000000000#%PAM-1.0 # Fedora & Arch -auth sufficient pam_selinux_permit.so auth include system-auth auth optional pam_gnome_keyring.so account include system-auth password include system-auth session include system-auth # SuSE/Novell #auth include common-auth #auth optional pam_gnome_keyring.so #account include common-account #password include common-password #session include common-session cinnamon-screensaver-4.4.1/data/cinnamon-screensaver.desktop.in000066400000000000000000000006651357366610100247100ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Screensaver Comment=Launch screensaver and locker program Icon=preferences-desktop-screensaver Exec=cinnamon-screensaver OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Delay=5 X-GNOME-Autostart-Phase=Application X-GNOME-Autostart-Notify=true X-GNOME-Bugzilla-Bugzilla=GNOME X-GNOME-Bugzilla-Product=cinnamon-screensaver X-GNOME-Bugzilla-Component=general X-GNOME-Bugzilla-Version=@VERSION@ cinnamon-screensaver-4.4.1/data/icons/000077500000000000000000000000001357366610100176745ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/data/icons/Makefile.am000066400000000000000000000050411357366610100217300ustar00rootroot00000000000000NULL = public_icons_themes = \ hicolor \ $(NULL) public_icons = \ hicolor_actions_scalable_screensaver-unlock-symbolic.svg \ hicolor_actions_scalable_screensaver-switch-users-symbolic.svg \ hicolor_status_scalable_screensaver-notification-symbolic.svg \ hicolor_status_scalable_screensaver-blank.svg \ $(NULL) EXTRA_DIST = \ $(public_icons) \ $(NULL) ############################################################################### gtk_update_icon_cache = gtk-update-icon-cache -f -t update-icon-cache: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ for theme in $(public_icons_themes); do \ $(gtk_update_icon_cache) $(datadir)/icons/$$theme; \ done; \ else \ echo "*** Icon cache not updated. After (un)install, run this:"; \ for theme in $(public_icons_themes); do \ echo "*** $(gtk_update_icon_cache) $(datadir)/icons/$$theme"; \ done; \ fi install-icons: for icon in $(public_icons); do \ THEME=`echo $$icon | cut -d_ -f1`; \ CONTEXT=`echo $$icon | cut -d_ -f2`; \ SIZE=`echo $$icon | cut -d_ -f3`; \ ICONFILE=`echo $$icon | cut -d_ -f4`; \ mkdir -p $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT; \ $(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \ done; \ for icon in $(private_icons); do \ THEME=`echo $$icon | cut -d_ -f1`; \ CONTEXT=`echo $$icon | cut -d_ -f2`; \ SIZE=`echo $$icon | cut -d_ -f3`; \ ICONFILE=`echo $$icon | cut -d_ -f4`; \ mkdir -p $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT; \ $(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \ done uninstall-icons: -for icon in $(public_icons); do \ THEME=`echo $$icon | cut -d_ -f1`; \ CONTEXT=`echo $$icon | cut -d_ -f2`; \ SIZE=`echo $$icon | cut -d_ -f3`; \ ICONFILE=`echo $$icon | cut -d_ -f4`; \ rm -f $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \ done; \ for icon in $(private_icons); do \ THEME=`echo $$icon | cut -d_ -f1`; \ CONTEXT=`echo $$icon | cut -d_ -f2`; \ SIZE=`echo $$icon | cut -d_ -f3`; \ ICONFILE=`echo $$icon | cut -d_ -f4`; \ rm -f $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \ done install-data-local: install-icons update-icon-cache uninstall-local: uninstall-icons update-icon-cache cinnamon-screensaver-4.4.1/data/icons/hicolor_actions_scalable_screensaver-switch-users-symbolic.svg000066400000000000000000000053311357366610100343010ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme cinnamon-screensaver-4.4.1/data/icons/hicolor_actions_scalable_screensaver-unlock-symbolic.svg000066400000000000000000000051251357366610100331350ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme cinnamon-screensaver-4.4.1/data/icons/hicolor_status_scalable_screensaver-blank.svg000066400000000000000000000036701357366610100310000ustar00rootroot00000000000000 image/svg+xml cinnamon-screensaver-4.4.1/data/icons/hicolor_status_scalable_screensaver-notification-symbolic.svg000066400000000000000000000045111357366610100342110ustar00rootroot00000000000000 image/svg+xml Gnome Symbolic Icon Theme Gnome Symbolic Icon Theme cinnamon-screensaver-4.4.1/data/org.cinnamon.ScreenSaver.service.in000066400000000000000000000001321357366610100253530ustar00rootroot00000000000000[D-BUS Service] Name=org.cinnamon.ScreenSaver Exec=@EXPANDED_BINDIR@/cinnamon-screensaver cinnamon-screensaver-4.4.1/debian/000077500000000000000000000000001357366610100170725ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/debian/changelog000066400000000000000000001000121357366610100207360ustar00rootroot00000000000000cinnamon-screensaver (4.4.1) tricia; urgency=medium [ GeorchW ] * Fixed wrong font being applied in custom text (#328) [ claudiux ] * Update cinnamon-screensaver to fix #326 (#327) -- Clement Lefebvre Tue, 10 Dec 2019 09:58:06 +0000 cinnamon-screensaver (4.4.0) tricia; urgency=medium [ Michael Webster ] * passwordEntry.py: Render keyboard layout flags properly in hidpi. * cs-screen, stage.py: Move the pointer to the primary monitor (and, as a result, the unlock dialog as well) when initially waking. -- Clement Lefebvre Sat, 16 Nov 2019 12:24:53 +0100 cinnamon-screensaver (4.2.0) tina; urgency=medium [ Michael Webster ] * monitorView.py: refactor wallpaper transitioning to improve garbage collection. * Add on-screen keyboard. * stage.py: Only involve the stage fader if the transition time is not zero. * stage: re-realize when/if the GdkScreen's composited state changes. * Remove use of a fader on the stage window, eliminate off-screen mapping. (#309) [ Clement Lefebvre ] * OSK: Respect the cinnamon OSK activation mode [ Eli Schwartz ] * A couple small install fixups. (#302) [ Clement Lefebvre ] * Packaging: Remove obsolete build flag -- Clement Lefebvre Sun, 23 Jun 2019 15:42:14 +0200 cinnamon-screensaver (4.0.3) tessa; urgency=medium [ Michael Webster ] * all: Add low-resolution detection, adjust the clock and albumart widgets to be smaller in these cases. * audio panel: Don't show initially. * framedImage.py: Use surfaces for better hidpi display of album art. -- Clement Lefebvre Tue, 11 Dec 2018 11:24:36 +0000 cinnamon-screensaver (4.0.2) tessa; urgency=medium [ Michael Webster ] * floating.py: Revert accidental change to widget positioning frequency. -- Clement Lefebvre Thu, 06 Dec 2018 13:20:21 +0000 cinnamon-screensaver (4.0.1) tessa; urgency=medium [ Michael Webster ] * infoPanel.py: Don't attempt to access the power widget if we're disabled. -- Clement Lefebvre Mon, 12 Nov 2018 15:06:47 +0000 cinnamon-screensaver (4.0.0) tessa; urgency=medium [Michael Webster] * all: Remove xscreensaver and webkit support and plugins, simplify widget transitions. * info panel: Update the battery status when raising the lock screen. [schachmat] * Silence lintian warning about missing man pages. -- Clement Lefebvre Sat, 03 Nov 2018 10:45:05 +0000 cinnamon-screensaver (3.8.3) tara; urgency=medium [ Michael Webster ] * CsScreen/stage: Fix coverage changes when plugging in monitors that may affect scale factor. * power widget: Ensure widget state is correct when becoming Active, instead of only updating at the next power state change. * monitorView: don't use a transition for the view stack. * fader: Always run the callback, even if the fade is halted due to the widget not being mapped. * stage/screen: During any screen change, resize the stage backdrop immediately, to try to prevent incomplete coverage. [ Andrew Geng ] * Fall back to os.path.expanduser to find home dir. (#284) -- Clement Lefebvre Tue, 16 Oct 2018 16:35:16 +0100 cinnamon-screensaver (3.8.2) tara; urgency=medium [ Michael Webster ] * cs-notification-watcher.c: accept int variants for the transient hint. * clock.py: Always initialize self.clock, whether the clock is to be shown or not ("show-clock" setting,) but guard against it not being an actual WallClock in set_message. * cs-screen-x11.c: gdk_flush before retrieving updated monitor and screen information. This is done in stage.py when responding to our CsScreen's signals, but we should do it here before rebuilding the monitor info for sharing with the stage. * monitorView.py: Improve plugin behavior, logging, during screensaver activation/deactivation. * various: Add more and improve existing logging for debug mode, and implement and use a timer tracker for the deactivation idle callback. * debian/control: Remove python-rsvg from build deps (not available.) -- Clement Lefebvre Fri, 08 Jun 2018 11:37:49 +0100 cinnamon-screensaver (3.8.1) tara; urgency=medium [ Germán Franco ] * Remove border-image from the password entry (#277) -- Clement Lefebvre Sun, 06 May 2018 15:20:28 +0100 cinnamon-screensaver (3.8.0) tara; urgency=medium [ Michael Webster ] * stage.py: Disconnect from, and destroy the CsScreen last, when tearing down the stage. [ Clement Lefebvre ] * Add CI configuration * CI: Fix dependencies [ Michael Thies ] * keybindings: Allow suspend, hibernate and screen rotation from screensaver (#257) [ itzexor ] * libcscreensaver/service.py: fix xdg-screensaver suspend * doc: add back dbus interface documentation [ Michael Webster ] * dbus: Own other screensaver names to prevent them from being activated on demand during a cinnamon session. * nameBlocker.py: Watch for dbus activations and kill instead of simply blocking. See inline notes for explanation related to xdg-screensaver. * xscreensavers: Add safechild wrapper (from blueberry) - provides better control over screensaver hack processes, to prevent their lingering after the screensaver or cinnamon-settings is done with them. * xscreensavers: Use python3 for safechild, attempt to kill the hack process when terminated. * service, manager: always complete the lock invocation, whether we succeed or not, and whether we were already active or not. * webkit script: Use correct path to user webkit screensavers. [ Fabio Fantoni ] * debian: wrap-and-sort -bst (#274) * debian: Call autogen.sh with dh_autoreconf * cleanup debian/rules from not needed gnome things * debian: add missed gir to libcscreensaver0 * debian: right lib path from debian/rules without generate .install * debian: improve python3 support * Bump debhelper build-dep and compat to 10 * .gitignore: debian/files instead all debian folder * improve debian/cinnamon-screensaver.install * add debian/not-installed * debian: remove old prerm * update debian/copyright * improve debian/control * move pamhelper to libexec * debian: remove cinnamon-screensaver-pam-helper, integrating in cinnamon-screensaver pkg * circleci: remove mint18 job * debian/control: add break/replace anyway to remove old cinnamon-screensaver-pam-helper [ Clement Lefebvre ] * Don't show switch-user when org.cinnamon.desktop.lockdown disable-user-switching is False -- Clement Lefebvre Thu, 19 Apr 2018 12:46:03 +0100 cinnamon-screensaver (3.6.1) sylvia; urgency=medium * Disable fade-in effects on idle -- Clement Lefebvre Thu, 09 Nov 2017 12:43:32 +0000 cinnamon-screensaver (3.6.0) sylvia; urgency=medium [ Michael Webster ] * add an issue template * CsScreen: Fix hotplug/screen change detection and response, other issues. * logindClient.py: Produce a more helpful message when logind is running, but we're unable to figure out a valid session id. * manager/stage: Allow a second activation trigger to override a previous. * manager.py: Force secondary activations to be immediate. (prevents flash) * cs-notification-watcher.c: Ignore notifications that replace existing ones, by checking if the 'replaces_id' field of the notification is non-zero. * clock: Update for new wall clock API. * debian/control: Update cinnamon-desktop dependency for new WallClock api. [ Leigh Scott ] * fix indent (#238) [ Michael Webster ] * cs-screen-x11.c: Use Gdk to get the screen size, the previous method doesn't appear to update in time to have the new size, causing exposure to the desktop in some cases, such as resizing host windows of virtual machines. * cs-screen-x11.c: GdkScreen width and height arrive already scaled for hidpi. * logind/consolekit: Refresh screen and monitor info when coming back from inactive (such as sleep.) * stage.py: Call gdk_flush to allow the server to catch up before getting updated screen/monitor infos. * keybindings: remove ability to take screenshots, restore ability to use computer power button. [ Clement Lefebvre ] * l10n: Update POT file -- Clement Lefebvre Mon, 23 Oct 2017 15:50:38 +0100 cinnamon-screensaver (3.4.1) sonya; urgency=medium [ Michael Webster ] * stage.py: Kill any screensaver plugins when destroying all of the widgets - this will leave unfinished plugin processes. * framedImage: render images at their native size using the theme value as the maximum size, rather than desired size. This ensures the image displays at its best possible size for quality, but still makes sure an oversize image doesn't break anything. * stage.py: Don't re-allocate the floating widgets unless necessary to prevent obscuring of the unlock widget. This prevents the small jump of the clock when waking the computer, depending on settings. * framedImage: Remove some dead lines, use the correct css property, update commenting. * fix typo in 3.20 css file * clock: Update to use new wall-clock api to set the correct update interval depending on the provided date/time format. [ Clement Lefebvre ] * Don't lock the screen in live or guest sessions [ Michael Webster ] * framedImage.py: Stop using CSS for image size - since we now use the image's native size if it is reasonable to do so, there's no need for a theme to be involved. Just hardcode a sane maximum and keep images that size or less. is not valid CSS (even though that's what we're using min-height for here) [ leigh123linux ] * remove old webkit2-3.0 support -- Clement Lefebvre Tue, 20 Jun 2017 15:39:58 +0200 cinnamon-screensaver (3.4.0) sonya; urgency=medium [ leigh123linux ] * add libexec path [ Clement Lefebvre ] * l10n: Update POT file [ Michael Webster ] * Add --interactive-debug startup switch. This turns on GtkInspector, restricts the screensaver stage to a single monitor, and some other things to allow interaction with ui elements using the inspector tools. * mediaPlayerWatcher.py: catch SyntaxError exception when evaluating PlaybackStatus property. * framedImage.py: Just silently fail if a downloaded image fails to be loaded into a pixbuf. * some theme fixes for gtk 3.20+ * stage.py: clear clipboards only once, when waking. raise_unlock_widget gets called repeatedly when there is input (to refresh other things) - having it repeatedly clear the clipboard was unnecessary, and prevented keyboard navigation actions that included selection of characters - such as ctrl-a, shift-home and -end. * uPowerClient.py: aggregate the proxy's signal emissions into a single power-state-changed event for the power client. This prevents confusion at the stage level when updating for power events. * notifications: Add some debugging help. * notificationWidget.py: ignore network notifications - these occur often around suspend/resume time, and we don't want them artificially padding the notification count. * xscreensaver plugin: Use GSubprocess instead of g_spawn_async for hacks. * stage.py: Add some error-handling for widget creation, with exit strategy, in case something goes wrong. We don't want to leave the user with an inaccessible desktop. * xscreensaver plugin: provide a default .xscreensaver file if one doesn't already exist. [ Sparky Bluefang ] * Add /usr/lib/misc/xscreensaver/ to the xscreensaver search directories. [ Michael Webster ] * stage.py: More error-handling fixes. Add a debug package to the debian build. * authClient.py: Add some debugging info. * Add a CsScreen object: GdkScreen is unreliable for figuring out monitor sizes and resolutions, particularly in non-default configurations. * Enable notification watcher's debug code upon startup, rather than during widget construction. * Respect the "spanned" setting for wallpapers. Note, this will currently also affect the plugins as well, but I didn't see this as a serious drawback. * cs-screen-x11.c: Account for monitor scale factor. GTK expects the values to be scaled already. * cs-screen-x11.c: code cleanup (sorry git!) * singletons.py: Add some debugging for login manager commands. * Remove x11.py, move code to CsScreen class, remove python3-xlib dependency. * service.py: Wait to respond to the Lock command until the screensaver has called back that it is now active. * manager/stage: Lock immediately, without fade-in. This and the previous commit allow the screensaver to be activated synchronously from cinnamon-session in response to suspend/hibernate actions, and ensure it's fully active already when resuming. * cinnamon-screensaver-main.py: don't import the ScreensaverService until we're sure we'll need it. This prevents singletons from getting initialized too early, and we lose the correct state of status.Debug * cs-notification-watcher.c: transient hint should be a boolean type, not int. * service.py: Add the invocation to the queue prior to calling on the manager to lock. The active signal could be sent back before it gets added otherwise, causing us to leave the calling command hanging. * stage/fader: Realize the stage offscreen, then reposition it before starting our fade in. This prevents the initial flash sometimes seen when the idle fade kicks in. * cs-screen-x11.c: Use PointerRoot instead of None for XSetInputFocus. This does a better job of reacquiring keyboard control, and allows the screensaver to activate when a virtualbox guest window is focused. * stage/fader: Add the reposition call to the fader cycle, this ensures it gets reliably called in sync with redraws, otherwise we can still get a flash on realizing the window. * cs-auth-pam.c: Only attempt to remove the io watch if thread_done is FALSE. It is set to TRUE in the GIOFunc cs_auth_loop_quit, which also returns FALSE, signalling to remove the source. We can't zero out watch_id there, which was causing a warning when cs_auth_pam_verify_user exited. * volumeControl.py: Don't show if we can't get a valid CvcMixerControl, and only connect signals if we do. * mediaPlayerWatcher.py: use the async versions of the play/pause, previous and next methods. This prevents a dbus sync deadlock from freezing the screensaver. Observed issue using Google Play Desktop Music Player. (https://www.googleplaymusicdesktopplayer.com) * passwordEntry.py: Initialize self.original_group, don't perform draw callback without a live controller (this disparity can occur after session interruptions - sleep, switch user, etc... - but not consistently.) * passwordEntry.py: Reload the keyboard layout if the xkb configuration changes. * stage.py: fix screen changed callback [ leigh123linux ] * autogen.sh: don't run aclocal [ Michael Webster ] * cs-screen.h: remove XID typedef, include gdkx.h instead, which will include xlib. [ leigh123linux ] * Fix python shebang [ Clement Lefebvre ] * Fix csd-media-keys DBUS name -- Clement Lefebvre Thu, 04 May 2017 14:02:08 +0100 cinnamon-screensaver (3.2.13) serena; urgency=medium [ Dustin Falgout ] * AuthClient: Check for pam helper in subdirectory * fix typo [ Michael Webster ] * cinnamon-screensaver-pam-helper.c: debug mode - don't print message strings, they may contain the password. [ leigh123linux ] * add libexec path [ Michael Webster ] * manager.py: Fix pam helper cancellation in LMDE - we have an existing workaround for LMDE that skips the fade-out when unlocking, due to another issue. This causes our despawn_stage callback to be called immediately, which sets self.stage to None, before cancel_unlocking can be run. * keybindings.py: Don't allow the keyboard popup menu key to slip thru. * stage: Clear the clipboard if we're locked (should be inaccessible anyhow but...) * Add some tooltips to a few ui elements. * stage.py: Fix logic surrounding hiding/showing the floating widgets when power states change, or when a plugin is unable to run due to the power state. -- Clement Lefebvre Thu, 29 Dec 2016 15:03:13 +0000 cinnamon-screensaver (3.2.12) serena; urgency=medium * AuthClient: Find path for pam-helper according to runtime info -- Clement Lefebvre Thu, 22 Dec 2016 17:24:46 +0000 cinnamon-screensaver (3.2.11) serena; urgency=medium [ Vladimir Didenko ] * Move pam-helper binary to libexec directory - some distros forbid ELF binaries in /usr/share [ Clement Lefebvre ] * packaging: Move cinnamon-screensaver-pam-helper to its own package -- Clement Lefebvre Thu, 22 Dec 2016 15:43:30 +0000 cinnamon-screensaver (3.2.10) serena; urgency=medium [ leigh123linux ] * Fix FSF address [ Michael Webster ] * cinnamon-screensaver-pam-helper: Add a sleep to the stdin wait loop, make sure the helper is killed whenever the screensaver is deactivated. * manager.py: only try to cancel_unlocking if there is a stage. -- Clement Lefebvre Thu, 22 Dec 2016 11:50:00 +0000 cinnamon-screensaver (3.2.9) serena; urgency=medium [ Michael Webster ] * authClient.py: Use a constructor for GBytes creation (needed in LMDE introspection), ignore a message sent prior to the auth client being initialized (user hit enter as a means of bringing up the unlock dialog.) -- Clement Lefebvre Mon, 12 Dec 2016 15:29:50 +0000 cinnamon-screensaver (3.2.8) serena; urgency=medium [ Michael Webster ] * debian/cinnamon-screensaver.install: fix packaging of cinnamon- screensaver-pam-helper. -- Clement Lefebvre Sat, 10 Dec 2016 14:05:34 +0000 cinnamon-screensaver (3.2.7) serena; urgency=medium [ leigh123linux ] * Change shebang * Change shebang [ Michael Webster ] * stage.py: Keep floating widgets centered within their GtkAlign region instead of using the padding CSS property - this can only ever work by taking monitor size into account. * stage - the unlock dialog can take up more than 1/3 the width of the screen, so account for its width when positioning floating widgets during Awake state. [ leigh123linux ] * Add missing -lXext * remove spaces [ Clement Lefebvre ] * Volume control: Don't crash when PA returns no default sink * l10n: Update POT file [ Michael Webster ] * stage.py: Regrab the stage if grab is broken (notably by fingerprint-helper's gui.) * Fix pam authentication to work with multi-factor, fingerprint, etc.. * floating.py: Increase positioning delay to 30 seconds. * audioPanel.py: Don't show panel at all if no players are active. * Couple fixes: show floating widgets immediately upon sleep, add a description for AuthClient, send a failure notice when we fail. [ Dustin Falgout ] * Update pam config for multi-distro compatibility [ Michael Webster ] * Add preference to disable floating widgets... * clock.py: Make clock preference apply everywhere (like our other prefs) * cinnamon-screensaver-main.py: use setproctitle to set the process name as "cinnamon-screensaver" * configure.ac: Fix regression from git conflict - originally from aad72c98f1df63 * Add a build option to enable/disable use of setresuid/setresgid in the setuid.c file for some distributions. The default behavior remains to *not* use this. * Override the background color to transparent for various 'primary' widgets, this reduces (but does not eliminate) the tendency to get a 'flash' when the screensaver spawns its window. * mediaPlayerWatcher.py: handle metadata more gracefully - some players can return arrays of artist info, some a string - handle either. -- Clement Lefebvre Sat, 10 Dec 2016 11:48:37 +0000 cinnamon-screensaver (3.2.6) serena; urgency=medium * Remove import on BlinkLabel -- Clement Lefebvre Thu, 24 Nov 2016 22:38:57 +0000 cinnamon-screensaver (3.2.5) serena; urgency=medium * Remove position bar and position labels in infobar -- Clement Lefebvre Thu, 24 Nov 2016 18:55:32 +0000 cinnamon-screensaver (3.2.4) serena; urgency=medium [ Michael Webster ] * Replace cinnamon-screensaver bin script with cinnamon-screensaver.c, to perform setuid checks and fixes prior to python and gtk starting. * utils.py: remove liveuser check, it doesn't work as expected. -- Clement Lefebvre Wed, 23 Nov 2016 12:47:48 +0000 cinnamon-screensaver (3.2.3) serena; urgency=medium [ Willy Sudiarto Raharjo ] * Declare GdkX11. [ Michael Webster ] * events: For gtk < 3.18, skip the fade out animation, and immediately destroy the window. Move the deactivate command into an idle callback, so we're not attempting to destroy the window while in the middle of processing a motion event. * passwordEntry.py: emulate Gtk.Entry.grab_focus_without_selecting() - the real call was recently removed, as it doesn't exist in Gtk 3.14, however the behavior is still necessary - tabbing between buttons and entry will cause the entire partial password to be selected, causing overwrite. This restores the original functionality without requiring gtk 3.18+ * Fixes for Betsy/Jessie: * panels: Remove separators. Tweak spacing for keyboard layout icon in the gtk 3.18 css file. * utils.py: clean up get_user_name() calls. * Disable locking if pam files aren't found or if we're running as root. * utils.py: add 'liveuser' group check to user_can_lock() function. -- Clement Lefebvre Thu, 17 Nov 2016 09:49:37 +0000 cinnamon-screensaver (3.2.2) serena; urgency=medium * pkg: Added missing dep on python3-gi-cairo -- Clement Lefebvre Sun, 13 Nov 2016 13:13:58 +0000 cinnamon-screensaver (3.2.1) serena; urgency=medium [ Clement Lefebvre ] * pkg: Add intltool to build-dep * pkg: Don't depend on python3-xlib in LMDE * Layout/l10n: Fix minor visual issues [ Michael Webster ] * unlock/accountsServiceClient: don't cache the username and face path, instead fetch them from AccountsService when used. Also, allow for no face image by not using a fallback generic image, and hiding the image widget if there is no face for it. * Remove some Gtk 3.18+ api calls - with a small change to GdkScreen updating, the stacking order is correct at stage construction and never changes. [ Willy Sudiarto Raharjo ] * ConsoleKit: Add lock/unlock signal. -- Clement Lefebvre Sun, 13 Nov 2016 12:12:35 +0000 cinnamon-screensaver (3.2.0) serena; urgency=medium [ Michael Webster ] * Rewrite [ itzexor ] * utils.py: add back alternate display manager support for user switching [ Michael Webster ] * Terminate plugins more cleanly, terminate them when they're no longer visible, terminate them when we're on battery (and restart them when we get plugged back in), clean up handling of transition between plugin and wallpaper. * packaging: use pkg-config to figure out where our typelib/lib files go * cs-notification-watcher.c: ignore transient notifications (such as those from banshee on track changes) [ leigh123linux ] * Revert "Fix gtkdocize: GTK_DOC_CHECK not called in ./configure.ac" * Fix the gtkdoc issue properly [ Maximiliano Curia ] * Make AX_ macros optional and drop unused parts * Drop gnome-common, add autconf-archive build dependency [ Michael Webster ] * Add media player widget, reorganize files a bit * Remove borders from infobar widgets * Add audio buttons to the focus chain * notifications: Ignore notifications from active media players * Fix some names and lint. * media player: handle metadata safely, and make sure artist-album string is handled properly depending on the data we have available. * Update README.md * Make volume and position bars draw alike, make it easier to theme both, tweak layout of the audiobar a bit. Also, fix div by 0 when a track doesn't have a max position. * Rename Audio/InfoBar to Audio/InfoPanel * playerControl.py: Improve how we get h:m:s from the microseconds reported for position and track length. [ Corbin Auriti ] * Delete debug-screensaver.sh [ Michael Webster ] * Theme work - ensure everything is reasonably able to be themed, and provide fallback styling if the currently selected theme doesn't supply anything - this is done by searching for the toplevel style class - "csstage" corresponding to the toplevel window for the screensaver. * Add separate theming for Gtk 3.20+, update .gitignore, load a css file appropriate to the current Gtk version at startup (if no theme support is found). Fix error handling in mediaPlayerWatcher.py. * Update README.md, couple fixes to css files * update pot file * trackers: dump timer and connection list in debug mode after unlocking. * manager.py, stage.py: add some documentation. * More documentation.. * Add some documentation to the unlock dialog, make the user image size definable in CSS, reimplement the AccountsService handling as a client singleton like every other service. * More cleanup, documentation * Finish documentation * Fix a couple regressions from documenting/refactoring * Stage: Listen for GdkScreen changes in size and number of monitors, and reconstruct the monitorViews as needed. * stage.py: Fix oversized info panel. * Add script for testing keyboard layouts. * Use XAppKbdLayoutController to interact with libgnomekbd for switching keyboard layouts and getting reliable flag icons. * unlock.py: Split out PasswordEntry and FramedImage to their own files. * Fix keyboard layout representation in the password entry. GtkEntry is hardcoded to produce a menu-sized icon. We supply a blank icon, and draw our own where it belongs, and at a better size. This way, we can also provide themed text layout names as well, depending on user preference. * Add albumart widget. * finish implementing albumart preference. * stage: Don't let floating widgets overlap, catch a couple potential errors when loading pixbufs - namely when we interrupt it by skipping a track. * pyflakes cleanup * libcscreensaver: Fix new build warnings, fix shape extension detection for the event filter. * passwordEntry.py: Don't connect to draw and icon press signals if the keyboard layout controller is disabled. * Remove unused file. * proxies: Strip out unused interface elements to reduce lib size and runtime memory use (slightly.) * passwordEntry.py: Rework to stay in sync with XApp.KbdLayoutController changes. Perform all rendering/loading of icons ourselves, depend on new icon package, use new cinnamon desktop preferences for flag/case settings. * Add preferences to lock down media keys, media player controls, notification counter. -- Clement Lefebvre Sat, 09 Jul 2016 23:50:39 -0400 cinnamon-screensaver (3.0.1) sarah; urgency=medium [ JosephMcc ] * gs-lock-plug: Remove the hardcoded text colors [ Michael Webster ] * Fix unlock dialog display in hidpi. * gs-window-x11.c: fix a couple compiler warnings, clean up. * gs-lock-plug.c: look at AccountsService for user pic if .face is not found. Simplify some of the code - pixbuf loaders have built-in file checking. -- Clement Lefebvre Mon, 30 May 2016 16:08:20 +0100 cinnamon-screensaver (3.0.0) sarah; urgency=medium [ monsta ] * configure.ac: drop obsolete macro * configure.ac: use dots when printing dbus version [ Clement Lefebvre ] * Support new libsystemd (which replaces libsystemd-login) [ Michael Webster ] * Stop trying to make gnome-screensaver* a symlink to cinnamon-screensaver* -- Clement Lefebvre Sat, 23 Apr 2016 16:14:29 +0100 cinnamon-screensaver (2.8.0) rosa; urgency=medium [ JosephMcc ] * cleanup: replace deprecated gdk_cursor_unref() with g_object_unref() * cleanup an unused variable [ Michael Webster ] * gs-window-x11.c: Fix random crashing due to accessing invalid pointers when cleaning up the GSWindow instance. * gs-window-x11.c: Fix trying to control the screensaver socket after the plug has been removed (race condition) - by default the socket is destroyed when this happens. * gs-lock-plug.c: fix runtime warning -- Clement Lefebvre Fri, 16 Oct 2015 16:06:16 +0100 cinnamon-screensaver (2.6.4) rafaela; urgency=medium [ Joseph C Wang ] * fix segfault due to wrong object being destroyed -- Clement Lefebvre Fri, 26 Jun 2015 14:15:15 +0200 cinnamon-screensaver (2.6.3) rafaela; urgency=medium [ Dexter Chua ] * Fix zombie screensavers [ Clement Lefebvre ] * Removed Tower of Hanoi Webkit screensaver (takes too much CPU to be part of the default selection) -- Clement Lefebvre Tue, 02 Jun 2015 11:15:53 +0200 cinnamon-screensaver (2.6.2) rafaela; urgency=medium [ leigh123linux ] * bump version to account for cinnamon-desktop systemd schema change -- Clement Lefebvre Wed, 27 May 2015 10:01:57 +0200 cinnamon-screensaver (2.6.1) rafaela; urgency=medium * Replaced "use-systemd" with "screensaver-uses-logind" gsettings key -- Clement Lefebvre Mon, 25 May 2015 10:35:11 +0200 cinnamon-screensaver (2.6.0) rafaela; urgency=medium * 2.6.0 -- Clement Lefebvre Tue, 19 May 2015 17:26:43 +0200 cinnamon-screensaver (2.5.0) unstable; urgency=medium * bump for development -- Michael Webster Sat, 11 Apr 2015 09:09:01 -0400 cinnamon-screensaver (2.4.2) betsy; urgency=medium [ Michael Webster ] * desktop file: Fix OnlyShowIn line, remove autogenerated .in file. * gs-window-x11.c: Fix some leaks, readability * gs-window-x11.c: Fix black background * gnome-wall-clock.c: Fix regressions from b021f6f07ad8b4295ddd755eadf3e031f4456fe6 -- Clement Lefebvre Mon, 30 Mar 2015 15:08:10 +0200 cinnamon-screensaver (2.4.1) betsy; urgency=medium * DBus listener: correctly reply so the client doesn't block waiting * Reduce the number of wakeups -- Clement Lefebvre Wed, 18 Feb 2015 13:37:22 +0100 cinnamon-screensaver (2.4.0) rebecca; urgency=medium * 2.4.0 -- Clement Lefebvre Fri, 31 Oct 2014 16:05:26 +0100 cinnamon-screensaver (2.3.0) unstable; urgency=medium * 2.3.0 -- Clement Lefebvre Fri, 27 Jun 2014 14:24:03 +0100 cinnamon-screensaver (2.2.4) qiana; urgency=medium [ Andrew Rossignol ] * Fixed a transparency issue with certain themes. [ Clement Lefebvre ] * Fixed build issue -- Clement Lefebvre Fri, 06 Jun 2014 16:44:50 +0100 cinnamon-screensaver (2.2.3) qiana; urgency=medium * 2.2.3 -- Clement Lefebvre Thu, 08 May 2014 09:38:18 +0100 cinnamon-screensaver (2.2.2) qiana; urgency=medium * 2.2.2 -- Clement Lefebvre Fri, 02 May 2014 16:46:15 +0100 cinnamon-screensaver (2.2.1) qiana; urgency=medium * 2.2.1 -- Clement Lefebvre Thu, 01 May 2014 14:48:00 +0100 cinnamon-screensaver (2.2.0) qiana; urgency=medium * 2.2.0 -- Clement Lefebvre Sat, 12 Apr 2014 13:07:30 +0100 cinnamon-screensaver (2.0.3) petra; urgency=low * 2.0.3 -- Clement Lefebvre Sat, 26 Oct 2013 18:34:24 +0100 cinnamon-screensaver (2.0.2) petra; urgency=low * 2.0.2 -- Clement Lefebvre Tue, 22 Oct 2013 14:40:55 +0100 cinnamon-screensaver (2.0.1) petra; urgency=low * 2.0.1 -- Clement Lefebvre Fri, 18 Oct 2013 15:59:15 +0100 cinnamon-screensaver (2.0.0) petra; urgency=low * 2.0.0 -- Clement Lefebvre Wed, 02 Oct 2013 16:14:24 +0100 cinnamon-screensaver (1.9.1) petra; urgency=low * 1.9.1 -- Clement Lefebvre Mon, 30 Sep 2013 14:17:40 +0100 cinnamon-screensaver (1.8.0) olivia; urgency=low * 1.8.0 -- Clement Lefebvre Sun, 05 May 2013 12:25:34 +0100 cinnamon-screensaver (1.7.2) olivia; urgency=low * 1.7.2 -- Clement Lefebvre Sun, 28 Apr 2013 11:37:04 +0100 cinnamon-screensaver (1.7.1) olivia; urgency=low * 1.7.1 -- Clement Lefebvre Tue, 19 Feb 2013 16:35:10 +0000 cinnamon-screensaver (1.0.0) nadia; urgency=low * Initial version (based on gnome-screensaver 3.4.1) -- Clement Lefebvre Thu, 10 Jan 2013 16:50:43 +0000 cinnamon-screensaver-4.4.1/debian/cinnamon-screensaver-pam-helper.install000066400000000000000000000000531357366610100266300ustar00rootroot00000000000000/usr/lib/*/cinnamon-screensaver-pam-helper cinnamon-screensaver-4.4.1/debian/cinnamon-screensaver.install000066400000000000000000000004151357366610100246020ustar00rootroot00000000000000etc/pam.d/cinnamon-screensaver usr/bin usr/lib/*/cinnamon-screensaver/cinnamon-screensaver-pam-helper usr/share/applications usr/share/cinnamon-screensaver/*.css usr/share/cinnamon-screensaver/*.py usr/share/cinnamon-screensaver/*/*.py usr/share/dbus-1 usr/share/icons cinnamon-screensaver-4.4.1/debian/cinnamon-screensaver.lintian-overrides000066400000000000000000000002341357366610100265710ustar00rootroot00000000000000cinnamon-screensaver: binary-without-manpage usr/bin/cinnamon-screensaver cinnamon-screensaver: binary-without-manpage usr/bin/cinnamon-screensaver-command cinnamon-screensaver-4.4.1/debian/cinnamon-screensaver.pam000066400000000000000000000000701357366610100237060ustar00rootroot00000000000000@include common-auth auth optional pam_gnome_keyring.so cinnamon-screensaver-4.4.1/debian/compat000066400000000000000000000000031357366610100202710ustar00rootroot0000000000000010 cinnamon-screensaver-4.4.1/debian/control000066400000000000000000000042631357366610100205020ustar00rootroot00000000000000Source: cinnamon-screensaver Section: x11 Priority: optional Maintainer: Linux Mint Build-Depends: autoconf-archive, automake, debhelper (>= 10), dh-python, gnome-pkg-tools (>= 0.10), gobject-introspection, intltool (>= 0.40.0), libdbus-1-dev, libgirepository1.0-dev, libglib2.0-dev (>= 2.37.3), libgtk-3-dev (>= 3.1.4), libpam0g-dev, librsvg2-bin, libxext-dev, python3, Standards-Version: 3.9.6 Package: cinnamon-screensaver Architecture: any Pre-Depends: ${misc:Pre-Depends} Depends: cinnamon-desktop-data (>= 3.5), gir1.2-accountsservice-1.0, gir1.2-cinnamondesktop-3.0 (>= 3.5), gir1.2-gkbd-3.0, gir1.2-glib-2.0, gir1.2-gtk-3.0, gir1.2-xapp-1.0, iso-flag-png, libcscreensaver0 (= ${binary:Version}), python3, python3-gi, python3-gi-cairo, python3-setproctitle, python3-xapp (>= 1.0.1), python3-xlib, ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends}, Recommends: libpam-gnome-keyring Breaks: cinnamon-screensaver-pam-helper (<< 3.8), cinnamon-screensaver-webkit-plugin (<< 3.9), cinnamon-screensaver-x-plugin (<< 3.9) Replaces: cinnamon-screensaver-pam-helper (<< 3.8), cinnamon-screensaver-webkit-plugin (<< 3.9), cinnamon-screensaver-x-plugin (<< 3.9) Description: Cinnamon screen saver and locker cinnamon-screensaver is a screen saver and locker that aims to have simple, sane and secure defaults, and be well integrated with the Cinnamon desktop. Package: libcscreensaver-dbg Section: debug Priority: extra Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: libcscreensaver0 (= ${binary:Version}), ${misc:Depends} Description: Cinnamon Screensaver library - debug symbols This package contains the symbols files needed to debug the Cinnamon Screensaver library. Package: libcscreensaver0 Section: libs Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: ${gir:Depends}, ${misc:Depends}, ${shlibs:Depends} Description: library and introspection data used by cinnamon-screensaver cinnamon-screensaver is a screen saver and locker that aims to have simple, sane and secure defaults, and be well integrated with the Cinnamon desktop. . This package contains the library used by the screensaver. cinnamon-screensaver-4.4.1/debian/copyright000066400000000000000000000057661357366610100210430ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cinnamon-screensaver Upstream-Contact: Linux Mint Project Source: https://github.com/linuxmint/cinnamon-screensaver.git Files: * Copyright: 2016, Michael Webster License: GPL-2+ Files: COPYING.LIB Copyright: 1951, Franklin Street - Suite 500, Boston, MA, 02110-1335, USA 1991, Free Software Foundation, Inc License: LGPL-2+ Files: debian/* Copyright: 2014-2017, Maximiliano Curia Copyright: 2013-2017, Linux Mint Project License: LGPL-2+ Files: libcscreensaver/setuid.c libcscreensaver/setuid.h libcscreensaver/subprocs.c libcscreensaver/subprocs.h Copyright: 1991-2004, Jamie Zawinski 2004, William Jon McCann License: MIT/X11 Files: po/Makefile.in.in Copyright: 2004-2008, Rodney Dawes 1995-1997, Ulrich Drepper License: Permissive License: GPL-2+ This program is free software; you can 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. . On Debian systems, the complete text of the GNU General Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'. License: LGPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library 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 Library General Public License for more details. . On Debian systems, the complete text of the GNU Library General Public License version 2 can be found in `/usr/share/common-licenses/LGPL-2'. License: MIT/X11 Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. License: Permissive This file may be copied and used freely without restrictions. It may be used in projects which are not available under a GNU Public License, but which still want to provide support for the GNU gettext functionality. cinnamon-screensaver-4.4.1/debian/libcscreensaver0.install000066400000000000000000000002331357366610100237120ustar00rootroot00000000000000usr/lib/*/girepository-1.0/CScreensaver-1.0.typelib usr/lib/*/libcscreensaver.so.0 usr/lib/*/libcscreensaver.so.0.* usr/share/gir-1.0/CScreensaver-1.0.gir cinnamon-screensaver-4.4.1/debian/not-installed000066400000000000000000000003251357366610100215720ustar00rootroot00000000000000# Internal lib, no need for the dev parts usr/lib/*/libcscreensaver.la usr/lib/*/libcscreensaver.so usr/lib/*/pkgconfig/cscreensaver.pc usr/include/cinnamon-screensaver/ # precompiled python files */__pycache__/ cinnamon-screensaver-4.4.1/debian/rules000077500000000000000000000010551357366610100201530ustar00rootroot00000000000000#!/usr/bin/make -f export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) %: dh $@ --with=python3,gir override_dh_autoreconf: NOCONFIGURE=1 dh_autoreconf --as-needed ./autogen.sh override_dh_strip: dh_strip --dbg-package=libcscreensaver-dbg override_dh_auto_configure: dh_auto_configure -- \ --libexecdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH)/cinnamon-screensaver override_dh_install: dh_install --list-missing override_dh_python3: dh_python3 usr/share/cinnamon-screensaver cinnamon-screensaver-4.4.1/debian/source/000077500000000000000000000000001357366610100203725ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/debian/source/format000066400000000000000000000000151357366610100216010ustar00rootroot000000000000003.0 (native) cinnamon-screensaver-4.4.1/doc/000077500000000000000000000000001357366610100164155ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/doc/dbus-interface.html000066400000000000000000000372461357366610100222120ustar00rootroot00000000000000Cinnamon Screensaver 1.8.0 Documentation

Cinnamon Screensaver 1.8.0 Documentation

William Jon McCann

Version 1.8.0


Chapter1.DBUS Interface

This API is currently unstable and is likely to change in the future.

Introduction

Cinnamon Screensaver exposes a DBUS API for programs to obtain information about the screensaver state and to interact with the screensaver in limited ways.

The following constants are used to uniquely refer to the CinnamonScreensaver object when making DBUS method calls:

DBUS Service:org.cinnamon.ScreenSaver
DBUS Object Path:/org.cinnamon.ScreenSaver
DBUS Interface:org.cinnamon.ScreenSaver

Methods

These are the DBUS methods.

Lock

Request that the screen be locked.

DirectionTypeDescription
instringthe away message

Cycle

Request that the screen saver theme be restarted and, if applicable, switch to the next one in the list.

SimulateUserActivity

Simulate user activity. If the screensaver is activated this will attempt to deactivate and authentication will be requested if necessary. If the screensaver is not activated then the idle timers will be reset.

Throttle

Request that running themes while the screensaver is active be blocked until UnThrottle is called or the calling process exits.

DirectionTypeDescription
instringthe application name, e.g. "gnome-power-manager"
instringthe localized reason to inhibit, e.g. "on battery power"
outunsigned integerthe cookie

A cookie is a random, unique, non-zero UINT32 used to identify the throttle request.

UnThrottle

Cancel a previous call to Throttle() identified by the cookie.

DirectionTypeDescription
inunsigned integerthe cookie

SetActive

Request a change in the state of the screensaver. Set to TRUE to request that the screensaver activate. Active means that the screensaver has blanked the screen and may run a graphical theme. This does not necessary mean that the screen is locked.

DirectionTypeDescription
inbooleanTRUE to request activation, FALSE to request deactivation

GetActive

Returns the value of the current state of activity. See SetActive().

DirectionTypeDescription
outbooleanActivation state

GetActiveTime

Returns the number of seconds that the screensaver has been active. Returns zero if the screensaver is not active.

DirectionTypeDescription
outunsigned integerActive time in seconds

GetSessionIdle

Returns the value of the current state of session idleness.

DirectionTypeDescription
outbooleanIf the session is idle

GetSessionIdleTime

Returns the number of seconds that the session has been idle. Returns zero if the session is not idle.

DirectionTypeDescription
outunsigned integerIdle time in seconds

Signals

These are the DBUS signals.

ActiveChanged

See method GetActive().

DirectionTypeDescription
outbooleanReturns the value of the current state of activity.

SessionIdleChanged

See method GetActive().

DirectionTypeDescription
outbooleanReturns the value of the current state of activity.

AuthenticationRequestBegin

Emitted before an authentication request

AuthenticationRequestEnd

Emitted after an authentication request

Examples

You can get the number of seconds the screensaver has been active by running the following:

dbus-send --session \
          --dest=org.cinnamon.ScreenSaver \
          --type=method_call \
          --print-reply \
          --reply-timeout=20000 \
          /org/cinnamon/ScreenSaver \
          org.cinnamon.ScreenSaver.GetSessionIdleTime
    

You can activate the screensaver like so:

dbus-send --session \
          --dest=org.cinnamon.ScreenSaver \
          --type=method_call \
          --print-reply \
          --reply-timeout=20000 \
          /org/cinnamon/ScreenSaver \
          org.cinnamon.ScreenSaver.SetActive \
          boolean:true
    

You can monitor screensaver changes:

dbus-monitor --session \
          "type='signal',interface='org.cinnamon.ScreenSaver'"
    

Or watch for a specific screensaver signal:

dbus-monitor --session \
          "type='signal',interface='org.cinnamon.ScreenSaver',member='SessionIdleChanged'"
    
cinnamon-screensaver-4.4.1/files/000077500000000000000000000000001357366610100167525ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/files/Makefile.in000066400000000000000000000002471357366610100210220ustar00rootroot00000000000000all: clean: distclean: install: find -mindepth 1 -maxdepth 1 -type d -exec cp -R {} $(DESTDIR)/ \; uninstall: find -mindepth 1 -type f -exec rm $(DESTDIR)/{} \; cinnamon-screensaver-4.4.1/libcscreensaver/000077500000000000000000000000001357366610100210225ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/libcscreensaver/Makefile.am000066400000000000000000000176441357366610100230720ustar00rootroot00000000000000lib_LTLIBRARIES = libcscreensaver.la dbus_built_sources =\ cs-cinnamon-proxy.c \ cs-cinnamon-proxy.h \ cs-session-presence-proxy.c \ cs-session-presence-proxy.h \ cs-screensaver-proxy.c \ cs-screensaver-proxy.h \ cs-upower-proxy.c \ cs-upower-proxy.h \ cs-upower-device-proxy.c \ cs-upower-device-proxy.h \ cs-logind-manager-proxy.c \ cs-logind-manager-proxy.h \ cs-logind-session-proxy.c \ cs-logind-session-proxy.h \ cs-consolekit-manager-proxy.c \ cs-consolekit-manager-proxy.h \ cs-consolekit-session-proxy.c \ cs-consolekit-session-proxy.h \ cs-keybinding-handler-proxy.c \ cs-keybinding-handler-proxy.h \ cs-media-player-proxy.c \ cs-media-player-proxy.h cs-cinnamon-proxy.h : Makefile.am org.Cinnamon.xml gdbus-codegen \ --annotate "org.Cinnamon" org.gtk.GDBus.C.Name "Cinnamon" \ --c-namespace Cs \ --generate-c-code cs-cinnamon-proxy \ org.Cinnamon.xml \ $(NULL) cs-cinnamon-proxy.c : cs-cinnamon-proxy.h cs-session-presence-proxy.h : Makefile.am org.gnome.SessionManager.Presence.xml gdbus-codegen \ --annotate "org.gnome.SessionManager.Presence" org.gtk.GDBus.C.Name "SessionPresence" \ --c-namespace Cs \ --generate-c-code cs-session-presence-proxy \ org.gnome.SessionManager.Presence.xml \ $(NULL) cs-session-presence-proxy.c : cs-session-presence-proxy.h cs-upower-proxy.h : Makefile.am org.freedesktop.UPower.xml gdbus-codegen \ --annotate "org.freedesktop.UPower" org.gtk.GDBus.C.Name "UPower" \ --c-namespace Cs \ --generate-c-code cs-upower-proxy \ --annotate "org.freedesktop.UPower.EnumerateDevices()[devices]" org.gtk.GDBus.C.ForceGVariant true \ org.freedesktop.UPower.xml \ $(NULL) cs-upower-proxy.c : cs-upower-proxy.h cs-upower-device-proxy.h : Makefile.am org.freedesktop.UPower.Device.xml gdbus-codegen \ --annotate "org.freedesktop.UPower.Device" org.gtk.GDBus.C.Name "UPowerDevice" \ --c-namespace Cs \ --generate-c-code cs-upower-device-proxy \ org.freedesktop.UPower.Device.xml \ $(NULL) cs-upower-device-proxy.c : cs-upower-device-proxy.h cs-logind-manager-proxy.h : Makefile.am org.freedesktop.login1.Manager.xml gdbus-codegen \ --annotate "org.freedesktop.login1.Manager" org.gtk.GDBus.C.Name "LogindManager" \ --c-namespace Cs \ --generate-c-code cs-logind-manager-proxy \ org.freedesktop.login1.Manager.xml \ $(NULL) cs-logind-manager-proxy.c : cs-logind-manager-proxy.h cs-logind-session-proxy.h : Makefile.am org.freedesktop.login1.Session.xml gdbus-codegen \ --annotate "org.freedesktop.login1.Session" org.gtk.GDBus.C.Name "LogindSession" \ --c-namespace Cs \ --generate-c-code cs-logind-session-proxy \ org.freedesktop.login1.Session.xml \ $(NULL) cs-logind-session-proxy.c : cs-logind-session-proxy.h cs-consolekit-manager-proxy.h : Makefile.am org.freedesktop.ConsoleKit.Manager.xml gdbus-codegen \ --annotate "org.freedesktop.ConsoleKit.Manager" org.gtk.GDBus.C.Name "ConsoleKitManager" \ --c-namespace Cs \ --generate-c-code cs-consolekit-manager-proxy \ org.freedesktop.ConsoleKit.Manager.xml \ $(NULL) cs-consolekit-manager-proxy.c : cs-consolekit-manager-proxy.h cs-consolekit-session-proxy.h : Makefile.am org.freedesktop.ConsoleKit.Session.xml gdbus-codegen \ --annotate "org.freedesktop.ConsoleKit.Session" org.gtk.GDBus.C.Name "ConsoleKitSession" \ --c-namespace Cs \ --generate-c-code cs-consolekit-session-proxy \ org.freedesktop.ConsoleKit.Session.xml \ $(NULL) cs-consolekit-session-proxy.c : cs-consolekit-session-proxy.h cs-screensaver-proxy.h : Makefile.am org.cinnamon.ScreenSaver.xml gdbus-codegen \ --annotate "org.cinnamon.ScreenSaver" org.gtk.GDBus.C.Name "ScreenSaver" \ --c-namespace Cs \ --generate-c-code cs-screensaver-proxy \ org.cinnamon.ScreenSaver.xml \ $(NULL) cs-screensaver-proxy.c : cs-screensaver-proxy.h cs-keybinding-handler-proxy.h : Makefile.am org.cinnamon.SettingsDaemon.KeybindingHandler.xml gdbus-codegen \ --annotate "org.cinnamon.SettingsDaemon.KeybindingHandler" org.gtk.GDBus.C.Name "KeybindingHandler" \ --c-namespace Cs \ --generate-c-code cs-keybinding-handler-proxy \ org.cinnamon.SettingsDaemon.KeybindingHandler.xml \ $(NULL) cs-keybinding-handler-proxy.c : cs-keybinding-handler-proxy.h cs-media-player-proxy.h : Makefile.am org.mpris.MediaPlayer2.Player.xml gdbus-codegen \ --annotate "org.mpris.MediaPlayer2.Player" org.gtk.GDBus.C.Name "MediaPlayer" \ --c-namespace Cs \ --generate-c-code cs-media-player-proxy \ org.mpris.MediaPlayer2.Player.xml \ $(NULL) cs-media-player-proxy.c : cs-media-player-proxy.h AUTH_SOURCES = \ cs-auth-@AUTH_SCHEME@.c \ $(NULL) libcscreensaver_la_CPPFLAGS = \ $(WARN_CFLAGS) \ $(CSCREENSAVER_CFLAGS) \ -I$(srcdir) \ -DWITH_INTROSPECTION \ -DG_LOG_DOMAIN="\"CScreensaver\"" libcscreensaver_ladir = $(includedir)/cinnamon-screensaver/libcscreensaver libcscreensaver_la_HEADERS = \ cs-auth.h \ setuid.h \ $(NULL) libcscreensaver_la_gir_sources = \ cs-gdk-event-filter.h \ cs-gdk-event-filter-x11.c \ cs-notification-watcher.h \ cs-notification-watcher.c \ cs-screen.h \ cs-screen-x11.c \ $(dbus_built_sources) \ $(NULL) libcscreensaver_la_SOURCES = \ $(libcscreensaver_la_gir_sources) \ $(AUTH_SOURCES) \ subprocs.c \ subprocs.h \ setuid.c \ $(NULL) libcscreensaver_la_LIBADD = \ $(CSCREENSAVER_LIBS) \ $(AUTH_LIBS) \ $(NULL) noinst_PROGRAMS = \ test-passwd \ $(NULL) test_passwd_SOURCES = \ test-passwd.c \ cs-auth.h \ $(AUTH_SOURCES) \ setuid.c \ setuid.h \ subprocs.c \ subprocs.h \ $(NULL) test_passwd_LDADD = \ $(CSCREENSAVER_LIBS)\ $(AUTH_LIBS) \ $(NULL) test_passwd_CPPFLAGS = \ $(WARN_CFLAGS) \ $(CSCREENSAVER_CFLAGS) \ $(NULL) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cscreensaver.pc include $(INTROSPECTION_MAKEFILE) INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) CScreensaver-1.0.gir: libcscreensaver.la CScreensaver_1_0_gir_INCLUDES = Gtk-3.0 CScreensaver_1_0_gir_CFLAGS = $(INCLUDES) -I$(top_srcdir)/libcscreensaver -DWITH_INTROSPECTION CScreensaver_1_0_gir_LIBS = libcscreensaver.la CScreensaver_1_0_gir_SCANNERFLAGS = --identifier-prefix=Cs --symbol-prefix=cs_ CScreensaver_1_0_gir_FILES = $(libcscreensaver_la_gir_sources) INTROSPECTION_GIRS = CScreensaver-1.0.gir girdir = $(datadir)/gir-1.0 gir_DATA = CScreensaver-1.0.gir typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES = $(gir_DATA) \ $(typelib_DATA) \ $(dbus_built_sources) MAINTAINERCLEANFILES = \ Makefile.in EXTRA_DIST = \ cscreensaver.pc.in \ cscreensaver-uninstalled.pc.in \ org.Cinnamon.xml \ org.gnome.SessionManager.Presence.xml \ org.freedesktop.UPower.xml \ org.freedesktop.UPower.Device.xml \ org.freedesktop.login1.Manager.xml \ org.freedesktop.login1.Session.xml \ org.freedesktop.ConsoleKit.Manager.xml \ org.freedesktop.ConsoleKit.Session.xml \ org.cinnamon.ScreenSaver.xml \ org.cinnamon.SettingsDaemon.KeybindingHandler.xml \ org.mpris.MediaPlayer2.Player.xmlcinnamon-screensaver-4.4.1/libcscreensaver/cs-auth-pam.c000066400000000000000000000570111357366610100233110ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 William Jon McCann * Copyright (C) 2006 Ray Strode * Copyright (C) 2003 Bill Nottingham * Copyright (c) 1993-2003 Jamie Zawinski * * This program is free software; you can 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 - Suite 500, Boston, MA * 02110-1335, USA. * */ #include "config.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cs-auth.h" #include "subprocs.h" /* Some time between Red Hat 4.2 and 7.0, the words were transposed in the various PAM_x_CRED macro names. Yay! */ #ifndef PAM_REFRESH_CRED # define PAM_REFRESH_CRED PAM_CRED_REFRESH #endif #ifdef HAVE_PAM_FAIL_DELAY /* We handle delays ourself.*/ /* Don't set this to 0 (Linux bug workaround.) */ # define PAM_NO_DELAY(pamh) pam_fail_delay ((pamh), 1) #else /* !HAVE_PAM_FAIL_DELAY */ # define PAM_NO_DELAY(pamh) /* */ #endif /* !HAVE_PAM_FAIL_DELAY */ /* On SunOS 5.6, and on Linux with PAM 0.64, pam_strerror() takes two args. On some other Linux systems with some other version of PAM (e.g., whichever Debian release comes with a 2.2.5 kernel) it takes one arg. I can't tell which is more "recent" or "correct" behavior, so configure figures out which is in use for us. Shoot me! */ #ifdef PAM_STRERROR_TWO_ARGS # define PAM_STRERROR(pamh, status) pam_strerror((pamh), (status)) #else /* !PAM_STRERROR_TWO_ARGS */ # define PAM_STRERROR(pamh, status) pam_strerror((status)) #endif /* !PAM_STRERROR_TWO_ARGS */ static gboolean verbose_enabled = FALSE; static pam_handle_t *pam_handle = NULL; static gboolean did_we_ask_for_password = FALSE; #define DEBUG(...) if (verbose_enabled) g_printerr (__VA_ARGS__) struct pam_closure { const char *username; CsAuthMessageFunc cb_func; gpointer cb_data; int signal_fd; int result; }; typedef struct { struct pam_closure *closure; CsAuthMessageStyle style; const char *msg; char **resp; gboolean should_interrupt_stack; } GsAuthMessageHandlerData; static GCond *message_handled_condition; static GMutex *message_handler_mutex; GQuark cs_auth_error_quark (void) { static GQuark quark = 0; if (! quark) { quark = g_quark_from_static_string ("cs_auth_error"); } return quark; } void cs_auth_set_verbose (gboolean enabled) { verbose_enabled = enabled; } gboolean cs_auth_get_verbose (void) { return verbose_enabled; } static CsAuthMessageStyle pam_style_to_cs_style (int pam_style) { CsAuthMessageStyle style; switch (pam_style) { case PAM_PROMPT_ECHO_ON: style = CS_AUTH_MESSAGE_PROMPT_ECHO_ON; break; case PAM_PROMPT_ECHO_OFF: style = CS_AUTH_MESSAGE_PROMPT_ECHO_OFF; break; case PAM_ERROR_MSG: style = CS_AUTH_MESSAGE_ERROR_MSG; break; case PAM_TEXT_INFO: style = CS_AUTH_MESSAGE_TEXT_INFO; break; default: g_assert_not_reached (); break; } return style; } static gboolean auth_message_handler (CsAuthMessageStyle style, const char *msg, char **response, gpointer data) { gboolean ret; ret = TRUE; *response = NULL; switch (style) { case CS_AUTH_MESSAGE_PROMPT_ECHO_ON: break; case CS_AUTH_MESSAGE_PROMPT_ECHO_OFF: if (msg != NULL && g_str_has_prefix (msg, _("Password:"))) { did_we_ask_for_password = TRUE; } break; case CS_AUTH_MESSAGE_ERROR_MSG: break; case CS_AUTH_MESSAGE_TEXT_INFO: break; default: g_assert_not_reached (); } return ret; } static gboolean cs_auth_queued_message_handler (GsAuthMessageHandlerData *data) { gboolean res; if (cs_auth_get_verbose ()) { DEBUG ("Waiting for lock\n"); } g_mutex_lock (message_handler_mutex); if (cs_auth_get_verbose ()) { DEBUG ("Waiting for response\n"); } res = data->closure->cb_func (data->style, data->msg, data->resp, data->closure->cb_data); data->should_interrupt_stack = res == FALSE; g_printerr ("should interrupt: %d\n", data->should_interrupt_stack); g_cond_signal (message_handled_condition); g_mutex_unlock (message_handler_mutex); if (cs_auth_get_verbose ()) { DEBUG ("Got response\n"); } return FALSE; } static gboolean cs_auth_run_message_handler (struct pam_closure *c, CsAuthMessageStyle style, const char *msg, char **resp) { GsAuthMessageHandlerData data; data.closure = c; data.style = style; data.msg = msg; data.resp = resp; data.should_interrupt_stack = TRUE; g_mutex_lock (message_handler_mutex); /* Queue the callback in the gui (the main) thread */ g_idle_add ((GSourceFunc) cs_auth_queued_message_handler, &data); if (cs_auth_get_verbose ()) { DEBUG ("Waiting for respose to message style %d: '%s'\n", style, msg); } /* Wait for the response */ g_cond_wait (message_handled_condition, message_handler_mutex); g_mutex_unlock (message_handler_mutex); if (cs_auth_get_verbose ()) { DEBUG ("Got respose to message style %d: interrupt:%d\n", style, data.should_interrupt_stack); } return data.should_interrupt_stack == FALSE; } static int pam_conversation (int nmsgs, const struct pam_message **msg, struct pam_response **resp, void *closure) { int replies = 0; struct pam_response *reply = NULL; struct pam_closure *c = (struct pam_closure *) closure; gboolean res; int ret; reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply)); if (reply == NULL) { return PAM_CONV_ERR; } res = TRUE; ret = PAM_SUCCESS; for (replies = 0; replies < nmsgs && ret == PAM_SUCCESS; replies++) { CsAuthMessageStyle style; char *utf8_msg; style = pam_style_to_cs_style (msg [replies]->msg_style); utf8_msg = g_locale_to_utf8 (msg [replies]->msg, -1, NULL, NULL, NULL); /* if we couldn't convert text from locale then * assume utf-8 and hope for the best */ if (utf8_msg == NULL) { char *p; char *q; utf8_msg = g_strdup (msg [replies]->msg); p = utf8_msg; while (*p != '\0' && !g_utf8_validate ((const char *)p, -1, (const char **)&q)) { *q = '?'; p = q + 1; } } /* handle message locally first */ auth_message_handler (style, utf8_msg, &reply [replies].resp, NULL); if (c->cb_func != NULL) { if (cs_auth_get_verbose ()) { DEBUG ("Handling message style %d: '%s'\n", style, utf8_msg); } /* blocks until the gui responds */ res = cs_auth_run_message_handler (c, style, utf8_msg, &reply [replies].resp); if (cs_auth_get_verbose ()) { DEBUG ("Msg handler returned %d\n", res); } /* If the handler returns FALSE - interrupt the PAM stack */ if (res) { reply [replies].resp_retcode = PAM_SUCCESS; } else { int i; for (i = 0; i <= replies; i++) { free (reply [i].resp); } free (reply); reply = NULL; ret = PAM_CONV_ERR; } } g_free (utf8_msg); } *resp = reply; return ret; } static gboolean close_pam_handle (int status) { if (pam_handle != NULL) { int status2; status2 = pam_end (pam_handle, status); pam_handle = NULL; if (cs_auth_get_verbose ()) { DEBUG (" pam_end (...) ==> %d (%s)\n", status2, (status2 == PAM_SUCCESS ? "Success" : "Failure")); } } if (message_handled_condition != NULL) { g_cond_free (message_handled_condition); message_handled_condition = NULL; } if (message_handler_mutex != NULL) { g_mutex_free (message_handler_mutex); message_handler_mutex = NULL; } return TRUE; } static gboolean create_pam_handle (const char *username, const char *display, struct pam_conv *conv, int *status_code) { int status; const char *service = PAM_SERVICE_NAME; char *disp; gboolean ret; if (pam_handle != NULL) { g_warning ("create_pam_handle: Stale pam handle around, cleaning up\n"); close_pam_handle (PAM_SUCCESS); } /* init things */ pam_handle = NULL; status = -1; disp = NULL; ret = TRUE; /* Initialize a PAM session for the user */ if ((status = pam_start (service, username, conv, &pam_handle)) != PAM_SUCCESS) { pam_handle = NULL; g_warning (_("Unable to establish service %s: %s\n"), service, PAM_STRERROR (NULL, status)); if (status_code != NULL) { *status_code = status; } ret = FALSE; goto out; } if (cs_auth_get_verbose ()) { DEBUG ("pam_start (\"%s\", \"%s\", ...) ==> %d (%s)\n", service, username, status, PAM_STRERROR (pam_handle, status)); } disp = g_strdup (display); if (disp == NULL) { disp = g_strdup (":0.0"); } if ((status = pam_set_item (pam_handle, PAM_TTY, disp)) != PAM_SUCCESS) { g_warning (_("Can't set PAM_TTY=%s"), display); if (status_code != NULL) { *status_code = status; } ret = FALSE; goto out; } ret = TRUE; message_handled_condition = g_cond_new (); message_handler_mutex = g_mutex_new (); out: if (status_code != NULL) { *status_code = status; } g_free (disp); return ret; } static void set_pam_error (GError **error, int status) { if (status == PAM_AUTH_ERR || status == PAM_USER_UNKNOWN) { char *msg; if (did_we_ask_for_password) { msg = g_strdup (_("Incorrect password.")); } else { msg = g_strdup (_("Authentication failed.")); } g_set_error (error, CS_AUTH_ERROR, CS_AUTH_ERROR_AUTH_ERROR, "%s", msg); g_free (msg); } else if (status == PAM_PERM_DENIED) { g_set_error (error, CS_AUTH_ERROR, CS_AUTH_ERROR_AUTH_DENIED, "%s", _("Not permitted to gain access at this time.")); } else if (status == PAM_ACCT_EXPIRED) { g_set_error (error, CS_AUTH_ERROR, CS_AUTH_ERROR_AUTH_DENIED, "%s", _("No longer permitted to access the system.")); } } static int cs_auth_thread_func (int auth_operation_fd) { static const int flags = 0; int status; int status2; struct timespec timeout; sigset_t set; const void *p; timeout.tv_sec = 0; timeout.tv_nsec = 1; set = block_sigchld (); status = pam_authenticate (pam_handle, flags); sigtimedwait (&set, NULL, &timeout); unblock_sigchld (); if (cs_auth_get_verbose ()) { DEBUG (" pam_authenticate (...) ==> %d (%s)\n", status, PAM_STRERROR (pam_handle, status)); } if (status != PAM_SUCCESS) { goto done; } if ((status = pam_get_item (pam_handle, PAM_USER, &p)) != PAM_SUCCESS) { /* is not really an auth problem, but it will pretty much look as such, it shouldn't really happen */ goto done; } /* We don't actually care if the account modules fail or succeed, * but we need to run them anyway because certain pam modules * depend on side effects of the account modules getting run. */ status2 = pam_acct_mgmt (pam_handle, 0); if (cs_auth_get_verbose ()) { DEBUG ("pam_acct_mgmt (...) ==> %d (%s)\n", status2, PAM_STRERROR (pam_handle, status2)); } /* FIXME: should we handle these? */ switch (status2) { case PAM_SUCCESS: break; case PAM_NEW_AUTHTOK_REQD: break; case PAM_AUTHINFO_UNAVAIL: break; case PAM_ACCT_EXPIRED: break; case PAM_PERM_DENIED: break; default : break; } /* Each time we successfully authenticate, refresh credentials, for Kerberos/AFS/DCE/etc. If this fails, just ignore that failure and blunder along; it shouldn't matter. Note: this used to be PAM_REFRESH_CRED instead of PAM_REINITIALIZE_CRED, but Jason Heiss says that the Linux PAM library ignores that one, and only refreshes credentials when using PAM_REINITIALIZE_CRED. */ status2 = pam_setcred (pam_handle, PAM_REINITIALIZE_CRED); if (cs_auth_get_verbose ()) { DEBUG (" pam_setcred (...) ==> %d (%s)\n", status2, PAM_STRERROR (pam_handle, status2)); } done: /* we're done, close the fd and wake up the main * loop */ close (auth_operation_fd); return status; } static gboolean cs_auth_loop_quit (GIOChannel *source, GIOCondition condition, gboolean *thread_done) { *thread_done = TRUE; gtk_main_quit (); return FALSE; } static gboolean cs_auth_pam_verify_user (pam_handle_t *handle, int *status) { GThread *auth_thread; GIOChannel *channel; guint watch_id; int auth_operation_fds[2]; int auth_status; gboolean thread_done; channel = NULL; watch_id = 0; auth_status = PAM_AUTH_ERR; /* This pipe gives us a set of fds we can hook into * the event loop to be notified when our helper thread * is ready to be reaped. */ if (pipe (auth_operation_fds) < 0) { goto out; } if (fcntl (auth_operation_fds[0], F_SETFD, FD_CLOEXEC) < 0) { close (auth_operation_fds[0]); close (auth_operation_fds[1]); goto out; } if (fcntl (auth_operation_fds[1], F_SETFD, FD_CLOEXEC) < 0) { close (auth_operation_fds[0]); close (auth_operation_fds[1]); goto out; } channel = g_io_channel_unix_new (auth_operation_fds[0]); /* we use a recursive main loop to process ui events * while we wait on a thread to handle the blocking parts * of pam authentication. */ thread_done = FALSE; watch_id = g_io_add_watch (channel, G_IO_ERR | G_IO_HUP, (GIOFunc) cs_auth_loop_quit, &thread_done); auth_thread = g_thread_create ((GThreadFunc) cs_auth_thread_func, GINT_TO_POINTER (auth_operation_fds[1]), TRUE, NULL); if (auth_thread == NULL) { goto out; } gtk_main (); /* if the event loop was quit before the thread is done then we can't * reap the thread without blocking on it finishing. The * thread may not ever finish though if the pam module is blocking. * * The only time the event loop is going to stop when the thread isn't * done, however, is if the dialog quits early (from, e.g., "cancel"), * so we can just exit. An alternative option would be to switch to * using pthreads directly and calling pthread_cancel. */ if (!thread_done) { raise (SIGTERM); } auth_status = GPOINTER_TO_INT (g_thread_join (auth_thread)); out: if (watch_id != 0 && !thread_done) { g_source_remove (watch_id); watch_id = 0; } if (channel != NULL) { g_io_channel_unref (channel); } if (status) { *status = auth_status; } return auth_status == PAM_SUCCESS; } /** * cs_auth_verify_user: * @username: user name * @display: display string * @func: (scope async): the auth function callback * @data: (closure func): data for func * @error: Return location for error or %NULL. * * Starts a PAM thread for user authentication. * * Returns: Whether or not the user was authenticated successfully */ gboolean cs_auth_verify_user (const char *username, const char *display, CsAuthMessageFunc func, gpointer data, GError **error) { int status = -1; struct pam_conv conv; struct pam_closure c; struct passwd *pwent; pwent = getpwnam (username); if (pwent == NULL) { return FALSE; } c.username = username; c.cb_func = func; c.cb_data = data; conv.conv = &pam_conversation; conv.appdata_ptr = (void *) &c; /* Initialize PAM. */ create_pam_handle (username, display, &conv, &status); if (status != PAM_SUCCESS) { goto done; } pam_set_item (pam_handle, PAM_USER_PROMPT, _("Username:")); did_we_ask_for_password = FALSE; if (! cs_auth_pam_verify_user (pam_handle, &status)) { goto done; } done: if (status != PAM_SUCCESS) { set_pam_error (error, status); } close_pam_handle (status); return (status == PAM_SUCCESS ? TRUE : FALSE); } gboolean cs_auth_init (void) { return TRUE; } gboolean cs_auth_priv_init (void) { /* We have nothing to do at init-time. However, we might as well do some error checking. If "/etc/pam.d" exists and is a directory, but "/etc/pam.d/xlock" does not exist, warn that PAM probably isn't going to work. This is a priv-init instead of a non-priv init in case the directory is unreadable or something (don't know if that actually happens.) */ const char dir [] = "/etc/pam.d"; const char file [] = "/etc/pam.d/" PAM_SERVICE_NAME; const char file2 [] = "/etc/pam.conf"; struct stat st; if (g_stat (dir, &st) == 0 && st.st_mode & S_IFDIR) { if (g_stat (file, &st) != 0) { g_warning ("%s does not exist.\n" "Authentication via PAM is unlikely to work.", file); } } else if (g_stat (file2, &st) == 0) { FILE *f = g_fopen (file2, "r"); if (f) { gboolean ok = FALSE; char buf[255]; while (fgets (buf, sizeof(buf), f)) { if (strstr (buf, PAM_SERVICE_NAME)) { ok = TRUE; break; } } fclose (f); if (!ok) { g_warning ("%s does not list the `%s' service.\n" "Authentication via PAM is unlikely to work.", file2, PAM_SERVICE_NAME); } } /* else warn about file2 existing but being unreadable? */ } else { g_warning ("Neither %s nor %s exist.\n" "Authentication via PAM is unlikely to work.", file2, file); } /* Return true anyway, just in case. */ return TRUE; } cinnamon-screensaver-4.4.1/libcscreensaver/cs-auth.h000066400000000000000000000041421357366610100225400ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 William Jon McCann * * This program is free software; you can 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 - Suite 500, Boston, MA * 02110-1335, USA. * */ #ifndef __CS_AUTH_H #define __CS_AUTH_H #include G_BEGIN_DECLS typedef enum { CS_AUTH_MESSAGE_PROMPT_ECHO_ON, CS_AUTH_MESSAGE_PROMPT_ECHO_OFF, CS_AUTH_MESSAGE_ERROR_MSG, CS_AUTH_MESSAGE_TEXT_INFO } CsAuthMessageStyle; typedef enum { CS_AUTH_ERROR_GENERAL, CS_AUTH_ERROR_AUTH_ERROR, CS_AUTH_ERROR_USER_UNKNOWN, CS_AUTH_ERROR_AUTH_DENIED } CsAuthError; #define PAM_SERVICE_NAME "cinnamon-screensaver" typedef gboolean (* CsAuthMessageFunc) (CsAuthMessageStyle style, const char *msg, char **response, gpointer data); #define CS_AUTH_ERROR cs_auth_error_quark () GQuark cs_auth_error_quark (void); void cs_auth_set_verbose (gboolean verbose); gboolean cs_auth_get_verbose (void); gboolean cs_auth_priv_init (void); gboolean cs_auth_init (void); gboolean cs_auth_verify_user (const char *username, const char *display, CsAuthMessageFunc func, gpointer data, GError **error); G_END_DECLS #endif /* __CS_AUTH_H */ cinnamon-screensaver-4.4.1/libcscreensaver/cs-gdk-event-filter-x11.c000066400000000000000000000130661357366610100253550ustar00rootroot00000000000000/* * CsGdkEventFilter: An introspectable C class that establishes an event * trap for the screensaver. It watches for any X events that could result * in other windows showing up over our Stage, and ensures the Stage stays on * top. This will only ever be other override-redirect (non-managed) X windows, * such as native Firefox or Chrome notification popups. * */ #include "cs-gdk-event-filter.h" #include "config.h" #ifdef HAVE_SHAPE_EXT #include #endif #include #include G_DEFINE_TYPE (CsGdkEventFilter, cs_gdk_event_filter, G_TYPE_OBJECT); static void clear_widget (CsGdkEventFilter *filter); static void unshape_window (CsGdkEventFilter *filter) { g_return_if_fail (CS_IS_GDK_EVENT_FILTER (filter)); gdk_window_shape_combine_region (gtk_widget_get_window (GTK_WIDGET (filter->stage)), NULL, 0, 0); } static void raise_stage (CsGdkEventFilter *filter) { GdkWindow *win; g_return_if_fail (CS_IS_GDK_EVENT_FILTER (filter)); win = gtk_widget_get_window (GTK_WIDGET (filter->stage)); gdk_window_raise (win); } static gboolean x11_window_is_ours (Window window) { GdkWindow *gwindow; gboolean ret; ret = FALSE; gwindow = gdk_x11_window_lookup_for_display (gdk_display_get_default (), window); if (gwindow && (window != GDK_ROOT_WINDOW ())) { ret = TRUE; } return ret; } static void cs_gdk_event_filter_xevent (CsGdkEventFilter *filter, GdkXEvent *xevent) { XEvent *ev; ev = xevent; /* MapNotify is used to tell us when new windows are mapped. ConfigureNofify is used to tell us when windows are raised. */ switch (ev->xany.type) { case MapNotify: { XMapEvent *xme = &ev->xmap; if (! x11_window_is_ours (xme->window)) { raise_stage (filter); } break; } case ConfigureNotify: { XConfigureEvent *xce = &ev->xconfigure; if (! x11_window_is_ours (xce->window)) { raise_stage (filter); } break; } default: { #ifdef HAVE_SHAPE_EXT if (ev->xany.type == (filter->shape_event_base + ShapeNotify)) { unshape_window (filter); } #endif break; } } } static void select_popup_events (void) { XWindowAttributes attr; unsigned long events; gdk_error_trap_push (); memset (&attr, 0, sizeof (attr)); XGetWindowAttributes (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (), &attr); events = SubstructureNotifyMask | attr.your_event_mask; XSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_ROOT_WINDOW (), events); gdk_error_trap_pop_ignored (); } static void select_shape_events (CsGdkEventFilter *filter) { #ifdef HAVE_SHAPE_EXT unsigned long events; int shape_error_base; gdk_error_trap_push (); if (XShapeQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &filter->shape_event_base, &shape_error_base)) { events = ShapeNotifyMask; XShapeSelectInput (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (filter->stage))), events); } gdk_error_trap_pop_ignored (); #endif } static GdkFilterReturn xevent_filter (GdkXEvent *xevent, GdkEvent *event, CsGdkEventFilter *filter) { cs_gdk_event_filter_xevent (filter, xevent); return GDK_FILTER_CONTINUE; } static void cs_gdk_event_filter_init (CsGdkEventFilter *filter) { filter->shape_event_base = 0; filter->stage = NULL; } static void cs_gdk_event_filter_finalize (GObject *object) { CsGdkEventFilter *filter; g_return_if_fail (object != NULL); g_return_if_fail (CS_IS_GDK_EVENT_FILTER (object)); filter = CS_GDK_EVENT_FILTER (object); cs_gdk_event_filter_stop (filter); G_OBJECT_CLASS (cs_gdk_event_filter_parent_class)->finalize (object); } static void cs_gdk_event_filter_class_init (CsGdkEventFilterClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = cs_gdk_event_filter_finalize; } static void on_widget_finalized (CsGdkEventFilter *filter, GtkWidget *stage) { cs_gdk_event_filter_stop (filter); clear_widget (filter); } static void clear_widget (CsGdkEventFilter *filter) { if (filter->stage == NULL) return; g_object_weak_unref (G_OBJECT (filter->stage), (GWeakNotify) on_widget_finalized, filter); filter->stage = NULL; } void cs_gdk_event_filter_start (CsGdkEventFilter *filter, GtkWidget *stage) { g_return_if_fail(stage != NULL); filter->stage = stage; g_object_weak_ref (G_OBJECT (stage), (GWeakNotify) on_widget_finalized, filter); select_popup_events (); select_shape_events (filter); gdk_window_add_filter (NULL, (GdkFilterFunc) xevent_filter, filter); } void cs_gdk_event_filter_stop (CsGdkEventFilter *filter) { gdk_window_remove_filter (NULL, (GdkFilterFunc) xevent_filter, filter); clear_widget (filter); } CsGdkEventFilter * cs_gdk_event_filter_new (void) { GObject *result; result = g_object_new (CS_TYPE_GDK_EVENT_FILTER, NULL); return CS_GDK_EVENT_FILTER (result); } cinnamon-screensaver-4.4.1/libcscreensaver/cs-gdk-event-filter.h000066400000000000000000000025701357366610100247510ustar00rootroot00000000000000 #ifndef __CS_GDK_EVENT_FILTER_H #define __CS_GDK_EVENT_FILTER_H #include #include G_BEGIN_DECLS #define CS_TYPE_GDK_EVENT_FILTER (cs_gdk_event_filter_get_type ()) #define CS_GDK_EVENT_FILTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CS_TYPE_GDK_EVENT_FILTER, CsGdkEventFilter)) #define CS_GDK_EVENT_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CS_TYPE_GDK_EVENT_FILTER, CsGdkEventFilterClass)) #define CS_IS_GDK_EVENT_FILTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CS_TYPE_GDK_EVENT_FILTER)) #define CS_IS_GDK_EVENT_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CS_TYPE_GDK_EVENT_FILTER)) #define CS_GDK_EVENT_FILTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CS_TYPE_GDK_EVENT_FILTER, CsGdkEventFilterClass)) typedef struct { GObject obj; GtkWidget *stage; int shape_event_base; } CsGdkEventFilter; typedef struct { GObjectClass parent_class; } CsGdkEventFilterClass; GType cs_gdk_event_filter_get_type (void); CsGdkEventFilter *cs_gdk_event_filter_new (void); void cs_gdk_event_filter_start (CsGdkEventFilter *filter, GtkWidget *stage); void cs_gdk_event_filter_stop (CsGdkEventFilter *filter); G_END_DECLS #endif /* __CS_GDK_EVENT_FILTER_H */ cinnamon-screensaver-4.4.1/libcscreensaver/cs-notification-watcher.c000066400000000000000000000230121357366610100257100ustar00rootroot00000000000000/* * CsNotificationWatcher: An introspectable C class that eavesdrops on the * session bus, watching for calls to our notification handler (usually Cinnamon.) * * Any notifications received are checked for transiency (and ignored if they are) * and passed on to be handled by Cinnamon. * * Any non-transient notifications cause a signal to be sent to our notification * widget, along with the sender name (in order to filter our mpris player notifications.) */ #include "cs-notification-watcher.h" enum { NOTIFICATION_RECEIVED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (CsNotificationWatcher, cs_notification_watcher, G_TYPE_OBJECT); #define DBUS_SERVICE "org.freedesktop.DBus" #define DBUS_PATH "/org/freedesktop/DBus" #define DBUS_INTERFACE "org.freedesktop.DBus" #define MATCH_RULE "type='method_call', interface='org.freedesktop.Notifications', member='Notify', eavesdrop=true" #define NOTIFICATIONS_INTERFACE "org.freedesktop.Notifications" #define NOTIFY_METHOD "Notify" static gboolean debug_mode = FALSE; typedef struct { CsNotificationWatcher *watcher; gchar *sender; } NotificationIdleData; static gboolean idle_notify_received (gpointer user_data) { NotificationIdleData *data = (NotificationIdleData *) user_data; g_return_val_if_fail (CS_IS_NOTIFICATION_WATCHER (data->watcher), FALSE); g_signal_emit (data->watcher, signals[NOTIFICATION_RECEIVED], 0, data->sender); g_clear_pointer (&data->sender, g_free); g_slice_free (NotificationIdleData, data); return FALSE; } static GDBusMessage * notification_filter_func (GDBusConnection *connection, GDBusMessage *message, gboolean *incoming, gpointer user_data) { GDBusMessage *ret = NULL; gboolean transient = FALSE; gboolean replaces_existing = FALSE; gchar *sender_str = NULL; CsNotificationWatcher *watcher = CS_NOTIFICATION_WATCHER (user_data); if (incoming && g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL && g_strcmp0 (g_dbus_message_get_interface (message), NOTIFICATIONS_INTERFACE) == 0 && g_strcmp0 (g_dbus_message_get_member (message), NOTIFY_METHOD) == 0) { GVariant *body = g_dbus_message_get_body (message); if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE_TUPLE) && g_variant_n_children (body) >= 7) { GVariant *hints, *sender, *replaces_id; if (debug_mode) { GVariant *dbg_var = NULL; const gchar *dbg_str; g_printerr ("Notification received...\n"); dbg_var = g_variant_get_child_value (body, 0); if (dbg_var != NULL && g_variant_is_of_type (dbg_var, G_VARIANT_TYPE_STRING)) { dbg_str = g_variant_get_string (dbg_var, NULL); if (dbg_str != NULL) { g_printerr ("Sender: %s\n", dbg_str); } } g_clear_pointer (&dbg_var, g_variant_unref); dbg_var = g_variant_get_child_value (body, 3); if (dbg_var != NULL && g_variant_is_of_type (dbg_var, G_VARIANT_TYPE_STRING)) { dbg_str = g_variant_get_string (dbg_var, NULL); if (dbg_str != NULL) { g_printerr ("Summary: %s\n", dbg_str); } } g_clear_pointer (&dbg_var, g_variant_unref); dbg_var = g_variant_get_child_value (body, 4); if (dbg_var != NULL && g_variant_is_of_type (dbg_var, G_VARIANT_TYPE_STRING)) { dbg_str = g_variant_get_string (dbg_var, NULL); if (dbg_str != NULL) { g_printerr ("Body: %s\n", dbg_str); } } g_clear_pointer (&dbg_var, g_variant_unref); } hints = g_variant_get_child_value (body, 6); if (hints != NULL && g_variant_is_of_type (hints, G_VARIANT_TYPE_DICTIONARY)) { GVariant *transient_hint; transient_hint = g_variant_lookup_value (hints, "transient", G_VARIANT_TYPE_BOOLEAN); if (transient_hint) { transient = g_variant_get_boolean (transient_hint); g_variant_unref (transient_hint); if (debug_mode) { g_printerr ("notification has transient BOOLEAN hint: %s\n", transient ? "TRUE" : "FALSE"); } } else { transient_hint = g_variant_lookup_value (hints, "transient", G_VARIANT_TYPE_INT32); if (transient_hint) { transient = g_variant_get_int32 (transient_hint); if (debug_mode) { g_printerr ("notification has transient INT32 hint: %d, transient: %s\n", g_variant_get_int32 (transient_hint), transient ? "TRUE" : "FALSE"); } g_variant_unref (transient_hint); } } } g_clear_pointer (&hints, g_variant_unref); sender = g_variant_get_child_value (body, 0); if (sender) { sender_str = g_variant_dup_string (sender, NULL); } g_clear_pointer (&sender, g_variant_unref); replaces_id = g_variant_get_child_value (body, 1); if (replaces_id) { /* The replaces_id will be 0 if the notification is not replacing * another - if it's not zero, we can ignore it, so we don't accumulate * notifications from spammy programs (like dropbox can be) */ replaces_existing = g_variant_get_uint32 (replaces_id) > 0; } g_clear_pointer (&replaces_id, g_variant_unref); } } else { ret = message; } if (ret == NULL && !transient && !replaces_existing) { NotificationIdleData *data = g_slice_new0 (NotificationIdleData); data->watcher = watcher; data->sender = sender_str; g_idle_add (idle_notify_received, data); } return ret; } static void cs_notification_watcher_init (CsNotificationWatcher *watcher) { GError *error = NULL; GVariant *rulev; GVariant *result; watcher->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (!watcher->connection) { g_printerr ("CsNotificationWatcher: Could not connect to session bus - %s\n", error->message); g_clear_error (&error); return; } rulev = g_variant_new("(s)", MATCH_RULE); result = g_dbus_connection_call_sync (watcher->connection, DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE, "AddMatch", rulev, G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (!result) { g_printerr ("CsNotificationWatcher: Could not add match rule to bus - %s\n", error->message); g_clear_error (&error); return; } watcher->filter_id = g_dbus_connection_add_filter (watcher->connection, (GDBusMessageFilterFunction) notification_filter_func, watcher, NULL); } static void cs_notification_watcher_dispose (GObject *object) { CsNotificationWatcher *watcher; g_return_if_fail (object != NULL); g_return_if_fail (CS_IS_NOTIFICATION_WATCHER (object)); watcher = CS_NOTIFICATION_WATCHER (object); if (watcher->filter_id > 0) { g_dbus_connection_remove_filter (watcher->connection, watcher->filter_id); watcher->filter_id = 0; } g_clear_object (&watcher->connection); G_OBJECT_CLASS (cs_notification_watcher_parent_class)->dispose (object); } static void cs_notification_watcher_class_init (CsNotificationWatcherClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = cs_notification_watcher_dispose; signals [NOTIFICATION_RECEIVED] = g_signal_new ("notification-received", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsNotificationWatcherClass, notification_received), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 1, G_TYPE_STRING); } CsNotificationWatcher * cs_notification_watcher_new (gboolean debug) { GObject *result; debug_mode = debug; result = g_object_new (CS_TYPE_NOTIFICATION_WATCHER, NULL); return CS_NOTIFICATION_WATCHER (result); } cinnamon-screensaver-4.4.1/libcscreensaver/cs-notification-watcher.h000066400000000000000000000025741357366610100257270ustar00rootroot00000000000000 #ifndef __CS_NOTIFICATION_WATCHER_H #define __CS_NOTIFICATION_WATCHER_H #include #include #include G_BEGIN_DECLS #define CS_TYPE_NOTIFICATION_WATCHER (cs_notification_watcher_get_type ()) #define CS_NOTIFICATION_WATCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CS_TYPE_NOTIFICATION_WATCHER, CsNotificationWatcher)) #define CS_NOTIFICATION_WATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CS_TYPE_NOTIFICATION_WATCHER, CsNotificationWatcherClass)) #define CS_IS_NOTIFICATION_WATCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CS_TYPE_NOTIFICATION_WATCHER)) #define CS_IS_NOTIFICATION_WATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CS_TYPE_NOTIFICATION_WATCHER)) #define CS_NOTIFICATION_WATCHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CS_TYPE_NOTIFICATION_WATCHER, CsNotificationWatcherClass)) typedef struct { GObject obj; GDBusConnection *connection; gint filter_id; gboolean debug; } CsNotificationWatcher; typedef struct { GObjectClass parent_class; void (* notification_received) (CsNotificationWatcher *watcher, const gchar *sender); } CsNotificationWatcherClass; GType cs_notification_watcher_get_type (void); CsNotificationWatcher *cs_notification_watcher_new (gboolean debug); G_END_DECLS #endif /* __CS_NOTIFICATION_WATCHER_H */ cinnamon-screensaver-4.4.1/libcscreensaver/cs-screen-x11.c000066400000000000000000000571701357366610100234710ustar00rootroot00000000000000/* * CsScreen: An introspectable C class that establishes an event * trap for the screensaver. It watches for any X events that could result * in other windows showing up over our Stage, and ensures the Stage stays on * top. This will only ever be other override-redirect (non-managed) X windows, * such as native Firefox or Chrome notification popups. * */ #include "config.h" #include "cs-screen.h" #include #include #include #ifdef HAVE_SOLARIS_XINERAMA #include #endif #ifdef HAVE_XFREE_XINERAMA #include #endif #ifdef HAVE_RANDR #include #endif enum { SCREEN_MONITORS_CHANGED, SCREEN_SIZE_CHANGED, COMPOSITED_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; G_DEFINE_TYPE (CsScreen, cs_screen, G_TYPE_OBJECT); static gboolean debug_mode = FALSE; #define DEBUG(...) if (debug_mode) g_printerr (__VA_ARGS__) #define cs_XFree(p) do { if ((p)) XFree ((p)); } while (0) #define PRIMARY_MONITOR 0 static gboolean cs_rectangle_equal (const GdkRectangle *src1, const GdkRectangle *src2) { return ((src1->x == src2->x) && (src1->y == src2->y) && (src1->width == src2->width) && (src1->height == src2->height)); } /* The list of monitors reported by the windowing system might include * mirrored monitors with identical bounds. Since mirrored monitors * shouldn't be treated as separate monitors for most purposes, we * filter them out here. (We ignore the possibility of partially * overlapping monitors because they are rare and it's hard to come * up with any sensible interpretation.) */ static void filter_mirrored_monitors (CsScreen *screen) { int i, j; /* Currently always true and simplifies things */ g_assert (screen->primary_monitor_index == 0); for (i = 1; i < screen->n_monitor_infos; i++) { /* In case we've filtered previous monitors */ screen->monitor_infos[i].number = i; for (j = 0; j < i; j++) { if (cs_rectangle_equal (&screen->monitor_infos[i].rect, &screen->monitor_infos[j].rect)) { memmove (&screen->monitor_infos[i], &screen->monitor_infos[i + 1], (screen->n_monitor_infos - i - 1) * sizeof (CsMonitorInfo)); screen->n_monitor_infos--; i--; continue; } } } } #ifdef HAVE_RANDR static CsMonitorInfo * find_monitor_with_rect (CsScreen *screen, int x, int y, int w, int h) { CsMonitorInfo *info; int i; for (i = 0; i < screen->n_monitor_infos; i++) { info = &screen->monitor_infos[i]; if (x == info->rect.x && y == info->rect.y && w == info->rect.width && h == info->rect.height) { return info; } } return NULL; } /* In the case of multiple outputs of a single crtc (mirroring), we consider one of the * outputs the "main". This is the one we consider "owning" the windows, so if * the mirroring is changed to a dual monitor setup then the windows are moved to the * crtc that now has that main output. If one of the outputs is the primary that is * always the main, otherwise we just use the first. */ static XID find_main_output_for_crtc (XRRScreenResources *resources, XRRCrtcInfo *crtc, Display *xdisplay, XID xroot) { XRROutputInfo *output; RROutput primary_output; int i; XID res; primary_output = XRRGetOutputPrimary (xdisplay, xroot); res = None; for (i = 0; i < crtc->noutput; i++) { output = XRRGetOutputInfo (xdisplay, resources, crtc->outputs[i]); if (output->connection != RR_Disconnected && (res == None || crtc->outputs[i] == primary_output)) { res = crtc->outputs[i]; } XRRFreeOutputInfo (output); } return res; } #endif static void apply_scale_factor (CsMonitorInfo *infos, gint n_infos, gint factor) { gint i; for (i = 0; i < n_infos; i++) { infos[i].rect.x /= factor; infos[i].rect.y /= factor; infos[i].rect.width /= factor; infos[i].rect.height /= factor; DEBUG ("Scale factor of %d applied. Monitor %d is %d,%d %d x %d\n", factor, infos[i].number, infos[i].rect.x, infos[i].rect.y, infos[i].rect.width, infos[i].rect.height); } } #define MONITOR_WIDTH_THRESHOLD 1200 #define MONITOR_HEIGHT_THRESHOLD 1000 static gboolean get_low_res_mode (CsScreen *screen, CsMonitorInfo *infos, gint n_infos) { gint i; gint smallest_width, smallest_height; smallest_width = smallest_height = G_MAXINT; for (i = 0; i < n_infos; i++) { smallest_width = MIN (infos[i].rect.width, smallest_width); smallest_height = MIN (infos[i].rect.height, smallest_height); } screen->smallest_width = smallest_width; screen->smallest_height = smallest_height; if (smallest_width < MONITOR_WIDTH_THRESHOLD || smallest_height < MONITOR_HEIGHT_THRESHOLD) { DEBUG ("Narrowest monitor width after scaling (%dx%d) is below threshold of %dx%d, applying low-res mode\n", smallest_width, smallest_height, MONITOR_WIDTH_THRESHOLD, MONITOR_HEIGHT_THRESHOLD); return TRUE; } return FALSE; } static void reload_monitor_infos (CsScreen *screen) { GdkDisplay *gdk_display; Display *xdisplay; Window xroot; gdk_display = gdk_screen_get_display (screen->gdk_screen); xdisplay = gdk_x11_display_get_xdisplay (gdk_display); xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen->gdk_screen)); /* Any previous screen->monitor_infos is freed by the caller */ screen->monitor_infos = NULL; screen->n_monitor_infos = 0; /* Xinerama doesn't have a concept of primary monitor, however XRandR * does. However, the XRandR xinerama compat code always sorts the * primary output first, so we rely on that here. We could use the * native XRandR calls instead of xinerama, but that would be * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as * that is defined in terms of xinerama monitor indexes. * So, since we don't need anything in xrandr except the primary * we can keep using xinerama and use the first monitor as the * primary. */ screen->primary_monitor_index = PRIMARY_MONITOR; #ifdef HAVE_XFREE_XINERAMA if (screen->n_monitor_infos == 0 && XineramaIsActive (xdisplay)) { XineramaScreenInfo *infos; int n_infos; int i; n_infos = 0; infos = XineramaQueryScreens (xdisplay, &n_infos); DEBUG ("Found %d Xinerama screens on display %s\n", n_infos, gdk_display_get_name (gdk_display)); if (n_infos > 0) { screen->monitor_infos = g_new0 (CsMonitorInfo, n_infos); screen->n_monitor_infos = n_infos; i = 0; while (i < n_infos) { screen->monitor_infos[i].number = infos[i].screen_number; screen->monitor_infos[i].rect.x = infos[i].x_org; screen->monitor_infos[i].rect.y = infos[i].y_org; screen->monitor_infos[i].rect.width = infos[i].width; screen->monitor_infos[i].rect.height = infos[i].height; DEBUG ("Monitor %d is %d,%d %d x %d\n", screen->monitor_infos[i].number, screen->monitor_infos[i].rect.x, screen->monitor_infos[i].rect.y, screen->monitor_infos[i].rect.width, screen->monitor_infos[i].rect.height); ++i; } } cs_XFree (infos); #ifdef HAVE_RANDR { XRRScreenResources *resources; resources = XRRGetScreenResourcesCurrent (xdisplay, xroot); if (resources) { for (i = 0; i < resources->ncrtc; i++) { XRRCrtcInfo *crtc; CsMonitorInfo *info; crtc = XRRGetCrtcInfo (xdisplay, resources, resources->crtcs[i]); info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, (int)crtc->height); if (info) { info->output = find_main_output_for_crtc (resources, crtc, xdisplay, xroot); } XRRFreeCrtcInfo (crtc); } XRRFreeScreenResources (resources); } } #endif } else if (screen->n_monitor_infos > 0) { DEBUG ("No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n", gdk_display_get_name (gdk_display)); } #else DEBUG ("Muffin compiled without XFree86 Xinerama support\n"); #endif /* HAVE_XFREE_XINERAMA */ #ifdef HAVE_SOLARIS_XINERAMA /* This code from GDK, Copyright (C) 2002 Sun Microsystems */ if (screen->n_monitor_infos == 0 && XineramaGetState (xdisplay, gdk_screen_get_number (screen->gdk_screen))) { XRectangle monitors[MAXFRAMEBUFFERS]; unsigned char hints[16]; int result; int n_monitors; int i; n_monitors = 0; result = XineramaGetInfo (xdisplay, gdk_screen_get_number (screen->gdk_screen), monitors, hints, &n_monitors); /* Yes I know it should be Success but the current implementation * returns the num of monitor */ if (result > 0) { g_assert (n_monitors > 0); screen->monitor_infos = g_new0 (CsMonitorInfo, n_monitors); screen->n_monitor_infos = n_monitors; i = 0; while (i < n_monitors) { screen->monitor_infos[i].number = i; screen->monitor_infos[i].rect.x = monitors[i].x; screen->monitor_infos[i].rect.y = monitors[i].y; screen->monitor_infos[i].rect.width = monitors[i].width; screen->monitor_infos[i].rect.height = monitors[i].height; DEBUG ("Monitor %d is %d,%d %d x %d\n", screen->monitor_infos[i].number, screen->monitor_infos[i].rect.x, screen->monitor_infos[i].rect.y, screen->monitor_infos[i].rect.width, screen->monitor_infos[i].rect.height); ++i; } } } else if (screen->n_monitor_infos == 0) { DEBUG ("No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n", gdk_display_get_name (gdk_display)); } #else DEBUG ("Cinnamon Screensaver compiled without Solaris Xinerama support\n"); #endif /* HAVE_SOLARIS_XINERAMA */ /* If no Xinerama, fill in the single screen info so * we can use the field unconditionally */ if (screen->n_monitor_infos == 0) { DEBUG ("No Xinerama screens, using default screen info\n"); screen->monitor_infos = g_new0 (CsMonitorInfo, 1); screen->n_monitor_infos = 1; screen->monitor_infos[0].number = 0; screen->monitor_infos[0].rect = screen->rect; } filter_mirrored_monitors (screen); screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE; apply_scale_factor (screen->monitor_infos, screen->n_monitor_infos, gdk_screen_get_monitor_scale_factor (screen->gdk_screen, PRIMARY_MONITOR)); screen->low_res = get_low_res_mode (screen, screen->monitor_infos, screen->n_monitor_infos); g_assert (screen->n_monitor_infos > 0); g_assert (screen->monitor_infos != NULL); } static void reload_screen_info (CsScreen *screen) { screen->rect.x = screen->rect.y = 0; screen->rect.width = gdk_screen_get_width (screen->gdk_screen); screen->rect.height = gdk_screen_get_height (screen->gdk_screen); } static void on_monitors_changed (GdkScreen *gdk_screen, gpointer user_data) { CsMonitorInfo *old_monitor_infos; CsScreen *screen; screen = CS_SCREEN (user_data); reload_screen_info (screen); g_signal_emit (screen, signals[SCREEN_SIZE_CHANGED], 0); gdk_flush (); DEBUG ("CsScreen received 'monitors-changed' signal from GdkScreen\n"); old_monitor_infos = screen->monitor_infos; reload_monitor_infos (screen); g_free (old_monitor_infos); g_signal_emit (screen, signals[SCREEN_MONITORS_CHANGED], 0); } static void on_screen_changed (GdkScreen *gdk_screen, gpointer user_data) { CsScreen *screen; screen = CS_SCREEN (user_data); DEBUG ("CsScreen received 'size-changed' signal from GdkScreen\n"); reload_screen_info (screen); g_signal_emit (screen, signals[SCREEN_SIZE_CHANGED], 0); } static void on_composited_changed (GdkScreen *gdk_screen, gpointer user_data) { CsScreen *screen; screen = CS_SCREEN (user_data); DEBUG ("CsScreen received 'composited-changed' signal from GdkScreen\n"); g_signal_emit (screen, signals[COMPOSITED_CHANGED], 0); } static void cs_screen_init (CsScreen *screen) { screen->gdk_screen = gdk_screen_get_default (); screen->monitors_changed_id = g_signal_connect (screen->gdk_screen, "monitors-changed", G_CALLBACK (on_monitors_changed), screen); screen->screen_size_changed_id = g_signal_connect (screen->gdk_screen, "size-changed", G_CALLBACK (on_screen_changed), screen); screen->composited_changed_id = g_signal_connect (screen->gdk_screen, "composited-changed", G_CALLBACK (on_composited_changed), screen); reload_screen_info (screen); reload_monitor_infos (screen); } static void cs_screen_finalize (GObject *object) { CsScreen *screen; g_return_if_fail (object != NULL); g_return_if_fail (CS_IS_SCREEN (object)); screen = CS_SCREEN (object); if (screen->monitor_infos) { g_free (screen->monitor_infos); } DEBUG ("CsScreen finalize\n"); G_OBJECT_CLASS (cs_screen_parent_class)->finalize (object); } static void cs_screen_dispose (GObject *object) { CsScreen *screen; g_return_if_fail (object != NULL); g_return_if_fail (CS_IS_SCREEN (object)); screen = CS_SCREEN (object); if (screen->monitors_changed_id > 0) { g_signal_handler_disconnect (screen->gdk_screen, screen->monitors_changed_id); screen->monitors_changed_id = 0; } if (screen->screen_size_changed_id > 0) { g_signal_handler_disconnect (screen->gdk_screen, screen->screen_size_changed_id); screen->screen_size_changed_id = 0; } if (screen->composited_changed_id > 0) { g_signal_handler_disconnect (screen->gdk_screen, screen->composited_changed_id); screen->composited_changed_id = 0; } DEBUG ("CsScreen dispose\n"); G_OBJECT_CLASS (cs_screen_parent_class)->dispose (object); } static void cs_screen_class_init (CsScreenClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = cs_screen_finalize; object_class->dispose = cs_screen_dispose; signals[SCREEN_MONITORS_CHANGED] = g_signal_new ("monitors-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); signals[SCREEN_SIZE_CHANGED] = g_signal_new ("size-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); signals[COMPOSITED_CHANGED] = g_signal_new ("composited-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } CsScreen * cs_screen_new (gboolean debug) { GObject *result; debug_mode = debug; result = g_object_new (CS_TYPE_SCREEN, NULL); return CS_SCREEN (result); } /** * cs_screen_get_monitor_geometry: * @screen: a #CsScreen * @monitor: the monitor number * @geometry: (out): location to store the monitor geometry * * Stores the location and size of the indicated monitor in @geometry. */ void cs_screen_get_monitor_geometry (CsScreen *screen, gint monitor, GdkRectangle *geometry) { g_return_if_fail (CS_IS_SCREEN (screen)); g_return_if_fail (monitor >= 0 && monitor < screen->n_monitor_infos); g_return_if_fail (geometry != NULL); geometry->x = screen->monitor_infos[monitor].rect.x; geometry->y = screen->monitor_infos[monitor].rect.y; geometry->width = screen->monitor_infos[monitor].rect.width; geometry->height = screen->monitor_infos[monitor].rect.height; } /** * cs_screen_get_screen_geometry: * @screen: a #CsScreen * @geometry: (out): location to store the screen geometry * * Stores the location and size of the screen in @geometry. */ void cs_screen_get_screen_geometry (CsScreen *screen, GdkRectangle *geometry) { g_return_if_fail (CS_IS_SCREEN (screen)); g_return_if_fail (geometry != NULL); geometry->x = screen->rect.x; geometry->y = screen->rect.y; geometry->width = screen->rect.width; geometry->height = screen->rect.height; } /** * cs_screen_get_primary_monitor: * @screen: a #CsScreen * * Gets the index of the primary monitor on this @screen. * * Return value: a monitor index */ gint cs_screen_get_primary_monitor (CsScreen *screen) { g_return_val_if_fail (CS_IS_SCREEN (screen), 0); return screen->primary_monitor_index; } /** * cs_screen_get_n_monitors: * @screen: a #CsScreen * * Gets the number of monitors that are joined together to form @screen. * * Return value: the number of monitors */ gint cs_screen_get_n_monitors (CsScreen *screen) { g_return_val_if_fail (CS_IS_SCREEN (screen), 0); return screen->n_monitor_infos; } /** * cs_screen_get_mouse_monitor: * @screen: a #CsScreen * * Gets the index of the monitor that the mouse pointer currently * occupies. * * Return value: the monitor index for the pointer */ gint cs_screen_get_mouse_monitor (CsScreen *screen) { GdkDisplay *gdk_display; Window xroot, root_return, child_return; int root_x_return, root_y_return; int win_x_return, win_y_return; unsigned int mask_return; gint scale_factor; gint i; gint ret = 0; g_return_val_if_fail (CS_IS_SCREEN (screen), 0); gdk_display = gdk_screen_get_display (screen->gdk_screen); xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen->gdk_screen)); gdk_error_trap_push (); XQueryPointer (gdk_x11_display_get_xdisplay (gdk_display), xroot, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); gdk_error_trap_pop_ignored (); scale_factor = gdk_screen_get_monitor_scale_factor (screen->gdk_screen, 0); root_x_return /= scale_factor; root_y_return /= scale_factor; for (i = 0; i < screen->n_monitor_infos; i++) { GdkRectangle iter = screen->monitor_infos[i].rect; if (root_x_return >= iter.x && root_x_return <= iter.x + iter.width && root_y_return >= iter.y && root_y_return <= iter.y + iter.height) { ret = i; break; } } return ret; } /** * cs_screen_get_low_res_mode: * @screen: a #CsScreen * * Gets whether or not one of our monitors falls below the low res threshold (1200 wide). * This lets us display certain things at smaller sizes to prevent truncating of images, etc. * * Returns: Whether or not to use low res mode. */ gboolean cs_screen_get_low_res_mode (CsScreen *screen) { g_return_val_if_fail (CS_IS_SCREEN (screen), FALSE); return screen->low_res; } /** * cs_screen_get_smallest_monitor_sizes: * @screen: a #CsScreen * @width: (out): width of the smallest monitor * @height: (out): height of the smallest monitor * * Gets whether or not one of our monitors falls below the low res threshold (1200 wide). * This lets us display certain things at smaller sizes to prevent truncating of images, etc. * * Returns: Whether or not to use low res mode. */ void cs_screen_get_smallest_monitor_sizes (CsScreen *screen, gint *width, gint *height) { g_return_if_fail (CS_IS_SCREEN (screen)); if (width != NULL) { *width = screen->smallest_width; } if (height != NULL) { *height = screen->smallest_height; } } /** * cs_screen_center_pointer_in_primary_monitor: * @screen: The #CsScreen * * Warps the mouse pointer to the center in x, and half again below center * in y, of the primary monitor. This is used during waking to have the * unlock dialog appear on the primary monitor (at least, initially). */ void cs_screen_place_pointer_in_primary_monitor (CsScreen *screen) { GdkDisplay *display; GdkRectangle rect; GdkSeat *seat; GdkDevice *pointer; g_return_if_fail (CS_IS_SCREEN (screen)); cs_screen_get_monitor_geometry (screen, screen->primary_monitor_index, &rect); display = gdk_screen_get_display (screen->gdk_screen); seat = gdk_display_get_default_seat (display); pointer = gdk_seat_get_pointer (seat); gdk_device_warp (pointer, screen->gdk_screen, rect.x + (rect.width * .5), rect.y + (rect.height * .75)); } /** * cs_screen_reset_screensaver: * * Resets the screensaver idle timer. If called when the screensaver is active * it will stop it. * */ void cs_screen_reset_screensaver (void) { XResetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); } void cs_screen_nuke_focus (void) { Window focus = 0; int rev = 0; DEBUG ("Nuking focus\n"); gdk_error_trap_push (); XGetInputFocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &focus, &rev); XSetInputFocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), PointerRoot, RevertToNone, CurrentTime); gdk_error_trap_pop_ignored (); } cinnamon-screensaver-4.4.1/libcscreensaver/cs-screen.h000066400000000000000000000051451357366610100230620ustar00rootroot00000000000000 #ifndef __CS_SCREEN_H #define __CS_SCREEN_H #include #include #include G_BEGIN_DECLS #define CS_TYPE_SCREEN (cs_screen_get_type ()) #define CS_SCREEN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CS_TYPE_SCREEN, CsScreen)) #define CS_SCREEN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CS_TYPE_SCREEN, CsScreenClass)) #define CS_IS_SCREEN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CS_TYPE_SCREEN)) #define CS_IS_SCREEN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CS_TYPE_SCREEN)) #define CS_SCREEN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CS_TYPE_SCREEN, CsScreenClass)) typedef struct _CsMonitorInfo CsMonitorInfo; struct _CsMonitorInfo { int number; GdkRectangle rect; gboolean is_primary; XID output; /* The primary or first output for this crtc, None if no xrandr */ }; typedef struct { GObject obj; GdkRectangle rect; GdkScreen *gdk_screen; CsMonitorInfo *monitor_infos; gint primary_monitor_index; gint n_monitor_infos; gulong monitors_changed_id; gulong screen_size_changed_id; gulong composited_changed_id; gboolean low_res; gint smallest_width; gint smallest_height; } CsScreen; typedef struct { GObjectClass parent_class; } CsScreenClass; GType cs_screen_get_type (void); CsScreen *cs_screen_new (gboolean debug); void cs_screen_get_monitor_geometry (CsScreen *screen, gint monitor, GdkRectangle *geometry); void cs_screen_get_screen_geometry (CsScreen *screen, GdkRectangle *geometry); gint cs_screen_get_primary_monitor (CsScreen *screen); gint cs_screen_get_n_monitors (CsScreen *screen); gint cs_screen_get_mouse_monitor (CsScreen *screen); gboolean cs_screen_get_low_res_mode (CsScreen *screen); void cs_screen_get_smallest_monitor_sizes (CsScreen *screen, gint *width, gint *height); void cs_screen_place_pointer_in_primary_monitor (CsScreen *screen); void cs_screen_reset_screensaver (void); void cs_screen_nuke_focus (void); G_END_DECLS #endif /* __CS_SCREEN_H */ cinnamon-screensaver-4.4.1/libcscreensaver/cscreensaver-uninstalled.pc.in000066400000000000000000000006041357366610100267560ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: cscreensaver Description: Small utility lib used by cinnamon-screensaver v3.1+ to provide a GdkWindow filter (not currently introspectable) Requires: gobject-2.0 gtk-3.0 gdk-3.0 Version: @VERSION@ Libs: ${pc_top_builddir}/${pcfiledir}/libcscreensaver.la Cflags: -I${pc_top_builddir}/${pcfiledir}/.. cinnamon-screensaver-4.4.1/libcscreensaver/cscreensaver.pc.in000066400000000000000000000005451357366610100244420ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: cscreensaver Description: Small utility lib used by cinnamon-screensaver v3.1+ to provide a GdkWindow filter (not currently introspectable) Requires: gobject-2.0 gtk+-3.0 gdk-3.0 Version: @VERSION@ Libs: -L${libdir} -lcscreensaver Cflags: -I${includedir}/cscreensaver cinnamon-screensaver-4.4.1/libcscreensaver/org.Cinnamon.xml000066400000000000000000000006671357366610100241050ustar00rootroot00000000000000 cinnamon-screensaver-4.4.1/libcscreensaver/org.cinnamon.ScreenSaver.xml000066400000000000000000000017431357366610100263600ustar00rootroot00000000000000 cinnamon-screensaver-4.4.1/libcscreensaver/org.cinnamon.SettingsDaemon.KeybindingHandler.xml000066400000000000000000000007671357366610100324510ustar00rootroot00000000000000 cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.ConsoleKit.Manager.xml000066400000000000000000000021261357366610100302700ustar00rootroot00000000000000 The object identifier for the current session Attempts to determine the session ID that the caller belongs to. See this example of using dbus-send: dbus-send --system --dest=org.freedesktop.ConsoleKit \ --type=method_call --print-reply --reply-timeout=2000 \ /org/freedesktop/ConsoleKit/Manager \ org.freedesktop.ConsoleKit.Manager.GetCurrentSession cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.ConsoleKit.Session.xml000066400000000000000000000050041357366610100303370ustar00rootroot00000000000000 Session objects represent and store information related to a user session. The properties associated with the Session specifically refer to the properties of the "session leader". This will cause a Lock signal to be emitted for this session. This method is restricted to privileged users by D-Bus policy. Lock signal This will cause an Unlock signal to be emitted for this session. This can be used by login managers to unlock a session before it is re-activated during fast-user-switching. This method is restricted to privileged users by D-Bus policy. Unlock signal TRUE if the session is active, otherwise FALSE Emitted when the active property has changed. Lock the desktop. Unlock the desktop. cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.UPower.Device.xml000066400000000000000000000230131357366610100272620ustar00rootroot00000000000000 ]> Objects implementing this interface are usually discovered through the org.freedesktop.UPower interface on the /org/freedesktop/UPower object on the D-Bus system bus service with the well-known name org.freedesktop.UPower using the EnumerateDevices method. $ dbus-send --print-reply \ --system \ --dest=org.freedesktop.UPower \ /org/freedesktop/UPower/devices/battery_BAT0 \ org.freedesktop.DBus.Properties.GetAll \ string:org.freedesktop.UPower.Device method return sender=:1.386 -> dest=:1.477 reply_serial=2 array [ dict entry( string "native-path" variant string "/sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0" ) dict entry( string "vendor" variant string "SONY" ) dict entry( string "model" variant string "42T4568" ) dict entry( string "serial" variant string "4179" ) dict entry( string "update-time" variant uint64 1226417875 ) dict entry( string "type" variant uint 2 ) dict entry( string "power-supply" variant boolean true ) dict entry( string "has-history" variant boolean true ) dict entry( string "has-statistics" variant boolean true ) dict entry( string "online" variant boolean false ) dict entry( string "energy" variant double 72.85 ) dict entry( string "energy-empty" variant double 0 ) dict entry( string "energy-full" variant double 74.55 ) dict entry( string "energy-full-design" variant double 74.88 ) dict entry( string "energy-rate" variant double 0 ) dict entry( string "voltage" variant double 16.415 ) dict entry( string "time-to-empty" variant int64 0 ) dict entry( string "time-to-full" variant int64 0 ) dict entry( string "percentage" variant double 97.7197 ) dict entry( string "is-present" variant boolean true ) dict entry( string "state" variant uint 3 ) dict entry( string "is-rechargeable" variant boolean true ) dict entry( string "capacity" variant double 100 ) dict entry( string "technology" variant uint 1 ) ] Unless otherwise noted, an empty string or the value 0 in a property on this interface means not set. Type of power source. 0Unknown 1Line Power 2Battery 3Ups 4Monitor 5Mouse 6Keyboard 7Pda 8Phone The amount of energy left in the power source expressed as a percentage between 0 and 100. Typically this is the same as (energy - energy-empty) / (energy-full - energy-empty). However, some primitive power sources are capable of only reporting percentages and in this case the energy-* properties will be unset while this property is set. This property is only valid if the property type has the value "battery". Whether power is currently being provided through line power. This property is only valid if the property type has the value "line-power". The battery power state. 0Unknown 1Charging 2Discharging 3Empty 4Fully charged 5Pending charge 6Pending discharge This property is only valid if the property type has the value "battery". Warning level of the battery: 0Unknown 1None 2Discharging (only for UPSes) 3Low 4Critical 5Action An icon name, following the Icon Naming Specification cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.UPower.xml000066400000000000000000000060331357366610100260670ustar00rootroot00000000000000 The UPower service is available via the system message bus. To access the service, use the org.freedesktop.UPower interface on the /org/freedesktop/UPower object on the D-Bus system bus service with the well-known name org.freedesktop.UPower. $ dbus-send --print-reply \ --system \ --dest=org.freedesktop.UPower \ /org/freedesktop/UPower \ org.freedesktop.UPower.EnumerateDevices method return sender=:1.386 -> dest=:1.451 reply_serial=2 array [ object path "/org/freedesktop/UPower/devices/line_power_AC" object path "/org/freedesktop/UPower/devices/battery_BAT0" ] An array of object paths for devices. Enumerate all power objects on the system. Object path of device that was added. Emitted when a device is added. Object path of device that was removed. Emitted when a device is removed. Indicates whether the system is running on battery power. This property is provided for convenience. cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.login1.Manager.xml000066400000000000000000000007001357366610100274030ustar00rootroot00000000000000 cinnamon-screensaver-4.4.1/libcscreensaver/org.freedesktop.login1.Session.xml000066400000000000000000000005501357366610100274570ustar00rootroot00000000000000 cinnamon-screensaver-4.4.1/libcscreensaver/org.gnome.SessionManager.Presence.xml000066400000000000000000000032041357366610100301160ustar00rootroot00000000000000 The status of the session. The status parameter must be one of the following: 0 Available 1 Invisible 2 Busy 3 Idle The new status value Indicates that the session status value has changed. cinnamon-screensaver-4.4.1/libcscreensaver/org.mpris.MediaPlayer2.Player.xml000066400000000000000000000666741357366610100272170ustar00rootroot00000000000000

This interface implements the methods for querying and providing basic control over what is currently playing.

A track is currently playing.

A track is currently paused.

There is no track currently playing.

A playback state.

The playback will stop when there are no more tracks to play

The current track will start again from the begining once it has finished playing

The playback loops through a list of tracks

A repeat / loop status

Unique track identifier.

If the media player implements the TrackList interface and allows the same track to appear multiple times in the tracklist, this must be unique within the scope of the tracklist.

Note that this should be a valid D-Bus object id, although clients should not assume that any object is actually exported with any interfaces at that path.

Media players may not use any paths starting with /org/mpris unless explicitly allowed by this specification. Such paths are intended to have special meaning, such as /org/mpris/MediaPlayer2/TrackList/NoTrack to indicate "no track".

This is a D-Bus object id as that is the definitive way to have unique identifiers on D-Bus. It also allows for future optional expansions to the specification where tracks are exported to D-Bus with an interface similar to org.gnome.UPnP.MediaItem2.

A playback rate

This is a multiplier, so a value of 0.5 indicates that playback is happening at half speed, while 1.5 means that 1.5 seconds of "track time" is consumed every second.

Audio volume level

  • 0.0 means mute.
  • 1.0 is a sensible maximum volume level (ex: 0dB).

Note that the volume may be higher than 1.0, although generally clients should not attempt to set it above 1.0.

Time in microseconds.

Skips to the next track in the tracklist.

If there is no next track (and endless playback and track repeat are both off), stop playback.

If playback is paused or stopped, it remains that way.

If CanGoNext is false, attempting to call this method should have no effect.

Skips to the previous track in the tracklist.

If there is no previous track (and endless playback and track repeat are both off), stop playback.

If playback is paused or stopped, it remains that way.

If CanGoPrevious is false, attempting to call this method should have no effect.

Pauses playback.

If playback is already paused, this has no effect.

Calling Play after this should cause playback to start again from the same position.

If CanPause is false, attempting to call this method should have no effect.

Pauses playback.

If playback is already paused, resumes playback.

If playback is stopped, starts playback.

If CanPause is false, attempting to call this method should have no effect and raise an error.

Stops playback.

If playback is already stopped, this has no effect.

Calling Play after this should cause playback to start again from the beginning of the track.

If CanControl is false, attempting to call this method should have no effect and raise an error.

Starts or resumes playback.

If already playing, this has no effect.

If paused, playback resumes from the current position.

If there is no track to play, this has no effect.

If CanPlay is false, attempting to call this method should have no effect.

The number of microseconds to seek forward.

Seeks forward in the current track by the specified number of microseconds.

A negative value seeks back. If this would mean seeking back further than the start of the track, the position is set to 0.

If the value passed in would mean seeking beyond the end of the track, acts like a call to Next.

If the CanSeek property is false, this has no effect.

The currently playing track's identifier.

If this does not match the id of the currently-playing track, the call is ignored as "stale".

/org/mpris/MediaPlayer2/TrackList/NoTrack is not a valid value for this argument.

Track position in microseconds.

This must be between 0 and <track_length>.

Sets the current track position in microseconds.

If the Position argument is less than 0, do nothing.

If the Position argument is greater than the track length, do nothing.

If the CanSeek property is false, this has no effect.

The reason for having this method, rather than making Position writable, is to include the TrackId argument to avoid race conditions where a client tries to seek to a position when the track has already changed.

Uri of the track to load. Its uri scheme should be an element of the org.mpris.MediaPlayer2.SupportedUriSchemes property and the mime-type should match one of the elements of the org.mpris.MediaPlayer2.SupportedMimeTypes.

Opens the Uri given as an argument

If the playback is stopped, starts playing

If the uri scheme or the mime-type of the uri to open is not supported, this method does nothing and may raise an error. In particular, if the list of available uri schemes is empty, this method may not be implemented.

Clients should not assume that the Uri has been opened as soon as this method returns. They should wait until the mpris:trackid field in the Metadata property changes.

If the media player implements the TrackList interface, then the opened track should be made part of the tracklist, the org.mpris.MediaPlayer2.TrackList.TrackAdded or org.mpris.MediaPlayer2.TrackList.TrackListReplaced signal should be fired, as well as the org.freedesktop.DBus.Properties.PropertiesChanged signal on the tracklist interface.

The current playback status.

May be "Playing", "Paused" or "Stopped".

The current loop / repeat status

May be:

  • "None" if the playback will stop when there are no more tracks to play
  • "Track" if the current track will start again from the begining once it has finished playing
  • "Playlist" if the playback loops through a list of tracks

If CanControl is false, attempting to set this property should have no effect and raise an error.

The current playback rate.

The value must fall in the range described by MinimumRate and MaximumRate, and must not be 0.0. If playback is paused, the PlaybackStatus property should be used to indicate this. A value of 0.0 should not be set by the client. If it is, the media player should act as though Pause was called.

If the media player has no ability to play at speeds other than the normal playback rate, this must still be implemented, and must return 1.0. The MinimumRate and MaximumRate properties must also be set to 1.0.

Not all values may be accepted by the media player. It is left to media player implementations to decide how to deal with values they cannot use; they may either ignore them or pick a "best fit" value. Clients are recommended to only use sensible fractions or multiples of 1 (eg: 0.5, 0.25, 1.5, 2.0, etc).

This allows clients to display (reasonably) accurate progress bars without having to regularly query the media player for the current position.

A value of false indicates that playback is progressing linearly through a playlist, while true means playback is progressing through a playlist in some other order.

If CanControl is false, attempting to set this property should have no effect and raise an error.

The metadata of the current element.

If there is a current track, this must have a "mpris:trackid" entry (of D-Bus type "o") at the very least, which contains a D-Bus path that uniquely identifies this track.

See the type documentation for more details.

The volume level.

When setting, if a negative value is passed, the volume should be set to 0.0.

If CanControl is false, attempting to set this property should have no effect and raise an error.

The current track position in microseconds, between 0 and the 'mpris:length' metadata entry (see Metadata).

Note: If the media player allows it, the current playback position can be changed either the SetPosition method or the Seek method on this interface. If this is not the case, the CanSeek property is false, and setting this property has no effect and can raise an error.

If the playback progresses in a way that is inconstistant with the Rate property, the Seeked signal is emited.

The minimum value which the Rate property can take. Clients should not attempt to set the Rate property below this value.

Note that even if this value is 0.0 or negative, clients should not attempt to set the Rate property to 0.0.

This value should always be 1.0 or less.

The maximum value which the Rate property can take. Clients should not attempt to set the Rate property above this value.

This value should always be 1.0 or greater.

Whether the client can call the Next method on this interface and expect the current track to change.

If it is unknown whether a call to Next will be successful (for example, when streaming tracks), this property should be set to true.

If CanControl is false, this property should also be false.

Even when playback can generally be controlled, there may not always be a next track to move to.

Whether the client can call the Previous method on this interface and expect the current track to change.

If it is unknown whether a call to Previous will be successful (for example, when streaming tracks), this property should be set to true.

If CanControl is false, this property should also be false.

Even when playback can generally be controlled, there may not always be a next previous to move to.

Whether playback can be started using Play or PlayPause.

Note that this is related to whether there is a "current track": the value should not depend on whether the track is currently paused or playing. In fact, if a track is currently playing (and CanControl is true), this should be true.

If CanControl is false, this property should also be false.

Even when playback can generally be controlled, it may not be possible to enter a "playing" state, for example if there is no "current track".

Whether playback can be paused using Pause or PlayPause.

Note that this is an intrinsic property of the current track: its value should not depend on whether the track is currently paused or playing. In fact, if playback is currently paused (and CanControl is true), this should be true.

If CanControl is false, this property should also be false.

Not all media is pausable: it may not be possible to pause some streamed media, for example.

Whether the client can control the playback position using Seek and SetPosition. This may be different for different tracks.

If CanControl is false, this property should also be false.

Not all media is seekable: it may not be possible to seek when playing some streamed media, for example.

Whether the media player may be controlled over this interface.

This property is not expected to change, as it describes an intrinsic capability of the implementation.

If this is false, clients should assume that all properties on this interface are read-only (and will raise errors if writing to them is attempted), no methods are implemented and all other properties starting with "Can" are also false.

This allows clients to determine whether to present and enable controls to the user in advance of attempting to call methods and write to properties.

The new position, in microseconds.

Indicates that the track position has changed in a way that is inconsistant with the current playing state.

When this signal is not received, clients should assume that:

  • When playing, the position progresses according to the rate property.
  • When paused, it remains constant.

This signal does not need to be emitted when playback starts or when the track changes, unless the track is starting at an unexpected position. An expected position would be the last known one when going from Paused to Playing, and 0 when going from Stopped to Playing.

cinnamon-screensaver-4.4.1/libcscreensaver/setuid.c000066400000000000000000000204311357366610100224630ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * setuid.c --- management of runtime privileges. * * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #include "config.h" #ifdef USE_SETRES #define _GNU_SOURCE #endif /* USE_SETRES */ #include #include #include #include #include #include /* for getpwnam() and struct passwd */ #include /* for getgrgid() and struct group */ #include "setuid.h" static char * uid_gid_string (uid_t uid, gid_t gid) { static char *buf; struct passwd *p = NULL; struct group *g = NULL; p = getpwuid (uid); g = getgrgid (gid); buf = g_strdup_printf ("%s/%s (%ld/%ld)", (p && p->pw_name ? p->pw_name : "???"), (g && g->gr_name ? g->gr_name : "???"), (long) uid, (long) gid); return buf; } static gboolean set_ids_by_number (uid_t uid, gid_t gid, char **message_ret) { int uid_errno = 0; int gid_errno = 0; int sgs_errno = 0; struct passwd *p = getpwuid (uid); struct group *g = getgrgid (gid); if (message_ret) *message_ret = NULL; /* Rumor has it that some implementations of of setuid() do nothing when called with -1; therefore, if the "nobody" user has a uid of -1, then that would be Really Bad. Rumor further has it that such systems really ought to be using -2 for "nobody", since that works. So, if we get a uid (or gid, for good measure) of -1, switch to -2 instead. Note that this must be done after we've looked up the user/group names with getpwuid(-1) and/or getgrgid(-1). */ if (gid == (gid_t) -1) gid = (gid_t) -2; if (uid == (uid_t) -1) uid = (uid_t) -2; #ifndef USE_SETRES errno = 0; if (setgroups (1, &gid) < 0) sgs_errno = errno ? errno : -1; errno = 0; if (setgid (gid) != 0) gid_errno = errno ? errno : -1; errno = 0; if (setuid (uid) != 0) uid_errno = errno ? errno : -1; #else /* !USE_SETRES */ errno = 0; if (setresgid (gid, gid, gid) != 0) gid_errno = errno ? errno : -1; errno = 0; if (setresuid (uid, uid, uid) != 0) uid_errno = errno ? errno : -1; #endif /* USE_SETRES */ if (uid_errno == 0 && gid_errno == 0 && sgs_errno == 0) { static char *reason; reason = g_strdup_printf ("changed uid/gid to %s/%s (%ld/%ld).", (p && p->pw_name ? p->pw_name : "???"), (g && g->gr_name ? g->gr_name : "???"), (long) uid, (long) gid); if (message_ret) *message_ret = g_strdup (reason); g_free (reason); return TRUE; } else { char *reason = NULL; if (sgs_errno) { reason = g_strdup_printf ("couldn't setgroups to %s (%ld)", (g && g->gr_name ? g->gr_name : "???"), (long) gid); if (sgs_errno == -1) fprintf (stderr, "%s: unknown error\n", reason); else { errno = sgs_errno; perror (reason); } g_free (reason); reason = NULL; } if (gid_errno) { reason = g_strdup_printf ("couldn't set gid to %s (%ld)", (g && g->gr_name ? g->gr_name : "???"), (long) gid); if (gid_errno == -1) fprintf (stderr, "%s: unknown error\n", reason); else { errno = gid_errno; perror (reason); } g_free (reason); reason = NULL; } if (uid_errno) { reason = g_strdup_printf ("couldn't set uid to %s (%ld)", (p && p->pw_name ? p->pw_name : "???"), (long) uid); if (uid_errno == -1) fprintf (stderr, "%s: unknown error\n", reason); else { errno = uid_errno; perror (reason); } g_free (reason); reason = NULL; } return FALSE; } return FALSE; } /* If we've been run as setuid or setgid to someone else (most likely root) turn off the extra permissions so that random user-specified programs don't get special privileges. (On some systems it is necessary to install this program as setuid root in order to read the passwd file to implement lock-mode.) *** WARNING: DO NOT DISABLE ANY OF THE FOLLOWING CODE! If you do so, you will open a security hole. See the sections of the xscreensaver manual titled "LOCKING AND ROOT LOGINS", and "USING XDM". */ /* Returns TRUE if OK to lock, FALSE otherwise */ gboolean hack_uid (char **nolock_reason, char **orig_uid, char **uid_message) { char *reason; gboolean ret; ret = TRUE; reason = NULL; if (nolock_reason != NULL) { *nolock_reason = NULL; } if (orig_uid != NULL) { *orig_uid = NULL; } if (uid_message != NULL) { *uid_message = NULL; } /* Discard privileges, and set the effective user/group ids to the real user/group ids. That is, give up our "chmod +s" rights. */ { uid_t euid = geteuid (); gid_t egid = getegid (); uid_t uid = getuid (); gid_t gid = getgid (); if (orig_uid != NULL) { *orig_uid = uid_gid_string (euid, egid); } if (uid != euid || gid != egid) { #ifndef USE_SETRES if (! set_ids_by_number (uid, gid, uid_message)) { #else /* !USE_SETRES */ if (! set_ids_by_number (euid == 0 ? uid : euid, egid == 0 ? gid : egid, uid_message)) { #endif /* USE_SETRES */ reason = g_strdup ("unable to discard privileges."); ret = FALSE; goto out; } } } /* Locking can't work when running as root, because we have no way of knowing what the user id of the logged in user is (so we don't know whose password to prompt for.) *** WARNING: DO NOT DISABLE THIS CODE! If you do so, you will open a security hole. See the sections of the xscreensaver manual titled "LOCKING AND ROOT LOGINS", and "USING XDM". */ if (getuid () == (uid_t) 0) { reason = g_strdup ("running as root"); ret = FALSE; goto out; } out: if (nolock_reason != NULL) { *nolock_reason = g_strdup (reason); } g_free (reason); return ret; } cinnamon-screensaver-4.4.1/libcscreensaver/setuid.h000066400000000000000000000015331357366610100224720ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #ifndef __GS_SETUID_H #define __GS_SETUID_H #include G_BEGIN_DECLS gboolean hack_uid (char **nolock_reason, char **orig_uid, char **uid_message); G_END_DECLS #endif /* __GS_SETUID_H */ cinnamon-screensaver-4.4.1/libcscreensaver/subprocs.c000066400000000000000000000104061357366610100230270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * subprocs.c --- choosing, spawning, and killing screenhacks. * * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski * Modified: Copyright (c) 2004 William Jon McCann * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #include "config.h" #include #include #include #include #ifndef ESRCH # include #endif #include /* sys/resource.h needs this for timeval */ # include /* for waitpid() and associated macros */ #ifdef VMS # include # include /* for close */ # include /* for getpid */ # define pid_t int # define fork vfork #endif /* VMS */ #include /* for the signal names */ #include #include "subprocs.h" #if !defined(SIGCHLD) && defined(SIGCLD) # define SIGCHLD SIGCLD #endif /* Semaphore to temporarily turn the SIGCHLD handler into a no-op. Don't alter this directly -- use block_sigchld() / unblock_sigchld(). */ static int block_sigchld_handler = 0; #ifdef HAVE_SIGACTION sigset_t #else /* !HAVE_SIGACTION */ int #endif /* !HAVE_SIGACTION */ block_sigchld (void) { #ifdef HAVE_SIGACTION sigset_t child_set; sigemptyset (&child_set); sigaddset (&child_set, SIGCHLD); sigaddset (&child_set, SIGPIPE); sigprocmask (SIG_BLOCK, &child_set, 0); #endif /* HAVE_SIGACTION */ block_sigchld_handler++; #ifdef HAVE_SIGACTION return child_set; #else /* !HAVE_SIGACTION */ return 0; #endif /* !HAVE_SIGACTION */ } void unblock_sigchld (void) { #ifdef HAVE_SIGACTION sigset_t child_set; sigemptyset (&child_set); sigaddset (&child_set, SIGCHLD); sigaddset (&child_set, SIGPIPE); sigprocmask (SIG_UNBLOCK, &child_set, 0); #endif /* HAVE_SIGACTION */ block_sigchld_handler--; } int signal_pid (int pid, int signal) { int status = -1; gboolean verbose = TRUE; if (block_sigchld_handler) /* This function should not be called from the signal handler. */ abort(); block_sigchld (); /* we control the horizontal... */ status = kill (pid, signal); if (verbose && status < 0) { if (errno == ESRCH) g_message ("Child process %lu was already dead.", (unsigned long) pid); else { char buf [1024]; snprintf (buf, sizeof (buf), "Couldn't kill child process %lu", (unsigned long) pid); perror (buf); } } unblock_sigchld (); if (block_sigchld_handler < 0) abort (); return status; } #ifndef VMS void await_dying_children (int pid, gboolean debug) { while (1) { int wait_status = 0; pid_t kid; errno = 0; kid = waitpid (-1, &wait_status, WNOHANG|WUNTRACED); if (debug) { if (kid < 0 && errno) g_message ("waitpid(%d) ==> %ld (%d)", pid, (long) kid, errno); else if (kid != 0) g_message ("waitpid(%d) ==> %ld", pid, (long) kid); } /* 0 means no more children to reap. -1 means error -- except "interrupted system call" isn't a "real" error, so if we get that, we should just try again. */ if (kid < 0 && errno != EINTR) break; } } #else /* VMS */ static void await_dying_children (saver_info *si) { return; } #endif /* VMS */ cinnamon-screensaver-4.4.1/libcscreensaver/subprocs.h000066400000000000000000000021511357366610100230320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * subprocs.c --- choosing, spawning, and killing screenhacks. * * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #ifndef __GS_SUBPROCS_H #define __GS_SUBPROCS_H #include G_BEGIN_DECLS void unblock_sigchld (void); #ifdef HAVE_SIGACTION sigset_t #else /* !HAVE_SIGACTION */ int #endif /* !HAVE_SIGACTION */ block_sigchld (void); int signal_pid (int pid, int signal); void await_dying_children (int pid, gboolean debug); G_END_DECLS #endif /* __GS_SUBPROCS_H */ cinnamon-screensaver-4.4.1/libcscreensaver/test-passwd.c000066400000000000000000000163621357366610100234540ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005-2006 William Jon McCann * * This program is free software; you can 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 - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #include #include #include #include #include "cs-auth.h" #include "setuid.h" /* Initializations that potentially take place as a privileged user: If the executable is setuid root, then these initializations are run as root, before discarding privileges. */ static gboolean privileged_initialization (void) { gboolean ret; char *nolock_reason; char *orig_uid; char *uid_message; #ifndef NO_LOCKING /* before hack_uid () for proper permissions */ cs_auth_priv_init (); #endif /* NO_LOCKING */ ret = hack_uid (&nolock_reason, &orig_uid, &uid_message); if (nolock_reason) { g_warning ("Locking disabled: %s", nolock_reason); } if (uid_message && cs_auth_get_verbose ()) { g_print ("Modified UID: %s", uid_message); } g_free (nolock_reason); g_free (orig_uid); g_free (uid_message); return ret; } /* Figure out what locking mechanisms are supported. */ static gboolean lock_initialization (char **nolock_reason) { if (nolock_reason) { *nolock_reason = NULL; } #ifdef NO_LOCKING if (nolock_reason) { *nolock_reason = g_strdup ("not compiled with locking support"); } return FALSE; #else /* !NO_LOCKING */ /* Finish initializing locking, now that we're out of privileged code. */ if (! cs_auth_init ()) { if (nolock_reason) { *nolock_reason = g_strdup ("error getting password"); } return FALSE; } /* If locking is currently enabled, but the environment indicates that we have been launched as MDM's "Background" program, then disable locking just in case. */ if (getenv ("RUNNING_UNDER_MDM")) { if (nolock_reason) { *nolock_reason = g_strdup ("running under MDM"); } return FALSE; } /* If the server is XDarwin (MacOS X) then disable locking. (X grabs only affect X programs, so you can use Command-Tab to bring any other Mac program to the front, e.g., Terminal.) */ { gboolean macos = FALSE; #ifdef __APPLE__ /* Disable locking if *running* on Apple hardware, since we have no reliable way to determine whether the server is running on MacOS. Hopefully __APPLE__ means "MacOS" and not "Linux on Mac hardware" but I'm not really sure about that. */ macos = TRUE; #endif if (macos) { if (nolock_reason) { *nolock_reason = g_strdup ("Cannot lock securely on MacOS X"); } return FALSE; } } #endif /* NO_LOCKING */ return TRUE; } static char * request_password (const char *prompt) { char buf [255]; char *pass; char *password; struct termios ts0; struct termios ts1; tcgetattr (fileno (stdin), &ts0); ts1 = ts0; ts1.c_lflag &= ~ECHO; printf ("%s", prompt); if (tcsetattr (fileno (stdin), TCSAFLUSH, &ts1) != 0) { fprintf (stderr, "Could not set terminal attributes\n"); exit (1); } pass = fgets (buf, sizeof (buf) - 1, stdin); tcsetattr (fileno (stdin), TCSANOW, &ts0); if (!pass || !*pass) { exit (0); } if (pass [strlen (pass) - 1] == '\n') { pass [strlen (pass) - 1] = 0; } password = g_strdup (pass); memset (pass, '\b', strlen (pass)); return password; } static gboolean auth_message_handler (CsAuthMessageStyle style, const char *msg, char **response, gpointer data) { gboolean ret; g_message ("Got message style %d: '%s'", style, msg); ret = TRUE; switch (style) { case CS_AUTH_MESSAGE_PROMPT_ECHO_ON: break; case CS_AUTH_MESSAGE_PROMPT_ECHO_OFF: { char *password; password = request_password (msg); *response = password; } break; case CS_AUTH_MESSAGE_ERROR_MSG: break; case CS_AUTH_MESSAGE_TEXT_INFO: break; default: g_assert_not_reached (); } return ret; } int main (int argc, char **argv) { GError *error = NULL; gboolean verbose = TRUE; char *nolock_reason = NULL; #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, "/usr/share/locale"); # ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); # endif textdomain (GETTEXT_PACKAGE); #endif cs_auth_set_verbose (verbose); if (! privileged_initialization ()) { exit (1); } if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { fprintf (stderr, "%s", error->message); g_error_free (error); exit (1); } if (! lock_initialization (&nolock_reason)) { if (nolock_reason) { g_warning ("Screen locking disabled: %s", nolock_reason); g_free (nolock_reason); } exit (1); } again: error = NULL; if (cs_auth_verify_user (g_get_user_name (), g_getenv ("DISPLAY"), auth_message_handler, NULL, &error)) { printf ("Correct!\n"); } else { if (error != NULL) { fprintf (stderr, "ERROR: %s\n", error->message); g_error_free (error); } printf ("Incorrect\n"); goto again; } return 0; } cinnamon-screensaver-4.4.1/makepot000077500000000000000000000001611357366610100172340ustar00rootroot00000000000000#!/bin/bash xgettext --language=Python --from-code=UTF-8 --keyword=_ --output=cinnamon-screensaver.pot src/*.py cinnamon-screensaver-4.4.1/po/000077500000000000000000000000001357366610100162665ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/po/ChangeLog000066400000000000000000001760051357366610100200510ustar00rootroot000000000000002009-04-18 Funda Wang * zh_CN.po: Updated zh_CN translation. 2009-04-14 Reşat SABIQ * crh.po: Updated Crimean Tatar (Crimean Turkish) translation. 2009-04-06 Reşat SABIQ * LINGUAS: crh * crh.po: Added Crimean Tatar (Crimean Turkish) translation. 2009-04-05 Takeshi AIHANA * ja.po: Fixed #576532. 2009-03-24 Shankar Prasad * kn.po: Updated Kannada Translation. 2009-03-18 Djihed Afifi * ar.po: Updated Arabic translation by Djihed Afifi. 2009-03-16 Nickolay V. Shmyrev * ru.po: Updated Russian translation. 2009-03-16 Ignacio Casal Quinteiro * gl.po: Updated Galician translation by Suso Baleato. 2009-03-14 Praveen Arimbrathodiyil * ml.po: Updated Malayalam Translation by Abhshek Jacob. 2009-03-14 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2009-03-14 Kenneth Nielsen * da.po: Updated Danish translation by Ask H. Larsen 2009-03-13 Kostas Papadimas * el.po: Updated Greek Translation by Jennie Petoumenou. 2009-03-13 Sandeep Shedmake * mr.po: Updated Marathi Translations. 2009-03-11 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2009-03-10 Jorge Gonzalez * es.po: Updated Spanish translation 2009-03-11 Manoj Kumar Giri * or.po: Updated Oriya Translation. 2009-03-10 I. Felix * ta.po: Tamil Translation updated 2009-03-08 Petr Kovar * cs.po: Updated Czech translation. 2009-03-04 Luca Ferretti * it.po: Updated Italian translation. 2009-03-03 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation. 2009-03-02 Manoj Kumar Giri * or.po: Updated Oriya Translation. 2009-03-02 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-28 Yair Hershkovitz * he.po: Updated Hebrew translation. 2009-02-25 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2009-02-25 Takeshi AIHANA * ja.po: Updated Japanese translation. 2009-02-23 Philip Withnall * en_GB.po: Updated British English translation. 2009-02-23 Gabor Kelemen * hu.po: Translation updated. 2009-02-21 Claude Paroz * fr.po: Updated French translation. 2009-02-21 Baris Cicek * tr.po: Updated Turkish translation 2009-02-21 Christian Kirbach * de.po: Updated German translation by Wolfgang Stöggl. 2009-02-17 Gil Forcada * ca.po: Updated Catalan translation. 2009-02-17 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2009-02-15 Duarte Loreto * pt.po: Updated Portuguese translation. 2009-02-14 Jorge Gonzalez * es.po: Updated Spanish translation, fixes bug #569457 2009-02-14 Gabor Kelemen * hu.po: Translation updated. 2009-02-14 Wouter Bolsterlee * nl.po: Updated Dutch translation by Wouter Bolsterlee. 2009-02-11 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2009-02-11 Gil Forcada * ast.po: Added Asturian translation on behalf of Mikel González. 2009-02-11 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2009-02-11 Theppitak Karoonboonyanan * th.po: Updated Thai translation. >>>>>>> .r1619 2009-02-06 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2009-02-06 Clytie Siddall * vi.po: Updated Vietnamese translation. 2009-02-05 Sweta Kothari * gu.po: Committed Gujarati Translation. 2009-02-03 Tomasz Dominikowski * pl.po: Updated Polish translation 2009-02-02 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2009-01-28 Changwoo Ryu * ko.po: Updated Korean translation. 2009-01-27 Ilkka Tuohela * fi.po: Updated Finnish translation. 2009-01-26 Jonh Wendell * pt_BR.po: Updated translation by André Gondim. 2009-01-25 Raivis Dejus * lv.po: Updated Latvian translation. 2009-01-22 Daniel Nylander * sv.po: Updated Swedish translation. 2009-01-20 Jorge Gonzalez * es.po: Updated Spanish translation. 2008-10-23 Andre Klapper * LINGUAS: Added ast. * ast.po: Added Asturian translation on behalf of Mikel González. 2008-10-19 Djihed Afifi * ar.po: Updated Arabic Translation by Djihed Afifi. 2008-10-11 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation by Ihar Hračyška. 2008-09-27 Leonardo Ferreira Fontenelle * pt_BR.po: Removed obsolete translations because of bug #549898. 2008-09-23 Pema Geyleg * dz.po: Updated Dzongkha Translation 2008-09-21 Kenneth Nielsen * da.po: Updated Danish translation by Kenneth Nielsen 2008-09-21 Wadim Dziedzic * pl.po: Updated Polish translation 2008-09-20 Mugurel Tudor * ro.po: Updated Romanian translation by Mişu Moldovan 2008-09-20 Goran Rakić * sr.po, sr@latin.po: Updated Serbian Translation. 2008-09-18 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation 2008-09-18 Djihed Afifi * ar.po: Updated Arabic Translation by Djihed Afifi. 2008-09-17 I. Felix * ta.po: Tamil Translation updated 2008-09-16 Gil Forcada * ca.po: Updated Catalan translation. 2008-09-16 Shankar Prasad * kn.po: Updated Kannada Translation. 2008-09-15 Gabor Kelemen * hu.po: Translation updated. 2008-09-15 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-09-14 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-09-13 Leonardo Ferreira Fontenelle * pt_BR.po: Terminology in Brazilian Portuguese translation. 2008-09-13 Praveen Arimbrathodiyil * ml.po: Malayalam translation updated. 2008-09-13 Baris Cicek * tr.po: Updated Turkish Translation. 2008-09-12 Sandeep Shedmake * mr.po: Updated Marathi translations. 2008-09-10 Shankar Prasad * kn.po: Added Kannada translation * LINGUAS: Added Kannada(kn) to the list of Languages 2008-09-10 Luca Ferretti * it.po: Updated Italian translation. 2008-09-09 Robert Sedak * hr.po: Added Croatian translation. * LINGUAS: Added hr 2008-09-08 Changwoo Ryu * ko.po: Updated Korean translation. 2008-09-07 Wouter Bolsterlee * nl.po: Updated Dutch translation by Wouter Bolsterlee. 2008-09-06 Philip Withnall * en_GB.po: Updated British English translation. 2008-09-05 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2008-09-01 Hendrik Richter * de.po: Updated German translation. 2008-08-30 Seán de Búrca * ga.po: Updated Irish translation. 2008-08-29 Claude Paroz * fr.po: Updated French translation. 2008-08-29 Arangel Angov * mk.po: Updated Macedonian translation. 2008-08-28 Petr Kovar * cs.po: Updated Czech translation. 2008-08-25 Goran Rakic * LINGUAS, sr@latin.po, sr@Latn.po: Conversion from sr@Latn to sr@latin. 2008-08-24 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2008-08-22 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-08-20 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-08-12 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-08-11 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-08-07 Og Maciel * pt_BR.po: Updated translation by Vladimir Melo. 2008-08-06 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-08-6 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-08-05 Daniel Nylander * sv.po: Updated Swedish translation. 2008-08-04: Sweta Kothari * gu.po: Updated Gujarati Translation. 2008-08-02 Leonardo Ferreira Fontenelle * pt_BR.po: Terminology fixes by Vladimir Melo. 2008-07-29 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-07-10 Matej Urbančič * sl.po: Updated Slovenian translation. 2008-07-02 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-06-30 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-06-11 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-06-11 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-06-05 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-06-01 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-05-25 Clytie Siddall * vi.po: Updated Vietnamese translation. 2008-05-23 Jorge Gonzalez * es.po: Updated Spanish translation 2008-05-22 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-05-19 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-05-14 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2008-05-07 Andre Klapper * LINGUAS: * is.po: Added Icelandic Translation on behalf of Anna Ármannsdóttir 2008-04-21 Alexander Shopov * bg.po: Updated Bulgarian translation by Yavor Doganov 2008-04-04 Eskild Hustvedt * nn.po: Updated Norwegian Nynorsk translation 2008-03-16 Kostas Papadimas * el.po: Updated Greek translation. 2008-03-12 Sunil Mohan Adapa * te.po: Updated Telugu traslation done by Krishna Babu K . 2008-03-11 Andre Klapper * LINGUAS: * ps.po: Added Pashto translation on behalf of Zabeeh Khan (bug #521378). 2008-03-10 Marcel Telka * sk.po: Updated Slovak translation. 2008-03-10 Alexander Nyakhaychyk * be.po: Added Belarusian Translation. * LINGUAS: Added Belarusian Translation. 2008-03-10 Baris Cicek * tr.po: Updated Turkish translation from Deniz Kocak 2008-03-09 Kenneth Nielsen * da.po: Updated Danish translation 2008-03-09 Runa Bhattacharjee * bn_IN.po: Updated Bengali India Translation by Sankarshan Mukhopadhyay 2008-03-09 Gabor Kelemen * hu.po: Translation updated 2008-03-07 Mugurel Tudor *ro.po: Updated Romanian translation by Mişu Moldovan 2008-03-07 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2008-03-05 Rahul Bhalerao * mr.po: Added Marathi Translations by Sandeep Shedmake. * LINGUAS: Added an entry for Marathi (mr). 2008-03-03 Jorge Gonzalez * es.po: Updated Spanish translation 2008-03-03 Philip Withnall * en_GB.po: Updated British English translation. 2008-03-02 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2008-02-28 Takeshi AIHANA * ja.po: Updated Japanese translation. 2008-02-26 Changwoo Ryu * ko.po: Updated Korean translation. 2008-02-24 Ilkka Tuohela * fi.po: Updated Finnish translation (bug #518255). 2008-02-23 Yair Hershkovitz * he.po: Updated Hebrew translation. 2008-02-22 Claude Paroz * fr.po: Updated French translation by Robert-André Mauchin. 2008-02-22 Arangel Angov * mk.po: Updated Macedonian translation. 2008-02-19 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-02-17 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2008-02-16 Gil Forcada * ca.po: Updated Catalan translation. 2008-02-14 Priit Laes * et.po: Translation updated by Ivar Smolin 2008-02-14 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2008-02-14 Pawan Chitrakar * ne.po: Updated Nepali Translation. 2008-02-13 Ilkka Tuohela * fi.po: Updated Finnish translation. 2008-02-11 Petr Kovar * cs.po: Updated Czech translation. 2008-02-09 Duarte Loreto * pt.po: Updated Portuguese translation. 2008-02-09 Andre Klapper * de.po: Updated German translation. 2008-02-08 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2008-02-08 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2008-02-07 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2008-02-6 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2008-02-05 Amitakhya Phukan * LINGUAS: Added as. * as.po: Updated assamese translations. 2008-02-04 Wouter Bolsterlee * nl.po: Dutch translation updated by Wouter Bolsterlee. 2008-02-02 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2008-02-02 Yannig Marchegay * oc.po: Updated Occitan translation. 2008-02-02 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated by Vladimir Melo. 2008-02-02 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2008-02-01 Daniel Nylander * sv.po: Updated Swedish translation. 2008-01-31 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Husseini. 2008-01-30 William Jon McCann * POTFILES.in: Update files. 2008-01-29 Jorge Gonzalez * es.po: Updated Spanish translation 2008-01-29 Luca Ferretti * POTIFILES.in: added new file. * it.po: Updated Italian translation. 2008-01-21 Gil Forcada * ca.po: Small fix thanks to David Planella. 2008-01-16 Yair Hershkovitz * he.po: Updated Hebrew translation from Rosseta. 2008-01-09 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2007-12-31 Yannig Marchegay * oc.po: Updated Occitan translation. 2007-12-20 Seán de Búrca * ga.po: Added Irish translation. * LINGUAS: Added Irish. 2007-12-13 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation from Eskild. 2007-12-13 Kjartan Maraas * nn.po: Added Norwegian nynorsk translation from Eskild Hustvedt 2007-12-08 Jakub Friedl * cs.po: Czech Translation updated by Petr Kovar. 2007-12-01 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2007-11-25 Nickolay V. Shmyrev * ru.po: Updated Russian translation by Vasiliy Faronov 2007-11-14 Matej Urbančič * sl.po: Updated Slovenian translation. 2007-10-31 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-10-23 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Husseini. 2007-10-21 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Husseini. 2007-10-21 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Husseini. 2007-10-15 Matej Urbančič * sl.po: Updated Slovenian translation. 2007-10-15 Yair Hershkovitz * he.po: Updated Hebrew translation. 2007-09-30 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2007-09-24 Changwoo Ryu * ko.po: Updated Korean translation. 2007-09-18 Goran Rakić * sr.po, sr@Latn.po: Updated Serbian translation (by Miloš Popović) 2007-09-17 Baris Cicek * tr.po: Updated Turkish translation from Deniz Kocak 2007-09-17 Takeshi AIHANA * ja.po: Fixed wrong translation. 2007-09-17 Danishka Navin * si.po: Sinhala Translation updated by Danishka Navin 2007-09-16 Nickolay V. Shmyrev * ru.po: Updated Russian translation. 2007-09-16 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-09-15 Andre Klapper * sk.po: Updated Slovak translation on behalf of Peter Tuharsky . 2007-09-15 Mugurel Tudor * LINGUAS: added ro * ro.po: Added Romanian translation by Alexandru Szasz 2007-09-13 Djihed Afifi * ar.po: Updated Arabic Translation by Anas Husseini. 2007-09-12 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2007-09-09 Nikos Charonitakis * el.po: Updated Greek translation. 2007-09-09 Kenneth Nielsen * da.po: Updated Danish translation 2007-09-06 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-09-06 Stéphane Raimbault * fr.po: Updated French translation by Jonathan Ernst and Stéphane Raimbault. 2007-09-05 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2007-09-05 Ani Peter * ml.po: Updated Malayalam Translation 2007-09-04 Luca Ferretti * it.po: Updated Italian translation. 2007-09-04 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-09-04 Gabor Kelemen * hu.po: Translation updated. 2007-09-03 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-09-03 Priit Laes * et.po: Estonian translation updates by Ivar Smolin 2007-09-03 Duarte Loreto * pt.po: Updated Portuguese translation. 2007-09-01 Gil Forcada * ca.po: Updated catalan translation. 2007-08-31 Ani Peter * ml.po: Updated Malayalam Translation 2007-08-29 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2007-08-27 Changwoo Ryu * ko.po: Updated Korean translation by Young-Ho Cha. 2007-08-23 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-08-23 Sunil Mohan Adapa * te.po: Added Telugu translation done by Srinivas Chary . 2007-08-17 Ani Peter * ml.po: Updated Malayalam TRanslation 2007-08-16 Priit Laes * et.po: Estonian translation updates by Ivar Smolin 2007-08-16 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-08-15 Hendrik Richter * de.po: Updated German translation. 2007-08-13 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-08-12 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-08-11 Leonardo Ferreira Fontenelle * pt_BR.po: Brazilian Portuguese translation updated by Vladimir Melo . 2007-08-11 Daniel Nylander * sv.po: Updated Swedish translation. 2007-08-06 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-08-04 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation 2007-08-03 Jorge Gonzalez * es.po: Updated Spanish translation 2007-08-03 Ihar Hrachyshka * be@latin.po: Updated Belarusian Latin translation. 2007-08-03 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-08-01 Daniel Nylander * sv.po: Updated Swedish translation. 2007-07-31 Jorge Gonzalez * es.po: Updated Spanish translation 2007-07-25 Andre Klapper * de.po: updated german translation. 2007-07-24 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-07-21 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-07-17 Daniel Nylander * sv.po: Updated Swedish translation. 2007-07-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-07-16 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-07-13 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-07-13 I. Felix * ta.po: Tamil Translation updated by Tirumurthi Vasudevan 2007-07-11 Gabor Kelemen * hu.po: Translation updated. 2007-07-10 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-07-06 Jorge Gonzalez * es.po: Updated Spanish translation 2007-07-01 Nguyễn Thái Ngọc Duy * vi.po: Updated Vietnamese translation. 2007-06-29 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-06-27 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-06-22 I. Felix * si.po: Sinhala Translation updated by Danishka Navin * LINGUAS: Added Sinhala (si) to The List of Languages. 2007-06-21 I Felix * ta.po: Updated Tamil Translation. 2007-06-13 Pema Geyleg * dz.po: Updated dzongkha translation. 2007-05-31 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-05-30 Priit Laes * et.po: Updated Estonian translation by Ivar Smolin . 2007-05-29 Ihar Hrachyshka * be@latin.po: Added Belarusian Latin translation. 2007-05-18 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2007-05-08 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2007-05-04 Jorge Gonzalez * es.po: Updated Spanish translation 2007-04-25 David Lodge * en_GB.po: Updated British English translation 2007-04-24 Daniel Nylander * sv.po: Updated Swedish translation. 2007-04-05 Raivis Dejus * lv.po: Updated Latvian Translation. 2007-04-02 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-03-31 Inaki Larranaga Murgoitio * eu.po: Updated Basque translation. 2007-03-31 Funda Wang * zh_CN.po: Updated Simplified Chinese translation from Yang Zhang. 2007-03-27 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. * POTFILES.in: Updated. 2007-03-22 Peter Bach * da.po: Updated Danish translation. 2007-03-18 Matic Zgur * sl.po: Updated Slovenian translation. 2007-03-10 Nickolay V. Shmyrev * ru.po: Updated Russian translation. 2007-03-06 Pema Geyleg * dz.po: Updated Dzongkha Translation. 2007-03-06 Jovan Naumovski * mk.po: Updated Macedonian translation. 2007-03-05 Ankit Patel * gu.po: Updated Gujarati Translation. 2007-03-04 Luca Ferretti * it.po: Updated Italian translation. 2007-03-03 Yair Hershkovitz * he.po: Updated Hebrew translation. 2007-02-28 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-02-28 Djihed Afifi * ar.po: Updated Arabic Translation by Khaled Hosny. 2007-02-27 Abel Cheung * POTFILES.in: Some desktop files have been renamed. 2007-02-27 Abel Cheung * zh_HK.po, zh_TW.po: Updated traditional Chinese translation by Woodman Tuen . 2007-02-27 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-02-25 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2007-02-24 Gabor Kelemen * hu.po: Translation updated. 2007-02-25 Changwoo Ryu * ko.po: Updated Korean translation. 2007-02-22 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2007-02-21 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2007-02-20 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2007-02-19 Ilkka Tuohela * fi.po: Updated Finnish translation. 2007-02-18 Takeshi AIHANA * ja.po: Updated Japanese translation. 2007-02-17 Hendrik Brandt * de.op: Updated German translation. 2007-02-17 David Lodge * POTFILES.in: Changed a couple of the savers to use .in.in instead of .in so that the pot file would generate 2007-02-15 William Jon McCann * POTFILES.in: Remove FUSA. 2007-02-14 Duarte Loreto * pt.po: Updated Portuguese translation. 2007-02-10 Lasse Bang Mikkelsen * da.po: Updated Danish translation by Kenneth Nielsen 2007-02-06 Leonardo Ferreira Fontenelle * pt_BR.po: Updated Brazilian Portuguese translation by Og Maciel . 2007-02-02 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-01-31 Stéphane Raimbault * fr.po: Updated French translation by Robert-André Mauchin and Stéphane Raimbault. 2007-01-30 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2007-01-30 William Jon McCann * POTFILES.in: Removed deleted file 2007-01-26 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2007-01-12 Kjartan Maraas * nb.po: Fix a typo. Thanks to Bjarte Lund for saving me from some embarrassment. Closes bug #395567. 2007-01-11 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation by Gil Forcada . 2007-01-07 Priit Laes * et.po: Estonian translation update by Ivar Smolin. 2007-01-06 Clytie Siddall * vi.po: Updated Vietnamese translation. 2007-01-01 David Lodge * en_GB.po: Updated English (British) translation 2006-12-27 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-24 Djihed Afifi * ar.po: Updated Arabic Translation. 2006-12-20 Raivis Dejus * lv.po: Updated Latvian Translation. 2006-12-18 Djihed Afifi * ar.po: Added Arabic Translation. * LINGUAS: Added ar. 2006-12-14 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-12-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-12-11 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-12-07 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-11-19 Daniel Nylander * sv.po: Updated Swedish translation. 2006-11-08 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-11-01 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-10-21 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-20 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-10-20 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-10-19 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-10-19 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-10-17 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-10-13 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-13 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-10-09 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-10-08 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-04 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-10-03 Jakub Friedl * cs.po: Czech translation update. 2006-10-02 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-27 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-25 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-09-14 Luca Ferretti * it.po: Updated Italian translation. 2006-09-14 Satoru SATOH * ja.po: Fixed up mismatch between nplurals and number of plural forms some messages have. 2006-09-10 David Lodge * en_GB.po: Updated English (British) translation. 2006-09-05 Lucas Rocha * pt_BR.po: Updated Brazilian Portuguese translation by Leonardo Ferreira Fontenelle and Henrique Grolli Bassotto 2006-09-04 Baris Cicek * tr.po: Added Turkish Translation from Deniz Kocak * LINGUAS: Added entry for "tr" (turkish); 2006-09-04 Roozbeh Pournader * fa.po: Added Persian translation by Elnaz Sarbar and Meelad Zakaria. * LINGUAS: Added entry for "fa" (Persian). 2006-09-04 Abel Cheung * zh_HK.po: Updated Chinese (Hong Kong) translation from Ching-Hung Lin . * zh_TW.po: Updated Chinese (Taiwan) translation from Ching-Hung Lin . 2006-09-03 Subhransu Behera * or.po: Updated Oriya Translation. 2006-09-02 Kostas Papadimas * el.po: Updated Greek Translation 2006-09-01 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-31 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-08-31 Gabor Kelemen * hu.po: Translation updated. 2006-08-31 Duarte Loreto * pt.po: Updated Portuguese translation. 2006-08-30 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2006-08-29 Christophe Merlet * fr.po: Updated French translation from Robert-André Mauchin . 2006-08-29 Gintautas Miliauskas * lt.po: Updated Lithuanian translation. 2006-08-27 Theppitak Karoonboonyanan * th.po: Fixed plural forms. 2006-08-26 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-24 Raivis Dejus * lv.po: Updated Latvian translation. 2006-08-24 Inaki Larranaga * eu.po: Added Basque translation. * LINGUAS: Added "eu" (Basque) entry. 2006-08-22 Matic Žgur * sl.po: Updated Slovenian translation. 2006-08-21 Subhransu Behera * or.po: Added and Updated Oriya Translation. * LINGUAS: Added Oriya (or) to The List of Languages. 2006-08-19 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-08-19 Maxim Dziumanenko * uk.po: Update Ukrainian translation. 2006-08-16 Erdal Ronahi * ku.po: Updated Kurdish translations by Riza Seckin 2006-08-16 Hendrik Richter * de.po: Updated German translation. 2006-08-16 Daniel Nylander * sv.po: Updated Swedish translation. 2006-08-16 Gabor Kelemen * hu.po: Translation updated. 2006-08-15 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-08-15 Leonid Kanter * ru.po: Updated Russian translation 2006-08-14 Sanlig Badral * mn.po: Added Mongolian translation. * LINGUAS: Added mn entry. 2006-08-14 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-08-12 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2006-08-12 Changwoo Ryu * ko.po: Updated Korean translation. 2008-08-10 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation by Gil Forcada 2006-08-10 Guntupalli Karunakar * dz.po: Updated Dzongkha translation by Dzongkhalinux team, DIT 2006-08-09 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-08-09 Satoru SATOH * ja.po: Updated Japanese translation. 2006-08-08 Ani Peter * ml.po: Added and Updated Malayalam translation * LINGUAS: Added Malayalam (ml) to the list of Languages 2006-08-02 Jovan Naumovski * mk.po: Updated Macedonian translation. 2006-08-02 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-08-02 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-08-01 Jovan Naumovski * mk.po: Updated/fixed Macedonian translation. 2006-08-01 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-08-01 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-07-31 Christophe Merlet * fr.po: Updated French translation. 2006-07-30 Arangel Angov * sl.po: Added Slovenian translation. 2006-07-30 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2006-07-29 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-07-27 Ahmad Riza H Nst * id.po: Updated. 2006-07-27 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-07-26 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-07-25 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-07-23 Changwoo Ryu * ko.po: Updated Korean translation. 2006-07-21 Jakub Friedl * cs.po: Updated Czech translation 2006-07-21 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation by Gil Forcada. 2006-07-20 Hendrik Richter * de.po: Updated German translation. 2006-07-20 Kostas Papadimas * el.po: Updated Greek translation. 2006-07-20 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-07-19 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-07-19 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-07-18 Guntupalli Karunakar * dz.po: Updated Dzongkha translation by Dzongkhalinux team, DIT 2006-07-17 Thierry Randrianiriana * mg.po: Added Malagasy translation. * LINGUAS: Added Malagasy 'mg'. 2006-07-16 Daniel Nylander * sv.po: Updated Swedish translation. 2006-07-14 Priit Laes * et.po: Translation updated. 2006-07-14 Jakub Friedl * cs.po: Updated Czech translation 2006-07-05 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2006-07-03 Runa Bhattacharjee * bn_IN.po: Added Bengali India Translation * LINGUAS: Added Bengali India (bn_IN) to the list of languages. 2006-07-03 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-07-02 Benoît Dejean * fr.po: Updated French translation. 2006-07-01 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-07-01 Pawan Chitrakar * ne.po: Added Nepali translation * LINGUAS: Added ne 2006-06-30 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-06-30 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-06-30 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-30 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-29 Rajesh Ranjan * hi.po: Updated Hindi Translation. 2006-06-29 Yair Hershkovitz * he.po: Added Hebrew translation. 2006-06-28 Guntupalli Karunakar * dz.po: Updated Dzongkha translation by Dzongkhalinux, DIT 2006-06-27 Jovan Naumovski * mk.po: Updated Macedonian Translation. 2006-06-23 I. felix * ta.po: Added Tamil translation. * LINGUAS: Added Tamil (ta) entry. 2006-06-19 Raivis Dejus * lv.po: Added Latvian translation. * LINGUAS: Added Latvian (lv) entry. 2006-06-16 Jakub Friedl * cs.po: Updated Czech translation. 2006-06-15 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-06-15 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-06-15 Hendrik Richter * de.po: Updated German translation. 2006-06-15 Daniel Nylander * sv.po: Updated Swedish translation. 2006-06-15 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-06-14 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-13 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-13 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-12 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-12 Jakub Friedl * cs.po: Updated Czech translation. 2006-06-12 Kjartan Maraas * POTFILES.in: Add src/gs-auth-pam.c * nb.po: Updated Norwegian bokmål translation. 2006-06-12 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-09 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-06-09 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-06-09 Jakub Friedl * cs.po: Updated Czech translation. 2006-06-07 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-06-06 Jakub Friedl * cs.po: Updated Czech translation. 2006-05-30 Pema Geyleg * dz.po: Updated Dzongkha translation. 2006-05-29 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-05-29 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-29 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-05-29 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-05-28 Pema Geyleg * dz.po: updated Dzongkha translation. 2006-05-26 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-05-25 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-05-23 Jakub Friedl * cs.po: Updated Czech translation. 2006-05-19 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-05-19 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-05-16 Nickolay V. Shmyrev * LINGUAS: Added Russian translation. 2006-05-14 Chao-Hsiung Liao * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). * zh_TW.po: Updated Traditional Chinese translation(Taiwan). 2006-05-11 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-05-06 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-04-30 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. 2006-04-26 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-25 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-24 William Jon McCann * POTFILES.in: Add new file. 2006-04-19 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-04-18 William Jon McCann * LINGUAS: Don't split over multiple lines as it breaks the build. 2006-04-18 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-04-17 Kjartan Maraas * LINGUAS: Remove obsolete entry for no_NO * no.po: And the translation. 2006-04-17 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-04-13 Vladimer Sichinava * ka.po: Updated Georgian translation. 2006-04-10 Artur Flinta * pl.po: Updated Polish translation by GNOME PL Team. 2006-04-08 Benoît Dejean * fr.po: Updated French translation. 2007-04-05 Pema Geyleg * dz.po: Added Dzongkha translation. 2006-04-03 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-03-31 Lukas Novotny * cs.po: Updated Czech translation. 2006-03-20 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-17 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-17 Wouter Bolsterlee * nl.po: Translation updated by Wouter Bolsterlee. 2006-03-17 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-14 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-03-13 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-13 Erdal Ronahi * ku.po: Added initial Kurdish translation 2006-03-13 Runa Bhattacharjee * bn.po: Added Bengali Translation (partial) by Mahay Alam Khan. 2006-03-12 Miloslav Trmac * cs.po: Updated Czech translation by Petr Tomeš. 2006-03-11 Guilherme de S. Pastore * pt_BR.po: Updated Brazilian Portuguese translation. 2006-03-11 Jens Seidel * de.po: Proofreading. 2006-03-11 Frank Arnold * de.po: Replaced wrong spaces caused by copy/paste inside gtranslator. 2006-03-11 Duarte Loreto * pt.po: Added Portuguese translation. 2006-03-10 Luca Ferretti * it.po: Updated Italian translation 2006-03-08 Rajesh Ranjan * hi.po: Added Hindi tranlsation. 2006-03-08 Lasse Bang Mikkelsen * da.po: Added Danish translation by David Nielsen. 2006-03-08 Laurent Dhima * sq.po: Added Albanian translation. 2006-03-08 Rhys Jones * cy.po: Added Welsh translation. 2006-03-07 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-07 Daniel Nylander * sv.po: Updated Swedish translation. 2006-03-06 Maxim Dziumanenko * uk.po: Updated Ukrainian translation. 2006-03-05 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. * no.po: Same. 2006-03-05 Priit Laes * et.po: Translation updated by Ivar Smolin. 2006-03-04 Priit Laes * et.po: Translation added by Ivar Smolin. 2006-03-02 Hendrik Richter * de.po: Updated German translation. 2003-03-02 Kang Jeong-Hee * ko.po: Updated Korean translation. 2006-03-01 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2006-03-01 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation. 2006-02-25 Luca Ferretti * it.po: Italian translation updated. 2006-02-25 Gabor Kelemen * hu.po: Hungarian translation updated. 2006-02-23 Leonid Kanter * ru.po: Initial Russian translation 2006-02-23 Kostas Papadimas *el.po Updated Greek Translation 2006-02-23 Kostas Papadimas *el.po Updated Greek Translation 2006-02-23 Clytie Siddall * ka.po: Added Georgian translation by Alexander Didebulidze and Vladimer SIchinava . 2006-02-23 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2006-02-21 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2006-02-21 Kang Jeong-Hee * ko.po: Added Korean translation 2006-02-21 Slobodan D. Sredojevic * sr.po, sr@Latn.po: Updated Serbian translation 2006-02-21 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-02-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-02-18 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. * no.po: Same. 2006-02-17 Satoru SATOH * ja.po: Updated Japanese translation. 2006-02-16 Nikos Charonitakis * el.po: Added Greek translation. 2006-02-16 Luca Ferretti * it.po: Updated Italian translation. 2006-02-16 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-02-16 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-02-15 Ilkka Tuohela * fi.po: Changed "%s on %s" to %s@%s for Finnish. 2006-02-15 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-02-15 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-02-15 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2006-02-11 Øivind Hoel * nb.po: Updated Norwegian Bokmål translation. 2006-02-10 Josep Puigdemont i Casamajó * ca.po: Updated Catalan translation, by Gil Forcada 2006-02-06 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2006-01-31 Lukas Novotny * cs.po: Updated Czech translation. 2006-01-30 Hendrik Brandt * de.po: Updated German translation. 2006-01-29 Hendrik Brandt * de.po: Updated German translation, plural bugfix. 2006-01-29 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2006-01-27 Chao-Hsiung Liao * zh_TW.po: Updated Traditional Chinese translation(Taiwan). * zh_HK.po: Updated Traditional Chinese translation(Hong Kong). 2006-01-25 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-01-18 Slobodan D. Sredojevic * sr.po, sr@Latn.po: Updated Serbian translation 2006-01-18 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-01-18 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2006-01-17 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-16 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-01-16 Clytie Siddall * vi.po: Updated Vietnamese translation. 2006-01-15 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2006-01-15 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2006-01-08 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2006-01-08 Takeshi AIHANA * ja.po: Updated Japanese translation. 2006-01-07 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2006-01-07 Ilkka Tuohela * fi.po: Updated Finnish translation. 2006-01-07 Chao-Hsiung Liao * zh_TW.po: Updated Traditional Chinese Translation.(Taiwan) * zh_HK.po: Added Traditional Chinese Translation.(Hong Kong) 2006-01-06 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2006-01-03 Slobodan D. Sredojevic * sr.po, sr@Latn.po: Added Serbian translation 2006-01-02 Josep Puigdemont i Casamajó * ca.po: Added Catalan translation. 2006-01-01 Ankit Patel * gu.po: Updated Gujarati Translation. 2006-01-01 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-12-31 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-31 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-30 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-12-26 Ilkka Tuohela * fi.po: Updated Finnish translation. 2005-12-26 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2005-12-23 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-12-20 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-12-20 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-12-19 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-12-19 Ankit Patel * gu.po: Added Gujarati Translation. 2005-12-19 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-12-18 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-12-17 Theppitak Karoonboonyanan * th.po: Updated Thai translation. 2005-12-14 William Jon McCann * POTFILES.in: Updated. 2005-12-13 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-12-13 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-12-13 Gabor Kelemen * hu.po: Hungarian translation updated. 2005-12-11 Miloslav Trmac * cs.po: Updated Czech translation. 2005-12-08 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. * no.po: Same. 2005-12-04 Theppitak Karoonboonyanan * th.po: Fixed typos. 2005-11-28 Ignacio Casal Quinteiro * gl.po: Updated Galician Translation. 2005-11-27 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2005-11-27 Theppitak Karoonboonyanan * th.po: Added Thai translation. 2005-11-27 Marcel Telka * sk.po: Updated Slovak translation. 2005-11-22 Alexander Shopov * bg.po: Updated Bulgarian translation by Alexander Shopov 2005-11-20 Amanpreet Singh Alam * pa.po: Add Punjabi (pa) Translaiton 2005-11-20 Ilkka Tuohela * fi.po: Updated Finnish translation. 2005-11-17 Marcel Telka * sk.po: Added Slovak translation. 2005-11-14 Christophe Merlet * fr.po: Updated French translation from Davy Defaud . 2005-11-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-11-06 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-11-04 Žygimantas Beručka * lt.po: Updated Lithuanian translation. 2005-11-04 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-11-02 Miloslav Trmac * cs.po: Updated Czech translation. 2005-11-03 Christophe Merlet * fr.po: Updated French translation from Davy Defaud . 2005-11-01 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-10-31 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-29 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-10-28 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-10-26 Gabor Kelemen * hu.po: Hungarian translation added. 2005-10-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-16 Kjartan Maraas * nb.po: Updated Norwegian bokmål translation. * no.po: Same. 2005-10-14 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-11 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-10-11 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-10-09 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-10-08 Funda Wang * zh_CN.po: Updated Simplified Chinese translation. 2005-10-07 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-06 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2005-10-05 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-04 Žygimantas Beručka * lt.po: Added Lithuanian translation. 2005-10-02 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-10-02 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-09-30 Kjartan Maraas * nb.po: Added Norwegian bokmål translation. * no.po: Same. 2005-09-29 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-09-29 Alexander Shopov * bg.po: Updated Bulgarian translation by Rostislav Raykov 2005-09-27 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-09-25 Miloslav Trmac * cs.po: Added Czech translation. 2005-09-24 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-09-23 William Jon McCann * POTFILES.in: Remove obsolete and add new files. 2005-09-22 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-09-21 Ilkka Tuohela * fi.po Updated Finnish translation 2005-09-18 Alessio Frusciante * it.po: Added Italian translation by Luca Ferretti . 2005-09-17 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-09-16 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-09-06 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-09-05 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-09-02 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-09-01 Vincent van Adrighem * nl.po: Translation updated by Tino Meinen. 2005-08-31 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-08-31 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-08-27 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-08-27 Clytie Siddall * vi.po: Updated Vietnamese translation. 2005-08-26 Christophe Merlet * fr.po: Added French translation from Eric Maeker . 2005-08-24 William Jon McCann * POTFILES.in: Add missing files. 2005-08-10 Alexander Shopov * bg.po: Added Bulgarian translation by Rostislav Raykov 2005-08-02 Maxim Dziumanenko * uk.po: Added Ukrainian translation. 2005-07-25 Tommi Vainikainen * fi.po: Added Finnish translation. 2005-07-19 Takeshi AIHANA * ja.po: Updated Japanese translation. 2005-07-18 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-18 Vincent van Adrighem * nl.po: Translation added by Tino Meinen. 2005-07-15 Abel Cheung * zh_TW.po: New traditional Chinese translation from GNOME HK Team 2005-07-06 Christian Rose * sv.po: Updated Swedish translation. 2005-07-04 Hendrik Richter * de.po: Fixed German translation by Jens Seidel . 2005-07-03 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-07-03 Takeshi AIHANA * ja.po: Added Japanese translation. 2005-06-26 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-06-23 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-06-17 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-06-13 William Jon McCann * POTFILES: Add new file. 2005-06-05 James Ogley * en_GB.po: Updated British English translation. 2005-06-04 Francisco Javier F. Serrador * es.po: Updated Spanish translation. 2005-05-24 Frank Arnold * de.po: Updated German translation. 2005-05-23 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-23 William Jon McCann * POTFILES.in: Add missing file. 2005-05-21 Frank Arnold * de.po: Added German translation. 2005-05-19 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-05 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-04 Adam Weinberger * en_CA.po: Updated Canadian English translation. 2005-05-01 Francisco Javier F. Serrador * es.po: Added Spanish translation. 2005-04-29 Christian Rose * POTFILES.in: Added missing files. * sv.po: Updated Swedish translation. 2005-04-24 Raphael Higino * pt_BR.po: Updated Brazilian Portuguese translation. 2005-04-19 Gareth Owen * en_GB.po: Added British English translation 2005-04-15 Adam Weinberger * en_CA.po: Added Canadian English translation. 2005-04-15 Raphael Higino * pt_BR.po: Added Brazilian Portuguese translation. 2005-04-15 Funda Wang * zh_CN.po: Added Simplified Chinese translation. 2005-04-14 Christian Rose * sv.po: Added Swedish translation. 2005-04-14 Christian Rose * POTFILES.in: Added this file. * .cvsignore: Updated this file. cinnamon-screensaver-4.4.1/po/LINGUAS000066400000000000000000000000611357366610100173100ustar00rootroot00000000000000# please keep this list sorted alphabetically # cinnamon-screensaver-4.4.1/po/Makefile.in.in000066400000000000000000000157561357366610100207560ustar00rootroot00000000000000# Makefile for program source directory in GNU NLS utilities package. # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper # Copyright (C) 2004-2008 Rodney Dawes # # This file may be copied and used freely without restrictions. It may # be used in projects which are not available under a GNU Public License, # but which still want to provide support for the GNU gettext functionality. # # - Modified by Owen Taylor to use GETTEXT_PACKAGE # instead of PACKAGE and to look for po2tbl in ./ not in intl/ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize # # - Modified by Rodney Dawes for use with intltool # # We have the following line for use by intltoolize: # INTLTOOL_MAKEFILE GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datadir = @datadir@ datarootdir = @datarootdir@ libdir = @libdir@ localedir = @localedir@ subdir = po install_sh = @install_sh@ # Automake >= 1.8 provides @mkdir_p@. # Until it can be supposed, use the safe fallback: mkdir_p = $(install_sh) -d INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ XGETTEXT = @XGETTEXT@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot ALL_LINGUAS = @ALL_LINGUAS@ PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) DISTFILES = Makefile.in.in POTFILES.in $(POFILES) EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS POTFILES = \ # This comment gets stripped out CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) .SUFFIXES: .SUFFIXES: .po .pox .gmo .mo .msg .cat AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot $(MSGMERGE) $* $(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< .po.gmo: $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ && rm -f $$file && $(GMSGFMT) -o $$file $< .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ && rm -f $@ && gencat $@ $*.msg all: all-@USE_NLS@ all-yes: $(CATALOGS) all-no: $(GETTEXT_PACKAGE).pot: $(POTFILES) $(GENPOT) install: install-data install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ dir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $$dir; \ if test -r $$lang.gmo; then \ $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ else \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $(srcdir)/$$lang.gmo as" \ "$$dir/$(GETTEXT_PACKAGE).mo"; \ fi; \ if test -r $$lang.gmo.m; then \ $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ if test -r $(srcdir)/$$lang.gmo.m ; then \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $(srcdir)/$$lang.gmo.m as" \ "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ true; \ fi; \ fi; \ done # Empty stubs to satisfy archaic automake needs dvi info ctags tags CTAGS TAGS ID: # Define this as empty until I found a useful application. install-exec installcheck: uninstall: linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ done check: all $(GETTEXT_PACKAGE).pot rm -f missing notexist srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m if [ -r missing -o -r notexist ]; then \ exit 1; \ fi mostlyclean: rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp rm -f .intltool-merge-cache clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES stamp-it rm -f *.mo *.msg *.cat *.cat.m *.gmo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f Makefile.in.in distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(DISTFILES) dists="$(DISTFILES)"; \ extra_dists="$(EXTRA_DISTFILES)"; \ for file in $$extra_dists; do \ test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ done; \ for file in $$dists; do \ test -f $$file || file="$(srcdir)/$$file"; \ ln $$file $(distdir) 2> /dev/null \ || cp -p $$file $(distdir); \ done update-po: Makefile $(MAKE) $(GETTEXT_PACKAGE).pot tmpdir=`pwd`; \ linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ echo "$$lang:"; \ result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ if $$result; then \ if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.gmo failed!"; \ rm -f $$tmpdir/$$lang.new.po; \ fi; \ done Makefile POTFILES: stamp-it @if test ! -f $@; then \ rm -f stamp-it; \ $(MAKE) stamp-it; \ fi stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ $(SHELL) ./config.status # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: cinnamon-screensaver-4.4.1/po/POTFILES.in000066400000000000000000000002731357366610100200450ustar00rootroot00000000000000# List of source files containing translatable strings. # Please keep this file sorted alphabetically. src/clock.py src/unlock.py src/cinnamon-screensaver-command.py src/playerControl.py cinnamon-screensaver-4.4.1/po/POTFILES.skip000066400000000000000000000000441357366610100204010ustar00rootroot00000000000000src/cinnamon-screensaver.desktop.in cinnamon-screensaver-4.4.1/src/000077500000000000000000000000001357366610100164375ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/Makefile.am000066400000000000000000000031051357366610100204720ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = binfiles dbusdepot widgets util pamhelper appdir = $(datadir)/cinnamon-screensaver app_PYTHON = \ __init__.py \ albumArt.py \ audioPanel.py \ baseWindow.py \ clock.py \ config.py \ constants.py \ floating.py \ infoPanel.py \ manager.py \ monitorView.py \ osk.py \ passwordEntry.py \ playerControl.py \ service.py \ singletons.py \ stage.py \ status.py \ unlock.py \ volumeControl.py \ $(NULL) app_DATA = cinnamon-screensaver-gtk3.14.css \ cinnamon-screensaver-gtk3.18.css \ cinnamon-screensaver-gtk3.20.css \ $(NULL) app_SCRIPTS = cinnamon-screensaver-main.py \ cinnamon-screensaver-command.py \ $(NULL) config.py: config.py.in Makefile $(AM_V_GEN)sed \ -e s!\@prefix\@!$(prefix)! \ -e s!\@datadir\@!$(datadir)! \ -e s!\@pkgdatadir\@!$(pkgdatadir)! \ -e s!\@libexecdir\@!$(libexecdir)! \ -e s!\@libdir\@!$(libdir)! \ -e s!\@PACKAGE\@!$(PACKAGE)! \ -e s!\@VERSION\@!$(VERSION)! \ -e s!\@GETTEXT_PACKAGE\@!$(GETTEXT_PACKAGE)! \ < $< > $@ all-local: config.py EXTRA_DIST = \ config.py.in \ debug-screensaver.sh \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/__init__.py000066400000000000000000000000001357366610100205360ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/albumArt.py000066400000000000000000000044371357366610100205700ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, Gtk from util import trackers, settings from baseWindow import BaseWindow from floating import Floating from widgets.framedImage import FramedImage import singletons import status class AlbumArt(Floating, BaseWindow): """ AlbumArt It is a child of the Stage's GtkOverlay, and its placement is controlled by the overlay's child positioning function. When not Awake, it positions itself around all monitors using a timer which randomizes its halign and valign properties as well as its current monitor. """ def __init__(self, away_message=None, initial_monitor=0): super(AlbumArt, self).__init__(initial_monitor) self.get_style_context().add_class("albumart") self.set_halign(Gtk.Align.END) if not settings.get_show_albumart(): return self.watcher = singletons.MediaPlayerWatcher self.player = self.watcher.get_best_player() self.current_url = None self.image = FramedImage(status.screen.get_low_res_mode(), scale_up=True) self.image.show() self.image.set_opacity(0.0) self.add(self.image) trackers.con_tracker_get().connect(self.image, "surface-changed", self.on_surface_changed) if self.player != None: trackers.con_tracker_get().connect(self.player, "metadata-changed", self.on_metadata_changed) self.on_metadata_changed(self.player) def on_surface_changed(self, image, surface): if surface != None: self.image.set_opacity(1.0) else: self.image.set_opacity(0.0) def on_metadata_changed(self, player): self.update_image() def update_image(self): url = self.player.get_albumart_url() if url == self.current_url: return self.current_url = url if url == "": self.image.clear_image() f = Gio.File.new_for_uri(url) if f.get_uri_scheme() == "file": self.image.set_from_path(f.get_path()) elif f.get_uri_scheme() == "http": self.image.set_from_file(f) cinnamon-screensaver-4.4.1/src/audioPanel.py000066400000000000000000000030011357366610100210640ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk from baseWindow import BaseWindow from volumeControl import VolumeControl from playerControl import PlayerControl from util import utils, settings import status class AudioPanel(BaseWindow): def __init__(self): """ Upper left panel - only shows when Awake. Will always show the volume slider, and will only show the player controls if there is a controllable mpris player available. """ super(AudioPanel, self).__init__() self.monitor_index = status.screen.get_primary_monitor() self.update_geometry() if not settings.get_allow_media_control(): self.disabled = True return self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.box.set_halign(Gtk.Align.FILL) self.box.get_style_context().add_class("toppanel") self.box.get_style_context().add_class("audiopanel") self.add(self.box) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.box.pack_start(hbox, True, True, 6) self.volume_widget = VolumeControl() hbox.pack_start(self.volume_widget, False, False, 0) self.player_widget = PlayerControl() hbox.pack_start(self.player_widget, False, False, 0) should_show = self.player_widget.should_show() if not self.player_widget.should_show(): self.disabled = True def show_panel(self): if not self.disabled: self.show_all()cinnamon-screensaver-4.4.1/src/baseWindow.py000066400000000000000000000013111357366610100211070ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, GObject, Gdk from util import trackers import status class BaseWindow(Gtk.Bin): """ BaseWindow is the base class for all of the Stage GtkOverlay's immediate children. """ def __init__(self, *args): super(BaseWindow, self).__init__() self.disabled = False c = Gdk.RGBA(0, 0, 0, 0) self.override_background_color (Gtk.StateFlags.NORMAL, c); def destroy_window(self): self.destroy() def update_geometry(self): if status.Spanned: self.rect = status.screen.get_screen_geometry() else: self.rect = status.screen.get_monitor_geometry(self.monitor_index) cinnamon-screensaver-4.4.1/src/binfiles/000077500000000000000000000000001357366610100202325ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/binfiles/Makefile.am000066400000000000000000000010371357366610100222670ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 SUBDIRS= NULL = %:%.in Makefile $(AM_V_GEN)sed \ -e s!\@datadir\@!$(datadir)! \ < $< > $@ all-local: cinnamon-screensaver cinnamon-screensaver-command bin_SCRIPTS = cinnamon-screensaver cinnamon-screensaver-command EXTRA_DIST = \ cinnamon-screensaver.in \ cinnamon-screensaver-command.in \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/binfiles/cinnamon-screensaver-command.in000066400000000000000000000001241357366610100263130ustar00rootroot00000000000000#!/bin/sh exec @datadir@/cinnamon-screensaver/cinnamon-screensaver-command.py "$@" cinnamon-screensaver-4.4.1/src/binfiles/cinnamon-screensaver.in000066400000000000000000000001211357366610100246740ustar00rootroot00000000000000#!/bin/sh exec @datadir@/cinnamon-screensaver/cinnamon-screensaver-main.py "$@" cinnamon-screensaver-4.4.1/src/cinnamon-screensaver-command.py000077500000000000000000000101521357366610100245470ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('CScreensaver', '1.0') from gi.repository import GLib import signal import argparse import gettext from enum import IntEnum from dbusdepot.screensaverClient import ScreenSaverClient import config signal.signal(signal.SIGINT, signal.SIG_DFL) gettext.install("cinnamon-screensaver", "/usr/share/locale") class Action(IntEnum): EXIT = 1 QUERY = 2 TIME = 3 LOCK = 4 ACTIVATE = 5 DEACTIVATE = 6 VERSION = 7 class ScreensaverCommand: """ This is a standalone executable that provides a simple way of controlling the screensaver via its dbus interface. """ def __init__(self, mainloop): self.mainloop = mainloop parser = argparse.ArgumentParser(description='Cinnamon Screensaver Command') parser.add_argument('--exit', '-e', dest="action_id", action='store_const', const=Action.EXIT, help=_('Causes the screensaver to exit gracefully')) parser.add_argument('--query', '-q', dest="action_id", action='store_const', const=Action.QUERY, help=_('Query the state of the screensaver')) parser.add_argument('--time', '-t', dest="action_id", action='store_const', const=Action.TIME, help=_('Query the length of time the screensaver has been active')) parser.add_argument('--lock', '-l', dest="action_id", action='store_const', const=Action.LOCK, help=_('Tells the running screensaver process to lock the screen immediately')) parser.add_argument('--activate', '-a', dest="action_id", action='store_const', const=Action.ACTIVATE, help=_('Turn the screensaver on (blank the screen)')) parser.add_argument('--deactivate', '-d', dest="action_id", action='store_const', const=Action.DEACTIVATE, help=_('If the screensaver is active then deactivate it (un-blank the screen)')) parser.add_argument('--version', '-V', dest="action_id", action='store_const', const=Action.VERSION, help=_('Version of this application')) parser.add_argument('--away-message', '-m', dest="message", action='store', default="", help=_('Message to be displayed in lock screen')) args = parser.parse_args() if not args.action_id: parser.print_help() quit() if args.action_id == Action.VERSION: print("cinnamon-screensaver %s" % (config.VERSION)) quit() self.action_id = args.action_id self.message = args.message self.client = ScreenSaverClient() self.client.connect("client-ready", self.on_client_ready) def on_client_ready(self, client, success): if not success or client.proxy == None: print("Can't connect to screensaver!") self.mainloop.quit() else: self.perform_action() def perform_action(self): if self.action_id == Action.EXIT: self.client.proxy.call_quit_sync() elif self.action_id == Action.QUERY: if self.client.proxy.call_get_active_sync(): print(_("The screensaver is active\n")) else: print(_("The screensaver is inactive\n")) elif self.action_id == Action.TIME: time = self.client.proxy.call_get_active_time_sync() if time == 0: print(_("The screensaver is not currently active.\n")) else: print(gettext.ngettext ("The screensaver has been active for %d second.\n", "The screensaver has been active for %d seconds.\n", time) % time) elif self.action_id == Action.LOCK: self.client.proxy.call_lock_sync(self.message) elif self.action_id == Action.ACTIVATE: self.client.proxy.call_set_active_sync(True) elif self.action_id == Action.DEACTIVATE: self.client.proxy.call_set_active_sync(False) self.mainloop.quit() if __name__ == "__main__": ml = GLib.MainLoop.new(None, True) main = ScreensaverCommand(ml) ml.run() cinnamon-screensaver-4.4.1/src/cinnamon-screensaver-gtk3.14.css000066400000000000000000000111141357366610100243600ustar00rootroot00000000000000.csstage { background-image: none; background-color: black; } .csstage .unlockbox { color: #eeeeee; font-size: 20px; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .clock { color: #eeeeee; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .albumart { } .csstage .albumart .framedimage { border-radius: 2px; border: 2px solid; border-color: #eeeeee; box-shadow: 1px 1px alpha(black, 0.8); } .csstage .toppanel { border-color: alpha(white, .2); border-style: solid; color: white; background-color: transparent; background-image: linear-gradient(to bottom, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)); } .csstage .audiopanel { border-width: 0 1px 1px 0; border-radius: 0 0 3px 0; background-color: rgba(255, 255, 255, .05); } .csstage .infopanel { border-width: 0 0 1px 1px; border-radius: 0 0 0 3px; background-color: rgba(255, 255, 255, .05); } .csstage .notificationwidget, .csstage .powerwidget { font-size: 12px; font-weight: bold; color: white; background-color: transparent; background-image: none; text-shadow: 1px 1px alpha(black, 0.8); padding: 6px; } .csstage .auth-message { font-size: 12px; color: red; } .csstage .caps-message { font-size: 12px; color: orange; } .csstage .framedimage { background-color: alpha(grey, .25); background-clip: border-box; box-shadow: 1px 1px alpha(black, 0.8); } .csstage .faceimage { border-radius: 4px; border: 4px solid; border-color: @theme_selected_bg_color; } .csstage .albumart { color: rgba(320, 0, 0, 0); } .csstage .passwordentry { font-size: 12px; box-shadow: none; border-color: alpha(white, .2); border-style: solid; color: white; background-image: none; background-color: transparent; border-image: none; border-width: 1px; padding: 5px 10px 5px 5px; } .csstage .passwordentry:focused { background-color: transparent; background-image: none; border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } /* Use :backdrop for alt-text keyboard layout */ .csstage .passwordentry:backdrop { font-family: monospace; font-size: 16px; color: @theme_selected_bg_color; } .csstage .passwordentry.progressbar { margin: 2px; padding: 0; border-radius: 0; border-width: 0 0 2px; border-color: alpha(@theme_selected_bg_color, .7); } .csstage .passwordentry.progressbar:focused { background-color: transparent; } .csstage .passwordentry.image.left { padding: 0 15px 0 0; } .csstage .transparentbutton { -gtk-icon-style: requested; border-color: alpha(white, .2); border-image: none; box-shadow: none; background-image: none; background-color: transparent; border-radius: 20px; outline-radius: 20px; outline-color: transparent; color: alpha(white, .7); border-width: 1px; padding: 4px; } .csstage .transparentbutton image { color: alpha(white, .7); } .csstage .transparentbutton:insensitive { color: #333333; } .csstage .transparentbutton:focused { background-color: alpha(grey, .3); border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:prelight { border-color: alpha(white, .2); background-color: alpha(grey, .2); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:prelight:focused { border-color: @theme_selected_bg_color; background-color: alpha(grey, .4); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:active { border-color: @theme_selected_bg_color; background-color: alpha(grey, .6); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:active:focused { border-color: @theme_selected_bg_color; background-color: alpha(grey, .9); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .volumeslider { -GtkScale-slider-length: 4; -GtkRange-slider-width: 30; background-color: rgba(255, 255, 255, .1); color: @theme_selected_bg_color; padding: 3px 0px 3px 0px; } .csstage .volumeslider:insensitive { background-color: alpha(white, .5); } .csstage .trackname { font-family: monospace; font-size: 12px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage .albumartist { font-family: monospace; font-size: 8px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage GtkViewport { background-color: transparent; background-image: none; } cinnamon-screensaver-4.4.1/src/cinnamon-screensaver-gtk3.18.css000066400000000000000000000110551357366610100243700ustar00rootroot00000000000000.csstage { background-image: none; background-color: black; } .csstage .unlockbox { color: #eeeeee; font-size: 20px; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .clock { color: #eeeeee; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .albumart { } .csstage .albumart .framedimage { border-radius: 2px; border: 2px solid; border-color: #eeeeee; box-shadow: 1px 1px alpha(black, 0.8); } .csstage .toppanel { border-color: alpha(white, .2); border-style: solid; color: white; background-color: transparent; background-image: linear-gradient(to bottom, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)); } .csstage .audiopanel { border-width: 0 1px 1px 0; border-radius: 0 0 3px 0; background-color: rgba(255, 255, 255, .05); } .csstage .infopanel { border-width: 0 0 1px 1px; border-radius: 0 0 0 3px; background-color: rgba(255, 255, 255, .05); } .csstage .notificationwidget, .csstage .powerwidget { font-size: 12px; font-weight: bold; color: white; background-color: transparent; background-image: none; text-shadow: 1px 1px alpha(black, 0.8); padding: 6px; } .csstage .auth-message { font-size: 12px; color: red; } .csstage .caps-message { font-size: 12px; color: orange; } .csstage .framedimage { background-color: alpha(grey, .25); background-clip: border-box; box-shadow: 1px 1px alpha(black, 0.8); } .csstage .faceimage { border-radius: 4px; border: 4px solid; border-color: @theme_selected_bg_color; } .csstage .albumart { } .csstage .passwordentry { font-size: 12px; box-shadow: none; border-color: alpha(white, .2); border-style: solid; color: white; background-image: none; background-color: transparent; border-image: none; border-width: 1px; padding: 5px 10px 5px 5px; } .csstage .passwordentry:focused { background-color: transparent; background-image: none; border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } /* Use :backdrop for alt-text keyboard layout */ .csstage .passwordentry:backdrop { font-family: monospace; font-size: 16px; color: @theme_selected_bg_color; } .csstage .passwordentry.progressbar { margin: 2px; padding: 0; border-radius: 0; border-width: 0 0 2px; border-color: alpha(@theme_selected_bg_color, .7); } .csstage .passwordentry.progressbar:focused { background-color: transparent; } .csstage .passwordentry.image.left { padding: 0 15px 0 0; } .csstage .transparentbutton { -gtk-icon-style: requested; border-color: alpha(white, .2); border-image: none; box-shadow: none; background-image: none; background-color: transparent; border-radius: 20px; outline-radius: 20px; outline-color: transparent; color: alpha(white, .7); border-width: 1px; padding: 4px; } .csstage .transparentbutton image { color: alpha(white, .7); } .csstage .transparentbutton:insensitive { color: #333333; } .csstage .transparentbutton:focused { background-color: alpha(grey, .3); border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:prelight { border-color: alpha(white, .2); background-color: alpha(grey, .2); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:prelight:focused { border-color: @theme_selected_bg_color; background-color: alpha(grey, .4); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:active { border-color: @theme_selected_bg_color; background-color: alpha(grey, .6); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .transparentbutton:active:focused { border-color: @theme_selected_bg_color; background-color: alpha(grey, .9); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .volumeslider { -GtkScale-slider-length: 4; -GtkRange-slider-width: 30; background-color: rgba(255, 255, 255, .1); color: @theme_selected_bg_color; padding: 3px 0px 3px 0px; } .csstage .volumeslider:insensitive { background-color: alpha(white, .5); } .csstage .trackname { font-family: monospace; font-size: 12px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage .albumartist { font-family: monospace; font-size: 8px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage GtkViewport { background-color: transparent; background-image: none; } cinnamon-screensaver-4.4.1/src/cinnamon-screensaver-gtk3.20.css000066400000000000000000000131541357366610100243630ustar00rootroot00000000000000.csstage { } .csstage .unlockbox { color: #eeeeee; font-size: 20px; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .clock { color: #eeeeee; text-shadow: 1px 1px alpha(black, 0.8); } .csstage .toppanel { border-color: alpha(white, .2); border-style: solid; color: white; background-color: transparent; background-image: linear-gradient(to bottom, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)); } .csstage .audiopanel { border-width: 0 1px 1px 0; border-radius: 0 0 3px 0; background-color: rgba(255, 255, 255, .05); } .csstage .infopanel { border-width: 0 0 1px 1px; border-radius: 0 0 0 3px; background-color: rgba(255, 255, 255, .05); } .csstage .notificationwidget, .csstage .powerwidget { font-size: 12px; font-weight: bold; color: white; background-color: transparent; background-image: none; text-shadow: 1px 1px alpha(black, 0.8); padding: 6px; } .csstage .auth-message { font-size: 15px; color: red; } .csstage .caps-message { font-size: 15px; color: orange; } .csstage .framedimage { border-radius: 4px; border: 4px solid; background-color: alpha(grey, .25); background-clip: border-box; border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(black, 0.8); } .csstage .passwordentry { font-size: 15px; box-shadow: none; border-color: alpha(white, .2); border-style: solid; color: white; background-image: none; background-color: transparent; border-image: none; border-width: 1px; box-shadow: none; } .csstage .passwordentry progress { margin: 2px; padding: 0; border-radius: 0; border-width: 0 0 2px; border-color: alpha(@theme_selected_bg_color, .7); } .csstage .passwordentry progress:focus { background-color: transparent; } .csstage .passwordentry image.left { padding-right: 10px; } /* Use :backdrop for alt-text keyboard layout */ .csstage .passwordentry:backdrop { font-family: monospace; font-size: 14px; color: @theme_selected_bg_color; } .csstage .transparentbutton { -gtk-icon-style: requested; border-color: alpha(white, .2); border-image: none; box-shadow: none; background-image: none; background-color: transparent; border-radius: 20px; -gtk-outline-radius: 20px; outline-color: transparent; color: alpha(white, .7); border-width: 1px; padding: 4px; } .csstage .transparentbutton image { color: alpha(white, .7); } .csstage .transparentbutton:disabled image { color: #333333; } .csstage .passwordentry:focus, .csstage .transparentbutton:focus { background-color: alpha(grey, .3); border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } .csstage .passwordentry:hover, .csstage .transparentbutton:hover { border-color: alpha(white, .2); background-color: alpha(grey, .2); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .passwordentry:hover:focus, .csstage .transparentbutton:hover:focus { border-color: @theme_selected_bg_color; background-color: alpha(grey, .4); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .passwordentry:active, .csstage .transparentbutton:active { border-color: @theme_selected_bg_color; background-color: alpha(grey, .6); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .passwordentry:active:focus, .csstage .transparentbutton:active:focus { border-color: @theme_selected_bg_color; background-color: alpha(grey, .9); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .volumeslider { min-height: 24px; min-width: 100px; background-color: rgba(255, 255, 255, .1); color: @theme_selected_bg_color; padding: 3px 0px 3px 0px; } .csstage scale.volumeslider slider { min-height: 24px; min-width: 4px; margin: -9px; } .csstage .volumeslider:disabled { background-color: alpha(white, .5); } .csstage .trackname { font-family: monospace; font-size: 12px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage .albumartist { font-family: monospace; font-size: 8px; text-shadow: 1px 1px alpha(black, 0.8); background-image: none; background-color: transparent; } .csstage GtkViewport { background-color: transparent; background-image: none; } .csstage .osk-button { -gtk-icon-style: requested; border-color: alpha(white, .2); border-image: none; box-shadow: none; background-image: none; background-color: transparent; border-radius: 4px; -gtk-outline-radius: 4px; outline-color: transparent; color: alpha(white, .7); border-width: 1px; padding: 4px; } .csstage .osk-button image { color: alpha(white, .7); } .csstage .osk-button:disabled image { color: #333333; } .csstage .osk-button:focus { background-color: alpha(grey, .3); border-color: @theme_selected_bg_color; box-shadow: 1px 1px alpha(white, 0.1); } .csstage .osk-button:hover { border-color: alpha(white, .2); background-color: alpha(grey, .2); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .osk-button:hover:focus { border-color: @theme_selected_bg_color; background-color: alpha(grey, .4); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .osk-button:active { border-color: @theme_selected_bg_color; background-color: alpha(grey, .5); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .osk-button:active:focus { border-color: @theme_selected_bg_color; background-color: alpha(grey, .55); box-shadow: 1px 1px alpha(white, 0.1); } .csstage .osk-popover { background-color: black; }cinnamon-screensaver-4.4.1/src/cinnamon-screensaver-main.py000077500000000000000000000111541357366610100240600ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('Gtk', '3.0') gi.require_version('GdkX11', '3.0') gi.require_version('CScreensaver', '1.0') from gi.repository import Gtk, Gdk, CScreensaver import signal import gettext import argparse import os import setproctitle import config import status from util import utils signal.signal(signal.SIGINT, signal.SIG_DFL) gettext.install("cinnamon-screensaver", "/usr/share/locale") class Main: """ This is the main entry point to the program, and it shows up in the process list. We do any theme preparation here as well. We start the ScreensaverService from here. """ def __init__(self): parser = argparse.ArgumentParser(description='Cinnamon Screensaver') parser.add_argument('--debug', dest='debug', action='store_true', help='Print out some extra debugging info') parser.add_argument('--interactive-debug', dest='interactive', action='store_true', help='If multiple monitors are in use, only cover one monitor, and launch GtkInspector') parser.add_argument('--disable-locking', dest='lock_disabled', action='store_true', help='Disable the lock screen') parser.add_argument('--version', dest='version', action='store_true', help='Display the current version') parser.add_argument('--no-daemon', dest='no_daemon', action='store_true', help="Deprecated: left for compatibility only - we never become a daemon") args = parser.parse_args() if args.version: print("cinnamon-screensaver %s" % (config.VERSION)) quit() status.LockEnabled = not args.lock_disabled status.Debug = args.debug status.InteractiveDebug = args.interactive if status.Debug: print("Debug mode active") if args.lock_disabled: print("Locking disabled") from service import ScreensaverService # This is here mainly to allow the notification watcher to have a valid status.Debug value import singletons Gtk.Settings.get_default().connect("notify::gtk-theme-name", self.on_theme_changed) self.do_style_overrides() ScreensaverService() Gtk.main() def on_theme_changed(self, settings, pspec, data=None): self.do_style_overrides() def do_style_overrides(self): """ Here we try to check for theme support in the current system's gtk theme. We do this by retrieving a string of the current theme's final style sheet, then searching for the .csstage style class. If it's found, we return, otherwise we add our own application-priority provider as a fallback. While we have the theme string, we check for a variable name we can use for the fallback experience, and adjust it in our application stylesheet if necessary before adding it as a provider. """ theme_name = Gtk.Settings.get_default().get_property("gtk-theme-name") provider = Gtk.CssProvider.get_named(theme_name) css = provider.to_string() if ".csstage" not in css: print("Cinnamon Screensaver support not found in current theme - adding some...") if utils.have_gtk_version("3.20.0"): path = os.path.join(config.pkgdatadir, "cinnamon-screensaver-gtk3.20.css") elif utils.have_gtk_version("3.18.0"): path = os.path.join(config.pkgdatadir, "cinnamon-screensaver-gtk3.18.css") else: path = os.path.join(config.pkgdatadir, "cinnamon-screensaver-gtk3.14.css") f = open(path, 'r') fallback_css = f.read() f.close() if "@define-color theme_selected_bg_color" in css: pass elif "@define-color selected_bg_color" in css: print("replacing theme_selected_bg_color with selected_bg_color") fallback_css = fallback_css.replace("@theme_selected_bg_color", "@selected_bg_color") else: print("replacing theme_selected_bg_color with Adwaita blue") fallback_css = fallback_css.replace("@selected_bg_color", "#4a90d9") fallback_prov = Gtk.CssProvider() if fallback_prov.load_from_data(fallback_css.encode()): Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default(), fallback_prov, 600) Gtk.StyleContext.reset_widgets(Gdk.Screen.get_default()) if __name__ == "__main__": setproctitle.setproctitle('cinnamon-screensaver') main = Main() cinnamon-screensaver-4.4.1/src/clock.py000066400000000000000000000132761357366610100201150ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import CinnamonDesktop, GLib, Gtk, Gio, Pango from util import utils, trackers, settings from baseWindow import BaseWindow from floating import Floating MAX_WIDTH = 320 MAX_WIDTH_LOW_RES = 200 class ClockWidget(Floating, BaseWindow): """ ClockWidget displays the time and away message on the screen. It is a child of the Stage's GtkOverlay, and its placement is controlled by the overlay's child positioning function. When not Awake, it positions itself around all monitors using a timer which randomizes its halign and valign properties as well as its current monitor. """ def __init__(self, away_message=None, initial_monitor=0, low_res=False): super(ClockWidget, self).__init__(initial_monitor) self.get_style_context().add_class("clock") self.set_halign(Gtk.Align.START) self.set_property("margin", 6) self.clock = None self.low_res = low_res if not settings.get_show_clock(): return self.away_message = away_message box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(box) box.show() self.label = Gtk.Label() self.label.show() self.label.set_line_wrap(True) self.label.set_alignment(0.5, 0.5) box.pack_start(self.label, True, False, 6) self.msg_label = Gtk.Label() self.msg_label.show() self.msg_label.set_line_wrap(True) self.msg_label.set_alignment(0.5, 0.5) if self.low_res: self.msg_label.set_max_width_chars(50) else: self.msg_label.set_max_width_chars(80) box.pack_start(self.msg_label, True, True, 6) self.clock = CinnamonDesktop.WallClock() self.set_clock_format() trackers.con_tracker_get().connect(self.clock, "notify::clock", self.on_clock_changed) tz = Gio.File.new_for_path(path="/etc/localtime") self.tz_monitor = tz.monitor_file(0, None) trackers.con_tracker_get().connect(self.tz_monitor, "changed", self.on_tz_changed) trackers.con_tracker_get().connect(self, "destroy", self.on_destroy) self.update_clock() def set_clock_format(self): date_format = "" time_format = "" if settings.get_use_custom_format(): date_format = settings.get_custom_date_format() time_format = settings.get_custom_time_format() else: date_format = self.clock.get_default_date_format() time_format = self.clock.get_default_time_format() # %l is 12-hr hours, but it adds a space to 0-9, which looks bad here. # The '-' modifier tells the GDateTime formatter not to pad the value. time_format = time_format.replace('%l', '%-l') time_font = Pango.FontDescription.from_string(settings.get_time_font()) date_font = Pango.FontDescription.from_string(settings.get_date_font()) if self.low_res: time_size = time_font.get_size() * .66 date_size = date_font.get_size() * .66 time_font.set_size(int(time_size)) date_font.set_size(int(date_size)) time_format = ('%s\n' + \ '%s') \ % (time_font.to_string(), time_format, date_font.to_string(), date_format) self.clock.set_format_string(time_format) def on_clock_changed(self, clock, pspec): self.update_clock() def on_tz_changed(self, monitor, file, other, event): self.update_clock() def update_clock(self): default_message = GLib.markup_escape_text (settings.get_default_away_message(), -1) font_message = Pango.FontDescription.from_string(settings.get_message_font()) if self.low_res: msg_size = font_message.get_size() * .66 font_message.set_size(int(msg_size)) if self.away_message and self.away_message != "": user_name = utils.get_user_display_name() markup = ('' + '{1}' + '\n ~ {2}' + '\n ').format( font_message.to_string(), self.away_message, user_name) else: markup = '%s\n ' %\ (font_message.to_string(), default_message) self.label.set_markup(self.clock.get_clock()) self.msg_label.set_markup(markup) def set_message(self, msg=""): if not self.clock: return self.away_message = msg self.update_clock() def on_destroy(self, data=None): trackers.con_tracker_get().disconnect(self.clock, "notify::clock", self.on_clock_changed) trackers.con_tracker_get().disconnect(self.tz_monitor, "changed", self.on_tz_changed) trackers.con_tracker_get().disconnect(self, "destroy", self.on_destroy) self.clock = None self.tz_monitor = None cinnamon-screensaver-4.4.1/src/config.py.in000066400000000000000000000004211357366610100206600ustar00rootroot00000000000000# Generated file - DO NOT EDIT. Edit config.py.in instead. prefix="@prefix@" datadir="@datadir@" localedir=datadir+"/locale" pkgdatadir="@pkgdatadir@" libdir="@libdir@" libexecdir="@libexecdir@" PACKAGE="@PACKAGE@" VERSION="@VERSION@" GETTEXT_PACKAGE="@GETTEXT_PACKAGE@" cinnamon-screensaver-4.4.1/src/constants.py000066400000000000000000000012321357366610100210230ustar00rootroot00000000000000#!/usr/bin/python3 # Idle time in seconds before the unlock dialog will disappear and we go back to sleep. UNLOCK_TIMEOUT = 30 # Time in ms to wait before releasing the keyboard and mouse grabs # after an idle-activation is canceled. GRAB_RELEASE_TIMEOUT = 1 * 1000 # Used by powerWidget - the level a battery must be below before the battery icon widget in the infopanel # will show even when asleep (active but not awake.) BATTERY_CRITICAL_PERCENT = 20 # Cinnamon Screensaver SS_SERVICE = "org.cinnamon.ScreenSaver" SS_PATH = "/org/cinnamon/ScreenSaver" SS_INTERFACE = "org.cinnamon.ScreenSaver" cinnamon-screensaver-4.4.1/src/dbusdepot/000077500000000000000000000000001357366610100204305ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/dbusdepot/Makefile.am000066400000000000000000000012071357366610100224640ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = appdir = $(datadir)/cinnamon-screensaver/dbusdepot app_PYTHON = \ __init__.py \ accountsServiceClient.py \ baseClient.py \ cinnamonClient.py \ consoleKitClient.py \ keybindingHandlerClient.py \ logindClient.py \ loginInterface.py \ mediaPlayerWatcher.py \ nameBlocker.py \ screensaverClient.py \ sessionClient.py \ uPowerClient.py \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/dbusdepot/__init__.py000066400000000000000000000000001357366610100225270ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/dbusdepot/accountsServiceClient.py000066400000000000000000000026671357366610100253140ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('AccountsService', '1.0') from gi.repository import GObject, AccountsService import os from util import utils, trackers class AccountsServiceClient(GObject.Object): """ Singleton for working with the AccountsService, which we use to retrieve the user's face image and their real name. """ __gsignals__ = { 'account-loaded': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): super(AccountsServiceClient, self).__init__() self.is_loaded = False self.service = AccountsService.UserManager.get_default().get_user(utils.get_user_name()) trackers.con_tracker_get().connect(self.service, "notify::is-loaded", self.on_accounts_service_loaded) def on_accounts_service_loaded(self, service, param): self.is_loaded = True self.emit("account-loaded") def get_real_name(self): return self.service.get_real_name() def get_face_path(self): face_path = None home_path = self.service.get_home_dir() if home_path is None: home_path = os.path.expanduser('~') for path in [os.path.join(home_path, ".face"), self.service.get_icon_file()]: if os.path.exists(path): face_path = path break return face_path cinnamon-screensaver-4.4.1/src/dbusdepot/baseClient.py000066400000000000000000000057451357366610100230660ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, GLib class BaseClient(GObject.GObject): """ The base constructor for all of our generated GDBusProxies. This initializes and sets self.proxy, then fires on_client_setup_complete() or on_failure(), which the subclasses implement, depending on the outcome. These clients are technically one more level of abstraction than would be needed in a perfect world, where all dbus proxies work as they should and are supported properly by the actual providers they proxy for, but they provide a convenient and relatively clean way of implementing workarounds and alternate ways of retrieving or calculating values when the interface itself is broken in some way (this is common.) They also provide a bit of fault tolerance in cases where one or more of these providers do not exist on the bus, and we can provide sane default values for our widgets. """ def __init__(self, bustype, proxy_class, service, path): """ Asynchronously initialize the GDBusProxy - we'll call on_client_setup_complete() or on_failure() depending on this outcome. """ super(BaseClient, self).__init__() self.proxy_class = proxy_class self.path = path self.proxy = None self.watch_name_id = Gio.bus_watch_name(bustype, service, Gio.BusNameWatcherFlags.NONE, self._on_appeared, self.on_failure) def _on_appeared(self, connection, name, name_owner, data=None): try: self.proxy_class.new(connection, Gio.DBusProxyFlags.NONE, name, self.path, None, self._on_proxy_ready) except GLib.Error: self.proxy = None self.on_failure() Gio.bus_unwatch_name(self.watch_name_id) def _on_proxy_ready(self, object, result, data=None): self.proxy = self.proxy_class.new_finish(result) self.on_client_setup_complete() def ensure_proxy_alive(self): """ Use this as a safety check to see if a given proxy is valid and owned. """ return self.proxy and self.proxy.get_name_owner() != None def on_client_setup_complete(self): """ Subclasses must implement this - to complete setup after self.proxy is successfully initialized. """ print("You need to implement on_client_setup_complete(self) in your real client class") raise NotImplementedError def on_failure(self, *args): """ Can be implemented by subclasses, but not necessary. Nothing further is done anyhow if on_client_setup_complete() is never called. """ pass cinnamon-screensaver-4.4.1/src/dbusdepot/cinnamonClient.py000066400000000000000000000022401357366610100237410ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, CScreensaver from dbusdepot.baseClient import BaseClient class CinnamonClient(BaseClient): """ Simple client to talk to Cinnamon's dbus interface. Currently its only use is for attempting to force an exit from overview and expo mode (both of which do a fullscreen grab and would prevent the screensaver from acquiring one.) """ CINNAMON_SERVICE = "org.Cinnamon" CINNAMON_PATH = "/org/Cinnamon" def __init__(self): super(CinnamonClient, self).__init__(Gio.BusType.SESSION, CScreensaver.CinnamonProxy, self.CINNAMON_SERVICE, self.CINNAMON_PATH) def on_client_setup_complete(self): pass def exit_expo_and_overview(self): if self.ensure_proxy_alive(): self.proxy.set_property("overview-active", False) self.proxy.set_property("expo-active", False) def on_failure(self, *args): print("Failed to connect to Cinnamon - screensaver will not activate when expo or overview modes are active.") cinnamon-screensaver-4.4.1/src/dbusdepot/consoleKitClient.py000066400000000000000000000053551357366610100242630ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GLib, CScreensaver from dbusdepot.baseClient import BaseClient from dbusdepot.loginInterface import LoginInterface class ConsoleKitClient(LoginInterface, BaseClient): """ Client for communicating with ConsoleKit - this is a backup to logind, if it's not available. """ CK_SERVICE = "org.freedesktop.ConsoleKit" CK_MANAGER_PATH = "/org/freedesktop/ConsoleKit/Manager" def __init__(self): """ We first try to connect to the ConsoleKit manager. """ super(ConsoleKitClient, self).__init__(Gio.BusType.SYSTEM, CScreensaver.ConsoleKitManagerProxy, self.CK_SERVICE, self.CK_MANAGER_PATH) self.session_proxy = None self.session_id = None def on_client_setup_complete(self): """ If our manager connection succeeds, we ask it for the current session id and then attempt to connect to its session interface. """ self.session_id = self.proxy.call_get_current_session_sync() try: self.session_proxy = CScreensaver.ConsoleKitSessionProxy.new_for_bus(Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, self.CK_SERVICE, self.session_id, None, self.on_session_ready, None) except GLib.Error: self.session_proxy = None self.on_failure() def on_session_ready(self, object, result, data=None): """ Once we're connected to the session interface, we can respond to signals sent from it - used primarily when returning from suspend, hibernation or the login screen. """ self.session_proxy = CScreensaver.ConsoleKitSessionProxy.new_for_bus_finish(result) self.session_proxy.connect("unlock", lambda proxy: self.emit("unlock")) self.session_proxy.connect("lock", lambda proxy: self.emit("lock")) self.session_proxy.connect("active-changed", self.on_active_changed) self.emit("startup-status", True) def on_active_changed(self, proxy, active, data=None): if active: self.emit("active") def on_failure(self, *args): self.emit("startup-status", False) cinnamon-screensaver-4.4.1/src/dbusdepot/keybindingHandlerClient.py000066400000000000000000000022271357366610100255650ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, CScreensaver from dbusdepot.baseClient import BaseClient class KeybindingHandlerClient(BaseClient): """ Connects to the media key interface of cinnamon-settings-daemon. This calls the keybinding handler for shortcuts received by the Keybindings object. """ KEYBINDING_HANDLER_SERVICE = "org.cinnamon.SettingsDaemon.KeybindingHandler" KEYBINDING_HANDLER_PATH = "/org/cinnamon/SettingsDaemon/KeybindingHandler" def __init__(self): super(KeybindingHandlerClient, self).__init__(Gio.BusType.SESSION, CScreensaver.KeybindingHandlerProxy, self.KEYBINDING_HANDLER_SERVICE, self.KEYBINDING_HANDLER_PATH) def on_client_setup_complete(self): pass def handle_keybinding(self, mk_type): if self.proxy: self.proxy.call_handle_keybinding(mk_type, None, None) def on_failure(self, *args): print("Failed to connect to the keybinding handler - media key shortcuts will not work.") cinnamon-screensaver-4.4.1/src/dbusdepot/loginInterface.py000066400000000000000000000010351357366610100237320ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import GObject class LoginInterface(GObject.Object): """ A common signal interface for our Logind and ConsoleKit clients. """ __gsignals__ = { 'startup-status': (GObject.SignalFlags.RUN_LAST, None, (bool, )), 'lock': (GObject.SignalFlags.RUN_LAST, None, ()), 'unlock': (GObject.SignalFlags.RUN_LAST, None, ()), 'active': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self, *args): super(LoginInterface, self).__init__(*args) cinnamon-screensaver-4.4.1/src/dbusdepot/logindClient.py000066400000000000000000000074471357366610100234310ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GLib, CScreensaver import os from dbusdepot.baseClient import BaseClient from dbusdepot.loginInterface import LoginInterface class LogindClient(LoginInterface, BaseClient): """ A client for communicating with logind. At startup we check for its availability, falling back to ConsoleKit if it's not available. """ LOGIND_SERVICE = "org.freedesktop.login1" LOGIND_PATH = "/org/freedesktop/login1" def __init__(self): """ We first try to connect to the logind manager. """ super(LogindClient, self).__init__(Gio.BusType.SYSTEM, CScreensaver.LogindManagerProxy, self.LOGIND_SERVICE, self.LOGIND_PATH) self.pid = os.getpid() self.session_id = None self.session_proxy = None def on_client_setup_complete(self): """ If our manager connection succeeds, we ask it for the current session id and then attempt to connect to its session interface. Note: there are issues with retrieving this session id depending on how the screensaver instances was started, when running under systemd. If started from a terminal (which is running in a different scope than the current session,) we need to retrieve the session id via its environment variable. If the screensaver is started as part of the session (due to autostart conditions,) there is no issue here. """ try: self.session_id = self.proxy.call_get_session_by_pid_sync(self.pid) except GLib.Error: print("Not running under the session scope, trying XDG_SESSION_ID") id_suffix = os.getenv("XDG_SESSION_ID", "") if id_suffix != "": self.session_id = "/org/freedesktop/login1/session/%s" % (id_suffix,) print("found session: %s" % (id_suffix,)) else: print("Could not construct a valid ID for Logind session. Is XDG_SESSION_ID set?") self.session_proxy = None self.on_failure() return try: self.session_proxy = CScreensaver.LogindSessionProxy.new_for_bus(Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, self.LOGIND_SERVICE, self.session_id, None, self.on_session_ready, None) except GLib.Error: self.session_proxy = None self.on_failure() def on_session_ready(self, object, result, data=None): """ Once we're connected to the session interface, we can respond to signals sent from it - used primarily when returning from suspend, hibernation or the login screen. """ self.session_proxy = CScreensaver.LogindSessionProxy.new_for_bus_finish(result) self.session_proxy.connect("unlock", lambda proxy: self.emit("unlock")) self.session_proxy.connect("lock", lambda proxy: self.emit("lock")) self.session_proxy.connect("notify::active", self.on_active_changed) self.emit("startup-status", True) def on_active_changed(self, proxy, pspec, data=None): if self.session_proxy.get_property("active"): self.emit("active") def on_failure(self, *args): self.emit("startup-status", False) cinnamon-screensaver-4.4.1/src/dbusdepot/mediaPlayerWatcher.py000066400000000000000000000223501357366610100245560ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GLib, CScreensaver, GObject from enum import IntEnum from dbusdepot.baseClient import BaseClient from util import trackers class PlaybackStatus(IntEnum): Unknown = 0 Playing = 1 Paused = 2 Stopped = 3 class MprisClient(BaseClient): """ Represents a media player with an mpris dbus interface. There can be as many of these as there are players active in the session, but we only control the first active one in our list. These are instantiated by our MediaPlayerWatcher. """ __gsignals__ = { "status-changed": (GObject.SignalFlags.RUN_LAST, None, (int,)), "metadata-changed": (GObject.SignalFlags.RUN_LAST, None, ()) } def __init__(self, name, path): super(MprisClient, self).__init__(Gio.BusType.SESSION, CScreensaver.MediaPlayerProxy, name, path) self.metadata = None self.album_name = "" self.track_name = "" self.artist_name = "" self.albumart_url = "" def on_client_setup_complete(self): trackers.con_tracker_get().connect(self.proxy, "notify::playback-status", self.on_playback_status_changed) trackers.con_tracker_get().connect(self.proxy, "notify::metadata", self.on_metadata_changed) self.ensure_metadata() def get_playback_status(self): status = PlaybackStatus.Unknown if self.ensure_proxy_alive(): str_prop = self.proxy.get_property("playback-status") try: status = PlaybackStatus(eval("PlaybackStatus." + str_prop)) except (ValueError, TypeError, SyntaxError): pass return status def get_can_play_pause(self): if self.ensure_proxy_alive(): return self.proxy.get_property("can-play") or self.proxy.get_property("can-pause") return False def get_can_control(self): if self.ensure_proxy_alive(): return self.proxy.get_property("can-control") return False def play_pause(self): if self.ensure_proxy_alive(): self.proxy.call_play_pause() def get_can_go_next(self): if self.ensure_proxy_alive(): return self.proxy.get_property("can-go-next") return False def go_next(self): if self.ensure_proxy_alive(): self.proxy.call_next() def get_can_go_previous(self): if self.ensure_proxy_alive(): return self.proxy.get_property("can-go-previous") return False def go_previous(self): if self.ensure_proxy_alive(): self.proxy.call_previous() def get_name(self): if self.ensure_proxy_alive(): return self.proxy.get_name() return "" def get_track_name(self): self.ensure_metadata() return self.track_name def get_artist_name(self): self.ensure_metadata() return self.artist_name def get_album_name(self): self.ensure_metadata() return self.album_name def get_albumart_url(self): self.ensure_metadata() return self.albumart_url def on_failure(self, *args): pass def return_best_string(self, item): if type(item) == list: return ", ".join(item) elif type(item) == str: return item else: return "" def ensure_metadata(self): if not self.metadata: self.metadata = self.proxy.get_property("metadata") if self.metadata: try: self.track_name = self.return_best_string(self.metadata["xesam:title"]) except KeyError: self.track_name = "" try: self.album_name = self.return_best_string(self.metadata["xesam:album"]) except KeyError: self.album_name = "" try: self.artist_name = self.return_best_string(self.metadata["xesam:albumArtist"]) except KeyError: try: self.artist_name = self.return_best_string(self.metadata["xesam:artist"]) except: self.artist_name = "" try: self.albumart_url = self.return_best_string(self.metadata["mpris:artUrl"]) except KeyError: self.albumart_url = "" def on_playback_status_changed(self, proxy, pspec, data=None): self.emit("status-changed", self.get_playback_status()) def on_metadata_changed(self, proxy, pspec, data=None): self.metadata = None self.ensure_metadata() self.emit("metadata-changed") class MediaPlayerWatcher(GObject.Object): """ Media player interfaces are different from our other interfaces. There is no common owned name, players export their own unique interface, within the org.mpris.MediaPlayer2.* namespace. This allows multiple players to exist on the bus at one time. It requires us to list all interfaces and filter out all but the ones in that namespace. We then create separate Player clients for each one. """ MPRIS_PATH = "/org/mpris/MediaPlayer2" def __init__(self): """ Connect to the bus and retrieve a list of interfaces. """ super(MediaPlayerWatcher, self).__init__() self.player_clients = [] try: self.dbus_proxy = Gio.DBusProxy.new_for_bus_sync(Gio.BusType.SESSION, Gio.DBusProxyFlags.NONE, None, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", None) trackers.con_tracker_get().connect(self.dbus_proxy, "g-signal", self.on_dbus_proxy_signal) self.find_initial_players() except GLib.Error: self.dbus_proxy = None print("Cannot acquire session org.freedesktop.DBus client to watch for media players") def on_dbus_proxy_signal(self, proxy, sender, signal, parameters, data=None): """ NameOwnerChanged is called both when a name appears on the bus, as well as when it disappears. The filled parameters tell us whether we've gained or lost the player. """ if signal == "NameOwnerChanged": if parameters[2] != "": self.on_name_acquired(parameters[0]) else: self.on_name_lost(parameters[0]) def find_initial_players(self): self.dbus_proxy.call("ListNames", None, Gio.DBusCallFlags.NONE, -1, None, self.on_names_listed) def on_names_listed(self, bus, result, data=None): names = bus.call_finish(result)[0] for name in names: self.on_name_acquired(name) def on_name_acquired(self, name): """ Create an mpris client for any discovered interfaces. """ if name.startswith("org.mpris.MediaPlayer2."): self.player_clients.append(MprisClient(name, self.MPRIS_PATH)) def on_name_lost(self, name): """ Remove any clients that disappear off the bus. """ item = None for client in self.player_clients: if client.get_name() == name: item = client break if item: self.player_clients.remove(item) def get_best_player(self): """ Find the first player in our list that is either playing, or *can* be played. Players that are simply loaded but don't have any playlist queued up should not pass these tests - we have only limited control from the lockscreen. """ for client in self.player_clients: if client.get_playback_status() == PlaybackStatus.Playing: return client if client.get_can_play_pause() and client.get_can_control(): return client return None def get_all_player_names(self): """ Return a list of all player simple names - this is used by our notification code to ignore notifications sent from media players, which are usually unimportant, but not marked as transient (which would normally cause them to be ignored in the CsNotificationWatcher.) """ ret = [] for client in self.player_clients: fullname = client.get_name() split = fullname.split(".") ret.append(split[len(split) - 1].lower()) return ret cinnamon-screensaver-4.4.1/src/dbusdepot/nameBlocker.py000066400000000000000000000036411357366610100232300ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, GLib import status class NameBlocker(GObject.GObject): """ Terminates other screensavers. Ideally we'd just take ownership of their dbus names, but due to how DE detection works in xdg-screensaver, that script incorrectly assumes we're a gnome or mate session if their names are owned. """ def __init__(self): super(NameBlocker, self).__init__() self.owned_names = [] self.watch("org.gnome.ScreenSaver") self.watch("org.mate.ScreenSaver") def watch(self, name): handle = Gio.bus_watch_name(Gio.BusType.SESSION, name, Gio.BusNameWatcherFlags.NONE, self.on_name_appeared, self.on_name_lost) self.owned_names.append((handle, "name")) def unwatch_all(self): for (handle, name) in self.owned_names: if status.Debug: print("Releasing dbus name: %s" % name) Gio.bus_unown_name(handle) self.owned_names = [] def on_name_appeared(self, connection, name, name_owner, data=None): if status.Debug: print("%s appeared on the session bus, killing it" % name) connection.call(name_owner, "/" + name.replace(".", "/"), name, "Quit", None, None, Gio.DBusCallFlags.NONE, -1, None) def on_name_lost(self, connection, name, data=None): if status.Debug: print("%s is gone from the session bus" % name) def do_dispose(self): if status.Debug: print("nameBlocker do_dispose") self.unwatch_all() super(NameBlocker, self).do_dispose() cinnamon-screensaver-4.4.1/src/dbusdepot/screensaverClient.py000066400000000000000000000016251357366610100244650ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, CScreensaver from dbusdepot.baseClient import BaseClient import constants as c class ScreenSaverClient(BaseClient): """ This is the paired proxy paired to our ScreensaverService interface. It is only used by cinnamon-screensaver-command to communicate with the screensaver process. """ __gsignals__ = { 'client-ready': (GObject.SignalFlags.RUN_LAST, None, (bool,)), } def __init__(self): super(ScreenSaverClient, self).__init__(Gio.BusType.SESSION, CScreensaver.ScreenSaverProxy, c.SS_SERVICE, c.SS_PATH) def on_client_setup_complete(self): self.emit("client-ready", True) def on_failure(self, *args): self.emit("client-ready", False) cinnamon-screensaver-4.4.1/src/dbusdepot/sessionClient.py000066400000000000000000000024551357366610100236320ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, CScreensaver from dbusdepot.baseClient import BaseClient class SessionClient(BaseClient): """ This client is for connecting to the session manager's Presence interface - it is responsible for triggering activation of the screensaver when the session goes into an idle state. """ __gsignals__ = { 'idle-changed': (GObject.SignalFlags.RUN_LAST, None, (bool, )), } GSM_SERVICE = "org.gnome.SessionManager" GSM_PRESENCE_PATH = "/org/gnome/SessionManager/Presence" def __init__(self): super(SessionClient, self).__init__(Gio.BusType.SESSION, CScreensaver.SessionPresenceProxy, self.GSM_SERVICE, self.GSM_PRESENCE_PATH) self.idle = False def on_client_setup_complete(self): self.proxy.connect("status-changed", self.on_status_changed) def on_status_changed(self, proxy, status): new_idle = status == 3 if new_idle != self.idle: self.idle = new_idle self.emit("idle-changed", self.idle) def on_failure(self, *args): print("Failed to connect to session manager - idle detection will not work.") cinnamon-screensaver-4.4.1/src/dbusdepot/uPowerClient.py000066400000000000000000000141051357366610100234230ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, CScreensaver, GLib from enum import IntEnum from dbusdepot.baseClient import BaseClient class DeviceType(IntEnum): Unknown = 0 LinePower = 1 Battery = 2 Ups = 3 Monitor = 4 Mouse = 5 Keyboard = 6 Pda = 7 Phone = 8 class DeviceState(IntEnum): Unknown = 0 Charging = 1 Discharging = 2 Empty = 3 FullyCharged = 4 PendingCharge = 5 PendingDischarge = 6 class UPowerClient(BaseClient): """ This client communicates with the upower provider, tracking the power state of the system (laptops - are we on battery or plugged in?) """ __gsignals__ = { 'power-state-changed': (GObject.SignalFlags.RUN_LAST, None, ()), 'percentage-changed': (GObject.SignalFlags.RUN_LAST, None, (GObject.Object,)) } UPOWER_SERVICE = "org.freedesktop.UPower" UPOWER_PATH = "/org/freedesktop/UPower" def __init__(self): super(UPowerClient, self).__init__(Gio.BusType.SYSTEM, CScreensaver.UPowerProxy, self.UPOWER_SERVICE, self.UPOWER_PATH) self.have_battery = False self.plugged_in = False self.update_state_id = 0 self.devices_dirty = True self.relevant_devices = [] def on_client_setup_complete(self): self.proxy.connect("device-removed", self.on_device_added_or_removed) self.proxy.connect("device-added", self.on_device_added_or_removed) self.proxy.connect("notify::on-battery", self.on_battery_changed) self.queue_update_state() def on_device_added_or_removed(self, proxy, path): self.devices_dirty = True self.queue_update_state() def on_battery_changed(self, proxy, pspec, data=None): self.queue_update_state() def queue_update_state(self): if self.update_state_id > 0: GObject.source_remove(self.update_state_id) self.update_state_id = 0 GObject.idle_add(self.idle_update_cb) def idle_update_cb(self, data=None): if self.devices_dirty: self.rescan_devices() self.devices_dirty = False if self.update_state(): self.emit_changed() def rescan_devices(self): if len(self.relevant_devices) > 0: for path, dev in self.relevant_devices: dev.disconnect(dev.prop_changed_id) del dev del path self.relevant_devices = [] try: # The return type for this call has to be overridden in gdbus-codegen # (See the Makefile.am) - or else we get utf-8 errors (python3 issue?) for path in self.proxy.call_enumerate_devices_sync(): try: dev = CScreensaver.UPowerDeviceProxy.new_for_bus_sync(Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, self.UPOWER_SERVICE, path, None) if dev.get_property("type") in (DeviceType.Battery, DeviceType.LinePower): self.relevant_devices.append((path, dev)) dev.prop_changed_id = dev.connect("notify", self.on_device_properties_changed) except GLib.Error: print("UPowerClient had trouble connecting with device:", path, " - skipping it") except GLib.Error: print("UPowerClient had trouble enumerating through devices. The battery indicator will be disabled") self.queue_update_state() def update_state(self): changes = False old_plugged_in = self.plugged_in old_have_battery = self.have_battery # UPower doesn't necessarily have a LinePower device if there are no batteries. # Default to plugged in, then. new_plugged_in = True new_have_battery = False for path, dev in self.relevant_devices: if dev.get_property("type") == DeviceType.LinePower: new_plugged_in = dev.get_property("online") if dev.get_property("type") == DeviceType.Battery: new_have_battery = True if (new_plugged_in != old_plugged_in) or (new_have_battery != old_have_battery): changes = True self.have_battery = new_have_battery self.plugged_in = new_plugged_in return changes def on_device_properties_changed(self, proxy, pspec, data=None): if pspec.name in ("online", "icon-name", "state"): self.queue_update_state() if pspec.name == "percentage": self.emit_percentage_changed(proxy) def emit_changed(self): self.emit("power-state-changed") def emit_percentage_changed(self, battery): self.emit("percentage-changed", battery) def get_batteries(self): if len(self.relevant_devices) == 0: return [] ret = [] for path, dev in self.relevant_devices: if dev.get_property("type") == DeviceType.Battery: ret.append((path, dev)) return ret def full_and_on_ac_or_no_batteries(self): """ This figures out whether the power widget should be shown or not - currently we only show the widget if we have batteries and are not plugged in. """ batteries = self.get_batteries() if batteries == []: return True all_batteries_full = True for path, dev in batteries: if dev.get_property("state") not in (DeviceState.FullyCharged, DeviceState.Unknown): all_batteries_full = False break return self.plugged_in and all_batteries_full def on_failure(self, *args): print("Failed to establish a connection with UPower - the battery indicator will be disabled.") cinnamon-screensaver-4.4.1/src/floating.py000066400000000000000000000035261357366610100206220ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk import random import status from util import trackers from util import settings POSITIONING_TIMEOUT = 30 ALIGNMENTS = [int(Gtk.Align.START), int(Gtk.Align.END), int(Gtk.Align.CENTER)] class Floating: def __init__(self, initial_monitor=0): super(Floating, self).__init__() self.set_halign(Gtk.Align.CENTER) self.set_valign(Gtk.Align.CENTER) self.current_monitor = initial_monitor def start_positioning(self): self.show() if settings.get_allow_floating(): trackers.timer_tracker_get().cancel(str(self) + "positioning") trackers.timer_tracker_get().start_seconds(str(self) + "positioning", POSITIONING_TIMEOUT, self.positioning_callback) def stop_positioning(self): if settings.get_allow_floating(): trackers.timer_tracker_get().cancel(str(self) + "positioning") def positioning_callback(self): current_halign = int(self.get_halign()) horizontal = current_halign current_valign = int(self.get_valign()) vertical = current_valign while horizontal == current_halign: horizontal = ALIGNMENTS[random.randint(0, 2)] while vertical == current_valign: vertical = ALIGNMENTS[random.randint(0, 2)] self.set_halign(Gtk.Align(horizontal)) self.set_valign(Gtk.Align(vertical)) if status.screen.get_n_monitors() > 1: new_monitor = self.current_monitor n = status.screen.get_n_monitors() while new_monitor == self.current_monitor: new_monitor = random.randint(0, n - 1) self.current_monitor = new_monitor self.queue_resize() return True cinnamon-screensaver-4.4.1/src/infoPanel.py000066400000000000000000000060621357366610100207300ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk import status from util import utils, trackers, settings from baseWindow import BaseWindow from widgets.notificationWidget import NotificationWidget from widgets.powerWidget import PowerWidget class InfoPanel(BaseWindow): """ Upper right corner panel - contains the notification counter and any battery indicator(s) - this panel will generally show if it has anything relevant to say, regardless of our Awake state. """ def __init__(self): super(InfoPanel, self).__init__() self.monitor_index = status.screen.get_primary_monitor() self.update_geometry() if not settings.get_show_info_panel(): self.disabled = True return self.show_power = False self.show_notifications = False self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.box.set_halign(Gtk.Align.FILL) self.box.get_style_context().add_class("toppanel") self.box.get_style_context().add_class("infopanel") self.add(self.box) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.box.pack_start(hbox, False, False, 6) self.notification_widget = NotificationWidget() self.notification_widget.set_no_show_all(True) hbox.pack_start(self.notification_widget, True, True, 2) self.notification_widget.connect("notification", self.on_notification_received) self.power_widget = PowerWidget() self.power_widget.set_no_show_all(True) self.power_widget.connect("power-state-changed",self.on_power_state_changed) hbox.pack_start(self.power_widget, True, True, 2) self.show_all() def refresh_power_state(self): if self.disabled: return self.power_widget.refresh() def on_notification_received(self, obj): self.update_visibility() def on_power_state_changed(self, obj): self.update_visibility() def update_visibility(self): """ Determines whether or not to show the panel, depending on: - Whether the power widget should show (are we on battery?) - Whether the notification widget should show (are there any?) The panel will show if either of its child indicators has useful info. """ if self.disabled: return do_show = False battery_critical = False self.show_power = self.power_widget.should_show() if self.show_power: battery_critical = self.power_widget.battery_critical self.show_notifications = self.notification_widget.should_show() # Determine if we want to show all the time or only when status.Awake if status.Awake: if self.show_power or self.show_notifications: do_show = True elif self.show_notifications or battery_critical: do_show = True self.set_visible(do_show) self.power_widget.set_visible(self.show_power) self.notification_widget.set_visible(self.show_notifications) cinnamon-screensaver-4.4.1/src/manager.py000066400000000000000000000267541357366610100204410ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gdk, GObject import time import traceback import constants as c import status from stage import Stage import singletons from util import utils, settings, trackers from util.focusNavigator import FocusNavigator from util.grabHelper import GrabHelper class ScreensaverManager(GObject.Object): """ The ScreensaverManager is the central point where most major decision are made, and where ScreensaverService requests are acted upon. """ __gsignals__ = { 'active-changed': (GObject.SignalFlags.RUN_LAST, None, (bool, )), } def __init__(self): super(ScreensaverManager, self).__init__() self.activated_timestamp = 0 self.stage = None # Ensure our state status.Active = False status.Locked = False status.Awake = False self.grab_helper = GrabHelper(self) self.focus_nav = FocusNavigator() self.session_client = singletons.SessionClient trackers.con_tracker_get().connect(self.session_client, "idle-changed", self.on_session_idle_changed) self.cinnamon_client = singletons.CinnamonClient singletons.LoginClientResolver(self) def is_locked(self): """ Return if we're Locked - we could be Active without being locked. """ return status.Locked def lock(self, msg=""): """ Initiate locking (activating first if necessary.) Return True if we were already active and just need to set the lock flag (or we were already locked as well). Return False if we're not active, and need to construct a stage, etc... """ if not status.Active: if self.set_active(True, msg): self.stop_lock_delay() if utils.user_can_lock(): status.Locked = True return False else: if utils.user_can_lock(): status.Locked = True self.stage.set_message(msg) # Return True to complete any invocation immediately because: # - we were already active and possibly already locked # - we were unable to achieve a server grab, or something else # prevents the activation from proceeding, and we don't want to # block anything...?? return True def unlock(self): """ Initiate unlocking and deactivating """ self.set_active(False) status.Locked = False status.Awake = False def set_active(self, active, msg=None): """ Activates or deactivates the screensaver. Activation involves: - sending a request to Cinnamon to exit Overview or Expo - this could prevent a successful screen grab and keep the screensaver from activating. - grabbing the keyboard and mouse. - creating the screensaver Stage. Deactivation involves: - destroying the screensaver stage. - releasing our keyboard and mouse grabs. """ if active: if not status.Active: self.cinnamon_client.exit_expo_and_overview() if self.grab_helper.grab_root(False): if not self.stage: self.spawn_stage(msg, self.on_spawn_stage_complete) else: self.stage.activate(self.on_spawn_stage_complete) self.stage.set_message(msg) return True else: status.Active = False return False else: self.stage.set_message(msg) return True else: if self.stage: self.despawn_stage(self.on_despawn_stage_complete) status.focusWidgets = [] self.grab_helper.release() return True return False def get_active(self): """ Return whether we're Active or not (showing) - this is not necessarily Locked. """ return status.Active def get_active_time(self): """ Return how long we've been activated, or 0 if we're not """ if self.activated_timestamp != 0: return int(time.time() - self.activated_timestamp) else: return 0 def simulate_user_activity(self): """ Called upon any key, motion or button event, does different things depending on our current state. If we're idle: - do nothing If we're locked: - show the unlock widget (if it's already visible, this also has the effect of resetting the unlock timeout - see Stage.py) - show the mouse pointer, so the user can navigate the unlock screen. If we're Active but not Locked, simply deactivate (destroying the Stage and returning the screensaver back to idle mode.) """ if not status.Active: return if status.Debug and not status.Awake: print("manager: user activity, waking") if status.Locked and self.stage.initialize_pam(): if status.Debug and not status.Awake: print("manager: locked, raising unlock widget") self.stage.raise_unlock_widget() self.grab_helper.release_mouse() self.stage.maybe_update_layout() else: if status.Debug: print("manager: not locked, queueing idle deactivation") trackers.timer_tracker_get().add_idle("idle-deactivate", self.idle_deactivate) def idle_deactivate(self): self.set_active(False) trackers.timer_tracker_get().cancel("idle-deactivate") return False def spawn_stage(self, away_message, callback=None): """ Create the Stage and begin fading it in. This may run quickly, in the case of user-initiated activation, or slowly, when the session has gone idle. """ try: self.stage = Stage(self, away_message) self.stage.activate(callback) except Exception: print("Could not spawn screensaver stage:\n") traceback.print_exc() self.grab_helper.release() status.Active = False self.cancel_timers() def despawn_stage(self, callback=None): """ Begin destruction of the stage. """ self.stage.cancel_unlocking() self.stage.deactivate(callback) def on_spawn_stage_complete(self): """ Called after the stage become visible. All user events are now redirected to GrabHelper, our status is updated, our active timer is started, and emit an active-changed signal (Which is listened to by our ConsoleKit client if we're using it, and our own ScreensaverService.) """ self.grab_stage() status.Active = True self.emit("active-changed", True) self.start_timers() def on_despawn_stage_complete(self): """ Called after the stage has been hidden - the stage is destroyed, our status is updated, timer is canceled and active-changed is fired. """ was_active = status.Active == True status.Active = False if was_active: self.emit("active-changed", False) self.cancel_timers() self.stage.destroy_stage() self.stage = None # Ideal time to check for leaking connections that might prevent GC by python and gobject if trackers.DEBUG_SIGNALS: trackers.con_tracker_get().dump_connections_list() if trackers.DEBUG_TIMERS: trackers.timer_tracker_get().dump_timer_list() def grab_stage(self): """ Makes a hard grab on the Stage window, all keyboard and mouse events are dispatched or eaten by us now. """ if self.stage != None: self.grab_helper.move_to_window(self.stage.get_window(), True) def update_stage(self): """ Tells the stage to check its canvas size and make sure its windows are up-to-date. This is called when our login manager tells us its "Active" property has changed. We are always connected to the login manager, so we first check if we have a stage. """ if self.stage == None: return if status.Debug: print("manager: queuing stage refresh (login manager reported active?") self.stage.queue_refresh_stage() def start_timers(self): """ Stamps our current time starts our lock delay timer (the elapsed time to allow after activation, to lock the computer.) """ self.activated_timestamp = time.time() self.start_lock_delay() def cancel_timers(self): """ Zeros out our activated timestamp and cancels our lock delay timer. """ self.activated_timestamp = 0 self.stop_lock_delay() def cancel_unlock_widget(self): """ Return to sleep (not Awake) - hides the pointer and the unlock widget. """ self.grab_stage() self.stage.cancel_unlocking(); def on_lock_delay_timeout(self): """ Updates the lock status when our timer has hit its limit """ if status.Debug: print("manager: locking after delay ('lock-delay')") status.Locked = True return False def start_lock_delay(self): """ Setup the lock delay timer based on user prefs - if there is no delay, or if idle locking isn't enabled, we run the callback immediately, or simply return, respectively. """ if not settings.get_idle_lock_enabled(): return if not utils.user_can_lock(): return lock_delay = settings.get_idle_lock_delay() if lock_delay == 0: self.on_lock_delay_timeout() else: trackers.timer_tracker_get().start_seconds("idle-lock-delay", lock_delay, self.on_lock_delay_timeout) def stop_lock_delay(self): """ Cancels the lock delay timer. """ trackers.timer_tracker_get().cancel("idle-lock-delay") ##### EventHandler/GrabHelper/FocusNavigator calls. def queue_dialog_key_event(self, event): """ Forwards a captured key event to the stage->unlock dialog. """ self.stage.queue_dialog_key_event(event) def propagate_tab_event(self, shifted): """ Forwards a tab event to the focus navigator. """ self.focus_nav.navigate(shifted) def propagate_activation(self): """ Forwards an activation event (return) to the focus navigator. """ self.focus_nav.activate_focus() def get_focused_widget(self): """ Returns the currently focused widget from the FocusNavigator """ return self.focus_nav.get_focused_widget() def on_session_idle_changed(self, proxy, idle): """ Call back for the session client - initiates a slow fade-in for the stage when the session goes idle. Cancels the stage fade-in if idle becomes False before it has completed its animation. """ if idle and not status.Active: self.set_active(True) cinnamon-screensaver-4.4.1/src/monitorView.py000066400000000000000000000063701357366610100213410ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, Gio, GLib, GObject import re import cairo import signal import status from baseWindow import BaseWindow from util import settings, utils, trackers class WallpaperStack(Gtk.Stack): """ WallpaperStack implements a crossfade when changing backgrounds. An initial image is made and added to the GtkStack. When a new image is requested, it is created and added to the stack, then a crossfade transition is made to the new child. The former visible stack child is then destroyed. And this repeats. """ def __init__(self): super(WallpaperStack, self).__init__() self.set_transition_type(Gtk.StackTransitionType.NONE) self.set_transition_duration(1000) self.initialized = False self.current = None self.queued = None def transition_to_image(self, image): """ Queues a new image in the stack, and begins the transition to it. """ self.queued = image self.queued.set_visible(True) trackers.con_tracker_get().connect_after(image, "draw", self.shade_wallpaper) self.add(self.queued) if not self.initialized: self.visible_image_changed() self.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self.initialized = True return self.set_visible_child(self.queued) GObject.timeout_add(2000, self.visible_image_changed) def visible_image_changed(self, data=None): if self.current != None: tmp = self.current self.remove(tmp) tmp.destroy() self.current = self.queued self.queued = None return False def shade_wallpaper(self, widget, cr): """ This draw callback adds a shade mask over the current image. It is uniform when not Awake, and acquires a significant gradient vertically framing the unlock dialog when Awake. """ if not status.Awake: cr.set_source_rgba(0.0, 0.0, 0.0, 0.7) cr.paint() return False r = widget.get_allocation() pattern = cairo.LinearGradient(0, 0, 0, r.height) pattern.add_color_stop_rgba (0, 0, 0, 0, .75); pattern.add_color_stop_rgba (.35, 0, 0, 0, .9); pattern.add_color_stop_rgba (.65, 0, 0, 0, .9); pattern.add_color_stop_rgba (1, 0, 0, 0, .75); cr.set_source(pattern) cr.paint() return False class MonitorView(BaseWindow): """ A monitor-sized child of the stage that is responsible for displaying the currently-selected wallpaper or appropriate plug-in. """ def __init__(self, index): super(MonitorView, self).__init__() self.monitor_index = index self.update_geometry() self.wallpaper_stack = WallpaperStack() self.wallpaper_stack.show() self.wallpaper_stack.set_halign(Gtk.Align.FILL) self.wallpaper_stack.set_valign(Gtk.Align.FILL) self.add(self.wallpaper_stack) self.show_all() def set_next_wallpaper_image(self, image): self.wallpaper_stack.transition_to_image(image) cinnamon-screensaver-4.4.1/src/osk.py000066400000000000000000000221701357366610100176070ustar00rootroot00000000000000#!/usr/bin/python3 # coding: utf-8 import gi gi.require_version('Caribou', '1.0') from gi.repository import Gtk, Gdk, GObject, Caribou, Gio, GLib import status from util import utils, trackers, settings from widgets.transparentButton import TransparentButton from baseWindow import BaseWindow LARGEST_OSK_WIDTH = 1200 LARGEST_OSK_HEIGHT = 360 DEFAULT_PADDING = 2 class ExtendedKey(Gtk.Button): def __init__(self, label, xkey): super(ExtendedKey, self).__init__(label) self.get_style_context().add_class("osk-button") self._key = xkey self.connect("button-press-event", lambda widget, event: self._key.press()) self.connect("button-release-event", lambda widget, event: self._key.release()) def update_sizes(self, width, height): real_width = width * self._key.props.width self.set_size_request(real_width, height) class Key(Gtk.Button): def __init__(self, key): super(Key, self).__init__() self.get_style_context().add_class("osk-button") self._key = key self.checked = False self._extended_keys = key.get_extended_keys() self._extended_keyboard = None self._grabbed = False self._eventCaptureId = 0 self.set_label(self._key.props.label) self._popup = None self._popover_box = None if self._extended_keys: self._key.connect("notify::show-subkeys", self._on_show_subkeys_changed) self._popup = Gtk.Popover(relative_to=self) self._popup.get_style_context().add_class("osk-popover") self.get_extended_keys() self.connect("button-press-event", self.button_press_event) self.connect("button-release-event", self.button_release_event) if self._key.props.name in ("Control_L", "Alt_L"): self.model_press_handler = self._key.connect("key-pressed", self._model_key_pressed) self.model_release_handler = self._key.connect("key-released", self._model_key_released) def update_sizes(self, width, height): # The virtual key width is a multiplier based on the default key width. # Keys such as the spacebar use this to become proportionally wider than # other keys. real_width = width * self._key.props.width self.set_size_request(real_width, height) if self._popover_box: for child in self._popover_box.get_children(): child.update_sizes(width, height) def _model_key_pressed(self, key, data=None): print("pressed model") def _model_key_released(self, key, data=None): print("released model") def button_press_event(self, widget, event, data=None): # Pressing buttons quickly can be recognized as a double- or triple-click, ignore # when that happens. Extended keys should only appear on a click-hold. if event.type in (Gdk.EventType._2BUTTON_PRESS, Gdk.EventType._3BUTTON_PRESS): return Gdk.EVENT_PROPAGATE self._key.press() return Gdk.EVENT_PROPAGATE def button_release_event(self, widget, event, data=None): self._key.release() return Gdk.EVENT_PROPAGATE def get_uni_char(self, key): keyval = key.props.keyval unichar = Gdk.keyval_to_unicode(keyval) if unichar: return chr(unichar) else: return key.props.name def get_extended_keys(self): self._popover_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, margin=6) for xkey in self._extended_keys: label = self.get_uni_char(xkey) key = ExtendedKey(label, xkey) self._popover_box.pack_start(key, False, False, 2) self._popover_box.show_all() self._popup.add(self._popover_box) def _on_show_subkeys_changed(self, key, pspec, data=None): if self._key.props.show_subkeys: self._popup.popup() else: self._popup.popdown() class OnScreenKeyboard(BaseWindow): """ An on-screen keyboard that can be used to input the password in the lockscreen. If accessibility doesn't have the osk enabled, we don't construct the keyboard initially, to save footprint. If needed, the keyboard button can be pressed to display the keyboard on demand, and it gets constructed then. """ def __init__(self): super(OnScreenKeyboard, self).__init__() self.set_halign(Gtk.Align.CENTER) self.set_valign(Gtk.Align.END) self.props.margin = 30 smallest_width, smallest_height = status.screen.get_smallest_monitor_sizes() self.max_width = min(smallest_width, LARGEST_OSK_WIDTH) - 60 self.max_height = min(smallest_height / 3, LARGEST_OSK_HEIGHT) - 60 # print(self.max_width, self.max_height) self._group_stack = None self.base_stack = Gtk.Stack() self.add(self.base_stack) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, halign=Gtk.Align.CENTER, valign=Gtk.Align.END) activate_button = TransparentButton("input-keyboard-symbolic", Gtk.IconSize.LARGE_TOOLBAR) activate_button.connect("clicked", self.on_activate_button_clicked) box.pack_start(activate_button, False, False, 0) box.show_all() self.base_stack.add_named(box, "disabled") self.base_stack.show_all() if settings.get_osk_a11y_active(): self.build_and_show_keyboard() def on_activate_button_clicked(self, button, data=None): self.build_and_show_keyboard() def on_caribou_button_clicked(self, button, data=None): self.base_stack.set_visible_child_name("disabled") def build_and_show_keyboard(self): if not self._group_stack: self._keyboard = Caribou.KeyboardModel(keyboard_type=settings.get_osk_type()) self._group_stack = Gtk.Stack(visible=True) self._groups = {} self._add_keys() self._group_stack.show_all() self.base_stack.add_named(self._group_stack, "enabled") self.base_stack.set_visible_child_name("enabled") def _add_keys(self): groups = self._keyboard.get_groups() size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) for group_name in groups: group = self._keyboard.get_group(group_name) group.connect("notify::active-level", self._on_level_changed) layers = {} levels = group.get_levels() for level_name in levels: level = group.get_level(level_name) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) size_group.add_widget(box) self._load_rows(level, box) layers[level_name] = box box.show_all() self._group_stack.add_named(box, "%s::%s" % (group_name, level_name)) self._groups[group_name] = layers self.set_active_layer() def _on_level_changed(self, object, pspec, data=None): self.set_active_layer() def _load_rows(self, level, box): rows = level.get_rows() row_height = self.max_height / len(rows) for row in rows: self._add_rows(row.get_columns(), box, row_height) def _add_rows(self, keys, box, row_height): num_keys = 0 row_children = [] row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) for key in keys: right_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) left_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) children = key.get_children() right_box_members = [] for child in children: button = Key(child) num_keys += child.props.width row_children.append(button) if child.props.align == "right": right_box_members.append(button) else: left_box.pack_start(button, False, False, DEFAULT_PADDING) if right_box_members: right_box_members.reverse() for member in right_box_members: right_box.pack_end(member, False, False, DEFAULT_PADDING) if child.props.name == "Caribou_Prefs": button.connect("clicked", self.on_caribou_button_clicked) if left_box.get_children(): row.pack_start(left_box, True, True, 0) if right_box.get_children(): row.pack_end(right_box, True, True, 0) key_width = (self.max_width / (num_keys )) - (DEFAULT_PADDING * 2) key_height = row_height - (DEFAULT_PADDING * 2) for child in row_children: child.update_sizes(key_width, key_height) box.pack_start(row, False, False, DEFAULT_PADDING) def set_active_layer(self): active_group_name = self._keyboard.props.active_group active_group = self._keyboard.get_group(active_group_name) active_level = active_group.props.active_level layers = self._groups[active_group_name] self._group_stack.set_visible_child_name("%s::%s" % (active_group_name, active_level)) cinnamon-screensaver-4.4.1/src/pamhelper/000077500000000000000000000000001357366610100204145ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/pamhelper/Makefile.am000066400000000000000000000015031357366610100224470ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = pamhelperdatadir = $(datadir)/cinnamon-screensaver/pamhelper pamhelperdir = $(libexecdir)/pamhelper pamhelperdata_PYTHON = \ authClient.py \ $(NULL) libexec_PROGRAMS = \ cinnamon-screensaver-pam-helper \ $(NULL) cinnamon_screensaver_pam_helper_SOURCES = \ cinnamon-screensaver-pam-helper.c \ $(NULL) cinnamon_screensaver_pam_helper_LDADD = \ $(SCREENSAVER_PAM_LIBS) \ $(top_builddir)/libcscreensaver/libcscreensaver.la \ $(NULL) cinnamon_screensaver_pam_helper_CPPFLAGS = \ $(WARN_CFLAGS) \ $(SCREENSAVER_PAM_CFLAGS) \ -I$(top_builddir)/libcscreensaver \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/pamhelper/authClient.py000066400000000000000000000163401357366610100230720ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio, GObject, GLib, CScreensaver import config import re import os import signal import platform import status import sys class AuthClient(GObject.Object): """ The AuthClient manages spawning of our pam helper process, and communication with it. """ __gsignals__ = { 'auth-success': (GObject.SignalFlags.RUN_LAST, None, ()), 'auth-failure': (GObject.SignalFlags.RUN_LAST, None, ()), 'auth-cancel': (GObject.SignalFlags.RUN_LAST, None, ()), 'auth-busy': (GObject.SignalFlags.RUN_LAST, None, (bool,)), 'auth-prompt': (GObject.SignalFlags.RUN_LAST, None, (str,)) } def __init__(self): super(AuthClient, self).__init__() self.initialized = False self.proc = None self.out_pipe = None self.in_pipe = None def initialize(self): if self.initialized: return True if status.Debug: print("authClient: attempting to initialize") try: helper_path = None architecture = platform.machine() paths = [config.libexecdir, "/usr/lib", "/usr/lib/cinnamon-screensaver", "/usr/libexec", "/usr/libexec/cinnamon-screensaver"] # On x86 archs, iterate through multiple paths # For instance, on a Mint i686 box, the path is actually /usr/lib/i386-linux-gnu x86archs = ["i386", "i486", "i586", "i686"] if architecture in x86archs: for arch in x86archs: paths += ["/usr/lib/%s" % arch, "/usr/lib/%s-linux-gnu" % arch] elif architecture == "x86_64": paths += ["/usr/lib/x86_64", "/usr/lib/x86_64-linux-gnu", "/usr/lib64"] else: paths += ["/usr/lib/%s" % architecture, "/usr/lib/%s-linux-gnu" % architecture] for path in paths: full_path = os.path.join(path, "cinnamon-screensaver-pam-helper") if os.path.exists(full_path): helper_path = full_path break if helper_path is None: print ("authClient: critical Error: PAM Helper could not be found!") if status.Debug: argv = (helper_path, "--debug", None) self.proc = Gio.Subprocess.new(argv, Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE) else: argv = (helper_path, None) self.proc = Gio.Subprocess.new(argv, Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_SILENCE) except GLib.Error as e: print("authClient: error starting cinnamon-screensaver-pam-helper: %s" % e.message) return False self.proc.wait_check_async(None, self.on_proc_completed, None) self.out_pipe = self.proc.get_stdout_pipe() self.out_pipe.read_bytes_async(1024, GLib.PRIORITY_DEFAULT, None, self.message_from_child) self.in_pipe = self.proc.get_stdin_pipe() self.initialized = True if status.Debug: print("authClient: initialized") return True def cancel(self): if self.proc != None: self.message_to_child("CS_PAM_AUTH_REQUEST_SUBPROCESS_EXIT\n"); else: if status.Debug: print("authClient: cancel requested, but no helper process") def on_proc_completed(self, proc, res, data=None): if status.Debug: print("authClient: helper process completed...") try: ret = proc.wait_check_finish(res) except GLib.Error as e: if status.Debug: print("helper process did not exit cleanly: %s" % e.message) if self.in_pipe != None: self.in_pipe.clear_pending() try: self.in_pipe.close(None) except GLib.Error as e: if status.Debug: print("helper process did not close in_pipe cleanly: %s" % e.message) self.in_pipe = None if self.out_pipe != None: self.out_pipe.clear_pending() try: self.out_pipe.close(None) except GLib.Error as e: if status.Debug: print("helper process did not close out_pipe cleanly: %s" % e.message) self.out_pipe = None self.initialized = False self.proc = None def message_to_child(self, string): if not self.initialized: return if status.Debug: print("authClient: message to child") try: b = GLib.Bytes.new(string.encode()) s = self.in_pipe.write_bytes(b) self.in_pipe.flush(None) except GLib.Error as e: print("Error writing to child - %s" % e.message) def message_from_child(self, pipe, res): if pipe.is_closed(): return finished = False bytes_read = pipe.read_bytes_finish(res) if bytes_read: raw_string = bytes_read.get_data().decode() lines = raw_string.split("\n") for output in lines: if status.Debug: print("Output from pam helper: '%s'" % output) if output: if "CS_PAM_AUTH_FAILURE" in output: self.emit_idle_failure() if "CS_PAM_AUTH_SUCCESS" in output: self.emit_idle_success() finished = True if "CS_PAM_AUTH_CANCELLED" in output: self.emit_idle_cancel() finished = True if "CS_PAM_AUTH_BUSY_TRUE" in output: self.emit_idle_busy_state(True) if "CS_PAM_AUTH_BUSY_FALSE" in output: self.emit_idle_busy_state(False) if "CS_PAM_AUTH_SET_PROMPT" in output: prompt = re.search('(?<=CS_PAM_AUTH_SET_PROMPT_)(.*)(?=_)', output).group(0) self.emit_idle_auth_prompt(prompt) if not finished: pipe.read_bytes_async(1024, GLib.PRIORITY_DEFAULT, None, self.message_from_child) def emit_idle_busy_state(self, busy): if status.Debug: print("authClient: idle add auth-busy") GObject.idle_add(self.emit, "auth-busy", busy) def emit_idle_failure(self): if status.Debug: print("authClient: idle add failure") GObject.idle_add(self.emit, "auth-failure") def emit_idle_success(self): if status.Debug: print("authClient: idle add success") GObject.idle_add(self.emit, "auth-success") def emit_idle_cancel(self): if status.Debug: print("authClient: idle add cancel") GObject.idle_add(self.emit, "auth-cancel") def emit_idle_auth_prompt(self, prompt): if status.Debug: print("authClient: idle add auth-prompt") GObject.idle_add(self.emit, "auth-prompt", prompt) cinnamon-screensaver-4.4.1/src/pamhelper/cinnamon-screensaver-pam-helper.c000066400000000000000000000266401357366610100267400ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2004-2006 William Jon McCann * * This program is free software; you can 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 - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_FAILURES 5 #define DEBUG(...) if (debug_mode) g_printerr (__VA_ARGS__) static gboolean debug_mode = FALSE; static gboolean quit_request = FALSE; static gchar *password_ptr = NULL; static GMutex password_mutex; static GCancellable *stdin_cancellable = NULL; static GOptionEntry entries [] = { { "debug", 0, 0, G_OPTION_ARG_NONE, &debug_mode, N_("Show debugging output"), NULL }, { NULL } }; #define CS_PAM_AUTH_FAILURE "CS_PAM_AUTH_FAILURE\n" #define CS_PAM_AUTH_SUCCESS "CS_PAM_AUTH_SUCCESS\n" #define CS_PAM_AUTH_CANCELLED "CS_PAM_AUTH_CANCELLED\n" #define CS_PAM_AUTH_BUSY_TRUE "CS_PAM_AUTH_BUSY_TRUE\n" #define CS_PAM_AUTH_BUSY_FALSE "CS_PAM_AUTH_BUSY_FALSE\n" #define CS_PAM_AUTH_SET_PROMPT_ "CS_PAM_AUTH_SET_PROMPT_" #define CS_PAM_AUTH_REQUEST_SUBPROCESS_EXIT "CS_PAM_AUTH_REQUEST_SUBPROCESS_EXIT" static void shutdown_and_quit (void) { if (!g_cancellable_is_cancelled (stdin_cancellable)) { g_cancellable_cancel (stdin_cancellable); } else { g_clear_object (&stdin_cancellable); g_clear_pointer (&password_ptr, g_free); gtk_main_quit (); } } static gboolean idle_shutdown_and_quit_cb (gpointer data) { shutdown_and_quit (); return FALSE; } static void send_failure (void) { printf (CS_PAM_AUTH_FAILURE); fflush (stdout); } static void send_success (void) { printf (CS_PAM_AUTH_SUCCESS); fflush (stdout); } static void send_cancelled (void) { printf (CS_PAM_AUTH_CANCELLED); fflush (stdout); } static void send_busy (gboolean busy) { if (busy) { printf (CS_PAM_AUTH_BUSY_TRUE); } else { printf (CS_PAM_AUTH_BUSY_FALSE); } fflush (stdout); } static void send_prompt (const gchar *msg) { printf (CS_PAM_AUTH_SET_PROMPT_ "%s_\n", msg); fflush (stdout); } static gboolean received_quit (const gchar *str) { if (g_strstr_len (str, -1, CS_PAM_AUTH_REQUEST_SUBPROCESS_EXIT)) { return TRUE; } return FALSE; } static gboolean auth_message_handler (CsAuthMessageStyle style, const char *msg, char **response, gpointer data) { gboolean ret; DEBUG ("Got message style %d: '%s'\n", style, msg); ret = TRUE; *response = NULL; switch (style) { case CS_AUTH_MESSAGE_PROMPT_ECHO_ON: break; case CS_AUTH_MESSAGE_PROMPT_ECHO_OFF: if (msg != NULL) { gchar *resp; send_prompt (msg); send_busy (FALSE); while (password_ptr == NULL) { gtk_main_iteration_do (FALSE); usleep (100 * 1000); } g_mutex_lock (&password_mutex); resp = g_strdup (password_ptr); DEBUG ("auth_message_handler processing response string\n"); if (!received_quit (resp)) { *response = resp; } else { quit_request = TRUE; *response = NULL; g_free (resp); } memset (password_ptr, '\b', strlen (password_ptr)); g_clear_pointer (&password_ptr, g_free); g_mutex_unlock (&password_mutex); } break; case CS_AUTH_MESSAGE_ERROR_MSG: break; case CS_AUTH_MESSAGE_TEXT_INFO: break; default: g_assert_not_reached (); } if (*response == NULL) { DEBUG ("Got no response\n"); ret = FALSE; } else { send_busy (TRUE); } /* we may have pending events that should be processed before continuing back into PAM */ while (gtk_events_pending ()) { gtk_main_iteration (); } if (quit_request) { send_cancelled (); g_idle_add ((GSourceFunc) idle_shutdown_and_quit_cb, NULL); } return ret; } static gboolean do_auth_check (void) { GError *error; gboolean res; error = NULL; res = cs_auth_verify_user (g_get_user_name (), g_getenv ("DISPLAY"), auth_message_handler, NULL, &error); DEBUG ("Verify user returned: %s\n", res ? "TRUE" : "FALSE"); if (!res) { if (error != NULL) { DEBUG ("Verify user returned error: %s\n", error->message); } if (error != NULL) { g_error_free (error); } } return res; } static gboolean auth_check_idle (gpointer user_data) { gboolean res; gboolean again; static guint loop_counter = 0; again = TRUE; res = do_auth_check (); if (res) { again = FALSE; send_success (); g_idle_add ((GSourceFunc) idle_shutdown_and_quit_cb, NULL); } else { loop_counter++; if (loop_counter < MAX_FAILURES) { send_failure (); DEBUG ("Authentication failed, retrying (%u)\n", loop_counter); } else { DEBUG ("Authentication failed, quitting (max failures)\n"); again = FALSE; /* Don't quit immediately, but rather request that cinnamon-screensaver * terminates us after it has finished the dialog shake. Time out * after 5 seconds and quit anyway if this doesn't happen though */ send_cancelled (); g_idle_add ((GSourceFunc) idle_shutdown_and_quit_cb, NULL); } } return again; } static void stdin_monitor_task_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { while (!g_cancellable_is_cancelled (stdin_cancellable)) { gchar buf[255]; gchar *input; input = fgets (buf, sizeof (buf) - 1, stdin); g_mutex_lock (&password_mutex); if (input [strlen (input) - 1] == '\n') { input [strlen (input) - 1] = 0; } password_ptr = g_strdup (input); memset (input, '\b', strlen (input)); g_mutex_unlock (&password_mutex); } g_task_return_boolean (task, TRUE); } static void stdin_monitor_task_finished (GObject *source, GAsyncResult *result, gpointer user_data) { g_task_propagate_boolean (G_TASK (result), NULL); g_clear_object (&stdin_cancellable); g_clear_pointer (&password_ptr, g_free); quit_request = FALSE; while (gtk_events_pending ()) { gtk_main_iteration (); } g_idle_add ((GSourceFunc) gtk_main_quit, NULL); } static void setup_stdin_monitor (void) { GTask *task; stdin_cancellable = g_cancellable_new (); task = g_task_new (NULL, stdin_cancellable, stdin_monitor_task_finished, NULL); g_task_set_return_on_cancel (task, TRUE); g_task_run_in_thread (task, stdin_monitor_task_thread); g_object_unref (task); } /* * Copyright (c) 1991-2004 Jamie Zawinski * Copyright (c) 2005 William Jon McCann * * Initializations that potentially take place as a privileged user: If the executable is setuid root, then these initializations are run as root, before discarding privileges. */ static gboolean privileged_initialization (int *argc, char **argv, gboolean verbose) { gboolean ret; char *nolock_reason; char *orig_uid; char *uid_message; #ifndef NO_LOCKING /* before hack_uid () for proper permissions */ cs_auth_priv_init (); #endif /* NO_LOCKING */ ret = hack_uid (&nolock_reason, &orig_uid, &uid_message); if (nolock_reason) { DEBUG ("Locking disabled: %s\n", nolock_reason); } if (uid_message && verbose) { g_print ("Modified UID: %s", uid_message); } g_free (nolock_reason); g_free (orig_uid); g_free (uid_message); return ret; } /* * Copyright (c) 1991-2004 Jamie Zawinski * Copyright (c) 2005 William Jon McCann * * Figure out what locking mechanisms are supported. */ static gboolean lock_initialization (int *argc, char **argv, char **nolock_reason, gboolean verbose) { if (nolock_reason != NULL) { *nolock_reason = NULL; } #ifdef NO_LOCKING if (nolock_reason != NULL) { *nolock_reason = g_strdup ("not compiled with locking support"); } return FALSE; #else /* !NO_LOCKING */ /* Finish initializing locking, now that we're out of privileged code. */ if (!cs_auth_init ()) { if (nolock_reason != NULL) { *nolock_reason = g_strdup ("error getting password"); } return FALSE; } #endif /* NO_LOCKING */ return TRUE; } static void response_lock_init_failed (void) { /* if we fail to lock then we should drop the dialog */ send_success (); } int main (int argc, char **argv) { GError *error = NULL; char *nolock_reason = NULL; bindtextdomain (GETTEXT_PACKAGE, "/usr/share/locale"); if (! privileged_initialization (&argc, argv, debug_mode)) { response_lock_init_failed (); exit (1); } error = NULL; if (! gtk_init_with_args (&argc, &argv, NULL, entries, NULL, &error)) { if (error != NULL) { fprintf (stderr, "%s", error->message); g_error_free (error); } exit (1); } if (! lock_initialization (&argc, argv, &nolock_reason, debug_mode)) { if (nolock_reason != NULL) { DEBUG ("Screen locking disabled: %s\n", nolock_reason); g_free (nolock_reason); } response_lock_init_failed (); exit (1); } cs_auth_set_verbose (debug_mode); quit_request = FALSE; setup_stdin_monitor (); g_idle_add ((GSourceFunc) auth_check_idle, NULL); gtk_main (); return 0; } cinnamon-screensaver-4.4.1/src/passwordEntry.py000066400000000000000000000222431357366610100217000ustar00rootroot00000000000000#!/usr/bin/python3 # coding: utf-8 import gi gi.require_version('CinnamonDesktop', '3.0') from gi.repository import Gtk, Gdk, GdkPixbuf, GLib import cairo from util import trackers, settings import singletons class PasswordEntry(Gtk.Entry): """ The GtkEntry where the user types their password. It also implements a clickable imagine showing the currently chosen keyboard layout, and allowing switching of the layout. """ def __init__(self): super(PasswordEntry, self).__init__() self.get_style_context().add_class("passwordentry") placeholder_text = _("Please enter your password...") self.set_width_chars(len(placeholder_text) + 1) # account for the flag self.set_has_frame(True) self.set_input_purpose(Gtk.InputPurpose.PASSWORD) self.set_visibility(False) self.set_property("caps-lock-warning", False) self.set_placeholder_text (placeholder_text) self.set_can_default(True) self.placeholder_text = placeholder_text self.current_icon_name = None self.current_flag_id = 0 self.original_group = 0 self.keyboard_controller = singletons.KeyboardLayoutController trackers.con_tracker_get().connect(self.keyboard_controller, "config-changed", self.on_config_changed) trackers.con_tracker_get().connect(self.keyboard_controller, "layout-changed", self.on_layout_changed) self.set_lockscreen_keyboard_layout() trackers.con_tracker_get().connect(self, "destroy", self.on_destroy) def on_draw(self, widget, cr, data=None): """ GtkEntry always makes its icons menu-sized, no matter how much actual space is available for the image. So, we use a transparent icon in update_layout_icon(), just so GtkEntry thinks there's an icon there, that way it allocates space for it, and responds to clicks in the area. """ if not self.keyboard_controller.get_enabled(): return False icon_rect = widget.get_icon_area(Gtk.EntryIconPosition.PRIMARY) x = icon_rect.x y = icon_rect.y + 2 width = (icon_rect.width // 2) * 2 height = icon_rect.height - 4 handled = False if settings.get_show_flags(): name = self.keyboard_controller.get_current_icon_name() ui_scale = self.get_scale_factor() if name: filename = "/usr/share/iso-flag-png/%s.png" % name try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, -1, height * ui_scale) logical_width = pixbuf.get_width() / ui_scale logical_height = pixbuf.get_height() / ui_scale render_x = (x + (width / 2) - (logical_width / 2)) render_y = (y + (height / 2) - (logical_height / 2)) if pixbuf: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, ui_scale, self.get_window()) cr.set_source_surface(surface, render_x, render_y) cr.paint() self.keyboard_controller.render_cairo_subscript(cr, render_x + (logical_width / 2), render_y + (logical_height / 2), logical_width / 2, logical_height / 2, self.keyboard_controller.get_current_flag_id()) handled = True except GLib.Error: pass if not handled: if settings.get_use_layout_variant_names(): name = self.keyboard_controller.get_current_variant_label() else: name = self.keyboard_controller.get_current_short_group_label() if settings.get_show_upper_case_layout(): name = name.upper() ctx = widget.get_style_context() ctx.save() ctx.set_state(Gtk.StateFlags.BACKDROP) font_size = ctx.get_property("font-size", Gtk.StateFlags.BACKDROP) family = ctx.get_property("font-family", Gtk.StateFlags.BACKDROP) cr.select_font_face(family[0], cairo.FONT_WEIGHT_NORMAL, cairo.FONT_SLANT_NORMAL) cr.set_font_size(font_size) (xb, yb, w, h, xa, ya) = cr.text_extents(name) # Drop shadow for visibility - 1px, 1px cr.set_source_rgba(0, 0, 0, 0.8) cr.move_to((x + (width / 2) - (w / 2)) + 1, (y + (height / 2) + (h / 2) + 1)) cr.show_text(name) # Text text_color = widget.get_style_context().get_color(Gtk.StateFlags.BACKDROP) Gdk.cairo_set_source_rgba(cr, text_color) cr.move_to((x + (width / 2) - (w / 2)), (y + (height / 2) + (h / 2))) cr.show_text(name) ctx.restore() return False def start_progress(self): self.set_progress_pulse_step(0.2) trackers.timer_tracker_get().start("auth-progress", 100, self.pulse) def stop_progress(self): trackers.timer_tracker_get().cancel("auth-progress") self.set_progress_fraction(0.0) def pulse(self): """ Periodic callback for the progress bar. """ self.progress_pulse() return True def on_layout_changed(self, controller, layout): self.grab_focus() self.update_layout_icon() def on_config_changed(self, controller): self.set_lockscreen_keyboard_layout() def on_icon_pressed(self, entry, icon_pos, event): if icon_pos == Gtk.EntryIconPosition.PRIMARY: self.keyboard_controller.next_group() def update_layout_icon(self): """ Set an empty icon here so the widget responds to clicks and allocates space for it. We'll do the actual flag or whatever in the 'draw' callback. Setting the icon here also ensures a redraw at the correct time to update the flag image. """ self.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, "screensaver-blank") self.set_icon_tooltip_text(Gtk.EntryIconPosition.PRIMARY, self.keyboard_controller.get_current_name()) self.update_saved_group(self.keyboard_controller.get_current_group()) def on_destroy(self, widget, data=None): self.stop_progress() trackers.con_tracker_get().disconnect(self.keyboard_controller, "config-changed", self.on_config_changed) trackers.con_tracker_get().disconnect(self.keyboard_controller, "layout-changed", self.on_layout_changed) self.restore_original_layout() def set_lockscreen_keyboard_layout(self): if not self.keyboard_controller.get_enabled(): return # If there are multiple keyboard layouts, we want to store # the one the user ends up using in the unlock widget, as they'll # want to use the same one each time, at least until they change # their password. saved_group = settings.get_kb_group() self.original_group = self.keyboard_controller.get_current_group() new_group = 0 if saved_group == -1: new_group = self.original_group else: new_group = saved_group self.keyboard_controller.set_current_group(new_group) self.update_saved_group(new_group) self.update_layout_icon() trackers.con_tracker_get().connect(self, "icon-press", self.on_icon_pressed) trackers.con_tracker_get().connect(self, "draw", self.on_draw) def update_saved_group(self, group): settings.set_kb_group(group) def restore_original_layout(self): """ Called when the unlock dialog is destroyed, restores the group that was active before the screensaver was activated. """ if not self.keyboard_controller.get_enabled(): return self.keyboard_controller.set_current_group(self.original_group) def grab_focus(self): Gtk.Widget.grab_focus(self) length = self.get_buffer().get_length() self.select_region(length, -1) cinnamon-screensaver-4.4.1/src/playerControl.py000066400000000000000000000146771357366610100216650ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('Cvc', '1.0') from gi.repository import Gtk import datetime from util import trackers, utils from dbusdepot.mediaPlayerWatcher import PlaybackStatus from widgets.marqueeLabel import MarqueeLabel from widgets.transparentButton import TransparentButton import singletons import status class PlayerControl(Gtk.Box): """ Provides info and controls for any active music or other media player. It is a a direct child of the AudioPanel, and is only shown if there is an active mpris interface we can connect to. """ def __init__(self): super(PlayerControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self.watcher = singletons.MediaPlayerWatcher self.player = self.watcher.get_best_player() if self.player: self.build_layout() def build_layout(self): player_status = self.player.get_playback_status() # Player buttons button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) button_box.set_homogeneous(True) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.pack_start(vbox, True, True, 2) vbox.pack_start(button_box, True, True, 0) vbox.set_valign(Gtk.Align.CENTER) self.previous_button = TransparentButton("media-skip-backward-symbolic", Gtk.IconSize.BUTTON) self.previous_button.show() trackers.con_tracker_get().connect(self.previous_button, "clicked", self.on_previous_clicked) button_box.pack_start(self.previous_button, True, True, 2) self.play_pause_button = TransparentButton(self.get_play_pause_icon_name(player_status), Gtk.IconSize.BUTTON) self.play_pause_button.show() trackers.con_tracker_get().connect(self.play_pause_button, "clicked", self.on_play_pause_clicked) button_box.pack_start(self.play_pause_button, True, True, 2) self.next_button = TransparentButton("media-skip-forward-symbolic", Gtk.IconSize.BUTTON) self.next_button.show() trackers.con_tracker_get().connect(self.next_button, "clicked", self.on_next_clicked) button_box.pack_start(self.next_button, True, True, 2) self.update_buttons(player_status) status.focusWidgets = status.focusWidgets + [self.previous_button, self.play_pause_button, self.next_button] # Track info vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.pack_start(vbox, True, True, 6) vbox.set_valign(Gtk.Align.CENTER) self.track_name_label = MarqueeLabel("") self.track_name_label.get_style_context().add_class("trackname") vbox.pack_start(self.track_name_label, True, True, 2) self.album_artist_label = MarqueeLabel("") self.album_artist_label.get_style_context().add_class("albumartist") vbox.pack_end(self.album_artist_label, True, True, 2) self.show_all() trackers.con_tracker_get().connect(self.player, "status-changed", self.on_playback_status_changed) trackers.con_tracker_get().connect(self.player, "metadata-changed", self.on_metadata_changed) self.on_playback_status_changed(self.player, player_status) self.on_metadata_changed(self.player) trackers.con_tracker_get().connect(self, "destroy", self.on_widget_destroy) def on_previous_clicked(self, button, data=None): self.player.go_previous() def on_next_clicked(self, button, data=None): self.player.go_next() def on_play_pause_clicked(self, button, data=None): self.player.play_pause() def get_play_pause_icon_name(self, status): if status == PlaybackStatus.Playing: icon_name = "media-playback-pause-symbolic" else: icon_name = "media-playback-start-symbolic" return icon_name def on_playback_status_changed(self, player, status, data=None): self.update_buttons(status) def on_metadata_changed(self, player): """ Update labels when the player metadata changes """ self.update_labels() def update_labels(self): """ Construct the track and artist-album labels as well as possible. """ self.track_name_label.set_text(self.player.get_track_name()) artist_name = self.player.get_artist_name() album_name = self.player.get_album_name() if artist_name != "" and album_name != "": self.album_artist_label.set_text("%s - %s" % (self.player.get_artist_name(), self.player.get_album_name())) elif artist_name != "": self.album_artist_label.set_text(artist_name) elif album_name != "": self.album_artist_label.set_text(album_name) else: self.album_artist_label.set_text("") def update_buttons(self, status): """ Updates the player buttons based on the current state """ self.play_pause_button.set_sensitive(self.player.get_can_play_pause()) self.next_button.set_sensitive(self.player.get_can_go_next()) self.previous_button.set_sensitive(self.player.get_can_go_previous()) icon_name = self.get_play_pause_icon_name(status) image = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.BUTTON) self.play_pause_button.set_image(image) def on_widget_destroy(self, widget, data=None): trackers.con_tracker_get().disconnect(self.player, "status-changed", self.on_playback_status_changed) trackers.con_tracker_get().disconnect(self, "destroy", self.on_widget_destroy) def should_show(self): """ Checked by the AudioPanel, whether or not this widget should be displayed. """ return self.player != None cinnamon-screensaver-4.4.1/src/service.py000077500000000000000000000135241357366610100204610ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('CScreensaver', '1.0') from gi.repository import Gtk, CScreensaver, Gio, GObject import constants as c from manager import ScreensaverManager import status class ScreensaverService(GObject.Object): """ This is the dbus service we run ourselves. It is the owner of our ScreensaverManager, and implements the org.cinnamon.Screensaver dbus interface. It is through this service that the screensaver is controlled. """ def __init__(self): """ Immediately attempt to own org.cinnamon.Screensaver. Failure to do so will result in simply quitting the program, as we can't run more than one instance at a time. Upon success we export our interface to the session bus. """ super(ScreensaverService, self).__init__() self.bus = Gio.bus_get_sync(Gio.BusType.SESSION) Gio.bus_own_name(Gio.BusType.SESSION, c.SS_SERVICE, Gio.BusNameOwnerFlags.NONE, self.on_bus_acquired, self.on_name_acquired, self.on_name_lost) def on_name_lost(self, connection, name, data=None): """ Failed to acquire our name - just exit. """ print("A screensaver is already running! Exiting...") Gtk.main_quit() def on_name_acquired(self, connection, name, data=None): """ Acquired our name - pass... The real work will begin on our bus_acquired callback. """ print("Starting screensaver...") def on_bus_acquired(self, connection, name, data=None): """ Export our interface to the session bus. Creates the ScreensaverManager. We are now ready to respond to requests by cinnamon-session and cinnamon-screensaver-command. """ self.bus = connection self.interface = CScreensaver.ScreenSaverSkeleton.new() self.interface.connect("handle-lock", self.handle_lock) self.interface.connect("handle-quit", self.handle_quit) self.interface.connect("handle-set-active", self.handle_set_active) self.interface.connect("handle-get-active", self.handle_get_active) self.interface.connect("handle-get-active-time", self.handle_get_active_time) self.interface.connect("handle-simulate-user-activity", self.handle_simulate_user_activity) self.manager = ScreensaverManager() self.manager.connect("active-changed", self.on_active_changed) """ The stage constructs itself and fades in asynchronously, and most importantly, as an idle callback. This can cause the screensaver to not be fully active when a call to suspend is made. Cinnamon-session calls to lock the screensaver synchronously, and if we don't completely finish construction before returning the dbus call completion, there's a chance the idle callback won't run until after the computer is resumed. We get an active-changed signal whenever the screensaver becomes completely active or inactive, so we'll queue up running iface.complete_lock() until we receive that signal. This allows the screensaver to be fully activated prior to cinnamon-session allowing the suspend/hibernate/whatever process to continue. For reference, this is called in cinnamon-session's csm-manager.c "manager_perhaps_lock" method. """ self.lock_queue = [] self.interface.export(self.bus, c.SS_PATH) # Interface handlers def handle_lock(self, iface, inv, msg): """ We want to be able to respond to locking synchronously for security reasons. Things like cinnamon-settings-daemon (power) and cinnamon-session use the cinnamon-screensaver-command helper script to lock the screen during certain events like sleep, hibernate, user switching, etc... If we receive a lock request, we forward it to the manager. It returns True if we were already active (or active and locked.) If so, we can complete the invocation immediately. Otherwise, we queue the invocation, and wait for an "active-changed" signal from the manager, and then complete the invocations (in the same order they were received.) """ if self.manager.lock(msg): iface.complete_lock(inv) else: self.lock_queue.append(inv) return True def handle_quit(self, iface, inv): self.manager.unlock() iface.complete_quit(inv) Gtk.main_quit() return True def handle_set_active(self, iface, inv, active): self.manager.set_active(active) iface.complete_set_active(inv) return True def handle_get_active(self, iface, inv): active = self.manager.get_active() iface.complete_get_active(inv, active) return True def handle_get_active_time(self, iface, inv): atime = self.manager.get_active_time() iface.complete_get_active_time(inv, atime) return True def handle_simulate_user_activity(self, iface, inv): if self.manager.is_locked(): self.manager.simulate_user_activity() else: if status.Debug: print("Calling XResetScreenSaver"); CScreensaver.Screen.reset_screensaver() iface.complete_simulate_user_activity(inv) return True def on_active_changed(self, manager, state, data=None): GObject.idle_add(self.on_active_changed_idle, state) def on_active_changed_idle(self, state): self.lock_queue.reverse() while len(self.lock_queue) > 0: invocation = self.lock_queue.pop() self.interface.complete_lock(invocation) self.lock_queue = [] self.interface.emit_active_changed(state) cinnamon-screensaver-4.4.1/src/singletons.py000066400000000000000000000142111357366610100211750ustar00rootroot00000000000000#!/usr/bin/python3 import gi from util import trackers, settings import status # Watch for, and kill, mate- and gnome-screensaver in case they're activated by a program # over dbus. from dbusdepot.nameBlocker import NameBlocker as _NameBlocker NameBlocker = _NameBlocker() # Our dbus proxies are abstracted out one level more than really necessary - we have # clients that the screensaver initializes, that can never fail. The actual connection # business to the various dbus address is performed asynchronously from within each client. # The following clients can fail to establish with their respective dbus interfaces without # competely breaking the program (or at least that's what we're after) - it just means that # depending on what fails, you may end up without keyboard shortcut support, or a battery # widget, etc... from dbusdepot.cinnamonClient import CinnamonClient as _CinnamonClient from dbusdepot.sessionClient import SessionClient as _SessionClient from dbusdepot.uPowerClient import UPowerClient as _UPowerClient from dbusdepot.keybindingHandlerClient import KeybindingHandlerClient as _KeybindingHandlerClient from dbusdepot.mediaPlayerWatcher import MediaPlayerWatcher as _MediaPlayerWatcher from dbusdepot.accountsServiceClient import AccountsServiceClient as _AccountsServiceClient CinnamonClient = _CinnamonClient() SessionClient = _SessionClient() UPowerClient = _UPowerClient() KeybindingHandlerClient = _KeybindingHandlerClient() MediaPlayerWatcher = _MediaPlayerWatcher() AccountsServiceClient = _AccountsServiceClient() # The notification watcher is a C introspected class - some of the functions it uses # don't work well via introspection. from gi.repository import CScreensaver NotificationWatcher = CScreensaver.NotificationWatcher.new(status.Debug) # We only need one instance of CinnamonDesktop.BG - have it listen to bg gsettings changes # and we just connect to "changed" on the Backgrounds object from our user (the Stage) gi.require_version('CinnamonDesktop', '3.0') from gi.repository import CinnamonDesktop Backgrounds = CinnamonDesktop.BG() Backgrounds.load_from_preferences(settings.bg_settings) settings.bg_settings.connect("changed", lambda s,k: Backgrounds.load_from_preferences(s)) # We use XAppKbdLayoutController as a wrapper around libgnomekbd to supply the icon theme # with icons, as well as providing correct group names. gi.require_version('XApp', '1.0') from gi.repository import XApp KeyboardLayoutController = XApp.KbdLayoutController() # The login client is a bit different - we can have either logind or ConsoleKit. # So, we have to do a bit more work to determine which one we're going to use. # This doesn't really need to impact the main startup business though - whichever # one we end up using, all we're doing is connecting to signals from one or the # other client. Whichever we end up with is invisible/not relevant to the rest of # the application. from dbusdepot.consoleKitClient import ConsoleKitClient from dbusdepot.logindClient import LogindClient class LoginClientResolver: def __init__(self, manager): self.manager = manager self.login_client = None self.try_logind() def try_logind(self): print("Trying to connect to logind...") login_client = LogindClient() trackers.con_tracker_get().connect(login_client, "startup-status", self.on_logind_startup_result) def on_logind_startup_result(self, client, success): trackers.con_tracker_get().disconnect(client, "startup-status", self.on_logind_startup_result) if success: print("Successfully using logind") self.login_client = client self.setup_manager_connections() else: print("Failed to connect to logind, or it doesn't exist.") self.try_console_kit() def try_console_kit(self): print("Trying to connect to ConsoleKit...") login_client = ConsoleKitClient() trackers.con_tracker_get().connect(login_client, "startup-status", self.on_consolekit_startup_result) def on_consolekit_startup_result(self, client, success): trackers.con_tracker_get().disconnect(client, "startup-status", self.on_consolekit_startup_result) if success: print("Successfully using ConsoleKit") self.login_client = client self.setup_manager_connections() else: print("Failed to connect to ConsoleKit, or it doesn't exist.\n") print("Unable to connect to either logind or ConsoleKit. Certain things will not work,") print("such as automatic unlocking when switching users from the desktop manager,") print("or locking in appropriate power/system-management events.") def setup_manager_connections(self): trackers.con_tracker_get().connect(self.login_client, "lock", self.on_session_manager_lock) trackers.con_tracker_get().connect(self.login_client, "unlock", self.on_session_manager_unlock) trackers.con_tracker_get().connect(self.login_client, "active", self.on_session_manager_active) def on_session_manager_lock(self, client): if status.Debug: print("Received Lock from session manager") self.manager.lock() def on_session_manager_unlock(self, client): if status.Debug: print("Received Unlock from session manager") self.manager.unlock() def on_session_manager_active(self, client): if status.Debug: print("Received Active changed from session manager") self.manager.update_stage() self.manager.simulate_user_activity() cinnamon-screensaver-4.4.1/src/stage.py000066400000000000000000001076571357366610100201340ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('CDesktopEnums', '3.0') from gi.repository import Gtk, Gdk, CScreensaver, CDesktopEnums, GObject import random import status import constants as c import singletons from monitorView import MonitorView from unlock import UnlockDialog from clock import ClockWidget from albumArt import AlbumArt from audioPanel import AudioPanel from infoPanel import InfoPanel from osk import OnScreenKeyboard from floating import ALIGNMENTS from util import utils, trackers, settings from util.eventHandler import EventHandler class Stage(Gtk.Window): """ The Stage is the toplevel window of the entire screensaver while in Active mode. It's the first thing made, the last thing destroyed, and all other widgets live inside of it (or rather, inside the GtkOverlay below) It is Gtk.WindowType.POPUP to avoid being managed/composited by muffin, and to prevent animation during its creation and destruction. The Stage reponds pretty much only to the instructions of the ScreensaverManager. """ def __init__(self, manager, away_message): if status.InteractiveDebug: Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL, decorated=True, skip_taskbar_hint=False) else: Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP, decorated=False, skip_taskbar_hint=True) self.get_style_context().add_class("csstage") trackers.con_tracker_get().connect(singletons.Backgrounds, "changed", self.on_bg_changed) self.destroying = False self.manager = manager status.screen = CScreensaver.Screen.new(status.Debug) self.away_message = away_message self.monitors = [] self.last_focus_monitor = -1 self.overlay = None self.clock_widget = None self.albumart_widget = None self.unlock_dialog = None self.audio_panel = None self.info_panel = None self.stage_refresh_id = 0 self.floaters = [] self.event_handler = EventHandler(manager) self.get_style_context().remove_class("background") self.set_events(self.get_events() | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK | Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.VISIBILITY_NOTIFY_MASK | Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK | Gdk.EventMask.FOCUS_CHANGE_MASK) c = Gdk.RGBA(0, 0, 0, 0) self.override_background_color (Gtk.StateFlags.NORMAL, c); self.update_geometry() self.overlay = Gtk.Overlay() trackers.con_tracker_get().connect(self.overlay, "realize", self.on_realized) trackers.con_tracker_get().connect(self.overlay, "get-child-position", self.position_overlay_child) self.overlay.show_all() self.add(self.overlay) # We hang onto the UPowerClient here so power events can # trigger changes to the info panel. self.power_client = singletons.UPowerClient trackers.con_tracker_get().connect(self.power_client, "power-state-changed", self.on_power_state_changed) # This filter suppresses any other windows that might share # our window group in muffin, from showing up over the Stage. # For instance: Chrome and Firefox native notifications. self.gdk_filter = CScreensaver.GdkEventFilter() trackers.con_tracker_get().connect(status.screen, "size-changed", self.on_screen_size_changed) trackers.con_tracker_get().connect(status.screen, "monitors-changed", self.on_monitors_changed) trackers.con_tracker_get().connect(status.screen, "composited-changed", self.on_composited_changed) trackers.con_tracker_get().connect(self, "grab-broken-event", self.on_grab_broken_event) if status.InteractiveDebug: self.set_interactive_debugging(True) def update_monitors(self): self.destroy_monitor_views() try: self.setup_monitors() for monitor in self.monitors: self.sink_child_widget(monitor) except Exception as e: print("Problem updating monitor views views: %s" % str(e)) def on_screen_size_changed(self, screen, data=None): """ The screen changing size should be acted upon immediately, to ensure coverage. Wallpapers are secondary. """ if status.Debug: print("Stage: Received screen size-changed signal, refreshing stage") self.update_geometry() self.move_onscreen() self.overlay.queue_resize() def on_monitors_changed(self, screen, data=None): """ Updating monitors also will trigger an immediate stage coverage update (same as on_screen_size_changed), and follow up at idle with actual monitor view refreshes (wallpapers.) """ if status.Debug: print("Stage: Received screen monitors-changed signal, refreshing stage") self.update_geometry() self.move_onscreen() self.overlay.queue_resize() Gdk.flush() self.queue_refresh_stage() def on_composited_changed(self, screen, data=None): if self.get_realized(): user_time = self.get_display().get_user_time() self.hide() self.unrealize() self.realize() self.get_window().set_user_time(user_time) self.show() GObject.idle_add(self.manager.grab_stage) def on_grab_broken_event(self, widget, event, data=None): GObject.idle_add(self.manager.grab_stage) return False def queue_refresh_stage(self): """ Queues a complete refresh of the stage, resizing the screen if necessary, reconstructing the individual monitor objects, etc... """ if self.stage_refresh_id > 0: GObject.source_remove(self.stage_refresh_id) self.stage_refresh_id = 0 self.stage_refresh_id = GObject.idle_add(self._update_full_stage_on_idle) def _update_full_stage_on_idle(self, data=None): self.stage_refresh_id = 0 self._refresh() return False def _refresh(self): Gdk.flush() if status.Debug: print("Stage: refresh callback") self.update_geometry() self.move_onscreen() self.update_monitors() self.overlay.queue_resize() def activate(self, callback): """ This is the primary way of making the Stage visible. """ self.set_opacity(1.0) self.move_onscreen() self.show() callback() def deactivate(self, callback): """ This is the primary way of destroying the stage. """ self.hide() callback() def on_realized(self, widget): """ Repositions the window when it is realized, to cover the entire GdkScreen (a rectangle exactly encompassing all monitors.) From here we also proceed to construct all overlay children and activate our window suppressor. """ window = self.get_window() utils.override_user_time(window) self.setup_children() self.gdk_filter.start(self) trackers.con_tracker_get().disconnect(self.overlay, "realize", self.on_realized) def move_onscreen(self): w = self.get_window() if w: w.move_resize(self.rect.x, self.rect.y, self.rect.width, self.rect.height) self.move(self.rect.x, self.rect.y) self.resize(self.rect.width, self.rect.height) def deactivate_after_timeout(self): self.manager.set_active(False) def setup_children(self): """ Creates all of our overlay children. If a new 'widget' gets added, this should be the setup point for it. We bail if something goes wrong on a critical widget - a monitor view or unlock widget. """ total_failure = False try: self.setup_monitors() except Exception as e: print("Problem setting up monitor views: %s" % str(e)) total_failure = True try: self.setup_unlock() except Exception as e: print("Problem setting up unlock dialog: %s" % str(e)) total_failure = True if not total_failure: try: self.setup_clock() except Exception as e: print("Problem setting up clock widget: %s" % str(e)) self.clock_widget = None try: self.setup_albumart() except Exception as e: print("Problem setting up albumart widget: %s" % str(e)) self.albumart_widget = None try: self.setup_status_bars() except Exception as e: print("Problem setting up status bars: %s" % str(e)) self.audio_panel = None self.info_panel = None try: self.setup_osk() except Exception as e: print("Problem setting up on-screen keyboard: %s" % str(e)) self.osk = None if total_failure: print("Total failure somewhere, deactivating screensaver.") GObject.idle_add(self.deactivate_after_timeout) def destroy_children(self): try: self.destroy_monitor_views() except Exception as e: print(e) try: if self.unlock_dialog != None: self.unlock_dialog.destroy() except Exception as e: print(e) try: if self.clock_widget != None: self.clock_widget.stop_positioning() self.clock_widget.destroy() except Exception as e: print(e) try: if self.albumart_widget != None: self.albumart_widget.stop_positioning() self.albumart_widget.destroy() except Exception as e: print(e) try: if self.info_panel != None: self.info_panel.destroy() except Exception as e: print(e) try: if self.info_panel != None: self.audio_panel.destroy() except Exception as e: print(e) try: if self.osk != None: self.osk.destroy() except Exception as e: print(e) self.unlock_dialog = None self.clock_widget = None self.albumart_widget = None self.info_panel = None self.audio_panel = None self.osk = None self.away_message = None self.monitors = [] self.floaters = [] def destroy_stage(self): """ Performs all tear-down necessary to destroy the Stage, destroying all children in the process, and finally destroying itself. """ trackers.con_tracker_get().disconnect(singletons.Backgrounds, "changed", self.on_bg_changed) trackers.con_tracker_get().disconnect(self.power_client, "power-state-changed", self.on_power_state_changed) trackers.con_tracker_get().disconnect(self, "grab-broken-event", self.on_grab_broken_event) self.set_timeout_active(None, False) self.destroy_children() self.gdk_filter.stop() self.gdk_filter = None trackers.con_tracker_get().disconnect(status.screen, "size-changed", self.on_screen_size_changed) trackers.con_tracker_get().disconnect(status.screen, "monitors-changed", self.on_monitors_changed) trackers.con_tracker_get().disconnect(self.overlay, "get-child-position", self.position_overlay_child) self.destroy() status.screen = None def setup_monitors(self): """ Iterate through the monitors, and create MonitorViews for each one to cover them. """ self.monitors = [] status.Spanned = settings.bg_settings.get_enum("picture-options") == CDesktopEnums.BackgroundStyle.SPANNED if status.InteractiveDebug or status.Spanned: monitors = (status.screen.get_primary_monitor(),) else: n = status.screen.get_n_monitors() monitors = () for i in range(n): monitors += (i,) for index in monitors: monitor = MonitorView(index) image = Gtk.Image() singletons.Backgrounds.create_and_set_gtk_image (image, monitor.rect.width, monitor.rect.height) monitor.set_next_wallpaper_image(image) self.monitors.append(monitor) self.add_child_widget(monitor) self.update_monitor_views() def on_bg_changed(self, bg): """ Callback for our GnomeBackground instance, this tells us when the background settings have changed, so we can update our wallpaper. """ for monitor in self.monitors: image = Gtk.Image() singletons.Backgrounds.create_and_set_gtk_image (image, monitor.rect.width, monitor.rect.height) monitor.set_next_wallpaper_image(image) def on_power_state_changed(self, client, data=None): """ Callback for UPower changes, this will make our MonitorViews update themselves according to user setting and power state. """ if status.Debug: print("stage: Power state changed, updating info panel") self.info_panel.update_visibility() def setup_clock(self): """ Construct the clock widget and add it to the overlay, but only actually show it if we're a) Not running a plug-in, and b) The user wants it via preferences. Initially invisible, regardless - its visibility is controlled via its own positioning timer. """ self.clock_widget = ClockWidget(self.away_message, status.screen.get_mouse_monitor(), status.screen.get_low_res_mode()) self.add_child_widget(self.clock_widget) self.floaters.append(self.clock_widget) if settings.get_show_clock(): self.clock_widget.start_positioning() def setup_albumart(self): """ Construct the AlbumArt widget and add it to the overlay, but only actually show it if we're a) Not running a plug-in, and b) The user wants it via preferences. Initially invisible, regardless - its visibility is controlled via its own positioning timer. """ self.albumart_widget = AlbumArt(None, status.screen.get_mouse_monitor()) self.add_child_widget(self.albumart_widget) self.floaters.append(self.clock_widget) if settings.get_show_albumart(): self.albumart_widget.start_positioning() def setup_osk(self): self.osk = OnScreenKeyboard() self.add_child_widget(self.osk) def setup_unlock(self): """ Construct the unlock dialog widget and add it to the overlay. It will always initially be invisible. Any time the screensaver is awake, and the unlock dialog is raised, a timer runs. After a certain elapsed time, the state will be reset, and the dialog will be hidden once more. Mouse and key events reset this timer, and the act of authentication temporarily suspends it - the unlock widget accomplishes this via its inhibit- and uninhibit-timeout signals We also listen to actual authentication events, to destroy the stage if there is success, and to do something cute if we fail (for now, this consists of 'blinking' the unlock dialog.) """ self.unlock_dialog = UnlockDialog() self.set_default(self.unlock_dialog.auth_unlock_button) self.add_child_widget(self.unlock_dialog) # Prevent a dialog timeout during authentication trackers.con_tracker_get().connect(self.unlock_dialog, "inhibit-timeout", self.set_timeout_active, False) trackers.con_tracker_get().connect(self.unlock_dialog, "uninhibit-timeout", self.set_timeout_active, True) # Respond to authentication success/failure trackers.con_tracker_get().connect(self.unlock_dialog, "authenticate-success", self.authentication_result_callback, True) trackers.con_tracker_get().connect(self.unlock_dialog, "authenticate-failure", self.authentication_result_callback, False) trackers.con_tracker_get().connect(self.unlock_dialog, "authenticate-cancel", self.authentication_cancel_callback) def setup_status_bars(self): """ Constructs the AudioPanel and InfoPanel and adds them to the overlay. """ self.audio_panel = AudioPanel() self.add_child_widget(self.audio_panel) self.info_panel = InfoPanel() self.add_child_widget(self.info_panel) self.info_panel.update_visibility() def queue_dialog_key_event(self, event): """ Sent from our EventHandler via the ScreensaverManager, this catches initial key events before the unlock dialog is made visible, so that the user doesn't have to first jiggle the mouse to wake things up before beginning to type their password. They can just start typing, and no keystrokes will be lost. """ self.unlock_dialog.queue_key_event(event) # Timer stuff - after a certain time, the unlock dialog will cancel itself. # This timer is suspended during authentication, and any time a new user event is received def reset_timeout(self): """ This is called when any user event is received in our EventHandler. This restarts our dialog timeout. """ self.set_timeout_active(None, True) def set_timeout_active(self, dialog, active): """ Start or stop the dialog timer """ if active and not status.InteractiveDebug: trackers.timer_tracker_get().start("wake-timeout", c.UNLOCK_TIMEOUT * 1000, self.on_wake_timeout) else: trackers.timer_tracker_get().cancel("wake-timeout") def on_wake_timeout(self): """ Go back to Sleep if we hit our timer limit """ self.set_timeout_active(None, False) self.manager.cancel_unlock_widget() return False def authentication_result_callback(self, dialog, success): """ Called by authentication success or failure. Either starts the stage despawning process or simply 'blinks' the unlock widget, depending on the outcome. """ if success: if self.clock_widget != None: self.clock_widget.hide() if self.albumart_widget != None: self.albumart_widget.hide() self.unlock_dialog.hide() self.manager.unlock() else: self.unlock_dialog.blink() def authentication_cancel_callback(self, dialog): self.cancel_unlock_widget() def set_message(self, msg): """ Passes along an away-message to the clock. """ if self.clock_widget != None: self.clock_widget.set_message(msg) def initialize_pam(self): return self.unlock_dialog.initialize_auth_client() def raise_unlock_widget(self): """ Bring the unlock widget to the front and make sure it's visible. """ self.reset_timeout() if status.Awake: return status.screen.place_pointer_in_primary_monitor () utils.clear_clipboards(self.unlock_dialog) if self.clock_widget != None: self.clock_widget.stop_positioning() if self.albumart_widget != None: self.albumart_widget.stop_positioning() status.Awake = True if self.info_panel: self.info_panel.refresh_power_state() if self.clock_widget != None: self.clock_widget.show() if self.albumart_widget != None: self.albumart_widget.show() self.unlock_dialog.show() if self.audio_panel != None: self.audio_panel.show_panel() if self.info_panel != None: self.info_panel.update_visibility() if self.osk != None: self.osk.show() def cancel_unlocking(self): if self.unlock_dialog: self.unlock_dialog.cancel_auth_client() def cancel_unlock_widget(self): """ Hide the unlock widget (and others) if the unlock has been canceled """ if not status.Awake: return self.set_timeout_active(None, False) utils.clear_clipboards(self.unlock_dialog) self.unlock_dialog.hide() if self.clock_widget != None: self.clock_widget.hide() if self.albumart_widget != None: self.albumart_widget.hide() if self.audio_panel != None: self.audio_panel.hide() if self.info_panel != None: self.info_panel.hide() if self.osk != None: self.osk.hide() self.unlock_dialog.cancel() status.Awake = False self.update_monitor_views() self.info_panel.update_visibility() def update_monitor_views(self): """ Updates all of our MonitorViews based on the power or Awake states. """ if not status.Awake: if self.clock_widget != None and settings.get_show_clock(): self.clock_widget.start_positioning() if self.albumart_widget != None and settings.get_show_albumart(): self.albumart_widget.start_positioning() for monitor in self.monitors: monitor.show() def destroy_monitor_views(self): """ Destroy all MonitorViews """ for monitor in self.monitors: monitor.destroy() del monitor def do_motion_notify_event(self, event): """ GtkWidget class motion-event handler. Delegate to EventHandler """ return self.event_handler.on_motion_event(event) def do_key_press_event(self, event): """ GtkWidget class key-press-event handler. Delegate to EventHandler """ return self.event_handler.on_key_press_event(event) def do_button_press_event(self, event): """ GtkWidget class button-press-event handler. Delegate to EventHandler """ return self.event_handler.on_button_press_event(event) def update_geometry(self): """ Override BaseWindow.update_geometry() - the Stage should always be the GdkScreen size, unless status.InteractiveDebug is True """ if status.InteractiveDebug: monitor_n = status.screen.get_primary_monitor() self.rect = status.screen.get_monitor_geometry(monitor_n) else: self.rect = status.screen.get_screen_geometry() if status.Debug: print("Stage.update_geometry - new backdrop position: %d, %d new size: %d x %d" % (self.rect.x, self.rect.y, self.rect.width, self.rect.height)) hints = Gdk.Geometry() hints.min_width = self.rect.width hints.min_height = self.rect.height hints.max_width = self.rect.width hints.max_height = self.rect.height hints.base_width = self.rect.width hints.base_height = self.rect.height self.set_geometry_hints(self, hints, Gdk.WindowHints.MIN_SIZE | Gdk.WindowHints.MAX_SIZE | Gdk.WindowHints.BASE_SIZE) # Overlay window management def get_mouse_monitor(self): if status.InteractiveDebug: return status.screen.get_primary_monitor() else: return status.screen.get_mouse_monitor() def maybe_update_layout(self): """ Called on all user events, moves widgets to the currently focused monitor if it changes (whichever monitor the mouse is in) """ current_focus_monitor = status.screen.get_mouse_monitor() if self.last_focus_monitor == -1: self.last_focus_monitor = current_focus_monitor return if self.unlock_dialog and current_focus_monitor != self.last_focus_monitor: self.last_focus_monitor = current_focus_monitor self.overlay.queue_resize() def add_child_widget(self, widget): """ Add a new child to the overlay """ self.overlay.add_overlay(widget) def sink_child_widget(self, widget): """ Move a child to the bottom of the overlay """ self.overlay.reorder_overlay(widget, 0) def position_overlay_child(self, overlay, child, allocation): """ Callback for our GtkOverlay, think of this as a mini- window manager for our Stage. Depending on what type child is, we position it differently. We always call child.get_preferred_size() whether we plan to use it or not - this prevents allocation warning spew, particularly in Gtk >= 3.20. Returning True says, yes draw it. Returning False tells it to skip drawing. If a new widget type is introduced that spawns directly on the stage, it must have its own handling code here. """ if isinstance(child, MonitorView): """ MonitorView is always the size and position of its assigned monitor. This is calculated and stored by the child in child.rect) """ w, h = child.get_preferred_size() allocation.x = child.rect.x allocation.y = child.rect.y allocation.width = child.rect.width allocation.height = child.rect.height return True if isinstance(child, UnlockDialog): """ UnlockDialog always shows on the currently focused monitor (the one the mouse is currently in), and is kept centered. """ monitor = status.screen.get_mouse_monitor() monitor_rect = status.screen.get_monitor_geometry(monitor) min_rect, nat_rect = child.get_preferred_size() allocation.width = nat_rect.width allocation.height = nat_rect.height allocation.x = monitor_rect.x + (monitor_rect.width / 2) - (allocation.width / 2) allocation.y = monitor_rect.y + (monitor_rect.height / 2) - (allocation.height / 2) return True if isinstance(child, ClockWidget) or isinstance(child, AlbumArt): """ ClockWidget and AlbumArt behave differently depending on if status.Awake is True or not. The widgets' halign and valign properties are used to store their gross position on the monitor. This limits the number of possible positions to (3 * 3 * n_monitors) when our screensaver is not Awake, and the widgets have an internal timer that randomizes halign, valign, and current monitor every so many seconds, calling a queue_resize on itself after each timer tick (which forces this function to run). """ min_rect, nat_rect = child.get_preferred_size() if status.Awake: current_monitor = status.screen.get_mouse_monitor() else: current_monitor = child.current_monitor monitor_rect = status.screen.get_monitor_geometry(current_monitor) region_w = monitor_rect.width / 3 region_h = monitor_rect.height if status.Awake: """ If we're Awake, force the clock to track to the active monitor, and be aligned to the left-center. The albumart widget aligns right-center. """ unlock_mw, unlock_nw = self.unlock_dialog.get_preferred_width() """ If, for whatever reason, we need more than 1/3 of the screen to fully display the unlock dialog, reduce our available region width to accomodate it, reducing the allocation for the floating widgets as required. """ if (unlock_nw > region_w): region_w = (monitor_rect.width - unlock_nw) / 2 region_h = monitor_rect.height if isinstance(child, ClockWidget): child.set_halign(Gtk.Align.START) else: child.set_halign(Gtk.Align.END) child.set_valign(Gtk.Align.CENTER) else: if settings.get_allow_floating(): for floater in self.floaters: """ Don't let our floating widgets end up in the same spot. """ if floater is child: continue if floater.get_halign() != child.get_halign() and floater.get_valign() != child.get_valign(): continue region_h = monitor_rect.height / 3 fa = floater.get_halign() ca = child.get_halign() while fa == ca: ca = ALIGNMENTS[random.randint(0, 2)] child.set_halign(ca) fa = floater.get_valign() ca = child.get_valign() while fa == ca: ca = ALIGNMENTS[random.randint(0, 2)] child.set_valign(ca) # Restrict the widget size to the allowable region sizes if necessary. allocation.width = min(nat_rect.width, region_w) allocation.height = min(nat_rect.height, region_h) # Calculate padding required to center widgets within their particular 1/9th of the monitor padding_left = padding_right = (region_w - allocation.width) / 2 padding_top = padding_bottom = (region_h - allocation.height) / 2 halign = child.get_halign() valign = child.get_valign() if halign == Gtk.Align.START: allocation.x = monitor_rect.x + padding_left elif halign == Gtk.Align.CENTER: allocation.x = monitor_rect.x + (monitor_rect.width / 2) - (allocation.width / 2) elif halign == Gtk.Align.END: allocation.x = monitor_rect.x + monitor_rect.width - allocation.width - padding_right if valign == Gtk.Align.START: allocation.y = monitor_rect.y + padding_top elif valign == Gtk.Align.CENTER: allocation.y = monitor_rect.y + (monitor_rect.height / 2) - (allocation.height / 2) elif valign == Gtk.Align.END: allocation.y = monitor_rect.y + monitor_rect.height - allocation.height - padding_bottom return True if isinstance(child, AudioPanel): """ The AudioPanel is only shown when Awake, and attaches itself to the upper-left corner of the active monitor. """ min_rect, nat_rect = child.get_preferred_size() if status.Awake: current_monitor = status.screen.get_mouse_monitor() monitor_rect = status.screen.get_monitor_geometry(current_monitor) allocation.x = monitor_rect.x allocation.y = monitor_rect.y allocation.width = nat_rect.width allocation.height = nat_rect.height else: allocation.x = child.rect.x allocation.y = child.rect.y allocation.width = nat_rect.width allocation.height = nat_rect.height return True if isinstance(child, InfoPanel): """ The InfoPanel can be shown while not Awake, but will only appear if a) We have received notifications while the screensaver is running, or b) we're either on battery or plugged in but with a non-full battery. It attaches itself to the upper-right corner of the monitor. """ min_rect, nat_rect = child.get_preferred_size() if status.Awake: current_monitor = status.screen.get_mouse_monitor() monitor_rect = status.screen.get_monitor_geometry(current_monitor) allocation.x = monitor_rect.x + monitor_rect.width - nat_rect.width allocation.y = monitor_rect.y allocation.width = nat_rect.width allocation.height = nat_rect.height else: allocation.x = child.rect.x + child.rect.width - nat_rect.width allocation.y = child.rect.y allocation.width = nat_rect.width allocation.height = nat_rect.height return True if isinstance(child, OnScreenKeyboard): """ The InfoPanel can be shown while not Awake, but will only appear if a) We have received notifications while the screensaver is running, or b) we're either on battery or plugged in but with a non-full battery. It attaches itself to the upper-right corner of the monitor. """ min_rect, nat_rect = child.get_preferred_size() current_monitor = status.screen.get_mouse_monitor() monitor_rect = status.screen.get_monitor_geometry(current_monitor) allocation.x = monitor_rect.x allocation.y = monitor_rect.y + monitor_rect.height - (monitor_rect.height / 3) allocation.width = monitor_rect.width allocation.height = monitor_rect.height / 3 return True return False cinnamon-screensaver-4.4.1/src/status.py000066400000000000000000000023561357366610100203420ustar00rootroot00000000000000#!/usr/bin/python3 # Our global state vars Active = False # Screensaver visible or not - False when it's completely idle. Locked = False # Independent of Active, whether the unlock dialog will show when we become Awake. Awake = False # Whether the unlock dialog is visible or not. # A list of focusable widgets that the user can tab between in the unlock screen. See FocusNavigator. focusWidgets = [] # This is different than the preference that turns off locking - that only prevents idle locking. The # user can still lock explicitly. The function checks for the existence of correct PAM files, # as well as adjusting the UID if this process is started as root. LockEnabled = True # Enables extra PAM/authentication/notification debugging # TODO: We do a *lot* of logging now, we should just use a debug() function that checks # for debug mode internally, instead of 'if status.Debug' everywhere. Debug = False # Forces the Stage to only cover a single monitor and launch a GtkInspector window. InteractiveDebug = False # If the wallpaper aspect is 'spanned' we will only create one MonitorView and manage it slightly # differently. This is an easy place to keep track of that. This is set in singletons.py. Spanned = False screen = None cinnamon-screensaver-4.4.1/src/tests/000077500000000000000000000000001357366610100176015ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/tests/test-auth000077500000000000000000000006671357366610100214560ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('CinnamonDesktop', '3.0') from gi.repository import CinnamonDesktop, GLib import getpass name = input("Username: ") password = getpass.getpass() def callback(success): if success: print("\n\nAccepted!") else: print("\n\nFailed!") ml.quit() CinnamonDesktop.desktop_check_user_password(name, password, callback) ml = GLib.MainLoop.new(None, True) ml.run() cinnamon-screensaver-4.4.1/src/tests/test-layouts000077500000000000000000000014201357366610100222010ustar00rootroot00000000000000#!/usr/bin/python3 import sys import signal import gettext import gi gi.require_version('Gtk', '3.0') gi.require_version('CScreensaver', '1.0') sys.path.append("/usr/share/cinnamon-screensaver") gettext.install("cinnamon-screensaver", "/usr/share/locale") from gi.repository import Gtk from unlock import PasswordEntry signal.signal(signal.SIGINT, signal.SIG_DFL) class Main: def __init__(self): win = Gtk.Window() box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) win.add(box) self.entry = PasswordEntry() box.pack_start(self.entry, True, True, 2) box.show_all() win.connect("delete-event", lambda w, e: Gtk.main_quit()) win.present() Gtk.main() if __name__ == "__main__": main = Main() cinnamon-screensaver-4.4.1/src/tests/test-notifications000077500000000000000000000017701357366610100233620ustar00rootroot00000000000000#!/usr/bin/python3 import subprocess import time import os print("Assertion: Notifications should not appear while the screensaver is active") print("Test: Activate the screensaver, then send a test notification a couple seconds later.") print("Expected outcome: Notification should *not* appear over the screensaver window.\n") print("Starting cinnamon-screensaver if necessary...") ps_output = subprocess.check_output(["ps", "-A"]) if "cinnamon-screen" not in ps_output.decode("utf-8"): os.system("cinnamon-screensaver &") time.sleep(2) print("Ok\n") print("Locking screen...") os.system("cinnamon-screensaver-command --lock") print("Ok\n") print("waiting a few seconds...") time.sleep(5) print("Ok\n") print("Sending a notification...") os.system("notify-send 'Test notification' 'You should not see this while the screen is locked'") print("Ok\n") print("waiting a few more seconds...") time.sleep(5) os.system("cinnamon-screensaver-command --deactivate") print("Unlocked. Terminating.") quit() cinnamon-screensaver-4.4.1/src/tests/test-osk000077500000000000000000000016271357366610100213060ustar00rootroot00000000000000#!/usr/bin/python3 import sys import signal import gettext import gi gi.require_version('Gtk', '3.0') gi.require_version('CScreensaver', '1.0') sys.path.append("/usr/share/cinnamon-screensaver") gettext.install("cinnamon-screensaver", "/usr/share/locale") from gi.repository import Gtk, CScreensaver from osk import OnScreenKeyboard import status signal.signal(signal.SIGINT, signal.SIG_DFL) class Main: def __init__(self): status.screen = CScreensaver.Screen.new(True) win = Gtk.Window() box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) win.add(box) win.get_style_context().add_class("csstage") self.osk = OnScreenKeyboard() box.pack_start(self.osk, True, True, 2) box.show_all() win.connect("delete-event", lambda w, e: Gtk.main_quit()) win.present() Gtk.main() if __name__ == "__main__": main = Main() cinnamon-screensaver-4.4.1/src/unlock.py000066400000000000000000000300401357366610100203010ustar00rootroot00000000000000#!/usr/bin/python3 # coding: utf-8 import gi from gi.repository import Gtk, Gdk, GObject, CScreensaver, Gio import traceback from util import utils, trackers import status import singletons from baseWindow import BaseWindow from widgets.framedImage import FramedImage from passwordEntry import PasswordEntry from pamhelper.authClient import AuthClient from widgets.transparentButton import TransparentButton class UnlockDialog(BaseWindow): """ The main widget for the unlock dialog - this is a direct child of the Stage's GtkOverlay. It has a number of parts, namely: - The user face image. - The user's real name (or username if the real name is unavailable) - The password entry widget - Unlock and Switch User buttons - A caps lock warning label - An invalid password error label """ __gsignals__ = { 'inhibit-timeout': (GObject.SignalFlags.RUN_LAST, None, ()), 'uninhibit-timeout': (GObject.SignalFlags.RUN_LAST, None, ()), 'authenticate-success': (GObject.SignalFlags.RUN_LAST, None, ()), 'authenticate-failure': (GObject.SignalFlags.RUN_LAST, None, ()), 'authenticate-cancel': (GObject.SignalFlags.RUN_LAST, None, ()) } def __init__(self): super(UnlockDialog, self).__init__() settings = Gio.Settings.new("org.cinnamon.desktop.lockdown") self.set_halign(Gtk.Align.CENTER) self.set_valign(Gtk.Align.CENTER) self.real_name = None self.user_name = None self.bounce_rect = None self.bounce_count = 0 self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) self.box.get_style_context().add_class("unlockbox") self.add(self.box) self.face_image = FramedImage(status.screen.get_low_res_mode()) self.face_image.set_halign(Gtk.Align.CENTER) self.face_image.get_style_context().add_class("faceimage") self.face_image.set_no_show_all(True) self.box.pack_start(self.face_image, False, False, 10) self.realname_label = Gtk.Label(None) self.realname_label.set_alignment(0, 0.5) self.realname_label.set_halign(Gtk.Align.CENTER) self.box.pack_start(self.realname_label, False, False, 10) self.entry_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.box.pack_start(self.entry_box, True, True, 2) self.password_entry = PasswordEntry() trackers.con_tracker_get().connect(self.password_entry, "changed", self.on_password_entry_text_changed) trackers.con_tracker_get().connect(self.password_entry, "button-press-event", self.on_password_entry_button_press) trackers.con_tracker_get().connect(self.password_entry, "activate", self.on_auth_enter_key) self.entry_box.pack_start(self.password_entry, False, False, 15) button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.entry_box.pack_end(button_box, False, False, 0) self.auth_unlock_button = TransparentButton("screensaver-unlock-symbolic", Gtk.IconSize.LARGE_TOOLBAR) self.auth_unlock_button.set_tooltip_text(_("Unlock")) trackers.con_tracker_get().connect(self.auth_unlock_button, "clicked", self.on_unlock_clicked) button_box.pack_start(self.auth_unlock_button, False, False, 4) status.focusWidgets = [self.password_entry, self.auth_unlock_button] if not settings.get_boolean("disable-user-switching"): self.auth_switch_button = TransparentButton("screensaver-switch-users-symbolic", Gtk.IconSize.LARGE_TOOLBAR) self.auth_switch_button.set_tooltip_text(_("Switch User")) trackers.con_tracker_get().connect(self.auth_switch_button, "clicked", self.on_switch_user_clicked) button_box.pack_start(self.auth_switch_button, False, False, 4) status.focusWidgets.append(self.auth_switch_button) vbox_messages = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) self.capslock_label = Gtk.Label("") self.capslock_label.get_style_context().add_class("caps-message") self.capslock_label.set_alignment(0.5, 0.5) vbox_messages.pack_start(self.capslock_label, False, False, 2) self.auth_message_label = Gtk.Label("") self.auth_message_label.get_style_context().add_class("auth-message") self.auth_message_label.set_alignment(0.5, 0.5) vbox_messages.pack_start(self.auth_message_label, False, False, 2) self.box.pack_start(vbox_messages, False, False, 0) self.real_name = utils.get_user_display_name() self.user_name = utils.get_user_name() self.update_realname_label() self.account_client = singletons.AccountsServiceClient if self.account_client.is_loaded: self.on_account_client_loaded(self.account_client) else: trackers.con_tracker_get().connect(self.account_client, "account-loaded", self.on_account_client_loaded) self.keymap = Gdk.Keymap.get_default() trackers.con_tracker_get().connect(self.keymap, "state-changed", self.keymap_handler) self.keymap_handler(self.keymap) self.auth_client = AuthClient() trackers.con_tracker_get().connect(self.auth_client, "auth-success", self.on_authentication_success) trackers.con_tracker_get().connect(self.auth_client, "auth-failure", self.on_authentication_failure) trackers.con_tracker_get().connect(self.auth_client, "auth-cancel", self.on_authentication_cancelled) trackers.con_tracker_get().connect(self.auth_client, "auth-busy", self.on_authentication_busy_changed) trackers.con_tracker_get().connect(self.auth_client, "auth-prompt", self.on_authentication_prompt_changed) self.box.show_all() def initialize_auth_client(self): return self.auth_client.initialize() def cancel_auth_client(self): self.clear_entry() self.auth_client.cancel() def on_authentication_success(self, auth_client): self.clear_entry() self.emit("authenticate-success") def on_authentication_failure(self, auth_client): """ Called upon authentication failure, clears the password, sets an error message, and refocuses the password entry. """ self.clear_entry() self.auth_message_label.set_text(_("Incorrect password")) self.emit("authenticate-failure") self.emit("uninhibit-timeout") def on_authentication_cancelled(self, auth_client): self.emit("authenticate-cancel") def on_authentication_busy_changed(self, auth_client, busy): if busy: self.auth_message_label.set_text("") self.clear_entry() self.entry_box.set_sensitive(False) self.password_entry.start_progress() self.password_entry.set_placeholder_text (_("Checking...")) else: self.entry_box.set_sensitive(True) self.password_entry.stop_progress() self.password_entry.set_placeholder_text (self.password_entry.placeholder_text) def on_authentication_prompt_changed(self, auth_client, prompt): if "password:" in prompt.lower(): prompt = _("Please enter your password...") else: prompt = prompt.replace(":", "") self.password_entry.placeholder_text = prompt self.password_entry.set_placeholder_text(self.password_entry.placeholder_text) def cancel(self): """ Clears the auth message text if we have any. """ self.auth_message_label.set_text("") def queue_key_event(self, event): """ Takes a propagated key event from the stage and passes it to the entry widget, possibly queueing up the first character of the password. """ if not self.password_entry.get_realized(): self.password_entry.realize() self.password_entry.grab_focus() self.password_entry.event(event) def keymap_handler(self, keymap): """ Handler for the GdkKeymap changing - updates our capslock indicator label. """ if keymap.get_caps_lock_state(): self.capslock_label.set_text(_("You have the Caps Lock key on.")) else: self.capslock_label.set_text("") def on_account_client_loaded(self, client): """ Handler for the AccountsService - requests the user real name and .face image. """ if client.get_real_name() != None: self.real_name = client.get_real_name() self.update_realname_label() if client.get_face_path() != None: self.face_image.set_from_path(client.get_face_path()) self.face_image.show() def on_password_entry_text_changed(self, editable): """ Handler for the password entry text changing - this controls the sensitivity of the unlock button, as well as returning visual focus to the entry any time a key event is received. """ if not self.password_entry.has_focus(): self.password_entry.grab_focus() def on_password_entry_button_press(self, widget, event): """ Prevents the usual copy/paste popup when right-clicking the PasswordEntry. """ if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def on_unlock_clicked(self, button=None): """ Callback for the unlock button. Activates the 'progress' animation in the GtkEntry, and attempts to authenticate the password. During this time, we also inhibit the unlock timeout, so we don't fade out while waiting for an authentication result (highly unlikely.) """ self.emit("inhibit-timeout") text = self.password_entry.get_text() # We must end with a newline, fgets relies upon that to continue. if text[-1:] != "\n": text += "\n" self.auth_client.message_to_child(text) def on_auth_enter_key(self, widget): """ Implicitly activates the unlock button when the Enter/Return key is pressed. """ self.on_unlock_clicked() def on_switch_user_clicked(self, widget): """ Callback for the switch-user button. """ utils.do_user_switch() def clear_entry(self): """ Clear the password entry widget. """ self.password_entry.set_text("") def update_realname_label(self): """ Updates the name label to the current real_name. """ self.realname_label.set_text(self.real_name) def blink(self): GObject.timeout_add(75, self.on_blink_tick) def on_blink_tick(self, data=None): window = self.get_window() if window == None: return False x, y = window.get_position() if self.bounce_count < 6: if self.bounce_count % 2 == 0: y += 6 else: y -= 6 self.get_window().move(x, y) self.queue_draw() self.bounce_count += 1 return True self.bounce_count = 0 return False cinnamon-screensaver-4.4.1/src/util/000077500000000000000000000000001357366610100174145ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/util/Makefile.am000066400000000000000000000007131357366610100214510ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = appdir = $(datadir)/cinnamon-screensaver/util app_PYTHON = \ __init__.py \ eventHandler.py \ fader.py \ focusNavigator.py \ grabHelper.py \ keybindings.py \ settings.py \ trackers.py \ utils.py MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/util/__init__.py000066400000000000000000000000001357366610100215130ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/util/eventHandler.py000066400000000000000000000046161357366610100224140ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gdk import status from util.keybindings import KeyBindings MOTION_THRESHOLD = 100 class EventHandler: """ The EventHandler receives all user key, button and motion events for the application. At various points it can be receiving them from the Stage window, an offscreen window, or the root GdkWindow. All events are stopped from passing beyond this point, to prevent any unintended events from propagating to Cinnamon or Muffin. """ def __init__(self, manager): self.manager = manager self.keybindings_handler = KeyBindings(manager) self.last_x = -1 self.last_y = -1 def on_user_activity(self): """ Any user event is a 'wake' event, and is propagated to the stage in order to reset our unlock cancellation timer. """ self.manager.simulate_user_activity() def on_motion_event(self, event): """ Any mouse movement is sent here - there is a threshold to reach when asleep, so that inadvertant motion doesn't wake the system unintentionally. """ if status.Awake: self.on_user_activity() return Gdk.EVENT_PROPAGATE if self.last_x == -1 or self.last_y == -1: self.last_x = event.x self.last_y = event.y return Gdk.EVENT_PROPAGATE distance = max(abs(self.last_x - event.x), abs(self.last_y - event.y)) if distance > MOTION_THRESHOLD: self.on_user_activity() return Gdk.EVENT_PROPAGATE def on_button_press_event(self, event): """ Any button presses are swallowed after interacting with their receiving widgets (in the case of buttons, entry, etc...) """ self.on_user_activity() return Gdk.EVENT_STOP def on_key_press_event(self, event): """ Any key events are checked with the KeybindingHandler in case a media shortcut is being used, or it's a special keystroke such as Escape or tab. Any other presses are sent to the password entry or swallowed. """ if self.keybindings_handler.maybe_handle_event(event): return Gdk.EVENT_STOP if status.Active: if status.Locked: self.manager.queue_dialog_key_event(event) self.on_user_activity() return Gdk.EVENT_STOP cinnamon-screensaver-4.4.1/src/util/fader.py000066400000000000000000000072221357366610100210520ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import GLib, GObject class Fader: """ The Fader is used by the Stage to fade in from the desktop. It uses a widget tick callback to change the opacity over time. """ def __init__(self, widget): self.widget = widget self.finished_cb = None self.repositioned = False self.starting_opacity = 0.0 self.current_opacity = 0.0 self.target_opacity = 0.0 self.tick_id = 0 self.start_time = 0 self.end_time = 0 def fade_in(self, ms, reposition_cb=None, finished_cb=None): GObject.idle_add(self._fade_in_idle, ms, reposition_cb, finished_cb) def fade_out(self, ms, finished_cb=None): GObject.idle_add(self._fade_out_idle, ms, finished_cb) def cancel(self): if self.tick_id > 0: self.widget.remove_tick_callback(self.tick_id) self.tick_id = 0 def _fade_in_idle(self, ms, reposition_cb=None, finished_cb=None): self.finished_cb = finished_cb self.reposition_cb = reposition_cb self.current_opacity = self.starting_opacity = self.widget.get_opacity() self.target_opacity = 1.0 if self.widget.get_mapped(): self.start_time = self.widget.get_frame_clock().get_frame_time() self.end_time = self.start_time + (ms * 1000) # ms to microsec if self.tick_id == 0: self.tick_id = self.widget.add_tick_callback(self._on_frame_tick_fade_in) self._fade_in_step(self.start_time) else: self.finished_cb() return GLib.SOURCE_REMOVE def _fade_out_idle(self, ms, finished_cb=None): self.finished_cb = finished_cb self.current_opacity = self.starting_opacity = self.widget.get_opacity() self.target_opacity = 0.0 if self.widget.get_mapped(): self.start_time = self.widget.get_frame_clock().get_frame_time() self.end_time = self.start_time + (ms * 1000) # ms to microsec if self.tick_id == 0: self.tick_id = self.widget.add_tick_callback(self._on_frame_tick_fade_out) self._fade_out_step(self.start_time) else: self.finished_cb() return GLib.SOURCE_REMOVE def _on_frame_tick_fade_in(self, widget, clock, data=None): now = clock.get_frame_time() self._fade_in_step(now) if not self.repositioned and self.current_opacity > .03: self.repositioned = True self.reposition_cb() if self.current_opacity == self.target_opacity: self.tick_id = 0 self.finished_cb() return GLib.SOURCE_REMOVE return GLib.SOURCE_CONTINUE def _fade_in_step(self, now): if now < self.end_time: t = ((now - self.start_time) / (self.end_time - self.start_time) * self.target_opacity) else: t = self.target_opacity self.current_opacity = t self.widget.set_opacity(self.current_opacity) def _on_frame_tick_fade_out(self, widget, clock, data=None): now = clock.get_frame_time() self._fade_out_step(now) if self.current_opacity == self.target_opacity: self.tick_id = 0 self.finished_cb() return GLib.SOURCE_REMOVE return GLib.SOURCE_CONTINUE def _fade_out_step(self, now): if now < self.end_time: t = self.starting_opacity - (((now - self.start_time) / (self.end_time - self.start_time)) * self.starting_opacity) else: t = self.target_opacity self.current_opacity = t self.widget.set_opacity(self.current_opacity) cinnamon-screensaver-4.4.1/src/util/focusNavigator.py000066400000000000000000000045421357366610100227650ustar00rootroot00000000000000#!/usr/bin/python3 # coding: utf-8 from gi.repository import Gtk import status class FocusNavigator: """ FocusNavigator helps with tab navigation between widgets in our status.focusWidgets list. Since we handle most user events ourselves, we also need to handle Tab events correctly. """ def __init__(self, widgets=[]): status.focusWidgets = widgets def _get_focus_index(self): widgets = status.focusWidgets focus_index = -1 for widget in widgets: if widget.has_focus(): focus_index = widgets.index(widget) break return focus_index def _focus_first_possible(self): widgets = status.focusWidgets for widget in widgets: if widget.get_sensitive(): widget.grab_focus() widget.grab_default() break def _focus_next(self, current): widgets = status.focusWidgets new = current + 1 if new >= len(widgets): new = 0 if not widgets[new].get_sensitive(): self._focus_next(new) return widgets[new].grab_focus() widgets[new].grab_default() def _focus_previous(self, current): widgets = status.focusWidgets new = current - 1 if new < 0: new = len(widgets) - 1 if not widgets[new].get_sensitive(): self._focus_previous(new) return widgets[new].grab_focus() widgets[new].grab_default() def navigate(self, reverse): current_index = self._get_focus_index() if current_index == -1: self._focus_first_possible() if reverse: self._focus_previous(current_index) else: self._focus_next(current_index) def activate_focus(self): widgets = status.focusWidgets focus_index = self._get_focus_index() if focus_index == -1: return widget = widgets[focus_index] if isinstance(widget, Gtk.Button): widget.clicked() elif isinstance(widget, Gtk.Entry): widget.activate() def get_focused_widget(self): widgets = status.focusWidgets focus_index = self._get_focus_index() if focus_index == -1: return None return widgets[focus_index] cinnamon-screensaver-4.4.1/src/util/grabHelper.py000066400000000000000000000122631357366610100220450ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gdk, Gtk, GdkX11, CScreensaver import time from util.eventHandler import EventHandler class GrabHelper: """ GrabHelper keeps track of keyboard and mouse grabs for the screensaver - we require these grabs to be successful in order for the screensaver to activate. This prevents muffin from receiving any key events (and activating any keyboard shortcuts other than ones we want to allow.) """ def __init__(self, manager = None): if manager: self.offscreen = OffscreenWindow(manager) self.offscreen.show() else: self.offscreen = None self.screen = Gdk.Screen.get_default() self.mouse_grab_window = None self.keyboard_grab_window = None self.mouse_hide_cursor = False def grab_root(self, hide_cursor): root = self.screen.get_root_window() return self.grab_window(root, hide_cursor) def grab_offscreen(self, hide_cursor): if self.offscreen == None: print("can't grab offscreen without an offscreen widget") return False window = self.offscreen.get_window() return self.grab_window(window, hide_cursor) def grab_window(self, window, hide_cursor): got_keyboard = False got_mouse = False def try_grab(grab_func, *args): retries = 0 while retries < 4: got = grab_func(*args) if got: return True retries = retries + 1 time.sleep(1) return False got_keyboard = try_grab(self.grab_keyboard, window) if not got_keyboard: try: CScreensaver.Screen.nuke_focus() except: pass got_keyboard = try_grab(self.grab_keyboard, window) got_mouse = try_grab(self.grab_mouse, window, hide_cursor) if not got_mouse or not got_keyboard: if got_keyboard: self.release_keyboard() if got_mouse: self.release_mouse() return False return True def move_to_window(self, window, hide_cursor): result = False while not result: result = self.move_keyboard(window) Gdk.flush() result = False while not result: result = self.move_mouse(window, hide_cursor) Gdk.flush() def release(self): self.release_mouse() self.release_keyboard() self.screen.get_display().sync() def reset_mouse(self): if self.mouse_grab_window is not None: self.mouse_grab_window = None self.mouse_hide_cursor = False def release_mouse(self): if self.mouse_grab_window is not None: Gdk.pointer_ungrab(Gdk.CURRENT_TIME) self.reset_mouse() def grab_mouse(self, window, hide_cursor = False): if hide_cursor: cursor = Gdk.Cursor(Gdk.CursorType.BLANK_CURSOR) else: cursor = None status = Gdk.pointer_grab(window, True, 0, None, cursor, Gdk.CURRENT_TIME) if status == Gdk.GrabStatus.SUCCESS: self.reset_mouse() self.mouse_grab_window = window self.mouse_hide_cursor = hide_cursor else: print("couldn't grab mouse") return status == Gdk.GrabStatus.SUCCESS def move_mouse(self, window, hide_cursor): GdkX11.x11_grab_server() old_window = self.mouse_grab_window if old_window: self.release_mouse() res = self.grab_mouse(window, hide_cursor) if not res: time.sleep(1) res = self.grab_mouse(window, hide_cursor) if not res and old_window: self.grab_mouse(old_window) GdkX11.x11_ungrab_server() return res def reset_keyboard(self): if self.keyboard_grab_window is not None: self.keyboard_grab_window = None def release_keyboard(self): if self.keyboard_grab_window is not None: Gdk.keyboard_ungrab(Gdk.CURRENT_TIME) self.reset_keyboard() def grab_keyboard(self, window): status = Gdk.keyboard_grab(window, False, Gdk.CURRENT_TIME) if status == Gdk.GrabStatus.SUCCESS: self.reset_keyboard() self.keyboard_grab_window = window else: print("couldn't grab keyboard") return status == Gdk.GrabStatus.SUCCESS def move_keyboard(self, window): GdkX11.x11_grab_server() old_window = self.keyboard_grab_window if old_window: self.release_keyboard() res = self.grab_keyboard(window) if not res: time.sleep(1) res = self.grab_keyboard(window) if not res and old_window: self.grab_keyboard(old_window) GdkX11.x11_ungrab_server() return res class OffscreenWindow(Gtk.Invisible): def __init__(self, manager): super(OffscreenWindow, self).__init__() self.event_handler = EventHandler(manager) def do_key_press_event(self, event): return self.event_handler.on_key_press_event(event) cinnamon-screensaver-4.4.1/src/util/keybindings.py000066400000000000000000000102161357366610100222740ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('CDesktopEnums', '3.0') from gi.repository import Gtk, GObject, Gdk, Gio, CinnamonDesktop from gi.repository.CDesktopEnums import MediaKeyType as MK import status import singletons from util import settings ALLOWED_ACTIONS = [MK.MUTE, MK.VOLUME_UP, MK.VOLUME_UP_QUIET, MK.VOLUME_DOWN, MK.VOLUME_DOWN_QUIET, MK.MIC_MUTE, MK.EJECT, MK.PLAY, MK.PAUSE, MK.STOP, MK.PREVIOUS, MK.NEXT, MK.REWIND, MK.FORWARD, MK.REPEAT, MK.RANDOM, MK.TOUCHPAD, MK.TOUCHPAD_ON, MK.TOUCHPAD_OFF, MK.SHUTDOWN, MK.SUSPEND, MK.HIBERNATE, MK.SCREEN_BRIGHTNESS_UP, MK.SCREEN_BRIGHTNESS_DOWN, MK.ROTATE_VIDEO, MK.KEYBOARD_BRIGHTNESS_UP, MK.KEYBOARD_BRIGHTNESS_DOWN, MK.KEYBOARD_BRIGHTNESS_TOGGLE] class ShortcutAction(GObject.GObject): """ A class representing a group of keybindings for a specific media key action. """ def __init__(self, action, bindings): super(ShortcutAction, self).__init__() self.action = action self.bindings = bindings self.parsed = [] for binding in self.bindings: key, codes, mods = Gtk.accelerator_parse_with_keycode(binding) self.parsed.append((key, codes, mods)) def activate(self, key, keycode, mods): for binding in self.parsed: if (key == binding[0] or keycode in binding[1]) and mods == binding[2]: return self.action return -1 class KeyBindings(GObject.GObject): """ Receives keystrokes from the EventHandler - it checks for media key activation, as well as special keys like Escape or Tab, and performs the appropriate actions. """ def __init__(self, manager): super(KeyBindings, self).__init__() self.manager = manager self.client = singletons.KeybindingHandlerClient self.keymap = Gdk.Keymap.get_default() self.media_key_settings = Gio.Settings(schema_id="org.cinnamon.desktop.keybindings.media-keys") self.shortcut_actions = [] self.load_bindings() def load_bindings(self): self.shortcut_actions = [] for action_id in ALLOWED_ACTIONS: bindings = self.media_key_settings.get_strv(CinnamonDesktop.desktop_get_media_key_string(action_id)) action = ShortcutAction(action_id, bindings) self.shortcut_actions.append(action) def maybe_handle_event(self, event): if event.type != Gdk.EventType.KEY_PRESS: return False filtered_state = Gdk.ModifierType(event.state & ~(Gdk.ModifierType.MOD2_MASK | Gdk.ModifierType.LOCK_MASK)) if filtered_state == 0 and event.keyval == Gdk.KEY_Escape: if status.Awake: self.manager.cancel_unlock_widget() return True if event.keyval == Gdk.KEY_Menu: return True if status.Awake: if (event.keyval in (Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab)): if event.keyval == Gdk.KEY_ISO_Left_Tab: self.manager.propagate_tab_event(True) else: self.manager.propagate_tab_event(False) return True elif event.keyval == Gdk.KEY_space and isinstance(self.manager.get_focused_widget(), Gtk.Button): self.manager.propagate_activation() return True if settings.get_allow_shortcuts(): for entry in self.shortcut_actions: res = entry.activate(event.keyval, event.hardware_keycode, filtered_state) if res == -1: continue else: self.client.handle_keybinding(res) return True return False cinnamon-screensaver-4.4.1/src/util/settings.py000066400000000000000000000107441357366610100216340ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gio # Background settings, the only one interested in this is Backgrounds in # singletons.py, and then only for the "changed" signal - it reloads # any individual gsettings internally. bg_settings = Gio.Settings(schema_id="org.cinnamon.desktop.background") # Screensaver settings - we have no need to listen to changes here, # They're read anew each time they're used, and while the screensaver # is active, the user won't be changing them. ss_settings = Gio.Settings(schema_id="org.cinnamon.desktop.screensaver") DEFAULT_MESSAGE_KEY = "default-message" SCREENSAVER_NAME_KEY = "screensaver-name" USER_SWITCH_ENABLED_KEY = "user-switch-enabled" IDLE_ACTIVATE_KEY = "idle-activation-enabled" LOCK_ENABLED_KEY = "lock-enabled" LOCK_DELAY_KEY = "lock-delay" USE_CUSTOM_FORMAT_KEY = "use-custom-format" DATE_FORMAT_KEY = "date-format" TIME_FORMAT_KEY = "time-format" FONT_DATE_KEY = "font-date" FONT_MESSAGE_KEY = "font-message" FONT_TIME_KEY = "font-time" KB_LAYOUT_KEY = "layout-group" SHOW_CLOCK_KEY = "show-clock" SHOW_ALBUMART = "show-album-art" ALLOW_SHORTCUTS = "allow-keyboard-shortcuts" ALLOW_MEDIA_CONTROL = "allow-media-control" SHOW_INFO_PANEL = "show-info-panel" FLOATING_WIDGETS = "floating-widgets" # Interface settings - the same logic applies here as above - we don't # need to listen to changes to these. if_settings = Gio.Settings(schema_id="org.cinnamon.desktop.interface") KBD_LAYOUT_SHOW_FLAGS = "keyboard-layout-show-flags" KBD_LAYOUT_USE_CAPS = "keyboard-layout-use-upper" KBD_LAYOUT_PREFER_VARIANT = "keyboard-layout-prefer-variant-names" osk_settings = Gio.Settings(schema_id="org.cinnamon.keyboard") OSK_TYPE = "keyboard-type" OSK_SIZE = "keyboard-size" OSK_ACTIVATION = "activation-mode" a11y_settings = Gio.Settings(schema_id="org.cinnamon.desktop.a11y.applications") OSK_A11Y_ENABLED = "screen-keyboard-enabled" # Every setting has a getter (and setter, rarely). This is mainly for # organizational purposes and cleanliness - it's easier to read in the # main code if you see "settings.get_default_away_message()" than seeing # "settings.ss_settings.get_string(settings.DEFAULT_MESSAGE_KEY)" or keeping # instances of GioSettings wherever we need them. def _check_string(string): if string and string != "": return string return "" def get_default_away_message(): msg = ss_settings.get_string(DEFAULT_MESSAGE_KEY) return _check_string(msg) def get_user_switch_enabled(): return ss_settings.get_boolean(USER_SWITCH_ENABLED_KEY) def get_idle_activate(): return ss_settings.get_boolean(IDLE_ACTIVATE_KEY) def get_idle_lock_enabled(): return ss_settings.get_boolean(LOCK_ENABLED_KEY) def get_idle_lock_delay(): return ss_settings.get_uint(LOCK_DELAY_KEY) def get_use_custom_format(): return ss_settings.get_boolean(USE_CUSTOM_FORMAT_KEY) def get_custom_date_format(): date_format = ss_settings.get_string(DATE_FORMAT_KEY) return _check_string(date_format) def get_custom_time_format(): time_format = ss_settings.get_string(TIME_FORMAT_KEY) return _check_string(time_format) def get_date_font(): date_font = ss_settings.get_string(FONT_DATE_KEY) return _check_string(date_font) def get_message_font(): message_font = ss_settings.get_string(FONT_MESSAGE_KEY) return _check_string(message_font) def get_time_font(): time_font = ss_settings.get_string(FONT_TIME_KEY) return _check_string(time_font) def get_show_flags(): return if_settings.get_boolean(KBD_LAYOUT_SHOW_FLAGS) def get_show_upper_case_layout(): return if_settings.get_boolean(KBD_LAYOUT_USE_CAPS) def get_use_layout_variant_names(): return if_settings.get_boolean(KBD_LAYOUT_PREFER_VARIANT) def get_kb_group(): return ss_settings.get_int(KB_LAYOUT_KEY) def set_kb_group(group): return ss_settings.set_int(KB_LAYOUT_KEY, group) def get_show_clock(): return ss_settings.get_boolean(SHOW_CLOCK_KEY) def get_show_albumart(): return ss_settings.get_boolean(SHOW_ALBUMART) def get_allow_shortcuts(): return ss_settings.get_boolean(ALLOW_SHORTCUTS) def get_allow_media_control(): return ss_settings.get_boolean(ALLOW_MEDIA_CONTROL) def get_show_info_panel(): return ss_settings.get_boolean(SHOW_INFO_PANEL) def get_allow_floating(): return ss_settings.get_boolean(FLOATING_WIDGETS) def get_osk_type(): return osk_settings.get_string(OSK_TYPE) def get_osk_a11y_active(): return (a11y_settings.get_boolean(OSK_A11Y_ENABLED) and osk_settings.get_string(OSK_ACTIVATION) == 'accessible')cinnamon-screensaver-4.4.1/src/util/trackers.py000066400000000000000000000162721357366610100216140ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import GObject, GLib DEBUG_TIMERS=False DEBUG_SIGNALS=False def _debug(*args): first = True output = "" for arg in args: if not first: output += ": " first = False output += str(arg) print(output) def debug_timers(*args): if DEBUG_TIMERS: _debug(*args) def debug_sigs(*args): if DEBUG_SIGNALS: _debug(*args) class TimerTracker: """ Utility class for tracking mainloop timers - they are stored as [name : timeout id] pairs. This is simply a way of managing them without having to individually track source ids. """ def __init__(self): self.timers = {} def do_callback(self, callback, name, *args): ret = callback(*args) if ret: return True self.cancel(name) return False def start(self, name, duration, callback, *args): self.cancel(name) timeout_id = GObject.timeout_add(duration, self.do_callback, callback, name, *args) debug_timers("adding timer of name", name, "duration (sec)", duration / 1000.0, "callback", str(callback), "id", timeout_id) self.timers[name] = timeout_id def start_seconds(self, name, duration, callback, *args): self.cancel(name) timeout_id = GObject.timeout_add_seconds(duration, self.do_callback, callback, name, *args) debug_timers("adding timer of name", name, "duration (sec)", duration, "callback", str(callback), "id", timeout_id) self.timers[name] = timeout_id def add_idle(self, name, callback, *args): self.cancel(name) idle_id = GObject.idle_add(self.do_callback, callback, name, *args) debug_timers("adding idle callback of name", name, "callback", str(callback), "id", idle_id) self.timers[name] = idle_id def cancel(self, name): try: if self.timers[name]: if GLib.MainContext.default().find_source_by_id(self.timers[name]): GObject.source_remove(self.timers[name]) debug_timers("cancel succeeded for", name, "source id", self.timers[name]) else: debug_timers("cancel failed (not a valid id) for", name, "source id", self.timers[name]) del self.timers[name] except KeyError: pass def dump_timer_list(self): print("Timer tracker dump:") i = 0 for timer in self.timers: print(timer) i += 1 print("%d timers total" % i) timer_tracker = TimerTracker() def timer_tracker_get(): global timer_tracker return timer_tracker class ConnectionTracker: """ Utility class for tracking GObject signal connections. It is tracked in [ name : (source id, instance) ] pairs. The name is generated as a magic string consisting of "instance hash+signal name+callback hash". As a convenience, we hang a weak reference on both the signal caller's instance as well as the callback's instance. If either of these instances are destroyed we will receive a notification and automatically attempt to disconnect the original signal connection. This will frequently fail, depending on what gets destroyed first (destruction of the source instance will usually mean implicit destruction of the callback.) """ def __init__(self): self.connections = {} def _name(self, instance, signal, callback): name = "%s-%s-%s" % (str(hash(instance)), signal, str(hash(callback))) return name def _disconnect_by_name(self, name): try: if self.connections[name]: (source_id, instance) = self.connections[name] if GObject.signal_handler_is_connected(instance, source_id): instance.disconnect(source_id) debug_sigs("_disconnect_by_name succeeded for", name, "id", source_id) else: debug_sigs("_disconnect_by_name failed (not a valid id) for", name, "id", source_id) del self.connections[name] except KeyError as e: debug_sigs("_disconnect_by_name failed (not being tracked or already disco'd) for", name, str(e)) def _connect_to_dispose(self, name, instance, callback): callback_instance = None try: callback_instance = callback.__self__ if callback_instance and isinstance(callback_instance, GObject.GObject): callback_instance.weak_ref(self._cleanup_disposed, name, "callback_instance") debug_sigs("_connect_to_dispose (callback_instance)", name) except: pass instance.weak_ref(self._cleanup_disposed, name, "instance") debug_sigs("_connect_to_dispose (instance)", name) def _cleanup_disposed(self, name, type_name): debug_sigs("_cleanup_disposed", type_name, name) self._disconnect_by_name(name) def connect(self, instance, signal, callback, *data): """ Wrapper for instance.connect() """ name = self._name(instance, signal, callback) self._disconnect_by_name(name) if data: source_id = instance.connect(signal, callback, *data) else: source_id = instance.connect(signal, callback) self.connections[name] = (source_id, instance) debug_sigs("connected", name, "id", source_id) self._connect_to_dispose(name, instance, callback) def connect_after(self, instance, signal, callback, *data): """ Wrapper for instance.connect_after() """ name = self._name(instance, signal, callback) self._disconnect_by_name(name) if data: source_id = instance.connect_after(signal, callback, data) else: source_id = instance.connect_after(signal, callback) self.connections[name] = (source_id, instance) debug_sigs("connected after", name, "id", source_id) self._connect_to_dispose(name, instance, callback) def handler_block(self, instance, signal, callback): """ Wrapper for g_signal_handler_block(). """ name = self._name(instance, signal, callback) if self.connections[name]: self.connections[name][1].handler_block(self.connections[name][0]) def handler_unblock(self, instance, signal, callback): """ Wrapper for g_signal_handler_unblock() """ name = self._name(instance, signal, callback) if self.connections[name]: self.connections[name][1].handler_unblock(self.connections[name][0]) def disconnect(self, instance, signal, callback): """ Wrapper for instance.disconnect() """ name = self._name(instance, signal, callback) debug_sigs("disconnect", name) self._disconnect_by_name(name) def dump_connections_list(self): print("Connection tracker dump:") i = 0 for connection in self.connections: print(connection) i += 1 print("%d connections total" % i) connection_tracker = ConnectionTracker() def con_tracker_get(): global connection_tracker return connection_tracker cinnamon-screensaver-4.4.1/src/util/utils.py000066400000000000000000000075661357366610100211440ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import GLib, Gio, Gdk, Gtk import os import grp import subprocess import xapp.os import config import status # Various utility functions that are used in multiple places. def nofail_locale_to_utf8(string): try: ret = GLib.locale_to_utf8(string, -1, 0, 0) except: try: ret, br, bw = GLib.locale_to_utf8(string, -1) except: ret = string return ret def get_user_name(): name = GLib.get_user_name() utf8_name = None if name: utf8_name = nofail_locale_to_utf8(name) return utf8_name def get_user_display_name(): name = GLib.get_real_name() if not name or name == "Unknown": name = get_user_name() utf8_name = None if name: utf8_name = nofail_locale_to_utf8(name) return utf8_name def get_host_name(): name = GLib.get_host_name() utf8_name = None if name: utf8_name = nofail_locale_to_utf8(name) return utf8_name def user_can_lock(): if not status.LockEnabled: return False name = get_user_name() # KeyError is generated if group doesn't exist, ignore it and allow lock try: group = grp.getgrnam("nopasswdlogin") if name in group.gr_mem: return False except KeyError: pass # Don't lock the screensaver in guest or live sessions if xapp.os.is_live_session() or xapp.os.is_guest_session(): return False return True def process_is_running(name): res = "" try: res = subprocess.check_output(["pidof", name]) except subprocess.CalledProcessError: pass return res != "" def do_user_switch(): if process_is_running("mdm"): command = "%s %s" % ("mdmflexiserver", "--startnew Standard") ctx = Gdk.Display.get_default().get_app_launch_context() app = Gio.AppInfo.create_from_commandline(command, "mdmflexiserver", 0) if app: app.launch(None, ctx) elif process_is_running("gdm"): command = "%s %s" % ("gdmflexiserver", "--startnew Standard") ctx = Gdk.Display.get_default().get_app_launch_context() app = Gio.AppInfo.create_from_commandline(command, "gdmflexiserver", 0) if app: app.launch(None, ctx) elif os.getenv("XDG_SEAT_PATH") is not None: try: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) bus.call_sync("org.freedesktop.DisplayManager", os.getenv("XDG_SEAT_PATH"), "org.freedesktop.DisplayManager.Seat", "SwitchToGreeter", None, None, Gio.DBusCallFlags.NONE, -1, None) except GLib.Error as err: print("Switch user failed: " + err.message) def session_is_cinnamon(): if "cinnamon" in GLib.getenv("DESKTOP_SESSION"): if GLib.find_program_in_path("cinnamon-session-quit"): return True return False def override_user_time(window): ev_time = Gtk.get_current_event_time() window.set_user_time(ev_time) def debug_allocation(alloc): print("x:%d, y:%d, width:%d, height:%d" % (alloc.x, alloc.y, alloc.width, alloc.height)) def CLAMP(value, low, high): return max(low, min(value, high)) def have_gtk_version(version_string): [major, minor, micro] = version_string.split(".", 3) return Gtk.get_major_version() >= eval(major) and \ Gtk.get_minor_version() >= eval(minor) and \ Gtk.get_micro_version() >= eval(micro) def clear_clipboards(widget): clipboard = widget.get_clipboard(Gdk.SELECTION_PRIMARY) clipboard.clear() clipboard.set_text("", -1) clipboard = widget.get_clipboard(Gdk.SELECTION_CLIPBOARD) clipboard.clear() clipboard.set_text("", -1) def do_quit(): Gtk.main_quit() cinnamon-screensaver-4.4.1/src/volumeControl.py000066400000000000000000000134221357366610100216630ustar00rootroot00000000000000#!/usr/bin/python3 import gi gi.require_version('Cvc', '1.0') from gi.repository import Gtk, Cvc, Gdk from widgets.volumeSlider import VolumeSlider from util import trackers, utils class VolumeControl(Gtk.Box): """ A direct child of the AudioPanel, it provides the volume slider. This shows any time we are Awake, regardless of any media player connections. We use libcvc to interact with the audio subsystem. """ def __init__(self): super(VolumeControl, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self.output = None self.controller = None self.volume_slider = VolumeSlider() self.volume_slider.show_all() self.set_no_show_all(True) self.pack_start(self.volume_slider, False, False, 6) self.initialize_sound_controller() def initialize_sound_controller(self): self.controller = Cvc.MixerControl(name="cinnamon-screensaver") trackers.con_tracker_get().connect(self.controller, "state-changed", self.on_state_changed) trackers.con_tracker_get().connect(self.controller, "default-sink-changed", self.on_state_changed) self.controller.open() self.on_state_changed() def on_state_changed(self, controller=None, state=0): if controller and controller != self.controller: old = self.controller self.controller = controller del old if self.controller.get_state() == Cvc.MixerControlState.READY: new = self.controller.get_default_sink() if new is not None: if self.output and self.output != new: old = self.output self.output = new del old else: self.output = new trackers.con_tracker_get().connect(self.output, "notify::is-muted", self.on_volume_changed) trackers.con_tracker_get().connect(self.output, "notify::volume", self.on_volume_changed) trackers.con_tracker_get().connect(self.volume_slider, "value-changed", self.on_volume_slider_changed) trackers.con_tracker_get().connect(self.volume_slider, "button-press-event", self.on_button_press_event) if not utils.have_gtk_version("3.18.0"): trackers.con_tracker_get().connect(self.volume_slider, "scroll-event", self.on_scroll_event) self.on_volume_changed(None, None) self.show() return self.hide() def on_volume_changed(self, output, pspec): vol = self.output.props.volume muted = self.output.get_is_muted() max_vol = self.controller.get_vol_max_norm() normalized_volume = int(min((vol / max_vol * 100), 100)) self.update_slider(normalized_volume, muted) def update_slider(self, volume, muted): trackers.con_tracker_get().handler_block(self.volume_slider, "value-changed", self.on_volume_slider_changed) self.volume_slider.set_muted(muted) self.volume_slider.set_value(volume) trackers.con_tracker_get().handler_unblock(self.volume_slider, "value-changed", self.on_volume_slider_changed) def on_volume_slider_changed(self, range, data=None): value = self.volume_slider.get_value() max_norm = self.controller.get_vol_max_norm() denormalized_volume = utils.CLAMP((value / 100) * max_norm, 0, max_norm) trackers.con_tracker_get().handler_block(self.output, "notify::volume", self.on_volume_changed) trackers.con_tracker_get().handler_block(self.output, "notify::is-muted", self.on_volume_changed) self.output.set_volume(denormalized_volume) self.output.push_volume() self.output.change_is_muted(False) trackers.con_tracker_get().handler_unblock(self.output, "notify::volume", self.on_volume_changed) trackers.con_tracker_get().handler_unblock(self.output, "notify::is-muted", self.on_volume_changed) def on_button_press_event(self, widget, event): if event.button == 2: self.output.set_is_muted(not self.volume_slider.muted) return Gdk.EVENT_PROPAGATE def on_scroll_event(self, widget, event): success, dx, dy = event.get_scroll_deltas() step = self.volume_slider.get_adjustment().get_step_increment() if dy < 0: self.volume_slider.set_value(self.volume_slider.get_value() + step) elif dy > 0: self.volume_slider.set_value(self.volume_slider.get_value() - step) return Gdk.EVENT_STOP cinnamon-screensaver-4.4.1/src/widgets/000077500000000000000000000000001357366610100201055ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/widgets/Makefile.am000066400000000000000000000007141357366610100221430ustar00rootroot00000000000000## We require new-style dependency handling. AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = appdir = $(datadir)/cinnamon-screensaver/widgets app_PYTHON = \ __init__.py \ framedImage.py \ marqueeLabel.py \ notificationWidget.py \ powerWidget.py \ transparentButton.py \ volumeSlider.py \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in -include $(top_srcdir)/git.mk cinnamon-screensaver-4.4.1/src/widgets/__init__.py000066400000000000000000000000001357366610100222040ustar00rootroot00000000000000cinnamon-screensaver-4.4.1/src/widgets/framedImage.py000066400000000000000000000102031357366610100226540ustar00rootroot00000000000000#!/usr/bin/python3 # coding: utf-8 import gi gi.require_version('CinnamonDesktop', '3.0') from gi.repository import Gtk, GdkPixbuf, Gio, GLib, GObject, Gdk from util import utils, trackers MAX_IMAGE_SIZE = 320 MAX_IMAGE_SIZE_LOW_RES = 200 class FramedImage(Gtk.Image): """ Widget to hold the user face image. It attempts to display an image at its native size, up to a max sane size. """ __gsignals__ = { "surface-changed": (GObject.SignalFlags.RUN_LAST, None, (object,)) } def __init__(self, low_res=False, scale_up=False): super(FramedImage, self).__init__() self.get_style_context().add_class("framedimage") self.cancellable = None self.file = None self.path = None self.scale_up = scale_up if low_res: self.max_size = MAX_IMAGE_SIZE_LOW_RES else: self.max_size = MAX_IMAGE_SIZE trackers.con_tracker_get().connect(self, "realize", self.on_realized) def on_realized(self, widget): self.generate_image() def clear_image(self): self.set_from_surface(None) self.emit("surface-changed", None) def set_from_path(self, path): self.path = path self.file = None if self.get_realized(): self.generate_image() def set_from_file(self, file): self.file = file self.path = None if self.get_realized(): self.generate_image() def set_image_internal(self, path): pixbuf = None scaled_max_size = self.max_size * self.get_scale_factor() try: pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) except GLib.Error as e: message = "Could not load pixbuf from '%s' for FramedImage: %s" % (path, e.message) error = True if pixbuf != None: if (pixbuf.get_height() > scaled_max_size or pixbuf.get_width() > scaled_max_size) or \ (self.scale_up and (pixbuf.get_height() < scaled_max_size / 2 or pixbuf.get_width() < scaled_max_size / 2)): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, scaled_max_size, scaled_max_size) except GLib.Error as e: message = "Could not scale pixbuf from '%s' for FramedImage: %s" % (path, e.message) error = True if pixbuf: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.get_scale_factor(), self.get_window()) self.set_from_surface(surface) self.emit("surface-changed", surface) else: print(message) self.clear_image() def generate_image(self): if self.path: self.set_image_internal(self.path) elif self.file: if self.cancellable != None: self.cancellable.cancel() self.cancellable = None self.cancellable = Gio.Cancellable() self.file.load_contents_async(self.cancellable, self.load_contents_async_callback) def load_contents_async_callback(self, file, result, data=None): try: success, contents, etag_out = file.load_contents_finish(result) except GLib.Error: self.clear_image() return if contents: cache_name = GLib.build_filenamev([GLib.get_user_cache_dir(), "cinnamon-screensaver-albumart-temp"]) cache_file = Gio.File.new_for_path(cache_name) cache_file.replace_contents_async(contents, None, False, Gio.FileCreateFlags.REPLACE_DESTINATION, self.cancellable, self.on_file_written) def on_file_written(self, file, result, data=None): try: if file.replace_contents_finish(result): self.set_image_internal(file.get_path()) except GLib.Error: pass cinnamon-screensaver-4.4.1/src/widgets/marqueeLabel.py000066400000000000000000000114401357366610100230560ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, GObject, GLib from util import trackers class _fixedViewport(Gtk.Viewport): """ This is needed by MarqueeLabel to restrict the size of our label, and cause the viewport to actually be functional. Otherwise, the text is trimmed, but no scrolling occurs. """ def __init__(self): super(_fixedViewport, self).__init__() self.set_shadow_type(Gtk.ShadowType.NONE) def do_get_preferred_width(self): return (400, 400) class MarqueeLabel(Gtk.Stack): """ A scrolling label for the PlayerControl - it uses the defined pattern as a mapping between elapsed time and the hadjustment of the _fixedViewport. If the label text is wider than the widget's actual width, we will scroll according to this map over the course of 15 seconds. It roughly translates to: 0.0 - 2.0 seconds: no movement. 2.0 - 10.0 seconds: gradually scroll to max adjustment of the viewport. 10.0 - 12.0 seconds: no movement. 12.0 - 15.0 seconds: scroll back to the starting position. This widget also implements a stack (similar to the one in MonitorView) which provides for a smooth label crossfade when track info changes. """ PATTERN = [( 0.0, 0.0), ( 2.0, 0.0), (10.0, 1.0), (12.0, 1.0), (15.0, 0.0)] LENGTH = len(PATTERN) def __init__(self, text): super(MarqueeLabel, self).__init__() self.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self.set_transition_duration(300) self.tick_id = 0 self.current = self._make_label(text) self.add(self.current) self.set_visible_child(self.current) def _make_label(self, text): vp = _fixedViewport() label = Gtk.Label(text) label.set_halign(Gtk.Align.START) vp.add(label) vp.show_all() return vp def set_text(self, text): if self.current.get_child().get_text() == text: return self.cancel_tick() self.queued = self._make_label(text) self.add(self.queued) self.set_visible_child(self.queued) tmp = self.current self.current = self.queued self.queued = None GObject.idle_add(tmp.destroy) if not self.current.get_realized(): trackers.con_tracker_get().connect(self.current, "realize", self.on_current_realized) else: GObject.idle_add(self._marquee_idle) def on_current_realized(self, widget, data=None): GObject.idle_add(self._marquee_idle) trackers.con_tracker_get().disconnect(widget, "realize", self.on_current_realized) def cancel_tick(self): if self.tick_id > 0: self.remove_tick_callback(self.tick_id) self.tick_id = 0 def _marquee_idle(self): self.hadjust = self.current.get_hadjustment() if (self.hadjust.get_upper() == self.hadjust.get_page_size()) == self.get_allocated_width(): return False self.start_time = self.get_frame_clock().get_frame_time() self.end_time = self.start_time + (self.PATTERN[self.LENGTH - 1][0] * 1000 * 1000) # sec to ms to μs if self.tick_id == 0: self.tick_id = self.add_tick_callback(self._on_marquee_tick) self._marquee_step(self.start_time) return GLib.SOURCE_REMOVE def _on_marquee_tick(self, widget, clock, data=None): now = clock.get_frame_time() self._marquee_step(now) if now >= self.end_time: self.start_time = self.end_time self.end_time += (self.PATTERN[self.LENGTH - 1][0] * 1000 * 1000) # sec to ms to μs return GLib.SOURCE_CONTINUE def interpolate_point(self, now): point = ((now - self.start_time) / 1000 / 1000) i = 0 while i < self.LENGTH: cindex, cval = self.PATTERN[i] if point > cindex: i += 1 continue if point == cindex: return cval pindex, pval = self.PATTERN[i - 1] diff = cval - pval duration = cindex - pindex ratio = diff / duration additive = (point - pindex) * ratio return pval + additive def _marquee_step(self, now): if now < self.end_time: t = self.interpolate_point(now) else: t = self.PATTERN[self.LENGTH - 1][1] new_position = ((self.hadjust.get_upper() - self.hadjust.get_page_size()) * t) self.hadjust.set_value(new_position) self.queue_draw() cinnamon-screensaver-4.4.1/src/widgets/notificationWidget.py000066400000000000000000000036411357366610100243150ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, GObject import singletons import status from util import trackers class NotificationWidget(Gtk.Frame): """ Notification widget is a child of the InfoPanel - it is only shown if we've received intercepted a non-transient notification that hasn't been sent from a media player. """ __gsignals__ = { "notification": (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): super(NotificationWidget, self).__init__() self.set_shadow_type(Gtk.ShadowType.NONE) self.get_style_context().add_class("notificationwidget") self.set_size_request(50, -1) self.notification_count = 0 box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.add(box) self.label = Gtk.Label.new("0") box.pack_start(self.label, False, False, 4) self.image = Gtk.Image.new_from_icon_name("screensaver-notification-symbolic", Gtk.IconSize.LARGE_TOOLBAR) box.pack_end(self.image, False, False, 4) box.show_all() self.notification_watcher = singletons.NotificationWatcher trackers.con_tracker_get().connect(self.notification_watcher, "notification-received", self.on_notification_received) def on_notification_received(self, proxy, sender, data=None): mp_watcher = singletons.MediaPlayerWatcher players = mp_watcher.get_all_player_names() if sender.lower() in players: return for ignored in ("network",): if ignored in sender.lower(): return self.notification_count += 1 self.update_label() self.emit("notification") def should_show(self): return self.notification_count > 0 def update_label(self): self.label.set_text(str(self.notification_count)) cinnamon-screensaver-4.4.1/src/widgets/powerWidget.py000066400000000000000000000064171357366610100227670ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, GObject from util import trackers import singletons import constants as c import status class PowerWidget(Gtk.Frame): """ PowerWidget is a child of InfoPanel, and is only shown if we're on a system that can run on battery power. It is usually only visible if the system is actually currently running on battery power. """ __gsignals__ = { 'power-state-changed': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): super(PowerWidget, self).__init__() self.set_shadow_type(Gtk.ShadowType.NONE) self.get_style_context().add_class("powerwidget") self.path_widget_pairs = [] self.box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.add(self.box) self.box.show_all() self.power_client = singletons.UPowerClient self.battery_critical = False trackers.con_tracker_get().connect(self.power_client, "power-state-changed", self.on_power_state_changed) trackers.con_tracker_get().connect(self.power_client, "percentage-changed", self.on_percentage_changed) self.power_client.rescan_devices() self.on_power_state_changed(self.power_client) def refresh(self): self.on_power_state_changed(self.power_client) def on_power_state_changed(self, client): for widget in self.box.get_children(): widget.destroy() self.path_widget_pairs = [] self.battery_critical = False self.construct_icons() self.emit("power-state-changed") def on_percentage_changed(self, client, battery): battery_path = battery.get_object_path() for path, widget in self.path_widget_pairs: if path == battery_path: self.update_battery_tooltip(widget, battery) break def construct_icons(self): """ The upower dbus interface actually tells us what icon name to use. """ batteries = self.power_client.get_batteries() for path, battery in batteries: if status.Debug: print("powerWidget: Updating battery info: %s - icon: %s - percentage: %s" % (path, battery.get_property("icon-name"), battery.get_property("percentage"))) image = Gtk.Image.new_from_icon_name(battery.get_property("icon-name"), Gtk.IconSize.LARGE_TOOLBAR) self.update_battery_tooltip(image, battery) self.box.pack_start(image, False, False, 4) self.path_widget_pairs.append((path, image)) self._should_show = True self.box.show_all() def update_battery_tooltip(self, widget, battery): text = "" try: pct = int(battery.get_property("percentage")) if pct > 0: text = _("%d%%" % pct) if pct < c.BATTERY_CRITICAL_PERCENT: self.battery_critical = True except Exception as e: pass widget.set_tooltip_text(text) def should_show(self): return not self.power_client.full_and_on_ac_or_no_batteries() cinnamon-screensaver-4.4.1/src/widgets/transparentButton.py000066400000000000000000000007031357366610100242140ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk class TransparentButton(Gtk.Button): """ Custom button widget used throughout. """ def __init__(self, name, size): super(TransparentButton, self).__init__() self.get_style_context().add_class("transparentbutton") image = Gtk.Image.new_from_icon_name(name, size) self.set_can_default(True) self.set_can_focus(True) self.set_image(image) cinnamon-screensaver-4.4.1/src/widgets/volumeSlider.py000066400000000000000000000047411357366610100231370ustar00rootroot00000000000000#!/usr/bin/python3 from gi.repository import Gtk, Gdk from util import trackers class VolumeSlider(Gtk.Scale): """ Custom GtkScale widget for controlling the volume. """ def __init__(self): super(VolumeSlider, self).__init__(orientation=Gtk.Orientation.HORIZONTAL) self.set_can_focus(False) self.muted = False self.set_range(0, 100.0) self.set_increments(5.0, 5.0) self.get_style_context().remove_class("scale") self.get_style_context().add_class("volumeslider") self.set_round_digits(0) self.set_draw_value(False) self.set_size_request(130, -1) self.set_halign(Gtk.Align.CENTER) self.set_valign(Gtk.Align.CENTER) trackers.con_tracker_get().connect(self, "draw", self.on_draw) def set_muted(self, muted): if muted != self.muted: self.muted = muted self.queue_draw() def on_draw(self, widget, cr): ctx = widget.get_style_context() alloc = self.get_allocation() padding = ctx.get_padding(Gtk.StateFlags.NORMAL) border = ctx.get_border(Gtk.StateFlags.NORMAL) x = padding.left + border.left y = padding.top + border.top width = alloc.width - padding.left - padding.right - border.left - border.right height = alloc.height - padding.top - padding.bottom - border.top - border.bottom floor = y + height end = x + width value = round(self.get_value()) value_x = x + ((value / 100) * width) value_y = floor - ((value / 100) * height) if self.muted: fill_color = ctx.get_color(Gtk.StateFlags.INSENSITIVE) bg_color = ctx.get_background_color(Gtk.StateFlags.INSENSITIVE) else: fill_color = ctx.get_color(Gtk.StateFlags.NORMAL) bg_color = ctx.get_background_color(Gtk.StateFlags.NORMAL) cr.save() cr.new_sub_path() cr.move_to(x, floor) cr.line_to(end, floor) cr.line_to(end, y) cr.close_path() Gdk.cairo_set_source_rgba(cr, bg_color) cr.fill() cr.restore() cr.save() cr.new_sub_path() cr.move_to(x, floor) cr.line_to(value_x, floor) cr.line_to(value_x, value_y) cr.close_path() Gdk.cairo_set_source_rgba(cr, fill_color) cr.fill() cr.restore() return True