pax_global_header00006660000000000000000000000064135640137730014523gustar00rootroot0000000000000052 comment=dbe0d2f01c130f9ee2f1e3fc86c2593e5971e135 cinnamon-settings-daemon-4.4.0/000077500000000000000000000000001356401377300164315ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/.circleci/000077500000000000000000000000001356401377300202645ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/.circleci/config.yml000066400000000000000000000036421356401377300222610ustar00rootroot00000000000000version: 2.0 shared: &shared steps: - checkout - run: name: Prepare environment command: apt-get update - run: name: Install dependencies command: | 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-settings-daemon-4.4.0/.github/000077500000000000000000000000001356401377300177715ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000004361356401377300225010ustar00rootroot00000000000000 ``` * csd version ('dpkg --list | grep cinnamon-settings-daemon' in Mint/Ubuntu) * 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-settings-daemon-4.4.0/.gitignore000066400000000000000000000070441356401377300204260ustar00rootroot00000000000000INSTALL Makefile Makefile.in aclocal.m4 autom4te.cache/ cinnamon-settings-daemon/*.la cinnamon-settings-daemon/*.lo cinnamon-settings-daemon/*.o cinnamon-settings-daemon/.deps/ cinnamon-settings-daemon/.libs/ cinnamon-settings-daemon/Makefile cinnamon-settings-daemon/Makefile.in cinnamon-settings-daemon/cinnamon-settings-daemon compile config.guess config.h config.h.in config.log config.status config.sub configure data/*.gschema.valid data/*.gschema.xml data/*.gschema.xml.in data/Makefile data/Makefile.in data/cinnamon-settings-daemon-uninstalled.pc data/cinnamon-settings-daemon.desktop data/cinnamon-settings-daemon.desktop.in data/cinnamon-settings-daemon.pc data/org.cinnamon.settings-daemon.enums.xml depcomp install-sh libtool ltmain.sh man/Makefile man/Makefile.in man/cinnamon-settings-daemon.1 missing omf.make plugins/*/*.la plugins/*/*.lo plugins/*/*.o plugins/*/.deps/ plugins/*/.libs/ plugins/*/Makefile plugins/*/Makefile.in plugins/Makefile plugins/Makefile.in plugins/a11y-keyboard/a11y-keyboard.cinnamon-settings-plugin plugins/a11y-keyboard/csd-test-a11y-keyboard plugins/a11y-keyboard/test-a11y-preferences-dialog plugins/a11y-settings/a11y-settings.cinnamon-settings-plugin plugins/a11y-settings/csd-test-a11y-settings plugins/automount/automount.cinnamon-settings-plugin plugins/automount/csd-test-automount plugins/background/background.cinnamon-settings-plugin plugins/background/csd-test-background plugins/clipboard/clipboard.cinnamon-settings-plugin plugins/color/color.cinnamon-settings-plugin plugins/common/csd-test-input-helper plugins/common/test-egg-key-parsing plugins/cursor/cursor.cinnamon-settings-plugin plugins/datetime/csd-datetime-mechanism plugins/datetime/csd-datetime-mechanism-glue.h plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.service plugins/datetime/org.cinnamon.settingsdaemon.datetimemechanism.policy plugins/datetime/test-system-timezone plugins/dummy/dummy.cinnamon-settings-plugin plugins/housekeeping/csd-disk-space-test plugins/housekeeping/csd-empty-trash-test plugins/housekeeping/housekeeping.cinnamon-settings-plugin plugins/keyboard/keyboard.cinnamon-settings-plugin plugins/media-keys/csd-test-media-keys plugins/media-keys/cut-n-paste/*.la plugins/media-keys/cut-n-paste/*.lo plugins/media-keys/cut-n-paste/*.o plugins/media-keys/cut-n-paste/.deps/ plugins/media-keys/cut-n-paste/.libs/ plugins/media-keys/media-keys.cinnamon-settings-plugin plugins/mouse/csd-locate-pointer plugins/mouse/csd-test-mouse plugins/mouse/mouse.cinnamon-settings-plugin plugins/orientation/csd-test-orientation plugins/orientation/orientation.cinnamon-settings-plugin plugins/power/csd-backlight-helper plugins/power/csd-test-power plugins/power/org.cinnamon.settings-daemon.plugins.power.policy plugins/power/org.cinnamon.settings-daemon.plugins.power.policy.in plugins/power/power.cinnamon-settings-plugin plugins/print-notifications/csd-printer plugins/print-notifications/csd-test-print-notifications plugins/print-notifications/print-notifications.cinnamon-settings-plugin plugins/screensaver-proxy/csd-test-screensaver-proxy plugins/screensaver-proxy/screensaver-proxy.cinnamon-settings-plugin plugins/smartcard/csd-test-smartcard plugins/smartcard/smartcard.cinnamon-settings-plugin plugins/sound/csd-test-sound plugins/sound/sound.cinnamon-settings-plugin plugins/xrandr/xrandr.cinnamon-settings-plugin plugins/xsettings/csd-test-xsettings plugins/xsettings/test-gtk-modules plugins/xsettings/xsettings.cinnamon-settings-plugin po/*.gmo po/.intltool-merge-cache po/Makefile po/Makefile.in po/POTFILES po/stamp-it stamp-h1 test-driver xmldocs.make cinnamon-settings-daemon-4.4.0/AUTHORS000066400000000000000000000001101356401377300174710ustar00rootroot00000000000000Jonathan Blandford William Jon McCann cinnamon-settings-daemon-4.4.0/COPYING000066400000000000000000000431221356401377300174660ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU 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, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 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-settings-daemon-4.4.0/COPYING.LIB000066400000000000000000000635041356401377300201010ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] 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 Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these 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 other code 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. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. 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, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) 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. d) 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. e) 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 materials to be 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 with 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 Lesser 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 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 Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. 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-settings-daemon-4.4.0/ChangeLog000066400000000000000000004261211356401377300202110ustar00rootroot000000000000002008-08-03 C de-Avillez * plugins/mouse/gsd-mouse-manager.c: add '-k' to syndaemon call, in order to ignore modifier keys when monitoring keyboard. Thanks to Dag Asheim for spotting this, and proposing a patch. 2008-07-01 Sergey Udaltsov * configure.ac, plugins/keyboard/gsd-keyboard-xkb.c: depend on libxklavier 4.0, updated API 2009-06-01 Jens Granseuer * plugins/housekeeping/gsd-disk-space.c: include config.h so the notifications stuff can actually be built (bug #584217) 2009-05-06 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (make_menu_item_for_output_title): Make the menu item label explicitly black. We don't want to follow the theme's colors, as the label is always shown against a light pastel background --- using the theme's colors makes the label hard to read on "inverse" themes. Fixes the cinnamon-settings-daemon part of bug #556050. 2009-04-15 Thomas H.P. Andersen * plugins/xrandr/gsd-xrandr-manager.c: (status_icon_start): * configure.ac: Replace deprecated gtk symbol gtk_status_icon_set_tooltip. Bump required gtk to 2.16. (bug #578480) 2009-04-14 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (print_countdown_text): use ngettext for the reset dialog (bug #575409) ==================== 2.26.1 ==================== 2009-04-14 Jens Granseuer * NEWS: * configure.ac: release 2.26.1 2009-04-11 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (gsd_keybindings_manager_start): move the lookup of allowed keys after the directory has been cached in callback registration to avoid GConf roundtrip (bug #578539) 2009-04-11 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (start_keyboard_idle_cb): preload GConf keyboard directory recursively to avoid roundtrips (bug #578542) 2009-04-08 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (user_says_things_are_ok): Use 30 seconds for the confirmation timeout, so that monitors can settle down and the user will have a chance to read the message. 2009-04-03 Jens Granseuer Patch by: * plugins/media-keys/Makefile.am: don't install the plugin descriptor if the plugin isn't installed (bug #577815) 2009-04-02 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (numlock_gconf_state_key): use info level instead of warning for the "NumLock remembering disabled" message (bug #577578) 2009-03-28 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (sanitize), (generate_fn_f7_configs): if the sanitized array ends up having no members at all return a NULL configuration since the following code assumes it has at least one valid setup if it's not NULL. Fixes a crash when closing the lid on some laptops (bug #576875) 2009-03-27 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (on_notification_closed), (on_slow_keys_action), (on_sticky_keys_action), (ax_slowkeys_warning_post_bubble), (ax_stickykeys_warning_post_bubble), (gsd_a11y_keyboard_manager_stop): fix crash when closing the a11y notification bubble caused by incompatible changes in libnotify API (bug #576535). Also remove workarounds for bugs in libnotify < 0.4.5 2009-03-27 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (restore_backup_configuration), (try_to_apply_intended_configuration): remove unused variables 2009-03-26 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (ensure_current_configuration_is_saved): New helper function. Ensures that a monitors.xml exists with the current/unchanged configuration, so that a latter gnome_rr_config_save() will create a backup file out of *that* original configuration. This lets the "revert" function from gnome-display-properties work properly on an initial login, even when there is no monitors.xml already present. 2009-03-25 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (restore_backup_configuration): Handle the case where no backup file was created for monitors.xml, because *that* file didn't exist (such as on a first-time login). 2009-03-25 Federico Mena Quintero Centralize the handling of GNOME_RR_ERROR_NO_MATCHING_CONFIG, as that is not really an error. * plugins/xrandr/gsd-xrandr-manager.c (apply_configuration_from_filename): New helper function; centralizes the handling of gnome_rr_config_apply_from_filename() and ignores GNOME_RR_ERROR_NO_MATCHING_CONFIG. That is not actually an error; it just means that the user probably changed his monitors and the stored set of configurations doesn't have a config that is usable for the new monitors. (restore_backup_configuration): Use apply_configuration_from_filename(). (try_to_apply_intended_configuration): Likewise. (apply_intended_configuration): Likewise. (apply_stored_configuration_at_startup): Likewise. 2009-03-19 Federico Mena Quintero http://bugzilla.gnome.org/show_bug.cgi?id=576006 - The confirmation dialog from the RANDR plugin can appear behind the window from gnome-display-properties. This also depends on a change to gnome-control-center. * plugins/xrandr/gsd-xrandr-manager.xml: Add an org.gnome.SettingsDaemon.XRANDR_2 interface in addition to the old XRANDR one, with an ApplyConfiguration method that also takes a parent window ID and a timestamp. * plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_2_apply_configuration): Implement the new DBus method with the parent window and timestamp. (user_says_things_are_ok): Use the parent window. 2009-03-19 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (user_says_things_are_ok): Revert the use of g_timeout_add_seconds(), since we actually care that the user sees real second ticks in the dialog. This isn't a neverending timeout anyway. 2009-03-18 Jens Granseuer * cinnamon-settings-daemon/Makefile.am: * plugins/a11y-keyboard/Makefile.am: * plugins/background/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/dummy/Makefile.am: * plugins/font/Makefile.am: * plugins/housekeeping/Makefile.am: * plugins/keybindings/Makefile.am: * plugins/keyboard/Makefile.am: * plugins/media-keys/Makefile.am: * plugins/mouse/Makefile.am: * plugins/screensaver/Makefile.am: * plugins/sound/Makefile.am: * plugins/typing-break/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrdb/Makefile.am: * plugins/xsettings/Makefile.am: revert build patch from r763 ==================== 2.26.0 ==================== 2009-03-16 Rodrigo Moya * NEWS: * configure.ac: release 2.26.0 2009-03-07 Jens Granseuer Based on patch by: Christopher Taylor * cinnamon-settings-daemon/Makefile.am: * plugins/a11y-keyboard/Makefile.am: * plugins/background/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/dummy/Makefile.am: * plugins/font/Makefile.am: * plugins/housekeeping/Makefile.am: * plugins/keybindings/Makefile.am: * plugins/keyboard/Makefile.am: * plugins/media-keys/Makefile.am: * plugins/mouse/Makefile.am: * plugins/screensaver/Makefile.am: * plugins/sound/Makefile.am: * plugins/typing-break/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrdb/Makefile.am: * plugins/xsettings/Makefile.am: make build work with -Wl,-z,defs linker options (bug #574452) ==================== 2.25.92 ==================== 2009-03-02 Jens Granseuer * NEWS: * configure.ac: release 2.25.92 2009-03-02 Jens Granseuer * cinnamon-settings-daemon/Makefile.am: also install the plugin header file because it is needed for custom plugins (bug #573610) 2009-02-23 Jens Granseuer * data/cinnamon-settings-daemon.schemas.in: add missing keys for a11y shortcut names (bug #572807) 2009-02-22 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (user_says_things_are_ok): use g_timeout_add_seconds instead of g_timeout_add 2009-02-21 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (timeout_response_cb): revert the screen resolution change if the user closes the window or hits escape (bug #571492) 2009-02-21 Jens Granseuer Fix compiler warnings. * plugins/housekeeping/gsd-disk-space.c: add missing include * plugins/housekeeping/gsd-housekeeping-manager.c: ditto * plugins/housekeeping/gsd-disk-space.h: don't declare public functions static 2009-02-20 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (parse_binding), (bindings_get_entry): don't output a warning for disabled shortcuts 2009-02-15 Jens Granseuer Patch by: Leo Iannacone * plugins/media-keys/gsd-media-keys-window.c: (on_expose_event): fix alignment of the composited media window (bug #567249) 2009-02-15 Luca Ferretti reviewed by: Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (ax_slowkeys_warning_post_dialog), (ax_stickykeys_warning_post_dialog): * plugins/mouse/gsd-mouse-manager.c: (set_mousetweaks_daemon): Don't use legacy icons for keyboard and mouse (bug #571823) 2009-02-15 Luca Ferretti reviewed by: Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (user_says_things_are_ok): HIG fix for button labels (bug #571819) 2009-02-15 Luca Ferretti reviewed by: Jens Granseuer * plugins/keyboard/modmap-dialog.glade: Fix label for "Don't show this message again" checkbox, isn't a `string change` due to reusing a yet available label (bug #571821) 2009-02-11 Jens Granseuer * plugins/common/eggaccelerators.c: (egg_accelerator_parse_virtual): don't return TRUE if we can't parse the accelerator at all; fixes crash with invalid keyboard shortuts (bug #571329) 2009-02-11 Matthias Clasen Bug 570590 – a11y plugin warning * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: Avoid warnings due to notifications on nonexisting statusicons. 2009-02-08 Jens Granseuer Patch by: Nirbheek Chauhan * configure.ac: add --without-libnotify to disable notifications (bug #570885) 2009-02-06 Matthias Clasen Bug 570743 – restart on crash * data/cinnamon-settings-daemon.desktop.in.in: Have gnome-session restart g-s-d if it crashes (heaven forbid!). 2009-02-04 Vincent Untz * configure.in: post-release bump to 2.25.91 ==================== 2.25.90 ==================== 2009-02-04 Vincent Untz * NEWS: * configure.in: version 2.25.90 2009-02-04 Vincent Untz * data/Makefile.am: fix distcheck 2009-02-03 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (restore_backup_configuration): Use gnome_rr_config_apply_from_filename(), as that's the new, non-deprecated API. (try_to_apply_intended_configuration): Likewise. (apply_intended_configuration): Likewise. (apply_stored_configuration_at_startup): Likewise. 2009-02-01 Frederic Peters * plugins/housekeeping/Makefile.am: * plugins/housekeeping/gsd-disk-space.c: add low diskspace checker files to housekeeping plug-in Makefile.am; and make its clean and setup methods available are made available. (bug #570132) 2009-01-31 Theppitak Karoonboonyanan * plugins/media-keys/Makefile.am: Fix include paths for non-source-dir builds. (bug #569955) 2009-01-28 Jens Granseuer * configure.ac: require gnome-desktop 2.25.6 due to recent changes 2009-01-27 Federico Mena Quintero http://bugzilla.gnome.org/show_bug.cgi?id=545115 - Ask for confirmation, with a timeout, after changing the RANDR configuration for if we leave the user with an unusable display. This also handles the case where the machine may crash after changing the configuration; the old/known-good configuration will be restored when the user restarts his session. Refactor: * plugins/xrandr/gsd-xrandr-manager.c (apply_stored_configuration_at_startup): Factor out the logic to apply the stored configuration at startup. (gsd_xrandr_manager_start): Use the function above. During startup, restore the backup configuration if it existed, to recover from the case when the machine crashes while applying an intended configuration. * plugins/xrandr/gsd-xrandr-manager.c (apply_stored_configuration_at_startup): First see if we have a backup configuration; if so, it means the machine or g-s-d crashed while changing the RANDR parameters. If there is no backup configuration, then we have a known-good configuration which we can use. (apply_intended_configuration): New function, used to load the intended configuration (i.e. the non-backup one). (restore_backup_configuration): Utility function to overwrite the known-bad configuration with the known-good backup one. Use a timeout-confirmation dialog after changing the display configuration: * plugins/xrandr/gsd-xrandr-manager.c (try_to_apply_intended_configuration): New function; applies the intended configuration, restores the backup configuration if that fails, or asks the user to confirm if the intended configuration is usable. (gsd_xrandr_manager_apply_configuration): Use try_to_apply_intended_configuration() in the implementation of the D-Bus method to apply RANDR configurations. This way all apps which use this D-Bus method will get confirmation for free. (output_rotation_item_activate_cb): Use try_to_apply_intended_configuration() so that the RANDR tray-icon also uses the confirmation/backup logic. (restore_backup_configuration): Restore the screen configuration itself in addition to restoring the file on disk from the backup. (user_says_things_are_ok): New utility function to handle a timeout-confirmation dialog. Fix error reporting at startup: * plugins/xrandr/gsd-xrandr-manager.c (error_message): Handle the case where the status_icon is not created yet; this happens during startup or when the status_icon is disabled by the user. Handle the case where there is no matching configuration at startup; this is not an error: * plugins/xrandr/gsd-xrandr-manager.c (apply_intended_configuration): "no matching configuration" is not an error when looking for a suitable configuration in monitors.xml; it simply means that the user has a different set of monitors than the ones that are available in that file. 2009-01-24 Jens Granseuer Patch by: Andres Freund Fix possible crash when pressing Fn-F7 (bug #568713) * plugins/xrandr/gsd-xrandr-manager.c: (handle_fn_f7): only try to dereference the error when it was actually set 2009-01-27 Federico Mena Quintero http://bugzilla.gnome.org/show_bug.cgi?id=545115 - Ask for confirmation, with a timeout, after changing the RANDR configuration for if we leave the user with an unusable display. This also handles the case where the machine may crash after changing the configuration; the old/known-good configuration will be restored when the user restarts his session. Refactor: * plugins/xrandr/gsd-xrandr-manager.c (apply_stored_configuration_at_startup): Factor out the logic to apply the stored configuration at startup. (gsd_xrandr_manager_start): Use the function above. 2009-01-26 Ray Strode Delay drawing the background until SessionRunning. * plugins/background/gsd-background-manager.c: (queue_draw_background): Cancel queued draw if nautilus is now running. (on_bus_message), (draw_background_after_session_loads), (gsd_background_manager_start): wait for SessionRunning and then queue background draw (gsd_background_manager_stop): remove message filter 2009-01-24 Jens Granseuer Patch by: Andres Freund Fix possible crash when pressing Fn-F7 (bug #568713) * plugins/xrandr/gsd-xrandr-manager.c: (handle_fn_f7): only try to dereference the error when it was actually set 2009-01-22 Bastien Nocera * data/apps_gnome_settings_daemon_keybindings.schemas.in: KEY_FILE maps to XF86Explorer, so use that to launch the file manager in the user's home directory 2009-01-19 Ray Strode Add crossfade transition when switching bgs (bug 552857) * plugins/background/gsd-background-manager.c (draw_background): Add use_crossfade argument that initiates the fade if TRUE. (on_bg_changed): call draw_background with crossfade. (on_bg_transitioned): new function that calls draw_background without crossfade during slide show transitioning. (setup_bg): set up transitioned signal handler. (queue_draw_background): draw_background without crossfade after 8 second timeout waiting for nautilus. 2009-01-19 Ray Strode * plugins/background/gsd-background-manager.c (gsd_background_manager_start): Don't draw_background immediately when nautilus is disabled. gnome_bg_load_from_preferences forces a "changed" signal to get emitted which will queue a draw anyway 2009-01-18 Jens Granseuer * plugins/media-keys/Makefile.am: fix automake warning 2009-01-18 Jens Granseuer * configure.ac: fix build with PulseAudio, too (bug #568179) 2009-01-17 Jens Granseuer * plugins/media-keys/Makefile.am: fix build without PulseAudio (bug #568015) 2009-01-15 Bastien Nocera * plugins/media-keys/cut-n-paste/*: Cut'n'paste code from the PulseAudio enabled code in gnome-media's gnome-volume-control * plugins/media-keys/actions/acme-volume-*.[ch]: Remove the old AcmeVolume code * plugins/media-keys/actions/acme.glade: * plugins/media-keys/actions/acme.h: Move to plugins/media-keys/ * configure.ac: Tell config.h when PulseAudio support is disabled * plugins/media-keys/gsd-media-keys-manager.c (update_dialog), (on_stream_event_notify), (do_sound_action), (update_default_sink), (on_control_ready), (on_control_default_sink_changed), (do_action), (gsd_media_keys_manager_start), (gsd_media_keys_manager_stop): Use PulseAudio directly to change the volume. It will automatically change the volume of the default audio output for the machine (Closes: #567177) * plugins/media-keys/Makefile.am: * plugins/media-keys/actions/Makefile.am: Changes for the above 2009-01-15 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (binding_unregister_keys), (gsd_keybindings_manager_stop): also ungrab keys when this module is disabled 2009-01-15 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (gsd_media_keys_manager_stop): ungrab shortcut keys when the plugin is disabled (bug #567867) 2009-01-14 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_start): If there was no file with a stored configuration, don't pop up an error message --- this is not an error when the daemon starts up. Fixes https://bugzilla.novell.com/show_bug.cgi?id=465968 2009-01-10 William Jon McCann * plugins/sound/gsd-sound-manager.c (register_config_callback): Fix typo. 2009-01-08 Jens Granseuer Based on a patch by: Lennart Poettering * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/sound/Makefile.am: * plugins/sound/gsd-sound-manager.c: * plugins/sound/gsd-sound-plugin.h: * plugins/sound/sound.cinnamon-settings-plugin.in: Add a new sound plugin that tells PulseAudio to drop its sample cache when the sound theme changes (bug #545386). 2009-01-08 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (gsd_media_keys_manager_grab_media_player_keys), (gsd_media_keys_manager_release_media_player_keys): add a little debugging output when de/registering media players (bug #564433) 2009-01-05 Bastien Nocera * plugins/xrdb/gsd-xrdb-manager.c (apply_settings): Quiet xrdb when there are duplicate rules in the .ad files (Closes: #566610) 2008-12-30 Matthias Clasen Bug 565310 – support hotkeys for a11y tools * configure.ac: Set GNOME_KEYBINDINGS_KEYSDIR. * data/cinnamon-settings-daemon.schemas.in: Add missing schemas for the keys in /destkop/gnome/applications/at, and also add new schemas for keys in /desktop/gnome/keybindings that define global keybindings for turning ATs on and off. Todo: There are no default key combinations in the schema yet. * data/50-accessibility.xml.in: Keybinding file to group the new keybindings in an "Accessibility" section in the keybinding capplet. * data/Makefile.am: Install the keybinding file in the proper location. * po/POTFILES.in: Add 50-accessibility.xml.in. 2008-12-31 Rodrigo Moya Patch by Vincent Untz from openSUSE package (bug #557647) * configure.ac: require giounix for diskspace checker * Makefile.am: * plugins/housekeeping/gsd-disk-space.[ch]: add low diskspace checker to housekeeping plugin. * plugins/housekeeping/gsd-housekeeping-manager.c (gsd_housekeeping_manager_start, gsd_housekeeping_manager_stop): start/stop the low diskspace checker. * plugins/housekeeping/housekeeping.cinnamon-settings-plugin.in: add new plugin capability to description * po/POTFILES.in: add new files 2008-12-28 Jens Granseuer * plugins/screensaver/gsd-screensaver-manager.c: (start_screensaver_cb), (gsd_screensaver_manager_start): spawn screensaver after a 30 second timeout instead of when idle so that it doesn't compete with other processes when the session starts (bug #564059). Also plug a few small leaks. 2008-12-28 Jens Granseuer Based on patch by: Jasper Lievisse Adriaanse * plugins/media-keys/gsd-media-keys-manager.c: (do_eject_action), (do_action): better support for Eject and Sleep actions on OpenBSD and FreeBSD (bug #565472) 2008-12-28 Jens Granseuer Patch by: Jasper Lievisse Adriaanse * plugins/typing-break/gsd-typing-break-manager.c: include signal.h to fix build on OpenBSD (bug #565470) 2008-12-28 Jens Granseuer Patch by: Frederic Peters * cinnamon-settings-daemon/main.c: (main): initialize thread system since ORBit no longer does it for us (#565515) ==================== 2.25.3 ==================== 2008-12-18 Bastien Nocera * NEWS: upd * configure.ac: 2.25.3 update gnome-desktop requirements for the new GnomeRR API * plugins/xrandr/Makefile.am: Fix distcheck 2008-12-07 Ray Strode Restore AccessX bits to original values on exit * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (struct CsdA11yKeyboardManagerPrivate): add new field to cache original AccessX bits. (start_a11y_keyboard_idle_cb): save bits. (restore_server_xkb_config), (gsd_a11y_keyboard_manager_stop): restore bits when stopping. 2008-12-07 Ray Strode Shutdown properly when bus goes away. Previously we were just letting libdbus call exit(1) for us. * cinnamon-settings-daemon/main.c (get_session_bus): Set up a filter function to catch disconection events. (bus_message_handler): quit event loop when disconnected from bus. 2008-12-07 Ray Strode Shutdown properly when killed. * cinnamon-settings-daemon/main.c (on_term_signal): top half of signal handling code. close a pipe when getting SIGTERM. (on_term_signal_pipe_closed), (watch_for_term_signal), (set_session_over_handler): bottom half. Quit event loop when term pipe gets closed. 2008-12-07 Ray Strode * cinnamon-settings-daemon/main.c: Rename pipefds to daemon_pipe_fds. This fits the naming style of the surrounding code better. Also, we're going to need another pipe, so better to use a specific name here. 2008-12-09 Jens Granseuer Patch by: Pedro Fragoso * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.h: * plugins/common/eggaccelerators.c: * plugins/common/eggaccelerators.h: * plugins/mouse/gsd-locate-pointer.h: only use top-level headers for glib and GTK+ (bug #563796) 2008-12-08 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (error_message): make libnotify optional again (bug #563226) (handle_fn_f7): fix memory leak, use g_debug instead of g_print 2008-12-07 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemon_detach): Don't call umask (bug #563543) 2008-12-04 Jens Granseuer * plugins/mouse/gsd-mouse-manager.c: (set_devicepresence_handler): fix crash with X servers that don't provide XInput (bug #562977) 2008-12-02 Federico Mena Quintero Use a DBus interface to tell the XRANDR manager to apply the stored configuration, instead of an X client message, so that we can pass errors back to the caller. * plugins/xrandr/gsd-xrandr-manager.xml: Trivial DBus interface to tell the XRANDR manager to apply the stored configuration. * plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_apply_configuration): Moved from on_client_message(). Now we are a DBus-Glib method, so that we can pass back errors to the remote caller. * plugins/xrandr/Makefile.am: Add the machinery to generate DBus glue. 2008-12-02 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (error_message): Renamed from error_dialog(); use libnotify instead of ugly dialogs for error messages. (gsd_xrandr_manager_start): Proxy the error from gnome_rr_screen_new() to our caller. (gsd_xrandr_manager_start): Display an error if we cannot apply the initially-loaded configuration. (generate_fn_f7_configs, get_allowed_rotations_for_output): Pass GError arguments to the gnome_rr_*() functions. (handle_fn_f7): Display an error if we cannot refresh the screen configuration or apply the new one. (output_rotation_item_activate_cb): Display an error if the rotation cannot be applied. Tue Dec 2 15:37:21 2008 Søren Sandmann * plugins/xrandr/gsd-xrandr-manager.c: Add support for fn-F7 type keys. ==================== 2.25.2 ==================== 2008-12-01 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.25.2 release. 2008-11-29 Jens Granseuer * plugins/keyboard/gsd-keyboard-xkb.c: (gsd_keyboard_xkb_init): fix check for xklavier device discovery 2008-11-29 Jens Granseuer * configure.ac: fix checks for various X11 libraries (bug #562661) * plugins/mouse/gsd-mouse-manager.c: (set_left_handed), (gsd_mouse_manager_idle_cb), (gsd_mouse_manager_stop): * plugins/xrandr/gsd-xrandr-manager.c: adapt ifdefs accordingly 2008-11-27 Sergey Udaltsov * configure.ac, plugins/keyboard/gsd-keyboard-xkb.c: introduce dependency on libxklavier 3.8. Use "new device" notification to reload XKB configuration when new keyboard is plugged in 2008-11-24 Behdad Esfahbod * cinnamon-settings-daemon/main.c (parse_args), (main): Fix --no-daemon (bug #562175) 2008-11-24 Jens Granseuer When multiple keys (keycodes) were mapped to the same keysym, g-s-d would only accept the first of those keycodes in the keymap as a valid shortcut. To fix this, instead of checking against a single keycode, we need to grab all keycodes that match the respective keysym (bug #561275). With thanks to Mario Limonciello * plugins/common/eggaccelerators.c: (egg_accelerator_parse_virtual): * plugins/common/eggaccelerators.h: possibly return multiple keycodes * plugins/common/gsd-keygrab.c: (grab_key_unsafe), (key_uses_keycode), (match_key): grab all matching keys * plugins/common/gsd-keygrab.h: * plugins/keybindings/gsd-keybindings-manager.c: (parse_binding), (bindings_get_entry), (same_keycode), (same_key), (key_already_used), (binding_register_keys), (gsd_keybindings_manager_stop): * plugins/media-keys/gsd-media-keys-manager.c: (update_kbd_cb), (init_kbd), (gsd_media_keys_manager_stop): update to handle changes in data structures 2008-11-23 Jens Granseuer Patch by: * configure.ac: add bundle_loader linker flag to fix compilation on MacOS X (bug #522673) 2008-11-20 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (find_by_time), (gsd_media_keys_manager_grab_media_player_keys): fix handling of time = GDK_CURRENT_TIME. Previously, apps that registered with GDK_CURRENT_TIME would be trumped by any app that registered with time != 0 (bug #559797) 2008-11-20 Jens Granseuer * plugins/mouse/gsd-mouse-manager.c: (set_devicepresence_handler): trap X errors so we don't crash on X servers that don't support DevicePresence (bug #560618) 2008-11-13 Jens Granseuer * data/desktop_gnome_keybindings.schemas.in: fix typo 2008-11-11 Matthias Clasen Bug 553434 – lockdown in the keybinding plugin * data/Makefile.am: Install the new schema file. * data/desktop_gnome_keybindings.schemas.in: Add schema for /desktop/gnome/keybindings/allowed_keys. * plugins/keybindings/gsd-keybinding-manager.c: Support locking down keybindings with a list of allowed keys. 2008-11-10 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemon_start): Check return value of pipe(). 2008-11-10 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemon_start), (daemon_detach), (daemon_terminate_parent), (main): Fork before gtk_init (bug #559695) 2008-11-09 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (do_sound_action): add debugging output for volume_step 2008-11-08 Jens Granseuer Patch by: William Grant * plugins/mouse/gsd-mouse-manager.c: (devicepresence_filter): listen for DeviceEnabled instead of DeviceAdded so we can be sure it has been initialized (bug #559827) 2008-11-06 Behdad Esfahbod * plugins/background/gsd-background-manager.c (setup_bg), (queue_draw_background), (gsd_background_manager_start): Delay constructing the GnomeBg object until we need it. This avoids unneeded change triggers caused by a bug in gnome-screensaver (fixed in trunk it seems). (bug #559639) 2008-11-06 Behdad Esfahbod * data/cinnamon-settings-daemon.schemas.in: Reshuffle plugin priorities a bit. Now that we do many of the plugins in idle callback, those can be put at the end. 2008-11-06 Behdad Esfahbod * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (maybe_show_status_icon), (ax_slowkeys_warning_post_bubble), (ax_stickykeys_warning_post_bubble), (gsd_a11y_keyboard_manager_stop), (gsd_a11y_keyboard_manager_ensure_status_icon), (gsd_a11y_keyboard_manager_init): Init status icon only when needed (bug #559558) 2008-11-06 Behdad Esfahbod * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (start_a11y_keyboard_idle_cb), (gsd_a11y_keyboard_manager_start): Start manager in idle callback (bug #559564) * plugins/media-keys/gsd-media-keys-manager.c (start_media_keys_idle_cb), (gsd_media_keys_manager_start): Start manager in idle callback (bug #559564). Leave the acme initialization in the main start function to force gstreamer cache up to date check before we let other applications start. 2008-11-06 Behdad Esfahbod * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (get_xkb_desc_rec): * plugins/common/gsd-keygrab.c (have_xkb): Remove more unnecessary X error traps and synchs (bug #559562) 2008-11-06 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (xkb_enabled), (gsd_a11y_keyboard_manager_start): remove unnecessary X error traps (bug #559562) 2008-11-05 Behdad Esfahbod * plugins/xsettings/fontconfig-monitor.c (fontconfig_cache_init): * plugins/xsettings/fontconfig-monitor.h: * plugins/xsettings/gsd-xsettings-manager.c (start_fontconfig_monitor): Only initialize fontconfig when starting up. A cache update is redundant there. (bug #559550) 2008-11-05 Behdad Esfahbod * plugins/keyboard/gsd-keyboard-manager.c (start_keyboard_idle_cb), (gsd_keyboard_manager_start): Start manager in idle callback (bug #559482) 2008-11-05 Behdad Esfahbod * plugins/keyboard/gsd-keyboard-xkb.c (gsd_keyboard_xkb_init): Add some performance logging annotations around libxklavier calls. 2008-11-05 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (numlock_xkb_init): XkbQueryExtension and friends shouldn't cause errors, so no need to try and trap them (bug #559346) ==================== 2.25.1 ==================== 2008-11-04 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.25.1 release 2008-11-04 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemonize), (main): Use a pipe to communicate between child and parent process instead of a signal. Signals are not queued, so if the child tried to signal the parent before the parent got a chance to wait for it, the signal would be lost and parent wait indefinitely for a signal that would never arrive. 2008-11-04 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemonize): Don't close stderr. Otherwise we just lose all our warnings that will not end up in ~/.xsession-errors. Also fix indentation. 2008-11-03 Jens Granseuer * plugins/keyboard/gsd-keyboard-xkb.c: add missing include 2008-11-03 Behdad Esfahbod * cinnamon-settings-daemon/main.c (daemonize), (main): Make parent wait for initialization in children to finish before returning. This makes gnome-session to wait for initialization to be done before spawning other processes. This way, apps start up with the right xsettings and other settings, and don't have to handle change signals right after starting up. (bug #559168) 2008-11-03 Behdad Esfahbod * cinnamon-settings-daemon/cinnamon-settings-manager.c (_load_file), (gnome_settings_manager_start), (gnome_settings_manager_stop): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c (gnome_settings_plugin_info_set_enabled_key_name): * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (register_config_callback): * plugins/keybindings/gsd-keybindings-manager.c (register_config_callback), (gsd_keybindings_manager_start): * plugins/keyboard/gsd-keyboard-manager.c (gsd_keyboard_manager_start): * plugins/keyboard/gsd-keyboard-xkb.c (register_config_callback): * plugins/mouse/gsd-mouse-manager.c (register_config_callback): * plugins/typing-break/gsd-typing-break-manager.c (gsd_typing_break_manager_start): * plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_start): * plugins/xsettings/gsd-xsettings-manager.c (register_config_callback), (gnome_xsettings_manager_start): Preload gconf dirs when feasible (bug #559167) 2008-11-03 Behdad Esfahbod * plugins/clipboard/gsd-clipboard-manager.c (start_clipboard_idle_cb), (gsd_clipboard_manager_start): Start manager in idle callback (bug #559166) * plugins/mouse/gsd-mouse-manager.c (gsd_mouse_manager_idle_cb), (gsd_mouse_manager_start): Start manager in idle callback (bug #559166) * plugins/xsettings/fontconfig-monitor.c (fontconfig_cache_update), (update): * plugins/xsettings/fontconfig-monitor.h: * plugins/xsettings/gsd-xsettings-manager.c (start_fontconfig_monitor_idle_cb), (start_fontconfig_monitor), (stop_fontconfig_monitor): Start fontconfig monitors in idle callback. However, make sure fontconfig caches are up to date during initialization (bug #559166) 2008-11-03 Behdad Esfahbod * plugins/mouse/gsd-mouse-manager.c (set_mousetweaks_daemon): Don't run "mousetweaks -s" at startup time (#559165) All "mousetweaks -s" does is shutdown the already-running daemon. When g-s-d starts, there is no daemon running. So, remember that and do not try to shut the non-existing daemon down. 2008-11-03 Behdad Esfahbod * plugins/common/gsd-keygrab.c (setup_modifiers), (grab_key_real), (grab_key_unsafe): * plugins/common/gsd-keygrab.h: * plugins/keybindings/gsd-keybindings-manager.c (binding_register_keys): * plugins/media-keys/gsd-media-keys-manager.c (update_kbd_cb), (init_kbd): Don't trap errors around grab_key (bug #559164) Such that we can do a single gdk_flush for multiple keys. The only downside is that we cannot write out in the warning which key is being accessed by another app. Not that we really care. 2008-11-03 Behdad Esfahbod * plugins/font/gsd-font-manager.c (setup_dir), (empty_check_dir), (setup_font_dir), (setup_cursor_dir), (load_font_paths), (gsd_font_manager_start): Cleanup font module (bug #559163) The old code had several flaws: - It tried to create directories in user's home even if we didn't have any use for them. - It called mkfontdir and XSync even if there was no fonts installed. The new code does the following: - Only call mkfontdir and XSync if there's actually any fonts in the relevant dirs. - Remove the ~/.gnome2/share/fonts and/or ~/.gnome2/share/cursor-fonts if they are empty and no cursor font is set. 2008-11-03 Behdad Esfahbod * cinnamon-settings-daemon/cinnamon-settings-manager.c (_load_file): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c (gnome_settings_plugin_info_fill_from_file), (load_plugin_module): * plugins/font/gsd-font-manager.c (child_watch_cb), (spawn_with_input): * plugins/keyboard/gsd-keyboard-xkb.c (gsd_keyboard_xkb_init): * plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_start): * plugins/xsettings/gsd-xsettings-manager.c (child_watch_cb), (spawn_with_input), (start_fontconfig_monitor), (stop_fontconfig_monitor), (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop): Improve performance logging annotations (bug #559162) 2008-11-03 Behdad Esfahbod * data/cinnamon-settings-daemon.schemas.in: Disable xrdb plugin by default (#bug #557807) 2008-11-02 Jens Granseuer * configure.ac: remove AM_MAINTAINER_MODE because it is deprecated and supposedly unsafe (bug #558503) 2008-11-01 Jens Granseuer Patch by: William Grant * plugins/mouse/gsd-mouse-manager.c: (devicepresence_filter), (set_devicepresence_handler), (set_mouse_settings), (gsd_mouse_manager_start), (gsd_mouse_manager_stop): listen for X device changes, and reconfigure the mouse if necessary so that the settings aren't ignored when hotplugging (bug #549267) 2008-10-29 Jens Granseuer Get rid of libgnome (bug #557808). * configure.ac: bump required gtk+ version to 2.13.1 * cinnamon-settings-daemon/main.c: (main): don't use g_program_init * plugins/a11y-keyboard/Makefile.am: * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (ax_response_callback), (ax_stickykeys_response), (ax_slowkeys_response), (on_slow_keys_action), (on_sticky_keys_action): replace gnome_help_display_desktop with gtk_show_uri 2008-10-29 Jens Granseuer * plugins/screensaver/gsd-screensaver-manager.c: (gsd_screensaver_manager_start): fix plugin activation, too 2008-10-29 Jens Granseuer * plugins/screensaver/gsd-screensaver-manager.c: (start_screensaver_idle_cb), (gsd_screensaver_manager_start): fix broken changes to screensaver plugin 2008-10-29 Jens Granseuer Remove ESD-based sound plugin (bug #557806). This means that g-s-d will no longer start a sound server (esd or PulseAudio) at session startup. This should be handled using the autostart mechanism of gnome-session instead. * configure.ac: * plugins/Makefile.am: * plugins/sound/Makefile.am: * plugins/sound/gsd-sound-manager.c: * plugins/sound/gsd-sound-manager.h: * plugins/sound/gsd-sound-plugin.c: * plugins/sound/gsd-sound-plugin.h: * plugins/sound/sound.cinnamon-settings-plugin.in: remove sound plugin 2008-10-29 Rodrigo Moya * plugins/screensaver/gsd-screensaver-manager.c (gsd_screensaver_manager_start): spawn screensaver process in idle callback as it was before. 2008-10-23 Jens Granseuer Based on a patch by: Bogdan Butnaru * plugins/media-keys/gsd-media-keys-window.c: (draw_waves), (draw_cross), (draw_action_volume): make the composited volume images more clear: draw waves matching current volume and show a cross when muted (bug #557307) 2008-10-23 Jens Granseuer * plugins/media-keys/actions/acme-volume-gstreamer.c: (acme_volume_gstreamer_finalize), (acme_volume_gstreamer_close_real), (acme_volume_gstreamer_open), (acme_volume_gstreamer_close), (acme_volume_gstreamer_init), (acme_volume_gstreamer_class_init): * plugins/media-keys/actions/acme-volume-gstreamer.h: clean up Volume initialization so that we don't get non-functional volume keys when the plugin starts up with an invalid configuration initially, even if the configuration is fixed afterwards (bug #552383) 2008-10-19 Matthias Clasen Bug 556797 – support the Gtk/ButtonImages XSetting * plugins/xsettings/gsd-xsettings-manager.c: Support the Gtk/ButtonImages xsetting. 2008-10-15 Matthias Clasen Bug 556307 – show the shutdown dialog when the power button is pressed * plugins/media-keys/gsd-media-keys-manager.c (do_exit_action): Show the shutdown dialog when the power button is pressed, not the logout dialog. 2008-10-12 Christian Persch Bug 555553 – format not a string literal and no format arguments * cinnamon-settings-daemon/cinnamon-settings-manager.c * cinnamon-settings-daemon/cinnamon-settings-module.c * cinnamon-settings-daemon/main.c * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c * plugins/xrdb/gsd-xrdb-manager.c: Use printf safely. 2008-10-06 Matthias Clasen Bug 555873 – fix gdm keyboard layout handling even more * plugins/keyboard/gsd-keyboard-xkb.c (apply_xkb_settings): Try harder to handle initial-login situations correctly, while not overwriting any user configuration. 2008-10-06 Matthias Clasen Bug 554525 – fix the picking up of the gdm layout * plugins/keyboard/gsd-keyboard-xkb.c (apply_xkb_settings): Active a specific group only after activating the right keyboard configuration. Because the other way around doesn't work. 2008-10-05 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (set_server_from_gconf): don't make togglekeys_enable depend on global AccessX state (bug #555009) 2008-10-04 Jens Granseuer Patch by: Eric Piel * plugins/xrandr/gsd-xrandr-manager.c: (output_rotation_item_activate_cb): ignore the "activate" signal for deselected items so that the rotation setting doesn't reset when the systray menu is opened (bug #554951) ==================== 2.24.0 ==================== 2008-09-23 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.24.0 release. 2008-09-22 Michael J. Chudobiak * plugins/housekeeping/gsd-housekeeping-manager.c: Made the housekeeping plugin less aggressive by default (bug #552680). Code freeze break approved by release team. 2008-09-16 Matthias Clasen * plugins/keyboard/gsd-keyboard-xkb.c: Remove an accidentally added debug printf. 2008-09-12 Jens Granseuer Also allow linking the module state to other boolean keys by using a string value that is the name of the key to use. Note that in this case the state won't be updated at runtime due to GConf limitations. * plugins/xsettings/gsd-xsettings-manager.c: (get_gtk_modules): enable linking to other keys 2008-09-12 Jens Granseuer Specify GTK modules to load in a GConf directory instead of the single /desktop/gnome/gtk-modules key. Apps can now easily install additional modules by dropping a key with the name of the module and a boolean value (enabled/disabled) into /apps/gnome_settings_daemon/gtk-modules/ (bug #539840). * plugins/xsettings/gsd-xsettings-manager.c: (get_gtk_modules), (gtk_modules_callback), (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop): remove the old gtk-modules key in favor of a GConf directory 2008-09-12 Jens Granseuer * COPYING: add GPLv2 copyright notice explicitly so that newer versions of autotools don't declare us GPLv3 (bug #551956) 2008-09-11 Jens Granseuer Make the volume popup not crash when invoking it on any screen but the first when using a compositing manager (bug #551677) * plugins/media-keys/gsd-media-keys-window.c: (gsd_media_keys_window_real_realize), (gsd_media_keys_window_init): do not set the window colormap at init time where we'll only use the colormap of the default screen. Instead, whenever the window is realized, update the colormap to match the current screen. 2008-09-10 Jens Granseuer Patch by: Simon Zheng * cinnamon-settings-daemon/main.c: (main): fix the fix for read-only home directories from bug #530975 ==================== 2.23.92 ==================== 2008-09-08 Rodrigo Moya * NEWS: prepare for 2.23.92 release. 2008-09-06 Matthias Clasen Bug 551062 – try harder to use the keyboard layout passed by gdm * plugins/keyboard/gsd-keyboard-xkb.c: Be tolerant of variants when trying to match the gdm-provided keyboard layout to the existing keyboard configuration. ==================== 2.23.91 ==================== 2008-09-01 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.23.91 release. 2008-08-28 William Jon McCann * configure.ac: Belated post release version bump 2008-08-27 Jens Granseuer * plugins/xsettings/gsd-xsettings-manager.c: (setup_xsettings_managers): use g_warning instead of g_error when setup fails so we don't abort (bug #549483) 2008-08-26 William Jon McCann * plugins/a11y-keyboard/Makefile.am: * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c (dpi_from_pixels_and_mm), (get_dpi_from_x_server), (config_get_large_print), (config_set_large_print): * plugins/a11y-keyboard/test-a11y-preferences-dialog.c (test_window), (main): Use a scale factor instead of a fixed DPI. Add a test program. 2008-08-22 William Jon McCann * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (on_notification_closed): Oops. Missing comma. 2008-08-22 William Jon McCann * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (on_notification_closed): Fix a crash due to an incorrect signal handler definition. 2008-08-21 Jens Granseuer * plugins/keyboard/gsd-keyboard-xkb.c: (apply_xkb_settings): fix a constness warning 2008-08-19 Claude Paroz * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.glade: Removed the translatable property on stock gtk-close. ==================== 2.23.90 ==================== 2008-08-18 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.23.90 release. 2008-08-14 William Jon McCann * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c (get_dpi_from_x_server): Use gdk api to get dpi. 2008-08-13 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (status_icon_popup_menu): Create the RANDR configuration and labeler before the menu items. 2008-08-13 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (status_icon_popup_menu): Add a separator to the menu before "Configure display settings". 2008-08-13 Federico Mena Quintero * plugins/xrandr/gsd-xrandr-manager.c (status_icon_popup_menu): When the menu comes up, create a GnomeRRLabeler so that the user can identify which physical monitors we are talking about. This will actually be visible in the popup menu once we implement the rotation commands. (status_icon_popup_menu_selection_done_cb): Hide and destroy the GnomeRRLabeler. (struct CsdXrandrManagerPrivate): New field "labeler". 2008-08-12 Federico Mena Quintero * configure.ac: For LIBSOUNDS, check for libgnomeui, not just libgnome. 2008-08-12 Jens Granseuer Even if we can't properly remove a client message handler at least make sure everything works as expected when enabling/disabling the plugin at runtime * plugins/xrandr/gsd-xrandr-manager.c: (on_client_message), (gsd_xrandr_manager_start): pass the manager as user data instead of the screen because the manager will remain stable during the lifetime of the daemon; also, don't filter messages when the plugin is disabled 2008-08-12 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (status_icon_start): remove obsolete comment 2008-08-11 Jens Granseuer * configure.ac: require gnome-desktop 2.23.90 * plugins/xrandr/gsd-xrandr-manager.c: (gsd_xrandr_manager_start), (gsd_xrandr_manager_stop), (gsd_xrandr_manager_init): try harder to clean up in _stop so we can enable/disable the plugin on the fly; not quite there, yet 2008-08-10 Jens Granseuer Patch by: Matthias Clasen * plugins/xrandr/gsd-xrandr-manager.c: (gsd_xrandr_manager_start): fail on start if we couldn't set up xrandr (bug #546446) 2008-08-08 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (gsd_xrandr_manager_init): pass the manager as callback data so we don't crash with a NULL pointer in on_randr_event 2008-08-08 Jens Granseuer * plugins/xrandr/gsd-xrandr-manager.c: (gsd_xrandr_manager_start): remove warning that isn't 2008-08-05 Jens Granseuer * configure.ac: require glib >= 2.17.3 * plugins/xsettings/fontconfig-monitor.c: (monitor_files): use g_file_monitor instead of g_file_monitor_file/directory (bug #546372) 2008-08-05 Jens Granseuer * plugins/font/gsd-font-manager.c: (gsd_font_manager_class_init), (gsd_font_manager_init): remove some unnecessary boilerplate 2008-08-05 Jens Granseuer * plugins/a11y-keyboard/Makefile.am: put the glade file where all the others are 2008-08-05 Jens Granseuer * configure.ac: simplify libnotify check, fix fontconfig result output 2008-08-05 William Jon McCann * configure.ac: * plugins/a11y-keyboard/Makefile.am: * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c (get_int), (set_clear), (maybe_show_status_icon), (on_notification_closed), (on_slow_keys_action), (on_sticky_keys_action), (ax_slowkeys_warning_post_bubble), (ax_slowkeys_warning_post_dialog), (ax_slowkeys_warning_post), (ax_stickykeys_warning_post_bubble), (ax_stickykeys_warning_post_dialog), (ax_stickykeys_warning_post), (set_gconf_from_server), (keyboard_callback), (gsd_a11y_keyboard_manager_start), (gsd_a11y_keyboard_manager_stop), (on_preferences_dialog_response), (on_status_icon_activate), (gsd_a11y_keyboard_manager_init): * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.c (gsd_a11y_preferences_dialog_set_property), (gsd_a11y_preferences_dialog_get_property), (gsd_a11y_preferences_dialog_constructor), (gsd_a11y_preferences_dialog_dispose), (gsd_a11y_preferences_dialog_class_init), (on_response), (config_get_string), (config_get_bool), (dpi_from_pixels_and_mm), (get_dpi_from_x_server), (config_get_large_print), (config_set_large_print), (config_get_high_contrast), (config_set_high_contrast), (config_get_sticky_keys), (config_set_sticky_keys), (config_get_bounce_keys), (config_set_bounce_keys), (config_get_slow_keys), (config_set_slow_keys), (config_have_at_gconf_condition), (config_get_at_screen_reader), (config_get_at_screen_keyboard), (config_get_at_screen_magnifier), (config_set_at_screen_reader), (config_set_at_screen_keyboard), (config_set_at_screen_magnifier), (on_sticky_keys_checkbutton_toggled), (on_bounce_keys_checkbutton_toggled), (on_slow_keys_checkbutton_toggled), (on_high_contrast_checkbutton_toggled), (on_at_screen_reader_checkbutton_toggled), (on_at_screen_keyboard_checkbutton_toggled), (on_at_screen_magnifier_checkbutton_toggled), (on_large_print_checkbutton_toggled), (ui_set_sticky_keys), (ui_set_bounce_keys), (ui_set_slow_keys), (ui_set_high_contrast), (ui_set_at_screen_reader), (ui_set_at_screen_keyboard), (ui_set_at_screen_magnifier), (ui_set_large_print), (key_changed_cb), (setup_dialog), (gsd_a11y_preferences_dialog_init), (gsd_a11y_preferences_dialog_finalize), (gsd_a11y_preferences_dialog_new): * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.glade: * plugins/a11y-keyboard/gsd-a11y-preferences-dialog.h: Add status icon when a11y hotkeys are enabled. Display Universal Access Preferences when it is clicked. Fixes #526070 2008-08-04 Jens Granseuer * configure.ac: fix PulseAudio check to not output "no" twice ==================== 2.23.6 ==================== 2008-08-04 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.23.6 release. 2008-08-03 Jens Granseuer * plugins/common/gsd-keygrab.c: (setup_modifiers), (grab_key), (match_key): resolve NumLock dynamically and make sure we ignore it so using e.g. the media keys works even when NumLock is on (still bug #165343) Tue Jul 29 01:09:46 2008 Søren Sandmann * plugins/xrandr/gsd-xrandr-manager.c (start_or_stop_icon): Make the display notification icon configurable. 2008-07-26 Matthias Clasen Bug 544733 – use standard icon names in the volume OSD, initially * plugins/media-keys/actions/acme.glade: Use standard icon names for the OSD. 2008-07-26 Wouter Bolsterlee * configure.ac: Bump glib dependency to 2.15. Fixes bug #544737. 2008-07-25 Rob Bradford * configure.ac: libsounds needs to use gtk+-2.0 now libgnomeui is removed. 2008-07-24 James Sharpe * configure.ac: * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: * plugins/sound/gsd-sound-manager.c: Remove libgnomeui. (bug #544347) ==================== 2.23.5 ==================== Thu Jul 24 14:48:04 2008 Søren Sandmann * Downgrade intltool requirement to 0.37.1. This bug http://bugzilla.gnome.org/show_bug.cgi?id=537352 says that's what I'm supposed to do. * Bump version number to 2.23.5 * NEWS: Update this file. 2008-07-22 Lennart Poettering Fixes #539786 * plugins/xsettings/gsd-xsettings-manager.c: add three new xsettings for event sounds. 2008-07-16 Jens Granseuer Patch by: Damien Carbery * data/cinnamon-settings-daemon-uninstalled.pc.in: fix include path for building against the uninstalled package (bug #543289) 2008-07-15 Gerd Kohlberger * plugins/mouse/gsd-mouse-manager.c: (set_mousetweaks_daemon): Remove 'daemon' from the warning message (see bug #543095). 2008-07-15 Jens Granseuer * plugins/common/gsd-keygrab.c: (match_key): always remove Shift from the consumed modifiers if we're matching the lowercase symbol to make more shortcuts with Shift work (bug #542275) Wed Jul 9 11:48:02 2008 Søren Sandmann * plugins/xrandr/gsd-xrandr-manager.c: Call the new gnome_rr functions instead of the old ones. 2008-06-28 Jens Granseuer * plugins/common/gsd-keygrab.c: don't ignore any ModX modifiers. This should finally make g-s-d recognize keybindings with Super and Meta although we still don't handle the corresponding virtual modifiers (bug #165343) 2008-06-20 Jens Granseuer * plugins/common/gsd-keygrab.c: (match_key): fix accel check so that we don't match e.g. XF86RaiseVolume if + XF86RaiseVolume was pressed (bug #538699). Also fix build without XKB 2008-06-18 Jens Granseuer * Makefile.am: * configure.ac: require intltool >= 0.40 2008-06-18 Jens Granseuer * configure.ac: bump gnome-desktop requirement to 2.23.5 Tue Jun 17 19:41:55 2008 Søren Sandmann * Merge randr-12 branch into trunk Mon Jun 16 14:50:53 2008 Søren Sandmann * Port to new gnome-desktop API Mon Jun 16 14:30:13 2008 Søren Sandmann * Merge from trunk. 2008-06-17 Colin Walters http://bugzilla.gnome.org/show_bug.cgi?id=533198 * configure.ac: Detect PulseAudio at build time; if available, default to always starting it (ignore the legacy esd GConf key /desktop/gnome/sound/enable_esd). If you're a system administrator or OS builder and want to disable PulseAudio, you should preferably figure out what the problem you have with it is; but failing that, just remove it from the install image. * plugins/sound/gsd-sound-manager.c: If we're not compiled with legacy sound pref, always start sound. ==================== 2.23.4 ==================== 2008-06-17 Rodrigo Moya * configure.ac: * NEWS: update for 2.23.4 release. 2008-06-14 Jens Granseuer Based on a patch by: Brian Cameron * configure.ac: * plugins/sound/Makefile.am: * plugins/sound/gsd-sound-manager.c: (start_gnome_sound): if available use the esd_serverdir variable to locate the esd daemon so it can be started even if it's not in the PATH (bug #531868) 2008-06-13 Jens Granseuer Based on a patch by: Bastien Nocera * plugins/common/gsd-keygrab.c: (match_key): properly match keybindings that need Shift for resolving the keysym (bug #536581) 2008-06-07 Behdad Esfahbod (Commit this again) * configure.ac: Check for fontconfig instead of xft2. * plugins/xsettings/Makefile.am: * plugins/xsettings/gsd-xsettings-manager.c (fontconfig_callback), (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop): Send a Fontconfig/Timestamp xsettings notification whenever fontconfig configurations change. (bug #490374) * plugins/xsettings/fontconfig-monitor.c: * plugins/xsettings/fontconfig-monitor.h: Monitor fontconfig configuration files using gio. ==================== 2.23.3 ====================== 2008-06-03 Jens Granseuer * configure.ac: use correct release number 2008-06-03 Jens Granseuer * NEWS: Update for 2.23.3 release. 2008-06-02 Behdad Esfahbod * configure.ac: * plugins/xsettings/Makefile.am: * plugins/xsettings/fontconfig-monitor.c: * plugins/xsettings/fontconfig-monitor.h: * plugins/xsettings/gsd-xsettings-manager.c (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop): Revert previous change. Working on a slightly different design. (bug #490374) 2008-06-02 Behdad Esfahbod * configure.ac: Check for fontconfig instead of xft2. * plugins/xsettings/Makefile.am: * plugins/xsettings/gsd-xsettings-manager.c (fontconfig_callback), (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop): Send a Fontconfig/Timestamp xsettings notification whenever fontconfig configurations change. (bug #490374) * plugins/xsettings/fontconfig-monitor.c: * plugins/xsettings/fontconfig-monitor.h: Monitor fontconfig configuration files using gio. 2008-06-02 Jens Granseuer * configure.ac: do not add stuff to GST_LIBS when gstreamer is disabled. Fixes build without gstreamer (bug #536177) 2008-06-02 Gerd Kohlberger * plugins/mouse/gsd-locate-pointer.c: (timeline_frame_cb): Keep animation centered below pointer. Bug #531665 2008-05-30 Jens Granseuer * plugins/font/gsd-font-manager.c: (load_xcursor_theme): fix a few leaks 2008-05-27 Jens Granseuer * cinnamon-settings-daemon/cinnamon-settings-manager.c: (_unload_plugin), (_unload_all): stop all plugins on shutdown 2008-05-27 Lucas Rocha * cinnamon-settings-daemon/main.c (set_session_over_handler, on_session_over, main): listen to "SessionOver" D-Bus signal from Session Manager to know when to shutdown. Bug #522017. 2008-05-14 William Jon McCann * plugins/mouse/gsd-mouse-manager.c (filter): Bummer. Revert part of last commit. 2008-05-14 William Jon McCann * plugins/mouse/gsd-mouse-manager.c (filter): Don't eat keypresses for multimedia key events Patch by Bastien Nocera 2008-05-13 Jens Granseuer * plugins/background/gsd-background-manager.c: (gsd_background_manager_start): reuse the GConf client we already have 2008-05-13 William Jon McCann * configure.ac: * plugins/background/Makefile.am: * plugins/background/gsd-background-manager.c (draw_background), (queue_draw_background), (on_bg_changed), (gconf_changed_callback), (watch_bg_preferences), (gsd_background_manager_start), (gsd_background_manager_stop): Use new gnome-desktop background preference loading api. Drop use of libbackground. 2008-05-08 Carlos Garnacho * plugins/media-keys/gsd-media-keys-window.c (gsd_media_keys_window_real_realize): New function, sets a fully transparent input shape, so that clicks go through the media keys windows. Bug #531862. (gsd_media_keys_window_class_init): The usual glue. 2008-05-08 Carlos Garnacho * plugins/mouse/gsd-locate-pointer.c (set_transparent_shape): new function, sets a fully transparent shape to the whole window. (timeline_finished_cb) (gsd_locate_pointer): set the window transparent once the animation is finished, and before it's shown for the first time. The shape will be changed afterwards while running the animation. This fixes some artifacts shown when showing/moving the window, bug #531861. (locate_pointer_expose): Plug a leak. 2008-05-02 Jens Granseuer Patch by: Brian Cameron * cinnamon-settings-daemon/main.c: (main): don't die when the user's home directory is read-only (bug #530975) 2008-05-02 Jens Granseuer Based on a patch by: Matthias Clasen * plugins/keyboard/gsd-keyboard-xkb.c: (apply_xkb_settings), (gsd_keyboard_xkb_init): if the user set a keyboard layout from the login screen, try to keep that setting (bug #531589) 2008-05-02 Jens Granseuer * plugins/background/gsd-background-manager.c: (gsd_background_manager_start): add a comment explaining why we are applying the prefs regardless of nautilus 2008-05-02 Jens Granseuer Patch by: Matthias Clasen * plugins/background/gsd-background-manager.c: (gsd_background_manager_start): eventually apply the settings even if nautilus is supposed to be handling the background to make people running without nautilus happy (bug #531487) 2008-04-29 Bastien Nocera * plugins/common/gsd-keygrab.c (have_xkb), (match_key): When checking whether a key matches our key event, check the keysym from the key event, to avoid triggering another keybindings with the same keycode, but different keysym, Fixes Eject being triggered when pressing the Stop key with the default inet keymap (Closes: #530356) 2008-04-23 Vincent Untz * configure.ac: post release version bump. ==================== 2.23.1.1 ==================== 2008-04-23 Vincent Untz * configure.in: * NEWS: Update for 2.23.1.1 release. 2008-04-21 Lucas Rocha Install .desktop for cinnamon-settings-daemon in a standard autostart directory as required by new gnome-session (bug #526984). * configure.ac: expand $libexecdir to be used on .desktop file. * acinclude.m4: added new m4 macro (AS_AC_EXPAND) for expanding variables. * data/Makefile.am, data/cinnamon-settings-daemon.desktop.in.in: install g-s-d .desktop file. 2008-04-21 Rodrigo Moya * configure.ac: post release version bump. ==== 2.23.1 ==== 2008-04-21 Rodrigo Moya * configure.in: * NEWS: Update for release. 2008-04-20 Jens Granseuer * plugins/media-keys/actions/acme-volume-alsa.c: (acme_volume_alsa_finalize), (acme_volume_alsa_class_init): * plugins/media-keys/actions/acme-volume-dummy.c: (acme_volume_dummy_finalize), (acme_volume_dummy_class_init): * plugins/media-keys/actions/acme-volume-gstreamer.c: (acme_volume_gstreamer_finalize), (acme_volume_gstreamer_class_init): * plugins/media-keys/actions/acme-volume-oss.c: (acme_volume_oss_finalize), (acme_volume_oss_class_init): * plugins/media-keys/actions/acme-volume.c: (acme_volume_class_init): drop redundant GType stuff 2008-04-19 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (bindings_get_entry): remove some code (and translatable strings) for error that can never happen 2008-04-18 Jens Granseuer * plugins/mouse/gsd-mouse-manager.c: (set_mousetweaks_daemon): when we can't launch the daemon reset the GConf keys before showing the error dialog. If we wait until after the dialog is closed, the user can still toggle the settings while it's open 2008-04-13 Jens Granseuer Extract some functionality used by several plugins into a separate shared helper library (bug #525426). * configure.ac: * plugins/Makefile.am: * plugins/common/Makefile.am: * plugins/common/gsd-keygrab.c: * plugins/common/gsd-keygrab.h: * plugins/common/eggaccelerators.c: * plugins/common/eggaccelerators.h: new shared components * plugins/keybindings/Makefile.am: * plugins/keybindings/eggaccelerators.c: * plugins/keybindings/eggaccelerators.h: * plugins/keybindings/gsd-keybindings-manager.c: (binding_register_keys), (keybindings_filter): * plugins/media-keys/Makefile.am: * plugins/media-keys/actions/Makefile.am: * plugins/media-keys/actions/acme.h: * plugins/media-keys/eggaccelerators.c: * plugins/media-keys/eggaccelerators.h: * plugins/media-keys/gsd-media-keys-manager.c: (update_kbd_cb), (init_kbd), (acme_filter_events): make keybindings and media-keys plugins use the shared components 2008-04-13 Sergey Udaltsov * plugins/keyboard/gsd-keyboard-xkb.c: dropped gconf backup 2008-04-12 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (do_grab): * plugins/media-keys/gsd-media-keys-manager.c: (grab_key): make some tiny optimizations and add some more comments on what's happening 2008-04-12 Jens Granseuer * cinnamon-settings-daemon/main.c: * plugins/media-keys/gsd-media-keys-manager.c: DBus API has been stable for a while; don't define DBUS_API_SUBJECT_TO_CHANGE anymore 2008-04-12 Jens Granseuer * cinnamon-settings-daemon/main.c: (acquire_name_on_proxy), (bus_register), (main): fix a few small leaks 2008-04-12 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (init_screens): drop redundant code 2008-04-11 Jens Granseuer * cinnamon-settings-daemon/main.c: turn into a daemon by default and make --no-daemon work 2008-04-11 Jens Granseuer * plugins/sound/gsd-sound-plugin.c: (impl_deactivate): fix typo 2008-04-11 Jens Granseuer Make xrandr, xrdb, and xsettings plugin deactivation work * plugins/xrandr/gsd-xrandr-manager.c: (apply_settings): cleanup * plugins/xrandr/gsd-xrandr-plugin.c: (impl_deactivate): * plugins/xrdb/gsd-xrdb-plugin.c: (impl_deactivate): * plugins/xsettings/gsd-xsettings-plugin.c: (impl_deactivate): stop manager on deactivation * plugins/xrdb/gsd-xrdb-manager.c: (gsd_xrdb_manager_start), (gsd_xrdb_manager_stop): * plugins/xsettings/gsd-xsettings-manager.c: (gsd_xsettings_error_quark), (find_translation_entry), (xsettings_callback), (register_config_callback), (terminate_cb), (setup_xsettings_managers), (gnome_xsettings_manager_start), (gnome_xsettings_manager_stop), (gnome_xsettings_manager_init): clean up properly on stop 2008-04-11 Jens Granseuer Make typing-break plugin deactivation work * plugins/typing-break/gsd-typing-break-manager.c: (register_config_callback), (gsd_typing_break_manager_start), (gsd_typing_break_manager_stop): clean up properly on stop * plugins/typing-break/gsd-typing-break-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-11 Jens Granseuer Make screensaver and sound plugin deactivation work (sort of). The screensaver is currently not reaped when deactivating the plugin, but since the plugin should go away anyway, it doesn't seem worth adding that right now. For the sound plugin, esd is currently not reaped when HAVE_ESD is set. Maybe we want to get rid of the esd API altogether? * plugins/sound/gsd-sound-manager.c: (apply_settings), (register_config_callback), (gsd_sound_manager_start), (gsd_sound_manager_stop): clean up a bit more on stop * plugins/screensaver/gsd-screensaver-plugin.c: (impl_deactivate): * plugins/sound/gsd-sound-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-11 Jens Granseuer Make mouse plugin deactivation work * plugins/mouse/gsd-mouse-manager.c: (register_config_callback), (gsd_mouse_manager_init), (gsd_mouse_manager_start), (gsd_mouse_manager_stop): clean up properly on stop * plugins/mouse/gsd-mouse-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-11 Jens Granseuer * plugins/keyboard/gsd-keyboard-xkb.c: (gsd_keyboard_xkb_shutdown): clear the user callback data even if initialiation failed * plugins/keyboard/gsd-xmodmap.c: (gsd_load_modmap_files): properly NULL-terminate g_build_filename 2008-04-11 Jens Granseuer Make media-keys plugin deactivation work * plugins/media-keys/gsd-media-keys-manager.c: (acme_error), (dialog_init), (init_kbd), (gsd_media_keys_manager_stop), (register_manager): clean up properly on stop * plugins/media-keys/gsd-media-keys-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-11 Jens Granseuer * plugins/keyboard/gsd-xmodmap.c: (check_button_callback), (gsd_load_modmap_files), (response_callback), (remove_string_from_list), (remove_button_clicked_callback), (load_button_clicked_callback), (gsd_modmap_dialog_call): fix memory leaks 2008-04-10 Jens Granseuer Make keyboard plugin deactivation work * plugins/keyboard/gsd-keyboard-manager.c: (register_config_callback), (gsd_keyboard_manager_start), (gsd_keyboard_manager_stop): * plugins/keyboard/gsd-keyboard-xkb.c: (register_config_callback), (gsd_keyboard_xkb_init), (gsd_keyboard_xkb_shutdown): * plugins/keyboard/gsd-keyboard-xkb.h: clean up properly on stop * plugins/keyboard/gsd-keyboard-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer Make keybinding plugin deactivation work * plugins/keybindings/gsd-keybindings-manager.c: (register_config_callback), (gsd_keybindings_manager_start), (gsd_keybindings_manager_stop): clean up properly on stop * plugins/keybindings/gsd-keybindings-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer * plugins/font/gsd-font-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer * plugins/dummy/gsd-dummy-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer * plugins/clipboard/gsd-clipboard-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer Make background plugin deactivation work * plugins/background/gsd-background-manager.c: (gsd_background_manager_start), (gsd_background_manager_stop): clean up properly on stop * plugins/background/gsd-background-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (gsd_a11y_keyboard_manager_stop): also remove GConf watch directory 2008-04-10 Jens Granseuer Make housekeeping plugin deactivation work * plugins/housekeeping/gsd-housekeeping-manager.c: (register_config_callback), (gsd_housekeeping_manager_start), (gsd_housekeeping_manager_stop), (gsd_housekeeping_manager_init): clean up properly on stop * plugins/housekeeping/gsd-housekeeping-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer Make a11y-keyboard plugin deactivation work * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (register_config_callback), (gsd_a11y_keyboard_manager_start), (gsd_a11y_keyboard_manager_stop): properly clean up on _stop * plugins/a11y-keyboard/gsd-a11y-keyboard-plugin.c: (impl_deactivate): stop manager on deactivation 2008-04-10 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (get_xkb_desc_rec), (set_server_from_gconf), (ax_slowkeys_warning_dialog_post), (ax_stickykeys_warning_dialog_post), (set_gconf_from_server), (cb_xkb_event_filter), (gsd_a11y_keyboard_manager_init): more cleanup 2008-04-10 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (grab_key_real): remove excessive key grab logging 2008-04-09 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (numlock_xkb_init), (numlock_set_xkb_state), (numlock_gconf_state_key), (numlock_xkb_callback), (numlock_install_xkb_callback), (apply_settings), (gsd_keyboard_manager_start): split XKB initialization and calbback installation which allows us to get rid of some more special-casing and yet another static variable 2008-04-09 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (xkb_enabled), (get_xkb_desc_rec), (gsd_a11y_keyboard_manager_start): don't install any listeners or callbacks when XKB is not available 2008-04-09 Michael J. Chudobiak * plugins/housekeeping/gsd-housekeeping-manager.c: (gsd_housekeeping_manager_stop): Purge thumbnail cache on shutdown if and only if the max size or max age parameters have been set to zero (for paranoid people) (bug #526999). 2008-04-07 Jens Granseuer Currently, the percentage by which to lower or raise the volume when hitting the multimedia keys is taken from GConf, with 6 being the default. We don't have any settings dialogs to actually change it, though. If the user now selects a mixer that supports fewer volume levels than the GConf setting implies (100/6) it becomes impossible to change the volume (without fiddling with the GConf setting). This patch adds a "threshold" property to the AcmeVolume class that denotes the minimum percentage required to actually affect the volume. The plugin now uses the step size read from GConf or the mixer threshold, depending on which one is bigger. (bug #441910) * plugins/media-keys/actions/acme-volume-alsa.c: (acme_volume_alsa_get_threshold), (acme_volume_alsa_class_init): * plugins/media-keys/actions/acme-volume-dummy.c: (acme_volume_dummy_get_threshold), (acme_volume_dummy_class_init): * plugins/media-keys/actions/acme-volume-gstreamer.c: (acme_volume_gstreamer_get_threshold), (acme_volume_gstreamer_class_init): * plugins/media-keys/actions/acme-volume-oss.c: (acme_volume_oss_get_threshold), (acme_volume_oss_class_init), (acme_volume_oss_mixer_check): * plugins/media-keys/actions/acme-volume.c: (acme_volume_get_threshold): * plugins/media-keys/actions/acme-volume.h: add get_threshold method * plugins/media-keys/gsd-media-keys-manager.c: (do_sound_action): use gconf value or threshold, depending on what's bigger 2008-04-07 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (do_sound_action): only use the built-in default for volume_step if we get an error from GConf, not just when the value is 0 which might be what the user wants (see the discussion on the Thinkpad driver again) 2008-04-07 Jens Granseuer Remove the Thinkpad driver again. See bug #524425 for some discussion. * configure.ac: * plugins/media-keys/actions/Makefile.am: * plugins/media-keys/actions/acme-volume-thinkpad.c: * plugins/media-keys/actions/acme-volume-thinkpad.h: * plugins/media-keys/actions/acme-volume.c: (acme_volume_new): remove extra Thinkpad support 2008-04-06 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (gsd_keyboard_get_hostname_key), (numlock_set_xkb_state), (numlock_gconf_state_key), (numlock_get_gconf_state), (numlock_set_gconf_state), (numlock_xkb_callback), (numlock_install_xkb_callback), (apply_settings), (gsd_keyboard_manager_start), (gsd_keyboard_manager_init): * plugins/keyboard/gsd-keyboard-xkb.c: (gsd_keyboard_xkb_init): * plugins/keyboard/gsd-keyboard-xkb.h: continued attempt at making XKB setup and error handling a bit less arcane and crufty 2008-04-06 Jens Granseuer * plugins/keyboard/gsd-keyboard-xkb.c: * plugins/keyboard/gsd-keyboard-xkb.h: initialize inited_ok or behaviour is undefined when xkb setup fails; don't export XklEngine 2008-04-06 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (do_action): make "Home" keybinding work again 2008-04-05 Jens Granseuer * configure.ac: * plugins/media-keys/actions/Makefile.am: hook up the Thinkpad support 2008-04-05 Jens Granseuer Patch by: Lorne Applebaum <4lorne@gmail.com> * plugins/media-keys/actions/acme-volume-thinkpad.c: * plugins/media-keys/actions/acme-volume-thinkpad.h: * plugins/media-keys/actions/acme-volume.c: (acme_volume_new): add a special volume subclass for better support of IBM Thinkpad hardware volume buttons (bug #524425) 2008-04-05 Jens Granseuer Patch by: Lorne Applebaum <4lorne@gmail.com> * plugins/media-keys/actions/acme-volume-dummy.h: fix TYPE macro and remove an unimplemented prototype 2008-04-01 Jens Granseuer * plugins/keyboard/gsd-keyboard-manager.c: (gsd_keyboard_manager_start): apply keyboard settings on startup, too (bug #525440) 2008-03-31 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (bindings_get_entry): fix various leaks and other memory management issues 2008-03-31 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (bindings_get_entry), (binding_register_keys): remove trailing newlines from messages since g_warning already takes care of those 2008-03-31 Jens Granseuer * plugins/keybindings/gsd-keybindings-manager.c: (do_grab): * plugins/media-keys/gsd-media-keys-manager.c: (grab_key): don't try to add grabs with invalid modifiers 2008-03-30 Gerd Kohlberger * plugins/mouse/gsd-mouse-manager.c: (set_mousetweaks_daemon): Set gconf keys back to false, if mousetweaks isn't installed. Bug #525042. 2008-03-30 Jens Granseuer * plugins/xsettings/gsd-xsettings-manager.c: add mapping for Gtk/Modules xsetting using GConf path /desktop/gnome/gtk-modules (bug #507386) 2008-03-30 Jens Granseuer * plugins/housekeeping/gsd-housekeeping-manager.c: change data types to match glib; avoid using time_t 2008-03-30 Jens Granseuer * plugins/media-keys/actions/acme-volume-dummy.c: (acme_volume_dummy_init), (acme_volume_dummy_class_init): change to use G_DEFINE_TYPE instead of open-coding it 2008-03-29 Jens Granseuer * configure.ac: fix profiling to be off by default 2008-03-29 Jens Granseuer * cinnamon-settings-daemon/main.c: mark string for translation 2008-03-29 Jens Granseuer * plugins/keybindings/eggaccelerators.c: (egg_accelerator_parse_virtual): * plugins/media-keys/eggaccelerators.c: (egg_accelerator_parse_virtual): readd a chunk that got lost in the last commit. *sigh*. Why do we have several differing copies of those files? 2008-03-29 Jens Granseuer * plugins/keybindings/eggaccelerators.c: (egg_accelerator_parse_virtual), (egg_virtual_accelerator_name), (egg_virtual_accelerator_label), (egg_keymap_resolve_virtual_modifiers), (egg_keymap_virtualize_modifiers), (reload_modmap), (egg_keymap_get_modmap): * plugins/keybindings/eggaccelerators.h: fix mismatched modifier mapping between egg and GTK (so that e.g. works) and replace some custom functionality with stock GTK 2008-03-29 Jens Granseuer * plugins/media-keys/eggaccelerators.c: (egg_accelerator_parse_virtual), (egg_virtual_accelerator_name), (egg_virtual_accelerator_label), (egg_keymap_resolve_virtual_modifiers), (egg_keymap_virtualize_modifiers), (reload_modmap), (egg_keymap_get_modmap): * plugins/media-keys/eggaccelerators.h: fix mismatched modifier mapping between egg and GTK (so that e.g. works) and replace some custom functionality with stock GTK 2008-03-29 Jens Granseuer * plugins/housekeeping/gsd-housekeeping-manager.c: (get_gconf_int_with_default): rename to better reflect what it does, and also use the default passed in if we don't get an int from GConf, or we'll end up with a value of 0 which is certainly not what we want (purge_thumbnail_cache): update callers 2008-03-28 Michael J. Chudobiak * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/housekeeping/Makefile.am: * plugins/housekeeping/gsd-housekeeping-manager.c: (thumb_data_free), (read_dir_for_purge), (purge_old_thumbnails), (sort_file_mtime), (get_gconf_int_with_nonzero_default), (purge_thumbnail_cache), (do_cleanup), (do_cleanup_once), (do_cleanup_soon), (bindings_callback), (register_config_callback), (gsd_housekeeping_manager_start), (gsd_housekeeping_manager_stop), (gsd_housekeeping_manager_class_init), (gsd_housekeeping_manager_init), (gsd_housekeeping_manager_new): * plugins/housekeeping/gsd-housekeeping-manager.h: * plugins/housekeeping/gsd-housekeeping-plugin.c: (gsd_housekeeping_plugin_init), (gsd_housekeeping_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_housekeeping_plugin_class_init): * plugins/housekeeping/gsd-housekeeping-plugin.h: * plugins/housekeeping/housekeeping.cinnamon-settings-plugin.in: Added a new "housekeeping" plugin to set limits on the size and age of the thumbnail cache (bug #523159). 2008-03-25 Jens Granseuer Patch by: Matthias Clasen * plugins/mouse/gsd-mouse-manager.c: (filter): don't eat key events; other plugins might need them as well (bug #523676) 2008-03-24 William Jon McCann * configure.ac: Add some stuff to the configuration summary. * plugins/media-keys/gsd-media-keys-manager.c: (gsd_media_keys_manager_start): Add a few more profiling points. 2008-03-24 William Jon McCann * cinnamon-settings-daemon/Makefile.am: * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (set_server_from_gconf), (gsd_a11y_keyboard_manager_start): * plugins/background/Makefile.am: * plugins/background/gsd-background-manager.c: (apply_prefs), (gsd_background_manager_start): * plugins/clipboard/gsd-clipboard-manager.c: (gsd_clipboard_manager_start): * plugins/dummy/gsd-dummy-manager.c: (gsd_dummy_manager_start): * plugins/font/gsd-font-manager.c: (load_xcursor_theme), (load_cursor), (gsd_font_manager_start): * plugins/keybindings/gsd-keybindings-manager.c: (gsd_keybindings_manager_start): * plugins/keyboard/gsd-keyboard-manager.c: (gsd_keyboard_manager_start): * plugins/media-keys/Makefile.am: * plugins/media-keys/gsd-media-keys-manager.c: (init_kbd), (gsd_media_keys_manager_start): * plugins/mouse/gsd-mouse-manager.c: (gsd_mouse_manager_start): * plugins/screensaver/gsd-screensaver-manager.c: (gsd_screensaver_manager_start): * plugins/sound/gsd-sound-manager.c: (start_gnome_sound), (reload_foreach_cb), (apply_settings), (gsd_sound_manager_start): * plugins/typing-break/gsd-typing-break-manager.c: (setup_typing_break), (gsd_typing_break_manager_start): * plugins/xrandr/gsd-xrandr-manager.c: (apply_settings): * plugins/xrdb/gsd-xrdb-manager.c: (apply_settings), (gsd_xrdb_manager_start): * plugins/xsettings/gsd-xsettings-manager.c: (xft_settings_set_xsettings), (xft_settings_set_xresources), (update_xft_settings), (gnome_xsettings_manager_start): Add profiling points to plugins. 2008-03-24 William Jon McCann * cinnamon-settings-daemon/cinnamon-settings-manager.c: (compare_location), (_load_file), (_load_dir): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (debug_info), (gnome_settings_plugin_info_fill_from_file), (gnome_settings_plugin_info_deactivate), (load_plugin_module), (gnome_settings_plugin_info_activate), (gnome_settings_plugin_info_is_active), (gnome_settings_plugin_info_get_enabled), (gnome_settings_plugin_info_is_available), (gnome_settings_plugin_info_get_name), (gnome_settings_plugin_info_get_description), (gnome_settings_plugin_info_get_authors), (gnome_settings_plugin_info_get_website), (gnome_settings_plugin_info_get_copyright), (gnome_settings_plugin_info_get_location), (gnome_settings_plugin_info_get_priority), (gnome_settings_plugin_info_set_priority): Fix a refcounting bug. Add a few more checks. Fix up a leak. Fixes #524183 2008-03-24 William Jon McCann * plugins/media-keys/gsd-media-keys-manager.c: (acme_filter_events): * plugins/sound/gsd-sound-manager.c: (start_gnome_sound): Fix two compiler warnings. 2008-03-24 William Jon McCann * cinnamon-settings-daemon/cinnamon-settings-manager.c: (gnome_settings_manager_start): * cinnamon-settings-daemon/cinnamon-settings-profile.c: (_gnome_settings_profile_log): * cinnamon-settings-daemon/cinnamon-settings-profile.h: * cinnamon-settings-daemon/main.c: (main): Add missing files. Add some more profiling points. 2008-03-24 William Jon McCann * configure.ac: * cinnamon-settings-daemon/Makefile.am: * cinnamon-settings-daemon/cinnamon-settings-manager.c: (_load_file), (_load_dir), (_load_all), (gnome_settings_manager_start): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (gnome_settings_plugin_info_fill_from_file), (load_plugin_module), (_activate_plugin): * cinnamon-settings-daemon/main.c: (bus_register), (main): Add some profiling code. Must specify --enable-profiling to configure. Can now be profiled like so: strace -ttt -f -o /tmp/logfile.strace cinnamon-settings-daemon python plot-timeline.py -o prettygraph.png /tmp/logfile.strace See: http://www.gnome.org/~federico/news-2006-03.html#09 2008-03-24 Jens Granseuer Patch by: Alexey Shabalin * plugins/sound/gsd-sound-manager.c: (apply_settings): now that "starting esd" can mean either esd or PulseAudio, check the GConf setting for starting the sound server even when esd is disabled (bug #523743) 2008-03-24 Jens Granseuer * plugins/dummy/Makefile.am: remove NULL definition so authors using this as the base for their own plugins don't get strange ideas 2008-03-20 William Jon McCann * plugins/media-keys/Makefile.am: * plugins/media-keys/gsd-media-keys-manager.c: (grab_key_real), (init_kbd), (acme_filter_events), (gsd_media_keys_manager_start): * plugins/media-keys/test-media-keys.c: (main): Add a tool to test media keys. 2008-03-16 William Jon McCann * plugins/sound/gsd-sound-manager.c: (reset_esd_pid), (start_gnome_sound), (wait_on_child), (stop_child), (stop_gnome_sound), (apply_settings), (gsd_sound_manager_dispose): Fix handling of child process. 2008-03-14 Jens Granseuer * plugins/media-keys/gsd-media-keys-window.c: (remove_hide_timeout): reset opacity when removing the timeout so that the fadeout is restarted when media keys are pressed while the popup is already fading out (bug #522499) 2008-03-13 Jens Granseuer * plugins/media-keys/actions/acme.glade: remove unused properties (and, in particular, an unused translated string) 2008-03-13 Jens Granseuer Patch by: Danny Baumann * plugins/media-keys/gsd-media-keys-window.c: (gsd_media_keys_window_new): set window type hint on the volume popup (bug #522232) 2008-03-11 Jens Granseuer * plugins/typing-break/gsd-typing-break-manager.c: (setup_typing_break): pass data to the timeout so shutting down the typing monitor works instead of segfaulting (bug #521786) (gsd_typing_break_manager_start): use g_timeout_add_seconds instead of g_timeout_add 2008-03-10 Rodrigo Moya * configure.ac: Post release version bump ==== 2.22.0 ==== 2008-03-10 Rodrigo Moya * NEWS: Update for release. 2008-03-08 Jens Granseuer * data/Makefile.am: * data/apps_gnome_settings_daemon_default_editor.schemas.in: * data/cinnamon-settings-daemon.schemas.in: remove obsolete settings for the removed default editor plugin 2008-03-01 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (ax_response_callback): don't pass the GError argument if we're not going to use it. Also remove some unnecessary casting 2008-02-29 William Jon McCann * cinnamon-settings-daemon/main.c: Disable debug by default again. 2008-02-29 Jens Granseuer * configure.ac: * plugins/mouse/Makefile.am: when building with XInput support, actually link against libXi, or we'll fail to load the plugin due to unresolved symbols (bug #519488) 2008-02-29 William Jon McCann * configure.ac: Post release version bump ==== 2.21.92 ==== 2008-02-29 William Jon McCann * NEWS: Update for release. 2008-02-29 William Jon McCann * configure.ac: Remove Werror. 2008-02-29 Jens Granseuer * cinnamon-settings-daemon/cinnamon-settings-manager.c: (register_manager), (gnome_settings_manager_start): minor clean-up 2008-02-28 William Jon McCann * cinnamon-settings-daemon/cinnamon-settings-manager.c: (gnome_settings_manager_error_quark), (_load_file), (gnome_settings_manager_awake), (gnome_settings_manager_start), (gnome_settings_manager_start_with_settings_prefix), (_set_settings_prefix), (gnome_settings_manager_set_property), (gnome_settings_manager_get_property), (gnome_settings_manager_class_init), (gnome_settings_manager_finalize), (gnome_settings_manager_new): * cinnamon-settings-daemon/cinnamon-settings-manager.h: * cinnamon-settings-daemon/cinnamon-settings-manager.xml: * cinnamon-settings-daemon/main.c: (main): When dbus activated only load the plugins when requested instead of at startup. Add a new method to start and set plugin settings prefix. This allows gdm to use dbus activation. It also fixes cases where g-s-d is activated and plugins are loaded unintentionally. 2008-02-29 Wouter Bolsterlee * plugins/sound/gsd-sound-manager.c (apply_settings): Add braces to fix amgiguous else. Avoids compiler warnings. 2008-02-28 Bastien Nocera * plugins/sound/gsd-sound-manager.c (reset_esd_pid), (start_gnome_sound), (stop_gnome_sound), (apply_settings), (gsd_sound_manager_stop): Start the sound server ourselves, as we need it to cache samples. If esd (or the PulseAudio esd compat bits) isn't available, just print an error, and don't try to cache the samples If you use PulseAudio instead of esound in your distribution, build with --disable-esd passed to configure (Closes: #518075) 2008-02-25 William Jon McCann * cinnamon-settings-daemon/main.c: (gsd_log_default_handler), (main): Add --debug command line option. Only print DEBUG level messages if --debug is used. 2008-02-25 William Jon McCann * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (gnome_settings_plugin_info_fill_from_file): Don't warn on missing priority since we don't recommend that it be used. 2008-02-22 William Jon McCann * data/cinnamon-settings-daemon.schemas.in: Take a stab at defining the default load priorities. Fixes #518155 2008-02-22 William Jon McCann * data/cinnamon-settings-daemon.schemas.in: * cinnamon-settings-daemon/cinnamon-settings-manager.c: (_load_file): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (gnome_settings_plugin_info_set_priority): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.h: Allow gconf to override priorities. Set sound plugin priority to 1 (highest). Fixes #515340 2008-02-22 William Jon McCann * cinnamon-settings-daemon/Makefile.am: * cinnamon-settings-daemon/cinnamon-settings-manager.c: (_load_info), (maybe_activate_plugin), (compare_location), (compare_priority), (on_plugin_activated), (on_plugin_deactivated), (_load_file), (_load_dir), (_load_all), (_unload_all), (gnome_settings_manager_start), (gnome_settings_manager_stop), (gnome_settings_manager_constructor), (gnome_settings_manager_class_init), (gnome_settings_manager_finalize): * cinnamon-settings-daemon/cinnamon-settings-manager.h: * cinnamon-settings-daemon/cinnamon-settings-manager.xml: * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (gnome_settings_plugin_info_class_init), (gnome_settings_plugin_info_set_enabled_key_name), (_deactivate_plugin), (_activate_plugin): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.h: * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.c: * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.h: Merge PluginsEngine functionality into Manager. Emit signals when plugins are activated or deactivated. Fixes #515341 2008-02-22 William Jon McCann * cinnamon-settings-daemon/Makefile.am: * cinnamon-settings-daemon/cinnamon-settings-manager.c: (gnome_settings_manager_start), (gnome_settings_manager_stop), (gnome_settings_manager_constructor), (gnome_settings_manager_finalize): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.c: (gnome_settings_plugin_info_finalize), (gnome_settings_plugin_info_class_init), (gnome_settings_plugin_info_init), (gnome_settings_plugin_info_fill_from_file), (plugin_enabled_cb), (gnome_settings_plugin_info_set_enabled_key_name), (gnome_settings_plugin_info_new_from_file), (_deactivate_plugin), (gnome_settings_plugin_info_deactivate), (load_plugin_module), (_activate_plugin), (gnome_settings_plugin_info_activate), (gnome_settings_plugin_info_is_active), (gnome_settings_plugin_info_get_enabled), (gnome_settings_plugin_info_is_available), (gnome_settings_plugin_info_get_name), (gnome_settings_plugin_info_get_description), (gnome_settings_plugin_info_get_authors), (gnome_settings_plugin_info_get_website), (gnome_settings_plugin_info_get_copyright), (gnome_settings_plugin_info_get_location), (gnome_settings_plugin_info_get_priority): * cinnamon-settings-daemon/cinnamon-settings-plugin-info.h: * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.c: (gnome_settings_plugins_engine_load), (maybe_activate_plugin), (compare_location), (compare_priority), (gnome_settings_plugins_engine_load_file), (gnome_settings_plugins_engine_load_dir), (gnome_settings_plugins_engine_load_all), (gnome_settings_plugins_engine_unload_all), (gnome_settings_plugins_engine_start), (gnome_settings_plugins_engine_garbage_collect), (gnome_settings_plugins_engine_stop), (gnome_settings_plugins_engine_get_plugins_list), (_set_gconf_prefix), (gnome_settings_plugins_engine_set_property), (gnome_settings_plugins_engine_get_property), (gnome_settings_plugins_engine_class_init), (gnome_settings_plugins_engine_init), (gnome_settings_plugins_engine_finalize), (gnome_settings_plugins_engine_new): * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.h: Refactor the PluginInfo structure into a class. This will facilitate fixing bug #515341 2008-02-22 Bastien Nocera * configure.ac: Only enable ALSA and OSS support if we don't have GStreamer support, as the media-keys code doesn't have any fallbacks if GStreamer fails to load (see acme-volume.c's _new ()) 2008-02-19 Vincent Untz * plugins/keyboard/gsd-keyboard-manager.c: (gsd_keyboard_get_hostname_key): escape the hostname before using it in a gconf path since it might contain invalid characters. Fix bug #517259. 2008-02-19 Jens Granseuer * configure.ac: remove some unused stuff * plugins/sound/Makefile.am: add missing ESD_CFLAGS/LIBS 2008-02-19 Jens Granseuer * configure.ac: * plugins/xrandr/Makefile.am: * plugins/xrandr/gsd-xrandr-manager.c: (gsd_xrandr_manager_class_init), (gsd_xrandr_manager_init), (gsd_xrandr_manager_finalize): build with XRandR if available, makes setting screen geometry at login time work again (bug #517418) 2008-02-16 Jens Granseuer * cinnamon-settings-daemon/main.c: mark string as translatable 2008-02-14 Jens Granseuer * plugins/background/gsd-background-manager.c: (gsd_background_manager_start): at startup, don't apply background prefs twice and don't check for nautilus running since we're usually started first 2008-02-12 Kjartan Maraas * configure.ac: Fix for 515956. Build with Gio. ==== 2.21.91 ==== 2008-02-11 Rodrigo Moya * configure.ac: * NEWS: prepare for 2.21.91. 2008-02-11 Rodrigo Moya Fixes bug #513990 * plugins/background/gsd-background-manager.c: use GIO instead of gnome-vfs. * plugins/configure.ac: * plugins/Makefile.am: * plugins/default-editor/*: removed useless default editor plugin. 2008-02-11 Rodrigo Moya Patch by Wouter Bolsterlee * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.c (gnome_settings_plugins_engine_load_all): assign return value from g_slist_sort to the plugins list variable. (bug #515340) 2008-02-10 Jens Granseuer * cinnamon-settings-daemon/main.c: update the default GConf prefix to match the changes from r112 or bug #514411 2008-02-09 Jens Granseuer Support for defining plugin start order got lost in the split from gnome-control-center, but it is essential for some plugins to work correctly. With this change the "Priority" keyword can be used in the ".cinnamon-settings-plugin" file to set plugin priorities. Priority can take values from 1 upwards, with 1 being maximum priority and 100 being the default if nothing is specified by the plugin. For multiple plugins with identical priority start order is undefined. (bug #515340) * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.c: (gnome_settings_plugins_engine_load), (activate_plugin), (compare_location), (compare_priority), (gnome_settings_plugins_engine_load_file), (gnome_settings_plugins_engine_load_all), (gnome_settings_plugins_engine_init), (gnome_settings_plugins_engine_shutdown), (gnome_settings_plugins_engine_get_plugins_list), (gnome_settings_plugins_engine_get_plugin_copyright), (gnome_settings_plugins_engine_get_plugin_priority): * cinnamon-settings-daemon/cinnamon-settings-plugins-engine.h: add back support for defining plugin start order 2008-02-09 Jens Granseuer * plugins/media-keys/gsd-media-keys-manager.c: (gsd_media_keys_manager_stop): declare variables at the beginning of a block to make older compilers happy 2008-02-09 Jens Granseuer * plugins/clipboard/gsd-clipboard-manager.c: (gsd_clipboard_error_quark): fix copy'n'paste error (bug #515426) 2008-02-08 Sebastien Bacher * configure.ac: check for xinput (bug #514942) 2008-02-08 Jens Granseuer * plugins/background/gsd-background-manager.c: (gsd_background_manager_start), (gsd_background_manager_stop): * plugins/keybindings/gsd-keybindings-manager.c: (gsd_keybindings_manager_start): * plugins/media-keys/gsd-media-keys-manager.c: (gsd_media_keys_manager_stop): fix leaks * plugins/default-editor/gsd-default-editor-manager.c: (gsd_default_editor_manager_start): fix leak and pass the correct data to the mime type callback * plugins/xsettings/gsd-xsettings-manager.c: (gnome_xsettings_manager_start): unref the GConfClient only after we're done with it 2008-02-08 Jens Granseuer * plugins/clipboard/gsd-clipboard-manager.c: (gsd_kbd_a11y_error_quark), (gsd_clipboard_manager_start): make sure we return a GError if initialization fails 2008-02-08 Matthias Clasen * plugins/keyboard/gsd-keyboard-manager.c (gsd_keyboard_manager_start): Load the XKB settings initially. Fixes bug #511771. 2008-02-07 Jens Granseuer * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: (gsd_kbd_a11y_error_quark), (gsd_a11y_keyboard_manager_start): make sure we return a GError if initialization fails (bug #514926) 2008-02-06 Jens Granseuer * plugins/media-keys/gsd-media-keys-window.c: (volume_controls_set_visible), (window_set_icon_name), (window_set_icon_file), (volume_level_changed), (gsd_media_keys_window_class_init), (gsd_media_keys_window_init): release the glade XML file as soon as possible and keep track of the two widgets we need. This way we can also get rid of the custom finalize method 2008-02-06 Jens Granseuer * data/cinnamon-settings-daemon.schemas.in: use gnome_settings_daemon for the GConf path. This is what the other g-s-d settings use as well, and there is no good reason to use two separate paths (bug #514411) 2008-02-06 Jens Granseuer * configure.ac: add separate checks for libbackground * plugins/background/libbackground/*: delete files and use the external copy from gnome-control-center to avoid duplication 2008-02-05 Jens Granseuer Based on a patch by: Damien Carberry * configure.ac: * data/cinnamon-settings-daemon-uninstalled.pc.in: add uninstalled.pc file for building against an uninstalled copy of g-s-d (bug #511820) 2008-02-05 Jens Granseuer Based on a patch by: Damien Carberry * Makefile.am: * autogen.sh: * configure.ac: * plugins/a11y-keyboard/Makefile.am: * plugins/background/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/default-editor/Makefile.am: * plugins/dummy/Makefile.am: * plugins/font/Makefile.am: * plugins/keybindings/Makefile.am: * plugins/keyboard/Makefile.am: * plugins/media-keys/Makefile.am: * plugins/media-keys/actions/Makefile.am: * plugins/mouse/Makefile.am: * plugins/screensaver/Makefile.am: * plugins/sound/Makefile.am: * plugins/typing-break/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrdb/Makefile.am: * plugins/xsettings/Makefile.am: * src: rename the src folder to cinnamon-settings-daemon. This is needed so we can supply an uninstalled.pc file for g-s-d (see discussion in bug #511820) 2008-02-04 Jens Granseuer * plugins/screensaver/gsd-screensaver-manager.c: (gsd_screensaver_manager_start): don't crash when running the screensaver fails. The plugin relies on the GError it passes always being filled in if we couldn't start the module, so set it up properly in those cases (bug #514385) 2008-02-04 Luca Ferretti reviewed by: Jens Granseuer * data/apps_gnome_settings_daemon_default_editor.schemas.in: * data/apps_gnome_settings_daemon_keybindings.schemas.in: * data/apps_gnome_settings_daemon_screensaver.schemas.in: * data/desktop_gnome_font_rendering.schemas.in: * data/cinnamon-settings-daemon.schemas.in: Review short and long descriptions for GConf keys, bug #514047. 2008-02-02 Jens Granseuer * src/Makefile.am: remove duplicate CFLAGS (and NULL) 2008-02-01 Christian Persch * configure.ac: Install the settings plugin to $(libdir)/cinnamon-settings-daemon-2.0. Fixes install with libdir == libexecdir, bug #504203. 2008-02-01 Christian Persch Bug #513246. * acinclude.m4: * configure.ac: * plugins/a11y-keyboard/Makefile.am: * plugins/background/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/default-editor/Makefile.am: * plugins/dummy/Makefile.am: * plugins/font/Makefile.am: * plugins/keybindings/Makefile.am: * plugins/keyboard/Makefile.am: * plugins/media-keys/Makefile.am: * plugins/media-keys/actions/Makefile.am: * plugins/mouse/Makefile.am: * plugins/screensaver/Makefile.am: * plugins/sound/Makefile.am: * plugins/typing-break/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrdb/Makefile.am: * plugins/xsettings/Makefile.am: Use a flat directory instead of a directory hierarchy to install the plugins into. Install data files under $(pkgdatadir), not under $(libdir). * src/Makefile.am: * src/cinnamon-settings-plugins-engine.c: (gnome_settings_plugin_info_free), (gnome_settings_plugins_engine_load), (gnome_settings_plugins_engine_load_file), (gnome_settings_plugins_engine_load_dir): Don't scan the plugins directory recursively. Use GSlice for the plugin info struct. ==== 2.21.90.2 ==== 2008-01-30 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.21.90.2. 2008-01-30 Gabor Kelemen * data/apps_gnome_settings_daemon_keybindings.schemas.in: Change E-mail schema's descriptions to be more verbose and sensible. Fix #512766. 2008-01-30 Christian Persch * configure.ac: * plugins/a11y-keyboard/Makefile.am: * plugins/a11y-keyboard/a11y-keyboard.cinnamon-settings-plugin.desktop .in: * plugins/background/Makefile.am: * plugins/background/background.cinnamon-settings-plugin.desktop.in: * plugins/clipboard/Makefile.am: * plugins/clipboard/clipboard.cinnamon-settings-plugin.desktop.in: * plugins/default-editor/Makefile.am: * plugins/default-editor/default-editor.cinnamon-settings-plugin.deskt op.in: * plugins/dummy/Makefile.am: * plugins/dummy/dummy.cinnamon-settings-plugin.desktop.in: * plugins/font/Makefile.am: * plugins/font/font.cinnamon-settings-plugin.desktop.in: * plugins/keybindings/Makefile.am: * plugins/keybindings/keybindings.cinnamon-settings-plugin.desktop.in: * plugins/keyboard/Makefile.am: * plugins/keyboard/keyboard.cinnamon-settings-plugin.desktop.in: * plugins/media-keys/Makefile.am: * plugins/media-keys/media-keys.cinnamon-settings-plugin.desktop.in: * plugins/mouse/Makefile.am: * plugins/mouse/mouse.cinnamon-settings-plugin.desktop.in: * plugins/screensaver/Makefile.am: * plugins/screensaver/screensaver.cinnamon-settings-plugin.desktop.in: * plugins/sound/Makefile.am: * plugins/sound/libsounds/Makefile.am: * plugins/sound/sound.cinnamon-settings-plugin.desktop.in: * plugins/typing-break/Makefile.am: * plugins/typing-break/typing-break.cinnamon-settings-plugin.desktop.in: * plugins/xrandr/Makefile.am: * plugins/xrandr/xrandr.cinnamon-settings-plugin.desktop.in: * plugins/xrdb/Makefile.am: * plugins/xrdb/xrdb.cinnamon-settings-plugin.desktop.in: * plugins/xsettings/Makefile.am: * plugins/xsettings/xsettings.cinnamon-settings-plugin.desktop.in: * po/POTFILES.in: No need to use weird naming of .cinnamon-settings-daemon.in files. Bug #512048. 2008-01-29 Rodrigo Moya * data/org.gnome.SettingsDaemon.service.in: use correct binary path. ==== 2.21.90.1 ==== 2008-01-29 Rodrigo Moya * NEWS: * configure.ac: prepare for 2.21.90.1. 2008-01-29 Rodrigo Moya * src/Makefile.am: use plain $libexecdir for g-s-d binary. ==== 2.21.90 ==== 2008-01-28 Rodrigo Moya * configure.ac: * NEWS: prepare for 2.21.90. 2008-01-28 Wouter Bolsterlee * data/Makefile.am: Suppress verbose GConf schema installation output. 2008-01-28 Wouter Bolsterlee * src/Makefile.am: Don't use weird autofu stuff to install cinnamon-settings-daemon into another directory, but define gsddir and gsd_PROGRAMS instead. Fixes bug #504203. 2008-01-28 Wouter Bolsterlee * data/org.gnome.SettingsDaemon.service.in: * src/Makefile.am: Hopefully allow $(libdir) to be the same directory as $(libexecdir) by installing the cinnamon-settings-daemon binary into a subdirectory of $(libexecdir), i.e. $(libexecdir)/cinnamon-settings-daemon/cinnamon-settings-daemon. Fixes bug #504203. 2008-01-28 Wouter Bolsterlee * src/main.c: (main): Don't leak the GnomeProgram instance. 2008-01-28 Wouter Bolsterlee * configure.ac: * src/main.c: (main): Initialize GnomeProgram to avoid critical warnings from libgnome. Fixes bug #509770. 2008-01-26 Jens Granseuer * data/cinnamon-settings-daemon.pc.in: DBus API has been frozen for a while now. No longer define DBUS_API_SUBJECT_TO_CHANGE 2008-01-25 Soren Sandmann * plugins/background/gsd-background-manager.c (GNOME_DESKTOP_USE_UNSTABLE_API): Define this macro before including gnome-bg.h 2008-01-25 Jens Granseuer * plugins/xsettings/gsd-xsettings-manager.c: (xft_settings_set_xresources): don't try to reference a non-existing variable (left-over cruft from the patch for bug #505470) 2008-01-25 Jens Granseuer * data/cinnamon-settings-daemon.schemas.in: fix typo in typing break key. Bug #510429. 2008-01-25 Jens Granseuer Patch by: * configure.ac: readd check for XFT2 that got lost in the g-s-d split. Bug #510925. 2008-01-25 Christian Persch * plugins/xsettings/gsd-xsettings-manager.c: (xft_settings_set_xresources): Use g_ascii_dtostr instead of setlocale. Bug #505470. 2008-01-25 Christian Persch * plugins/media-keys/Makefile.am: Fix build with builddir != srcdir. BUg #509142. 2008-01-24 Jens Granseuer * configure.ac: quote function names in AC_DEFUN to fix "underquoted definition" autoconf warning 2008-01-23 Kjartan Maraas * plugins/mouse/gsd-locate-pointer.c: (timeline_frame_cb), (timeline_finished_cb): Fix a couple typos that broke the build. 2008-01-22 Carlos Garnacho * plugins/mouse/gsd-locate-pointer.c: Reworked, add a more appealing animation if there's a composite manager present, also use a similar animation for the non-composite case, so most of the code is shared. * plugins/mouse/gsd-timeline.[ch]: New files, object to control the "locate pointer" animation. * plugins/mouse/Makefile.am: Added these files to build. ==== 2.21.5.2 ==== 2008-01-15 Rodrigo Moya * configure.ac: * NEWS: prepare for 2.21.5.2. 2008-01-15 Rodrigo Moya * plugins/sound/Makefile.am: * plugins/sound/libsounds/Makefile.am: use a libtool library for x86_64 warnings. * configure.ac: automake fixes for allowing long file names in tar.gz. ==== 2.21.5.1 ==== 2008-01-15 Rodrigo Moya * configure.ac: * NEWS: prepare for 2.21.5.1. ==== 2.21.5 ==== 2008-01-15 Rodrigo Moya * NEWS: prepare for 2.21.5. 2008-01-14 Rodrigo Moya * data/cinnamon-settings-daemon.pc.in: reverted last patch. 2008-01-14 Rodrigo Moya * data/cinnamon-settings-daemon.pc.in: added dbusapidir variable, for the gnome-control-center module to access the .xml DBus interfaces file. 2008-01-14 Denis Washington * plugins/xrandr/Makefile.in: This was probably committed by accident, remove it. 2008-01-14 Denis Washington * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c: Only consider /desktop/gnome/accessibility/keyboard/enable as option for enabling keyboard a11y features from the keyboard, not as global switch to turn all a11y features on/off. 2008-01-14 Denis Washington Patch from Gerd Kohlberger (bug #503547) * plugins/mouse/gsd-mouse-manager.c: Mousetweaks support. 2008-01-14 Rodrigo Moya * plugins/media-keys/gsd-media-keys-manager.c: reverted patch from bug #165343. 2007-12-24 Christian Persch * plugins/xsettings/gsd-xsettings-manager.c: Add Gtk/IMModule XSetting. Bug #504182, patch by Akira TAGOH. 2007-12-22 William Jon McCann * plugins/xsettings/gsd-xsettings-manager.c: use new setting from libgnome to make toolbar icon size setting work (bug #401030) Merge from gnome-control-center. 2007-12-22 William Jon McCann * plugins/xsettings/Makefile.am: * plugins/xsettings/gnome-xsettings-manager.c: * plugins/xsettings/gnome-xsettings-manager.h: * plugins/xsettings/gnome-xsettings-plugin.c: * plugins/xsettings/gnome-xsettings-plugin.h: * plugins/xsettings/gsd-xsettings-manager.c: * plugins/xsettings/gsd-xsettings-plugin.c: Rename files to be consistent with other plugins. 2007-12-21 William Jon McCann * plugins/background/Makefile.am: * plugins/background/background.cinnamon-settings-plugin.desktop.in: * plugins/background/gsd-background-manager.c: (gsd_background_manager_init): * plugins/background/test-background.c: (idle), (main): Init gnome-vfs and use the correct name in the desktop file. 2007-12-21 William Jon McCann * configure.ac: * plugins/background/gsd-background-manager.c: (nautilus_is_running), (apply_prefs), (queue_apply), (background_callback), (on_bg_changed), (gsd_background_manager_start): Merge g-c-c patch for animated backgrounds. Require gnome-desktop 2.21.4. Patch from: Soeren Sandmann 2007-12-18 William Jon McCann * configure.ac: Post release version bump ==== 2.21.4 ==== 2007-12-18 William Jon McCann * NEWS: Update for release. 2007-12-18 William Jon McCann * configure.ac: Update version number. 2007-12-18 William Jon McCann * src/cinnamon-settings-manager.c: (gnome_settings_manager_awake): * src/main.c: Turn off daemonizing for now since it confused D-Bus service activation. 2007-12-18 William Jon McCann * src/Makefile.am: * src/cinnamon-settings-manager.c: (gnome_settings_manager_awake), (register_manager), (gnome_settings_manager_class_init), (gnome_settings_manager_new): * src/cinnamon-settings-manager.h: * src/cinnamon-settings-manager.xml: Provide the awake method and install the dbus api header. 2007-12-17 William Jon McCann * plugins/background/Makefile.am: * plugins/sound/Makefile.am: Fix distcheck. 2007-12-17 William Jon McCann * plugins/Makefile.am: * plugins/a11y-keyboard/a11y-keyboard.cinnamon-settings-plugin.desktop .in: * plugins/a11y-keyboard/gsd-a11y-keyboard-manager.h: * plugins/a11y-keyboard/gsd-a11y-keyboard-plugin.c: (gsd_a11y_keyboard_plugin_init), (gsd_a11y_keyboard_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_a11y_keyboard_plugin_class_init): * plugins/a11y-keyboard/gsd-a11y-keyboard-plugin.h: Add a11y keyboard plugin. 2007-12-17 William Jon McCann * configure.ac: * plugins/Makefile.am: * plugins/typing-break/Makefile.am: * plugins/typing-break/gsd-typing-break-manager.c: (register_config_callback), (typing_break_timeout), (child_watch), (setup_typing_break), (typing_break_callback), (really_setup_typing_break), (gsd_typing_break_manager_start), (gsd_typing_break_manager_stop), (gsd_typing_break_manager_set_property), (gsd_typing_break_manager_get_property), (gsd_typing_break_manager_constructor), (gsd_typing_break_manager_dispose), (gsd_typing_break_manager_class_init), (gsd_typing_break_manager_init), (gsd_typing_break_manager_finalize), (gsd_typing_break_manager_new): * plugins/typing-break/gsd-typing-break-manager.h: * plugins/typing-break/gsd-typing-break-plugin.c: (gsd_typing_break_plugin_init), (gsd_typing_break_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_typing_break_plugin_class_init): * plugins/typing-break/gsd-typing-break-plugin.h: * plugins/typing-break/typing-break.cinnamon-settings-plugin.desktop.in: Add typing break plugin. 2007-12-17 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/sound/Makefile.am: * plugins/sound/gsd-sound-manager.c: (start_gnome_sound), (stop_gnome_sound), (reload_foreach_cb), (apply_settings), (register_config_callback), (sound_callback), (gsd_sound_manager_start), (gsd_sound_manager_stop), (gsd_sound_manager_set_property), (gsd_sound_manager_get_property), (gsd_sound_manager_constructor), (gsd_sound_manager_dispose), (gsd_sound_manager_class_init), (gsd_sound_manager_init), (gsd_sound_manager_finalize), (gsd_sound_manager_new): * plugins/sound/gsd-sound-manager.h: * plugins/sound/gsd-sound-plugin.c: (gsd_sound_plugin_init), (gsd_sound_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_sound_plugin_class_init): * plugins/sound/gsd-sound-plugin.h: * plugins/sound/sound.cinnamon-settings-plugin.desktop.in: * plugins/xrandr/Makefile.in: Add sound plugin 2007-12-17 William Jon McCann * data/cinnamon-settings-daemon.schemas.in: Add schemas for media keys. 2007-12-17 William Jon McCann * configure.ac: * plugins/Makefile.am: * plugins/dummy/gsd-dummy-manager.c: * plugins/media-keys/Makefile.am: * plugins/media-keys/actions/Makefile.am: * plugins/media-keys/actions/acme-volume-alsa.c: (acme_volume_alsa_finalize), (acme_volume_alsa_set_mute), (acme_volume_alsa_get_mute), (acme_volume_alsa_get_volume), (acme_volume_alsa_set_volume), (acme_volume_alsa_close_real), (acme_volume_alsa_open), (acme_volume_alsa_close), (acme_volume_alsa_init), (acme_volume_alsa_class_init): * plugins/media-keys/actions/acme-volume-alsa.h: * plugins/media-keys/actions/acme-volume-dummy.c: (acme_volume_dummy_finalize), (acme_volume_dummy_set_mute), (acme_volume_dummy_get_mute), (acme_volume_dummy_get_volume), (acme_volume_dummy_set_volume), (acme_volume_dummy_init), (acme_volume_dummy_class_init), (acme_volume_dummy_get_type): * plugins/media-keys/actions/acme-volume-dummy.h: * plugins/media-keys/actions/acme-volume-gstreamer.c: (acme_volume_gstreamer_finalize), (acme_volume_gstreamer_set_mute), (update_state), (acme_volume_gstreamer_get_mute), (acme_volume_gstreamer_get_volume), (acme_volume_gstreamer_set_volume), (acme_volume_gstreamer_close_real), (_acme_set_mixer), (acme_volume_gstreamer_open), (acme_volume_gstreamer_close), (acme_volume_gstreamer_init), (acme_volume_gstreamer_class_init): * plugins/media-keys/actions/acme-volume-gstreamer.h: * plugins/media-keys/actions/acme-volume-oss.c: (acme_volume_oss_finalize), (acme_volume_oss_vol_check), (acme_volume_oss_set_mute), (acme_volume_oss_get_mute), (acme_volume_oss_get_volume), (acme_volume_oss_set_volume), (acme_volume_oss_init), (acme_volume_oss_class_init), (acme_volume_oss_mixer_check): * plugins/media-keys/actions/acme-volume-oss.h: * plugins/media-keys/actions/acme-volume.c: (acme_volume_class_init), (acme_volume_init), (acme_volume_get_volume), (acme_volume_set_volume), (acme_volume_get_mute), (acme_volume_set_mute), (acme_volume_mute_toggle), (acme_volume_new): * plugins/media-keys/actions/acme-volume.h: * plugins/media-keys/actions/acme.glade: * plugins/media-keys/actions/acme.h: * plugins/media-keys/eggaccelerators.c: (is_alt), (is_ctl), (is_modx), (is_ctrl), (is_shft), (is_shift), (is_control), (is_release), (is_meta), (is_super), (is_hyper), (is_keycode), (egg_accelerator_parse_virtual), (egg_virtual_accelerator_name), (egg_keymap_resolve_virtual_modifiers), (egg_keymap_virtualize_modifiers), (reload_modmap), (egg_keymap_get_modmap): * plugins/media-keys/eggaccelerators.h: * plugins/media-keys/gsd-marshal.list: * plugins/media-keys/gsd-media-keys-manager.c: (init_screens), (acme_error), (get_term_command), (execute), (do_sleep_action), (dialog_init), (grab_key_real), (grab_key), (is_valid_shortcut), (update_kbd_cb), (init_kbd), (dialog_show), (do_unknown_action), (do_help_action), (do_mail_action), (do_media_action), (do_www_action), (do_exit_action), (do_eject_action), (do_sound_action), (find_by_application), (find_by_time), (gsd_media_keys_manager_grab_media_player_keys), (gsd_media_keys_manager_release_media_player_keys), (gsd_media_player_key_pressed), (do_multimedia_player_action), (do_action), (acme_get_screen_from_event), (acme_filter_events), (gsd_media_keys_manager_start), (gsd_media_keys_manager_stop), (gsd_media_keys_manager_set_property), (gsd_media_keys_manager_get_property), (gsd_media_keys_manager_constructor), (gsd_media_keys_manager_dispose), (gsd_media_keys_manager_class_init), (gsd_media_keys_manager_init), (gsd_media_keys_manager_finalize), (register_manager), (gsd_media_keys_manager_new): * plugins/media-keys/gsd-media-keys-manager.h: * plugins/media-keys/gsd-media-keys-manager.xml: * plugins/media-keys/gsd-media-keys-plugin.c: (gsd_media_keys_plugin_init), (gsd_media_keys_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_media_keys_plugin_class_init): * plugins/media-keys/gsd-media-keys-plugin.h: * plugins/media-keys/gsd-media-keys-window.c: (fade_timeout), (hide_timeout), (remove_hide_timeout), (add_hide_timeout), (update_window), (volume_controls_set_visible), (window_set_icon_name), (window_set_icon_file), (action_changed), (volume_level_changed), (volume_muted_changed), (gsd_media_keys_window_set_action), (gsd_media_keys_window_set_volume_muted), (gsd_media_keys_window_set_volume_level), (curved_rectangle), (load_pixbuf), (render_eject), (draw_eject), (draw_action_eject), (draw_waves), (draw_speaker), (render_speaker), (draw_volume_boxes), (draw_action_volume), (draw_action), (on_expose_event), (gsd_media_keys_window_real_show), (gsd_media_keys_window_real_hide), (gsd_media_keys_window_class_init), (gsd_media_keys_window_is_valid), (initialize_alpha_mode), (gsd_media_keys_window_init), (gsd_media_keys_window_finalize), (gsd_media_keys_window_new): * plugins/media-keys/gsd-media-keys-window.h: * plugins/media-keys/media-keys.cinnamon-settings-plugin.desktop.in: * plugins/media-keys/test-media-window.c: (update_state), (test_window), (main): * plugins/xrandr/Makefile.in: Add media keys plugin. 2007-12-17 William Jon McCann * configure.ac: * data/Makefile.am: * data/apps_gnome_settings_daemon_default_editor.schemas.in: * data/apps_gnome_settings_daemon_keybindings.schemas.in: * data/apps_gnome_settings_daemon_screensaver.schemas.in: * data/desktop_gnome_font_rendering.schemas.in: * plugins/default-editor/Makefile.am: * plugins/default-editor/gsd-default-editor-manager.c: (gsd_default_editor_manager_init): * plugins/keyboard/Makefile.am: * plugins/keyboard/gsd-keyboard-manager.c: * plugins/mouse/gsd-mouse-manager.c: * plugins/screensaver/gsd-screensaver-manager.c: (gsd_screensaver_manager_start): * plugins/xrandr/Makefile.in: * plugins/xrandr/gsd-xrandr-manager.c: * plugins/xrdb/Makefile.am: Add other schemas. Fix some zero length private data. Fix some install dirs. Add libgnomekbd deps. 2007-12-17 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/screensaver/Makefile.am: * plugins/screensaver/gsd-screensaver-manager.c: (key_toggled_cb), (gsd_screensaver_manager_start), (gsd_screensaver_manager_stop), (gsd_screensaver_manager_set_property), (gsd_screensaver_manager_get_property), (gsd_screensaver_manager_constructor), (gsd_screensaver_manager_dispose), (gsd_screensaver_manager_class_init), (gsd_screensaver_manager_init), (gsd_screensaver_manager_finalize), (gsd_screensaver_manager_new): * plugins/screensaver/gsd-screensaver-manager.h: * plugins/screensaver/gsd-screensaver-plugin.c: (gsd_screensaver_plugin_init), (gsd_screensaver_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_screensaver_plugin_class_init): * plugins/screensaver/gsd-screensaver-plugin.h: * plugins/screensaver/screensaver.cinnamon-settings-plugin.desktop.in: Add screensaver plugin. 2007-12-17 William Jon McCann * plugins/background/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/default-editor/Makefile.am: * plugins/dummy/Makefile.am: * plugins/font/Makefile.am: * plugins/keybindings/Makefile.am: * plugins/mouse/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrandr/Makefile.in: * plugins/xrdb/Makefile.am: * plugins/xsettings/Makefile.am: Install in subdirectories 2007-12-17 William Jon McCann * plugins/keyboard/Makefile.am: * plugins/keyboard/modmap-dialog.glade: Add missing glade file. 2007-12-17 William Jon McCann * plugins/font/gsd-font-manager.c: * src/cinnamon-settings-plugins-engine.c: (gnome_settings_plugins_engine_load_file), (gnome_settings_plugins_engine_activate_plugin), (gnome_settings_plugins_engine_deactivate_plugin): Fix an extraneous / in gconf path. Add a dummy var to pad out private data. 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/background/Makefile.am: * plugins/background/background.cinnamon-settings-plugin.desktop.in: * plugins/background/gsd-background-manager.c: (applier_idle), (background_callback), (gsd_background_manager_start), (gsd_background_manager_stop), (gsd_background_manager_set_property), (gsd_background_manager_get_property), (gsd_background_manager_constructor), (gsd_background_manager_dispose), (gsd_background_manager_class_init), (gsd_background_manager_init), (gsd_background_manager_finalize), (gsd_background_manager_new): * plugins/background/gsd-background-manager.h: * plugins/background/gsd-background-plugin.c: (gsd_background_plugin_init), (gsd_background_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_background_plugin_class_init): * plugins/background/gsd-background-plugin.h: Add background plugin. 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/default-editor/default-editor.cinnamon-settings-plugin.deskt op.in: * plugins/keybindings/Makefile.am: * plugins/keybindings/eggaccelerators.c: (is_alt), (is_ctl), (is_modx), (is_ctrl), (is_shft), (is_shift), (is_control), (is_release), (is_meta), (is_super), (is_hyper), (is_keycode), (egg_accelerator_parse_virtual), (egg_virtual_accelerator_name), (egg_keymap_resolve_virtual_modifiers), (egg_keymap_virtualize_modifiers), (reload_modmap), (egg_keymap_get_modmap): * plugins/keybindings/eggaccelerators.h: * plugins/keybindings/gsd-keybindings-manager.c: (get_screens_list), (entry_get_string), (parse_binding), (compare_bindings), (bindings_get_entry), (key_already_used), (grab_key), (do_grab), (binding_register_keys), (screen_exec_display_string), (get_exec_environment), (keybindings_filter), (bindings_callback), (register_config_callback), (gsd_keybindings_manager_start), (gsd_keybindings_manager_stop), (gsd_keybindings_manager_set_property), (gsd_keybindings_manager_get_property), (gsd_keybindings_manager_constructor), (gsd_keybindings_manager_dispose), (gsd_keybindings_manager_class_init), (gsd_keybindings_manager_init), (gsd_keybindings_manager_finalize), (gsd_keybindings_manager_new): * plugins/keybindings/gsd-keybindings-manager.h: * plugins/keybindings/gsd-keybindings-plugin.c: (gsd_keybindings_plugin_init), (gsd_keybindings_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_keybindings_plugin_class_init): * plugins/keybindings/gsd-keybindings-plugin.h: * plugins/keybindings/keybindings.cinnamon-settings-plugin.desktop.in: * plugins/keyboard/keyboard.cinnamon-settings-plugin.desktop.in: * plugins/mouse/mouse.cinnamon-settings-plugin.desktop.in: Add keybindings plugin. 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/mouse/Makefile.am: * plugins/mouse/gsd-locate-pointer.c: (locate_pointer_expose), (setup_window), (create_window), (locate_pointer_timeout), (gsd_locate_pointer): * plugins/mouse/gsd-locate-pointer.h: * plugins/mouse/gsd-mouse-manager.c: (gsd_mouse_manager_stop), (gsd_mouse_manager_set_property), (gsd_mouse_manager_get_property), (gsd_mouse_manager_constructor), (gsd_mouse_manager_dispose), (gsd_mouse_manager_class_init), (supports_xinput_devices), (configure_button_layout), (xinput_device_has_buttons), (set_xinput_devices_left_handed), (set_left_handed), (set_motion_acceleration), (set_motion_threshold), (filter), (set_locate_pointer), (mouse_callback), (register_config_callback), (gsd_mouse_manager_init), (gsd_mouse_manager_start), (gsd_mouse_manager_finalize), (gsd_mouse_manager_new): * plugins/mouse/gsd-mouse-manager.h: * plugins/mouse/gsd-mouse-plugin.c: (gsd_mouse_plugin_init), (gsd_mouse_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_mouse_plugin_class_init): * plugins/mouse/gsd-mouse-plugin.h: * plugins/mouse/mouse.cinnamon-settings-plugin.desktop.in: Add mouse plugin. 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/keyboard/Makefile.am: * plugins/keyboard/delayed-dialog.c: (gsd_delayed_show_dialog), (delayed_show_timeout), (message_filter): * plugins/keyboard/delayed-dialog.h: * plugins/keyboard/gsd-keyboard-manager.c: (xfree86_set_keyboard_autorepeat_rate), (xkb_set_keyboard_autorepeat_rate), (gsd_keyboard_get_hostname_key), (numlock_NumLock_modifier_mask), (numlock_set_xkb_state), (numlock_gconf_state_key), (numlock_get_gconf_state), (numlock_set_gconf_state), (numlock_xkb_callback), (numlock_install_xkb_callback), (apply_settings), (register_config_callback), (gsd_keyboard_manager_start), (gsd_keyboard_manager_stop), (gsd_keyboard_manager_set_property), (gsd_keyboard_manager_get_property), (gsd_keyboard_manager_constructor), (gsd_keyboard_manager_dispose), (gsd_keyboard_manager_class_init), (gsd_keyboard_manager_init), (gsd_keyboard_manager_finalize), (gsd_keyboard_manager_new): * plugins/keyboard/gsd-keyboard-manager.h: * plugins/keyboard/gsd-keyboard-plugin.c: (gsd_keyboard_plugin_init), (gsd_keyboard_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_keyboard_plugin_class_init): * plugins/keyboard/gsd-keyboard-plugin.h: * plugins/keyboard/gsd-keyboard-xkb.c: (gsd_keyboard_log_appender), (activation_error), (apply_settings), (apply_xkb_settings), (gsd_keyboard_xkb_analyze_sysconfig), (gsd_chk_file_list), (gsd_keyboard_xkb_chk_lcl_xmm), (gsd_keyboard_xkb_set_post_activation_callback), (gsd_keyboard_xkb_evt_filter), (register_config_callback), (gsd_keyboard_xkb_init), (gsd_keyboard_xkb_load): * plugins/keyboard/gsd-keyboard-xkb.h: * plugins/keyboard/gsd-xmodmap.c: (check_button_callback), (gsd_load_modmap_files), (response_callback), (get_selected_files_func), (remove_string_from_list), (remove_button_clicked_callback), (load_button_clicked_callback), (gsd_modmap_dialog_call): * plugins/keyboard/gsd-xmodmap.h: * plugins/keyboard/keyboard.cinnamon-settings-plugin.desktop.in: * plugins/xrandr/Makefile.in: Add the keyboard plugin. 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/default-editor/Makefile.am: * plugins/default-editor/default-editor.cinnamon-settings-plugin.deskt op.in: * plugins/default-editor/gsd-default-editor-manager.c: (sync_changes_cb), (register_config_callback), (vfs_change_cb), (gsd_default_editor_manager_start), (gsd_default_editor_manager_stop), (gsd_default_editor_manager_set_property), (gsd_default_editor_manager_get_property), (gsd_default_editor_manager_constructor), (gsd_default_editor_manager_dispose), (gsd_default_editor_manager_class_init), (gsd_default_editor_manager_init), (gsd_default_editor_manager_finalize), (gsd_default_editor_manager_new): * plugins/default-editor/gsd-default-editor-manager.h: * plugins/default-editor/gsd-default-editor-plugin.c: (gsd_default_editor_plugin_init), (gsd_default_editor_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_default_editor_plugin_class_init): * plugins/default-editor/gsd-default-editor-plugin.h: * plugins/font/Makefile: * plugins/font/Makefile.in: Add default editor plugin 2007-12-16 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/font/Makefile: * plugins/font/Makefile.am: * plugins/font/Makefile.in: * plugins/font/delayed-dialog.c: (gnome_settings_delayed_show_dialog), (delayed_show_timeout), (message_filter): * plugins/font/delayed-dialog.h: * plugins/font/font.cinnamon-settings-plugin.desktop.in: * plugins/font/gsd-font-manager.c: (write_all), (child_watch_cb), (spawn_with_input), (load_xcursor_theme), (load_cursor), (gsd_font_manager_start), (gsd_font_manager_stop), (gsd_font_manager_set_property), (gsd_font_manager_get_property), (gsd_font_manager_constructor), (gsd_font_manager_dispose), (gsd_font_manager_class_init), (gsd_font_manager_init), (gsd_font_manager_finalize), (gsd_font_manager_new): * plugins/font/gsd-font-manager.h: * plugins/font/gsd-font-plugin.c: (gsd_font_plugin_init), (gsd_font_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_font_plugin_class_init): * plugins/font/gsd-font-plugin.h: Add font plugin 2007-12-14 William Jon McCann * data/cinnamon-settings-daemon.schemas.in: Add schemas for clipboard and xrandr. 2007-12-14 William Jon McCann * configure.ac: * plugins/Makefile.am: * plugins/clipboard/Makefile.am: * plugins/clipboard/clipboard.cinnamon-settings-plugin.desktop.in: * plugins/clipboard/gsd-clipboard-manager.c: (target_data_ref), (target_data_unref), (conversion_free), (send_selection_notify), (finish_selection_request), (clipboard_bytes_per_item), (save_targets), (find_content_target), (find_content_type), (find_conversion_requestor), (get_property), (receive_incrementally), (send_incrementally), (convert_clipboard_manager), (convert_clipboard_target), (collect_incremental), (convert_clipboard), (clipboard_manager_process_event), (clipboard_manager_event_filter), (clipboard_manager_watch_cb), (gsd_clipboard_manager_start), (gsd_clipboard_manager_stop), (gsd_clipboard_manager_set_property), (gsd_clipboard_manager_get_property), (gsd_clipboard_manager_constructor), (gsd_clipboard_manager_dispose), (gsd_clipboard_manager_class_init), (gsd_clipboard_manager_init), (gsd_clipboard_manager_finalize), (gsd_clipboard_manager_new): * plugins/clipboard/gsd-clipboard-manager.h: * plugins/clipboard/gsd-clipboard-plugin.c: (gsd_clipboard_plugin_init), (gsd_clipboard_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_clipboard_plugin_class_init): * plugins/clipboard/gsd-clipboard-plugin.h: * plugins/clipboard/list.c: (list_foreach), (list_prepend), (list_free), (list_find), (list_remove), (list_length), (list_copy): * plugins/clipboard/list.h: * plugins/clipboard/xutils.c: (init_atoms), (timestamp_predicate), (get_server_time): * plugins/clipboard/xutils.h: Port over the clipboard module. 2007-12-14 William Jon McCann * configure.ac: * plugins/xrdb/Makefile.am: * plugins/xrdb/data/Editres.ad: * plugins/xrdb/data/Emacs.ad: * plugins/xrdb/data/General.ad: * plugins/xrdb/data/Makefile.am: * plugins/xrdb/data/Motif.ad: * plugins/xrdb/data/Tk.ad: * plugins/xrdb/data/Xaw.ad: Add the .ad files. 2007-12-14 William Jon McCann * configure.ac: * plugins/Makefile.am: * plugins/xrandr/Makefile.am: * plugins/xrandr/Makefile.in: * plugins/xrandr/gsd-xrandr-manager.c: (get_rotation), (get_resolution), (get_rate), (find_closest_size), (apply_settings), (gsd_xrandr_manager_start), (gsd_xrandr_manager_stop), (gsd_xrandr_manager_set_property), (gsd_xrandr_manager_get_property), (gsd_xrandr_manager_constructor), (gsd_xrandr_manager_dispose), (gsd_xrandr_manager_class_init), (gsd_xrandr_manager_init), (gsd_xrandr_manager_finalize), (gsd_xrandr_manager_new): * plugins/xrandr/gsd-xrandr-manager.h: * plugins/xrandr/gsd-xrandr-plugin.c: (gsd_xrandr_plugin_init), (gsd_xrandr_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_xrandr_plugin_class_init): * plugins/xrandr/gsd-xrandr-plugin.h: * plugins/xrandr/xrandr.cinnamon-settings-plugin.desktop.in: Add xrandr plugin. 2007-12-14 William Jon McCann * configure.ac: * plugins/Makefile.am: * plugins/dummy/Makefile.am: * plugins/dummy/gsd-dummy-manager.c: (gsd_dummy_manager_start), (gsd_dummy_manager_stop), (gsd_dummy_manager_set_property), (gsd_dummy_manager_get_property), (gsd_dummy_manager_constructor), (gsd_dummy_manager_dispose), (gsd_dummy_manager_class_init), (gsd_dummy_manager_init), (gsd_dummy_manager_finalize), (gsd_dummy_manager_new): * plugins/dummy/gsd-dummy-manager.h: * plugins/dummy/gsd-dummy-plugin.c: (impl_activate), (impl_deactivate), (gsd_dummy_plugin_class_init): * plugins/dummy/gsd-dummy-plugin.h: Build the dummy. 2007-12-14 William Jon McCann * configure.ac: * data/cinnamon-settings-daemon.schemas.in: * plugins/Makefile.am: * plugins/dummy/Makefile.am: * plugins/dummy/dummy.cinnamon-settings-plugin.desktop.in: * plugins/dummy/gsd-dummy-manager.c: (gsd_xrdb_manager_start), (gsd_xrdb_manager_stop), (gsd_xrdb_manager_set_property), (gsd_xrdb_manager_get_property), (gsd_xrdb_manager_constructor), (gsd_xrdb_manager_dispose), (gsd_xrdb_manager_class_init), (gsd_xrdb_manager_init), (gsd_xrdb_manager_finalize), (gsd_xrdb_manager_new): * plugins/dummy/gsd-dummy-manager.h: * plugins/dummy/gsd-dummy-plugin.c: (gsd_dummy_plugin_init), (gsd_dummy_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_dummy_plugin_class_init): * plugins/dummy/gsd-dummy-plugin.h: * plugins/xrdb/Makefile.am: * plugins/xrdb/gsd-xrdb-manager.c: (append_color_define), (color_shade), (append_theme_colors), (scan_ad_directory), (compare_basenames), (scan_for_files), (append_file), (append_xresource_file), (write_all), (child_watch_cb), (spawn_with_input), (apply_settings), (theme_changed), (gsd_xrdb_manager_start), (gsd_xrdb_manager_stop), (gsd_xrdb_manager_set_property), (gsd_xrdb_manager_get_property), (gsd_xrdb_manager_constructor), (gsd_xrdb_manager_dispose), (gsd_xrdb_manager_class_init), (gsd_xrdb_manager_init), (gsd_xrdb_manager_finalize), (gsd_xrdb_manager_new): * plugins/xrdb/gsd-xrdb-manager.h: * plugins/xrdb/gsd-xrdb-plugin.c: (gsd_xrdb_plugin_init), (gsd_xrdb_plugin_finalize), (impl_activate), (impl_deactivate), (gsd_xrdb_plugin_class_init): * plugins/xrdb/gsd-xrdb-plugin.h: * plugins/xrdb/xrdb.cinnamon-settings-plugin.desktop.in: * plugins/xsettings/gnome-xsettings-manager.h: Port over the xrdb module. Also add a skeleton plugin dir. 2007-12-14 William Jon McCann * MAINTAINERS: * configure.ac: * src/main.c: (get_bus_proxy), (acquire_name_on_proxy), (get_session_bus), (bus_register), (main): Grab a name on the session bus. 2007-12-14 William Jon McCann * configure.ac, etc: Initial checkin. Previously lived in gdm module. cinnamon-settings-daemon-4.4.0/MAINTAINERS000066400000000000000000000005401356401377300201250ustar00rootroot00000000000000Rodrigo Moya E-mail: rodrigo at gnome-db.org Userid: rodrigo Sebastien Bacher Email: seb128 at debian.org Userid: sbacher Thomas Wood Email: thos at gnome.org Userid: thos Jens Granseuer Email: jensgr at gmx.net Userid: jensg William Jon McCann Email: mccann at jhu.edu Userid: mccann Bastien Nocera Email: hadess at hadess dot net Userid: hadess cinnamon-settings-daemon-4.4.0/Makefile.am000066400000000000000000000004251356401377300204660ustar00rootroot00000000000000NULL = SUBDIRS = \ cinnamon-settings-daemon \ files \ plugins \ data \ po \ $(NULL) # Honor aclocal flags ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 EXTRA_DIST = \ MAINTAINERS \ ChangeLog \ README \ autogen.sh \ $(NULL) DISTCLEANFILES = \ $(NULL) cinnamon-settings-daemon-4.4.0/NEWS000066400000000000000000000000001356401377300171160ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/README000066400000000000000000000000001356401377300172770ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/README.rst000066400000000000000000000117071356401377300201260ustar00rootroot00000000000000cinnamon-settings-daemon is a collection of plugins. These plugins are started by cinnamon-session when you log in. The plugins run in the background, each with their own process. Plugins: ======== Here's a description of each plugin. a11y-keyboard ------------- a11y-settings ------------- automount --------- background ---------- clipboard --------- Xorg features two ways of copying and pasting content. The first one is ``X-clipboard``, which is commonly used in edit menus and using ``Ctrl+C`` and ``Ctrl+V``. The second one is ``X-selection`` which is used by selecting content with the mouse and pasting it with a middle-click. When you copy content from a window, that content is available either in ``X-clipboard`` or ``X-selection`` until the application which owns that window is terminated. This plugin keeps the content of ``X-clipboard`` in memory, so that even if the owner application exits the content continues to be available. color ----- common ------ cursor ------ datetime -------- dummy ----- This is a dummy plugin. It doesn't do anything. housekeeping ------------ **thumbnail cache** The thumbnail cache is cleaned up according to the settings stored in ``org.cinnamon.desktop.thumbnail-cache``. This is done 2 minutes after login and then once a day. **low disk space** Every minute, the plugin checks the mounted volume to see if they have low disk space, according to the settings stored in ``org.cinnamon.settings-daemon.plugins.housekeeping``. The plugin shows a notification when a volume is full. keyboard -------- This plugin handles the keyboard. **keyboard settings** It reads and listens to the ``org.cinnamon.settings-daemon.peripherals.keyboard`` settings and applies the configuration. **numlock state** It also listens to the state of the numlock key and saves it in the settings to ensure the state is remembered and preserved for the next session. **keyboard layout** The layout selection is done in cinnamon-control-center's region plugin (which is presented to the user in cinnamon-settings' keyboard module). That configuration is set directly via gkbd (libgnomekbd) and xkl (libxklavier). This plugin reads and listens to that configuration and assigns to the keyboard. **hotplug command** Although it isn't configured by default or used by cinnamon-settings, when a keyboard is plugged in, or removed, the plugin executes the command specified in ``org.cinnamon.settings-daemon.peripherals.input-devices hotplug-command`` with a series of argument to specify the event type, the device etc.. An example script which can be used for such a command is available in ``plugins/common/input-device-example.sh``. media-keys ---------- mouse ----- This plugin handles mice and touchpads. It reads and listens to the ``org.cinnamon.settings-daemon.peripherals.mouse`` and ``org.cinnamon.settings-daemon.peripherals.touchpad`` settings and applies the configuration in X11. This plugin supports synaptics and libinput devices. orientation ----------- power ----- print-notifications ------------------- This plugin shows printer notifications. On DBUS, it listens to events on ``org.cups.cupsd.Notifier``. Libnotify is used to show the notifications. screensaver-proxy ----------------- smartcard --------- sound ----- This plugin is use to play sound files or theme sounds via PulseAudio. It's available via dbus at ``org.cinnamon.SettingsDaemon.Sound``. Its configuration is ``org.cinnamon.desktop.sound``. wacom ----- This plugin handles wacom tablets. It reads and listens to the ``org.cinnamon.settings-daemon.peripherals.wacom`` and applies the configuration in X11. xrandr ------ xsettings --------- This plugin sets the settings for GTK and Xft. TESTING ======= To test a plugin: 1. Kill the running CSD plugin 2. Build the project 3. Run the built plugin in verbose mode For instance: * ``killall csd-sound`` (you might have to kill it twice, if CSM tries to restart it) * ``dpkg-buildpackage`` * ``plugins/sound/csd-sound --verbose`` TODO: ===== - Remove custom keybinding code (we handle that in Cinnamon now) - do we want to handle media keys in cinnamon also? Would get around the 'no meda keys while a menu is open' issue. - Switch to Gnome's keyboard layout (gsettings) handler - basically reverting Ubuntu's patch for this. This will allow us to implement ibus popups directly in Cinnamon - Look into backgrounds - we should be able to eliminate the background manager in the cinnamon gnome 3.8 compat rollup, and continue to handle backgrounds as we currently do - Investigate: How to keep gnome-settings-daemon from autostarting. It checks for environment=GNOME... which means Cinnamon also - is it time to have our own freedesktop.org name? -- Update on this: Setting session name to Cinnamon works - then add to main.c in cinnamon, to set XDG_CURRENT_DESKTOP=GNOME makes sure apps keep showing up - Multiple backgrounds on multiple monitors - /etc/acpi/powerbtn.sh - add cinnamon-settings-daemon to script - how? postinst? cinnamon-settings-daemon-4.4.0/autogen.sh000077500000000000000000000020261356401377300204320ustar00rootroot00000000000000#!/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 glib-gettextize --force --copy || exit 1 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-settings-daemon-4.4.0/cinnamon-settings-daemon.pot000066400000000000000000000772761356401377300241010ustar00rootroot00000000000000# 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: 2018-11-12 15:15+0000\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" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:377 #, c-format msgid "There was an error displaying help: %s" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:501 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:563 msgid "Slow Keys Turned On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:502 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:564 msgid "Slow Keys Turned Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:503 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:565 msgid "" "You just held down the Shift key for 8 seconds. This is the shortcut for " "the Slow Keys feature, which affects the way your keyboard works." msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:521 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:656 msgid "Universal Access" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:527 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:662 msgid "Turn Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:527 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:662 msgid "Turn On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:533 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:668 msgid "Leave On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:533 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:668 msgid "Leave Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:586 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:724 msgid "_Turn Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:586 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:724 msgid "_Turn On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:589 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:727 msgid "_Leave On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:589 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:727 msgid "_Leave Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:632 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:698 msgid "Sticky Keys Turned On" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:633 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:699 msgid "Sticky Keys Turned Off" msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:635 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:701 msgid "" "You just pressed the Shift key 5 times in a row. This is the shortcut for " "the Sticky Keys feature, which affects the way your keyboard works." msgstr "" #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:637 #: plugins/a11y-keyboard/csd-a11y-keyboard-manager.c:703 msgid "" "You just pressed two keys at once, or pressed the Shift key 5 times in a " "row. This turns off the Sticky Keys feature, which affects the way your " "keyboard works." msgstr "" #: plugins/a11y-keyboard/csd-a11y-preferences-dialog.c:410 msgid "Universal Access Preferences" msgstr "" #: plugins/a11y-settings/csd-a11y-settings-manager.c:268 msgid "Screen reader not found." msgstr "" #: plugins/a11y-settings/csd-a11y-settings-manager.c:269 msgid "Please install the 'orca' package." msgstr "" #: plugins/a11y-settings/csd-a11y-settings-manager.c:276 msgid "Open accessibility settings" msgstr "" #: plugins/automount/csd-automount-manager.c:149 #, c-format msgid "Unable to mount %s" msgstr "" #: plugins/automount/csd-automount-manager.c:277 #, c-format msgid "Unable to open a folder for %s" msgstr "" #: plugins/automount/csd-autorun.c:346 msgid "Ask what to do" msgstr "" #: plugins/automount/csd-autorun.c:352 msgid "Do Nothing" msgstr "" #: plugins/automount/csd-autorun.c:358 msgid "Open Folder" msgstr "" #: plugins/automount/csd-autorun.c:501 #, c-format msgid "Unable to eject %p" msgstr "" #: plugins/automount/csd-autorun.c:503 #, c-format msgid "Unable to unmount %p" msgstr "" #: plugins/automount/csd-autorun.c:710 msgid "You have just inserted an Audio CD." msgstr "" #: plugins/automount/csd-autorun.c:712 msgid "You have just inserted an Audio DVD." msgstr "" #: plugins/automount/csd-autorun.c:714 msgid "You have just inserted a Video DVD." msgstr "" #: plugins/automount/csd-autorun.c:716 msgid "You have just inserted a Video CD." msgstr "" #: plugins/automount/csd-autorun.c:718 msgid "You have just inserted a Super Video CD." msgstr "" #: plugins/automount/csd-autorun.c:720 msgid "You have just inserted a blank CD." msgstr "" #: plugins/automount/csd-autorun.c:722 msgid "You have just inserted a blank DVD." msgstr "" #: plugins/automount/csd-autorun.c:724 msgid "You have just inserted a blank Blu-Ray disc." msgstr "" #: plugins/automount/csd-autorun.c:726 msgid "You have just inserted a blank HD DVD." msgstr "" #: plugins/automount/csd-autorun.c:728 msgid "You have just inserted a Photo CD." msgstr "" #: plugins/automount/csd-autorun.c:730 msgid "You have just inserted a Picture CD." msgstr "" #: plugins/automount/csd-autorun.c:732 msgid "You have just inserted a medium with digital photos." msgstr "" #: plugins/automount/csd-autorun.c:734 msgid "You have just inserted a digital audio player." msgstr "" #: plugins/automount/csd-autorun.c:736 msgid "" "You have just inserted a medium with software intended to be automatically " "started." msgstr "" #: plugins/automount/csd-autorun.c:739 msgid "You have just inserted a medium." msgstr "" #: plugins/automount/csd-autorun.c:741 msgid "Choose what application to launch." msgstr "" #: plugins/automount/csd-autorun.c:751 #, c-format msgid "" "Select how to open \"%s\" and whether to perform this action in the future " "for other media of type \"%s\"." msgstr "" #: plugins/automount/csd-autorun.c:779 msgid "_Always perform this action" msgstr "" #: plugins/automount/csd-autorun.c:788 msgid "_Cancel" msgstr "" #: plugins/automount/csd-autorun.c:789 msgid "_Ok" msgstr "" #: plugins/automount/csd-autorun.c:794 msgid "_Eject" msgstr "" #: plugins/automount/csd-autorun.c:797 msgid "_Unmount" msgstr "" #: plugins/color/csd-color-manager.c:1836 msgid "Color" msgstr "" #: plugins/color/csd-color-manager.c:1841 msgid "Recalibrate now" msgstr "" #: plugins/color/csd-color-manager.c:1884 msgid "Recalibration required" msgstr "" #: plugins/color/csd-color-manager.c:1896 #, c-format msgid "The display '%s' should be recalibrated soon." msgstr "" #: plugins/color/csd-color-manager.c:1905 #, c-format msgid "The printer '%s' should be recalibrated soon." msgstr "" #: plugins/color/csd-color-manager.c:2229 #: plugins/color/csd-color-manager.c:2245 msgid "Cinnamon Settings Daemon Color Plugin" msgstr "" #: plugins/color/csd-color-manager.c:2231 msgid "Color calibration device added" msgstr "" #: plugins/color/csd-color-manager.c:2247 msgid "Color calibration device removed" msgstr "" #: plugins/housekeeping/csd-disk-space.c:334 #, c-format msgid "Low Disk Space on \"%s\"" msgstr "" #: plugins/housekeeping/csd-disk-space.c:336 #, c-format msgid "" "The volume \"%s\" has only %s disk space remaining. You may free up some " "space by emptying the trash." msgstr "" #: plugins/housekeeping/csd-disk-space.c:340 #: plugins/housekeeping/csd-ldsm-dialog.c:78 #, c-format msgid "The volume \"%s\" has only %s disk space remaining." msgstr "" #: plugins/housekeeping/csd-disk-space.c:345 #: plugins/housekeeping/csd-ldsm-dialog.c:202 msgid "Low Disk Space" msgstr "" #: plugins/housekeeping/csd-disk-space.c:347 #, c-format msgid "" "This computer has only %s disk space remaining. You may free up some space " "by emptying the trash." msgstr "" #: plugins/housekeeping/csd-disk-space.c:350 #: plugins/housekeeping/csd-ldsm-dialog.c:81 #, c-format msgid "This computer has only %s disk space remaining." msgstr "" #: plugins/housekeeping/csd-disk-space.c:365 msgid "Disk space" msgstr "" #: plugins/housekeeping/csd-disk-space.c:372 msgid "Examine" msgstr "" #: plugins/housekeeping/csd-disk-space.c:380 #: plugins/housekeeping/csd-ldsm-dialog.c:434 msgid "Empty Trash" msgstr "" #: plugins/housekeeping/csd-disk-space.c:387 #: plugins/housekeeping/csd-ldsm-dialog.c:449 msgid "Ignore" msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:63 msgid "Don't show any warnings again for this file system" msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:65 msgid "Don't show any warnings again" msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:97 msgid "" "You can free up disk space by emptying the Trash, removing unused programs " "or files, or moving files to another disk or partition." msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:100 msgid "" "You can free up disk space by removing unused programs or files, or by " "moving files to another disk or partition." msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:105 msgid "" "You can free up disk space by emptying the Trash, removing unused programs " "or files, or moving files to an external disk." msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:108 msgid "" "You can free up disk space by removing unused programs or files, or by " "moving files to an external disk." msgstr "" #: plugins/housekeeping/csd-ldsm-dialog.c:442 msgid "Examine..." msgstr "" #: plugins/keyboard/csd-keyboard-xkb.c:89 #, c-format msgid "" "Error activating XKB configuration.\n" "There can be various reasons for that.\n" "\n" "If you report this situation as a bug, include the results of\n" " %s\n" " %s\n" " %s\n" " %s" msgstr "" #: plugins/keyboard/csd-keyboard-xkb.c:258 msgid "_Layouts" msgstr "" #: plugins/keyboard/csd-keyboard-xkb.c:264 msgid "Show _Keyboard Layout..." msgstr "" #: plugins/keyboard/csd-keyboard-xkb.c:271 msgid "Region and Language Settings" msgstr "" #: plugins/power/csd-power-manager.c:1073 msgid "UPS Discharging" msgstr "" #: plugins/power/csd-power-manager.c:1078 #, c-format msgid "%s of UPS backup power remaining" msgstr "" #: plugins/power/csd-power-manager.c:1099 #: plugins/power/csd-power-manager.c:1319 #: plugins/power/csd-power-manager.c:1499 #: plugins/power/csd-power-manager.c:1648 msgid "Power" msgstr "" #: plugins/power/csd-power-manager.c:1231 msgid "Battery low" msgstr "" #: plugins/power/csd-power-manager.c:1234 msgid "Laptop battery low" msgstr "" #: plugins/power/csd-power-manager.c:1241 #, c-format msgid "Approximately %s remaining (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1246 msgid "UPS low" msgstr "" #: plugins/power/csd-power-manager.c:1252 #, c-format msgid "Approximately %s of remaining UPS backup power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1257 #: plugins/power/csd-power-manager.c:1422 msgid "Mouse battery low" msgstr "" #: plugins/power/csd-power-manager.c:1260 #, c-format msgid "Wireless mouse is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1264 #: plugins/power/csd-power-manager.c:1430 msgid "Keyboard battery low" msgstr "" #: plugins/power/csd-power-manager.c:1267 #, c-format msgid "Wireless keyboard is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1271 #: plugins/power/csd-power-manager.c:1439 msgid "PDA battery low" msgstr "" #: plugins/power/csd-power-manager.c:1274 #, c-format msgid "PDA is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1278 #: plugins/power/csd-power-manager.c:1449 #: plugins/power/csd-power-manager.c:1459 msgid "Cell phone battery low" msgstr "" #: plugins/power/csd-power-manager.c:1281 #, c-format msgid "Cell phone is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1285 msgid "Media player battery low" msgstr "" #: plugins/power/csd-power-manager.c:1288 #, c-format msgid "Media player is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1292 #: plugins/power/csd-power-manager.c:1468 msgid "Tablet battery low" msgstr "" #: plugins/power/csd-power-manager.c:1295 #, c-format msgid "Tablet is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1299 #: plugins/power/csd-power-manager.c:1477 msgid "Attached computer battery low" msgstr "" #: plugins/power/csd-power-manager.c:1302 #, c-format msgid "Attached computer is low in power (%.0f%%)" msgstr "" #: plugins/power/csd-power-manager.c:1336 msgid "Battery is low" msgstr "" #: plugins/power/csd-power-manager.c:1378 msgid "Battery critically low" msgstr "" #: plugins/power/csd-power-manager.c:1381 #: plugins/power/csd-power-manager.c:1564 msgid "Laptop battery critically low" msgstr "" #: plugins/power/csd-power-manager.c:1390 msgid "Plug in your AC adapter to avoid losing data." msgstr "" #: plugins/power/csd-power-manager.c:1394 msgid "Computer will suspend very soon unless it is plugged in." msgstr "" #: plugins/power/csd-power-manager.c:1398 msgid "Computer will hibernate very soon unless it is plugged in." msgstr "" #: plugins/power/csd-power-manager.c:1402 msgid "Computer will shutdown very soon unless it is plugged in." msgstr "" #: plugins/power/csd-power-manager.c:1410 #: plugins/power/csd-power-manager.c:1600 msgid "UPS critically low" msgstr "" #: plugins/power/csd-power-manager.c:1416 #, c-format msgid "" "Approximately %s of remaining UPS power (%.0f%%). Restore AC power to your " "computer to avoid losing data." msgstr "" #: plugins/power/csd-power-manager.c:1425 #, c-format msgid "" "Wireless mouse is very low in power (%.0f%%). This device will soon stop " "functioning if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1433 #, c-format msgid "" "Wireless keyboard is very low in power (%.0f%%). This device will soon stop " "functioning if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1442 #, c-format msgid "" "PDA is very low in power (%.0f%%). This device will soon stop functioning if " "not charged." msgstr "" #: plugins/power/csd-power-manager.c:1452 #, c-format msgid "" "Cell phone is very low in power (%.0f%%). This device will soon stop " "functioning if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1462 #, c-format msgid "" "Media player is very low in power (%.0f%%). This device will soon stop " "functioning if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1471 #, c-format msgid "" "Tablet is very low in power (%.0f%%). This device will soon stop functioning " "if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1480 #, c-format msgid "" "Attached computer is very low in power (%.0f%%). The device will soon " "shutdown if not charged." msgstr "" #: plugins/power/csd-power-manager.c:1517 #: plugins/power/csd-power-manager.c:1527 #: plugins/power/csd-power-manager.c:1663 msgid "Battery is critically low" msgstr "" #: plugins/power/csd-power-manager.c:1572 msgid "" "The battery is below the critical level and this computer will power-off when the battery becomes completely empty." msgstr "" #: plugins/power/csd-power-manager.c:1578 msgid "" "The battery is below the critical level and this computer is about to " "suspend.\n" "NOTE: A small amount of power is required to keep your computer in a " "suspended state." msgstr "" #: plugins/power/csd-power-manager.c:1585 msgid "" "The battery is below the critical level and this computer is about to " "hibernate." msgstr "" #: plugins/power/csd-power-manager.c:1590 msgid "" "The battery is below the critical level and this computer is about to " "shutdown." msgstr "" #: plugins/power/csd-power-manager.c:1608 msgid "" "UPS is below the critical level and this computer will power-off when " "the UPS becomes completely empty." msgstr "" #: plugins/power/csd-power-manager.c:1614 msgid "" "UPS is below the critical level and this computer is about to hibernate." msgstr "" #: plugins/power/csd-power-manager.c:1619 msgid "UPS is below the critical level and this computer is about to shutdown." msgstr "" #: plugins/power/csd-power-manager.c:2206 msgid "Lid has been opened" msgstr "" #: plugins/power/csd-power-manager.c:2351 msgid "Lid has been closed" msgstr "" #: plugins/power/csd-power-manager.c:4133 msgid "Power Manager" msgstr "" #: plugins/power/gpm-common.c:47 msgid "Unknown time" msgstr "" #: plugins/power/gpm-common.c:52 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:62 #, c-format msgid "%i hour" msgid_plural "%i hours" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:68 #, c-format msgid "%i %s %i %s" msgstr "" #: plugins/power/gpm-common.c:69 msgid "hour" msgid_plural "hours" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:70 msgid "minute" msgid_plural "minutes" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:319 #, c-format msgid "provides %s laptop runtime" msgstr "" #: plugins/power/gpm-common.c:330 #, c-format msgid "%s %s remaining" msgstr "" #: plugins/power/gpm-common.c:351 plugins/power/gpm-common.c:368 #, c-format msgid "%s %s until charged" msgstr "" #: plugins/power/gpm-common.c:358 #, c-format msgid "provides %s battery runtime" msgstr "" #: plugins/power/gpm-common.c:449 msgid "Product:" msgstr "" #: plugins/power/gpm-common.c:453 plugins/power/gpm-common.c:456 #: plugins/power/gpm-common.c:459 plugins/power/gpm-common.c:462 msgid "Status:" msgstr "" #: plugins/power/gpm-common.c:453 msgid "Missing" msgstr "" #: plugins/power/gpm-common.c:456 plugins/power/gpm-common.c:741 msgid "Charged" msgstr "" #: plugins/power/gpm-common.c:459 plugins/power/gpm-common.c:729 msgid "Charging" msgstr "" #: plugins/power/gpm-common.c:462 plugins/power/gpm-common.c:733 msgid "Discharging" msgstr "" #: plugins/power/gpm-common.c:467 msgid "Percentage charge:" msgstr "" #: plugins/power/gpm-common.c:471 msgid "Vendor:" msgstr "" #: plugins/power/gpm-common.c:476 msgid "Technology:" msgstr "" #: plugins/power/gpm-common.c:480 msgid "Serial number:" msgstr "" #: plugins/power/gpm-common.c:484 msgid "Model:" msgstr "" #: plugins/power/gpm-common.c:489 msgid "Charge time:" msgstr "" #: plugins/power/gpm-common.c:495 msgid "Discharge time:" msgstr "" #: plugins/power/gpm-common.c:502 msgid "Excellent" msgstr "" #: plugins/power/gpm-common.c:504 msgid "Good" msgstr "" #: plugins/power/gpm-common.c:506 msgid "Fair" msgstr "" #: plugins/power/gpm-common.c:508 msgid "Poor" msgstr "" #: plugins/power/gpm-common.c:512 msgid "Capacity:" msgstr "" #: plugins/power/gpm-common.c:518 plugins/power/gpm-common.c:543 msgid "Current charge:" msgstr "" #: plugins/power/gpm-common.c:524 msgid "Last full charge:" msgstr "" #: plugins/power/gpm-common.c:530 plugins/power/gpm-common.c:548 msgid "Design charge:" msgstr "" #: plugins/power/gpm-common.c:535 msgid "Charge rate:" msgstr "" #: plugins/power/gpm-common.c:567 msgid "AC adapter" msgid_plural "AC adapters" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:571 msgid "Laptop battery" msgid_plural "Laptop batteries" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:575 msgid "UPS" msgid_plural "UPSs" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:579 msgid "Monitor" msgid_plural "Monitors" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:583 msgid "Mouse" msgid_plural "Mice" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:587 msgid "Keyboard" msgid_plural "Keyboards" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:591 msgid "PDA" msgid_plural "PDAs" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:595 msgid "Cell phone" msgid_plural "Cell phones" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:599 msgid "Media player" msgid_plural "Media players" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:603 msgid "Tablet" msgid_plural "Tablets" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:607 msgid "Computer" msgid_plural "Computers" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:612 msgid "Game controller" msgid_plural "Game controllers" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:616 msgid "Unknown device" msgid_plural "Unknown devices" msgstr[0] "" msgstr[1] "" #: plugins/power/gpm-common.c:687 msgid "Lithium Ion" msgstr "" #: plugins/power/gpm-common.c:691 msgid "Lithium Polymer" msgstr "" #: plugins/power/gpm-common.c:695 msgid "Lithium Iron Phosphate" msgstr "" #: plugins/power/gpm-common.c:699 msgid "Lead acid" msgstr "" #: plugins/power/gpm-common.c:703 msgid "Nickel Cadmium" msgstr "" #: plugins/power/gpm-common.c:707 msgid "Nickel metal hydride" msgstr "" #: plugins/power/gpm-common.c:711 msgid "Unknown technology" msgstr "" #: plugins/power/gpm-common.c:737 msgid "Empty" msgstr "" #: plugins/power/gpm-common.c:745 msgid "Waiting to charge" msgstr "" #: plugins/power/gpm-common.c:749 msgid "Waiting to discharge" msgstr "" #: plugins/power/gpm-common.c:753 msgid "Unknown" msgstr "" #: plugins/power/gpm-common.c:782 msgid "Laptop battery not present" msgstr "" #: plugins/power/gpm-common.c:786 msgid "Laptop battery is charging" msgstr "" #: plugins/power/gpm-common.c:790 msgid "Laptop battery is discharging" msgstr "" #: plugins/power/gpm-common.c:794 msgid "Laptop battery is empty" msgstr "" #: plugins/power/gpm-common.c:798 msgid "Laptop battery is charged" msgstr "" #: plugins/power/gpm-common.c:802 msgid "Laptop battery is waiting to charge" msgstr "" #: plugins/power/gpm-common.c:806 msgid "Laptop battery is waiting to discharge" msgstr "" #: plugins/power/gpm-common.c:815 msgid "UPS is charging" msgstr "" #: plugins/power/gpm-common.c:819 msgid "UPS is discharging" msgstr "" #: plugins/power/gpm-common.c:823 msgid "UPS is empty" msgstr "" #: plugins/power/gpm-common.c:827 msgid "UPS is charged" msgstr "" #: plugins/power/gpm-common.c:836 msgid "Mouse is charging" msgstr "" #: plugins/power/gpm-common.c:840 msgid "Mouse is discharging" msgstr "" #: plugins/power/gpm-common.c:844 msgid "Mouse is empty" msgstr "" #: plugins/power/gpm-common.c:848 msgid "Mouse is charged" msgstr "" #: plugins/power/gpm-common.c:857 msgid "Keyboard is charging" msgstr "" #: plugins/power/gpm-common.c:861 msgid "Keyboard is discharging" msgstr "" #: plugins/power/gpm-common.c:865 msgid "Keyboard is empty" msgstr "" #: plugins/power/gpm-common.c:869 msgid "Keyboard is charged" msgstr "" #: plugins/power/gpm-common.c:878 msgid "PDA is charging" msgstr "" #: plugins/power/gpm-common.c:882 msgid "PDA is discharging" msgstr "" #: plugins/power/gpm-common.c:886 msgid "PDA is empty" msgstr "" #: plugins/power/gpm-common.c:890 msgid "PDA is charged" msgstr "" #: plugins/power/gpm-common.c:899 msgid "Cell phone is charging" msgstr "" #: plugins/power/gpm-common.c:903 msgid "Cell phone is discharging" msgstr "" #: plugins/power/gpm-common.c:907 msgid "Cell phone is empty" msgstr "" #: plugins/power/gpm-common.c:911 msgid "Cell phone is charged" msgstr "" #: plugins/power/gpm-common.c:920 msgid "Media player is charging" msgstr "" #: plugins/power/gpm-common.c:924 msgid "Media player is discharging" msgstr "" #: plugins/power/gpm-common.c:928 msgid "Media player is empty" msgstr "" #: plugins/power/gpm-common.c:932 msgid "Media player is charged" msgstr "" #: plugins/power/gpm-common.c:941 msgid "Tablet is charging" msgstr "" #: plugins/power/gpm-common.c:945 msgid "Tablet is discharging" msgstr "" #: plugins/power/gpm-common.c:949 msgid "Tablet is empty" msgstr "" #: plugins/power/gpm-common.c:953 msgid "Tablet is charged" msgstr "" #: plugins/power/gpm-common.c:962 msgid "Computer is charging" msgstr "" #: plugins/power/gpm-common.c:966 msgid "Computer is discharging" msgstr "" #: plugins/power/gpm-common.c:970 msgid "Computer is empty" msgstr "" #: plugins/power/gpm-common.c:974 msgid "Computer is charged" msgstr "" #: plugins/power/gpm-common.c:984 msgid "Game controller is charging" msgstr "" #: plugins/power/gpm-common.c:988 msgid "Game controller is discharging" msgstr "" #: plugins/power/gpm-common.c:992 msgid "Game controller is empty" msgstr "" #: plugins/power/gpm-common.c:996 msgid "Game controller is charged" msgstr "" #: plugins/print-notifications/csd-printer.c:890 msgid "Configuring new printer" msgstr "" #: plugins/print-notifications/csd-printer.c:892 msgid "Please wait..." msgstr "" #: plugins/print-notifications/csd-printer.c:919 msgid "Missing printer driver" msgstr "" #: plugins/print-notifications/csd-printer.c:928 #, c-format msgid "No printer driver for %s." msgstr "" #: plugins/print-notifications/csd-printer.c:933 msgid "No driver for this printer." msgstr "" #: plugins/print-notifications/csd-printer.c:1031 #: plugins/print-notifications/csd-print-notifications-manager.c:268 #: plugins/print-notifications/csd-print-notifications-manager.c:746 #: plugins/print-notifications/csd-print-notifications-manager.c:836 #: plugins/print-notifications/csd-print-notifications-manager.c:879 msgid "Printers" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:344 #, c-format msgid "Printer '%s' is low on toner." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:348 #, c-format msgid "Printer '%s' has no toner left." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:352 #, c-format msgid "Printer '%s' may not be connected." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:356 #, c-format msgid "The cover is open on printer '%s'." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:360 #, c-format msgid "There is a missing print filter for printer '%s'." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:365 #, c-format msgid "The door is open on printer '%s'." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:369 #, c-format msgid "Printer '%s' is low on a marker supply." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:373 #, c-format msgid "Printer '%s' is out of a marker supply." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:377 #, c-format msgid "Printer '%s' is low on paper." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:381 #, c-format msgid "Printer '%s' is out of paper." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:385 #, c-format msgid "Printer '%s' is currently off-line." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:389 #, c-format msgid "There is a problem on printer '%s'." msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:437 msgid "Toner low" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:439 msgid "Toner empty" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:441 msgid "Not connected?" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:443 msgid "Cover open" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:445 msgid "Printer configuration error" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:447 msgid "Door open" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:449 msgid "Marker supply low" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:451 msgid "Out of a marker supply" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:453 msgid "Paper low" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:455 msgid "Out of paper" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:457 msgid "Printer off-line" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:459 #: plugins/print-notifications/csd-print-notifications-manager.c:822 msgid "Printer error" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:507 msgid "Printer added" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:816 msgid "Printer report" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:819 msgid "Printer warning" msgstr "" #: plugins/print-notifications/csd-print-notifications-manager.c:829 #, c-format msgid "Printer '%s': '%s'." msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:529 msgid "received error or hang up from event source" msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:663 msgid "NSS security system could not be initialized" msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:791 msgid "no suitable smartcard driver could be found" msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:805 #, c-format msgid "smartcard driver '%s' could not be loaded" msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:877 #, c-format msgid "could not watch for incoming card events - %s" msgstr "" #: plugins/smartcard/csd-smartcard-manager.c:1275 msgid "encountered unexpected error while waiting for smartcard events" msgstr "" #: plugins/wacom/csd-wacom-device.c:1082 msgid "Left Ring" msgstr "" #: plugins/wacom/csd-wacom-device.c:1092 #, c-format msgid "Left Ring Mode #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1111 msgid "Right Ring" msgstr "" #: plugins/wacom/csd-wacom-device.c:1121 #, c-format msgid "Right Ring Mode #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1162 msgid "Left Touchstrip" msgstr "" #: plugins/wacom/csd-wacom-device.c:1172 #, c-format msgid "Left Touchstrip Mode #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1191 msgid "Right Touchstrip" msgstr "" #: plugins/wacom/csd-wacom-device.c:1201 #, c-format msgid "Right Touchstrip Mode #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1226 msgid "Left Touchring Mode Switch" msgstr "" #: plugins/wacom/csd-wacom-device.c:1228 msgid "Right Touchring Mode Switch" msgstr "" #: plugins/wacom/csd-wacom-device.c:1231 msgid "Left Touchstrip Mode Switch" msgstr "" #: plugins/wacom/csd-wacom-device.c:1233 msgid "Right Touchstrip Mode Switch" msgstr "" #: plugins/wacom/csd-wacom-device.c:1238 #, c-format msgid "Mode Switch #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1342 #, c-format msgid "Left Button #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1345 #, c-format msgid "Right Button #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1348 #, c-format msgid "Top Button #%d" msgstr "" #: plugins/wacom/csd-wacom-device.c:1351 #, c-format msgid "Bottom Button #%d" msgstr "" #: plugins/wacom/csd-wacom-osd-window.c:1016 #, c-format msgid "Mode %d: %s" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:528 msgid "Could not restore the display's configuration" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:553 msgid "Could not restore the display's configuration from a backup" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:574 #, c-format msgid "The display will be reset to its previous configuration in %d second" msgid_plural "" "The display will be reset to its previous configuration in %d seconds" msgstr[0] "" msgstr[1] "" #: plugins/xrandr/csd-xrandr-manager.c:623 msgid "Does the display look OK?" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:629 msgid "Confirm New Configuration" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:631 msgid "_Restore Previous Configuration" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:632 msgid "_Keep This Configuration" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:713 msgid "The selected configuration for displays could not be applied" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:1364 #, c-format msgid "Could not refresh the screen information: %s" msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:1368 msgid "Trying to switch the monitor configuration anyway." msgstr "" #: plugins/xrandr/csd-xrandr-manager.c:1862 msgid "Could not apply the stored configuration for monitors" msgstr "" cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/000077500000000000000000000000001356401377300233325ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/Makefile.am000066400000000000000000000017451356401377300253750ustar00rootroot00000000000000NULL = AM_CPPFLAGS = \ -DDATADIR=\""$(datadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DCINNAMON_SETTINGS_PLUGINDIR=\""$(plugindir)"\" \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) \ $(SETTINGS_DAEMON_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(LOGIND_CFLAGS) \ $(NULL) AM_CFLAGS = $(WARN_CFLAGS) AM_LDFLAGS = $(WARN_LDFLAGS) privlibdir = $(pkglibdir)-$(CSD_API_VERSION) privlib_LTLIBRARIES = \ libcsd.la \ $(NULL) libcsd_la_SOURCES = \ cinnamon-settings-profile.c \ cinnamon-settings-profile.h \ cinnamon-settings-session.c \ cinnamon-settings-session.h \ $(NULL) libcsd_la_CPPFLAGS = \ $(DISABLE_DEPRECATED_CFLAGS) \ $(AM_CPPFLAGS) \ $(NULL) libcsd_la_CFLAGS = \ $(WARN_CFLAGS) \ $(NULL) libcsd_la_LIBADD = \ $(LOGIND_LIBS) \ $(GIOUNIX_LIBS) \ $(NULL) libcsd_la_LDFLAGS = \ $(WARN_LDFLAGS) \ -export-dynamic \ -avoid-version \ -no-undefined \ $(NULL) # vim: ts=8 cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/cinnamon-settings-profile.c000066400000000000000000000037041356401377300306000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005 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 "cinnamon-settings-profile.h" void _cinnamon_settings_profile_log (const char *func, const char *note, const char *format, ...) { va_list args; char *str; char *formatted; if (format == NULL) { formatted = g_strdup (""); } else { va_start (args, format); formatted = g_strdup_vprintf (format, args); va_end (args); } if (func != NULL) { str = g_strdup_printf ("MARK: %s %s: %s %s", g_get_prgname(), func, note ? note : "", formatted); } else { str = g_strdup_printf ("MARK: %s: %s %s", g_get_prgname(), note ? note : "", formatted); } g_free (formatted); g_access (str, F_OK); g_free (str); } cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/cinnamon-settings-profile.h000066400000000000000000000043011356401377300305770ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005 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 * */ #ifndef __CINNAMON_SETTINGS_PROFILE_H #define __CINNAMON_SETTINGS_PROFILE_H #include G_BEGIN_DECLS #ifdef ENABLE_PROFILING #ifdef G_HAVE_ISO_VARARGS #define cinnamon_settings_profile_start(...) _cinnamon_settings_profile_log (G_STRFUNC, "start", __VA_ARGS__) #define cinnamon_settings_profile_end(...) _cinnamon_settings_profile_log (G_STRFUNC, "end", __VA_ARGS__) #define cinnamon_settings_profile_msg(...) _cinnamon_settings_profile_log (NULL, NULL, __VA_ARGS__) #elif defined(G_HAVE_GNUC_VARARGS) #define cinnamon_settings_profile_start(format...) _cinnamon_settings_profile_log (G_STRFUNC, "start", format) #define cinnamon_settings_profile_end(format...) _cinnamon_settings_profile_log (G_STRFUNC, "end", format) #define cinnamon_settings_profile_msg(format...) _cinnamon_settings_profile_log (NULL, NULL, format) #endif #else #define cinnamon_settings_profile_start(...) #define cinnamon_settings_profile_end(...) #define cinnamon_settings_profile_msg(...) #endif void _cinnamon_settings_profile_log (const char *func, const char *note, const char *format, ...) G_GNUC_PRINTF (3, 4); G_END_DECLS #endif /* __CINNAMON_SETTINGS_PROFILE_H */ cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/cinnamon-settings-session.c000066400000000000000000000267751356401377300306400ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "cinnamon-settings-session.h" #ifdef HAVE_LOGIND #include #endif typedef struct { GSource source; GPollFD pollfd; #ifdef HAVE_LOGIND sd_login_monitor *monitor; #endif } SdSource; #ifdef HAVE_LOGIND static gboolean sd_source_prepare (GSource *source, gint *timeout) { *timeout = -1; return FALSE; } static gboolean sd_source_check (GSource *source) { SdSource *sd_source = (SdSource *)source; return sd_source->pollfd.revents != 0; } static gboolean sd_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { SdSource *sd_source = (SdSource *)source; gboolean ret; g_warn_if_fail (callback != NULL); ret = (*callback) (user_data); sd_login_monitor_flush (sd_source->monitor); return ret; } static void sd_source_finalize (GSource *source) { SdSource *sd_source = (SdSource*)source; sd_login_monitor_unref (sd_source->monitor); } static GSourceFuncs sd_source_funcs = { sd_source_prepare, sd_source_check, sd_source_dispatch, sd_source_finalize }; static GSource * sd_source_new (void) { GSource *source; SdSource *sd_source; int ret; source = g_source_new (&sd_source_funcs, sizeof (SdSource)); sd_source = (SdSource *)source; if ((ret = sd_login_monitor_new (NULL, &sd_source->monitor)) < 0) { g_printerr ("Error getting login monitor: %d", ret); } else { sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor); sd_source->pollfd.events = G_IO_IN; g_source_add_poll (source, &sd_source->pollfd); } return source; } #endif static void cinnamon_settings_session_finalize (GObject *object); #define CINNAMON_SETTINGS_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CINNAMON_TYPE_SETTINGS_SESSION, CinnamonSettingsSessionPrivate)) #define CONSOLEKIT_NAME "org.freedesktop.ConsoleKit" #define CONSOLEKIT_PATH "/org/freedesktop/ConsoleKit" #define CONSOLEKIT_INTERFACE "org.freedesktop.ConsoleKit" #define CONSOLEKIT_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" #define CONSOLEKIT_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" #define CONSOLEKIT_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" #define CONSOLEKIT_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" struct CinnamonSettingsSessionPrivate { GSource *sd_source; // used in logind mode GDBusProxy *proxy_session; // used in consolekit mode GCancellable *cancellable; // used in consolekit mode gchar *session_id; CinnamonSettingsSessionState state; }; enum { PROP_0, PROP_STATE, PROP_LAST }; G_DEFINE_TYPE (CinnamonSettingsSession, cinnamon_settings_session, G_TYPE_OBJECT) CinnamonSettingsSessionState cinnamon_settings_session_get_state (CinnamonSettingsSession *session) { g_return_val_if_fail (CINNAMON_IS_SETTINGS_SESSION (session), CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN); return session->priv->state; } static void cinnamon_settings_session_set_state (CinnamonSettingsSession *session, gboolean active) { CinnamonSettingsSessionState state; state = active ? CINNAMON_SETTINGS_SESSION_STATE_ACTIVE : CINNAMON_SETTINGS_SESSION_STATE_INACTIVE; if (session->priv->state != state) { session->priv->state = state; g_object_notify (G_OBJECT (session), "state"); } } static void cinnamon_settings_session_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CinnamonSettingsSession *session = CINNAMON_SETTINGS_SESSION (object); switch (prop_id) { case PROP_STATE: g_value_set_enum (value, session->priv->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } GType cinnamon_settings_session_state_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN, "unknown", "Unknown" }, { CINNAMON_SETTINGS_SESSION_STATE_ACTIVE, "active", "Active" }, { CINNAMON_SETTINGS_SESSION_STATE_INACTIVE, "inactive", "Inactive" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("CinnamonSettingsSessionState", values); } return etype; } static void cinnamon_settings_session_class_init (CinnamonSettingsSessionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = cinnamon_settings_session_get_property; object_class->finalize = cinnamon_settings_session_finalize; g_type_class_add_private (klass, sizeof (CinnamonSettingsSessionPrivate)); g_object_class_install_property (object_class, PROP_STATE, g_param_spec_enum ("state", "The session state", NULL, CINNAMON_TYPE_SETTINGS_SESSION_STATE, CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN, G_PARAM_READABLE)); } #ifdef HAVE_LOGIND static gboolean sessions_changed (gpointer user_data) { CinnamonSettingsSession *session = user_data; gboolean active; active = sd_session_is_active (session->priv->session_id); cinnamon_settings_session_set_state (session, active); return TRUE; } #endif static void cinnamon_settings_session_proxy_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, CinnamonSettingsSession *session) { gboolean active; if (g_strcmp0 (signal_name, "ActiveChanged") == 0) { g_variant_get (parameters, "(b)", &active); g_debug ("emitting active: %i", active); cinnamon_settings_session_set_state (session, active); } } static void is_active_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gboolean active = FALSE; GError *error = NULL; GVariant *result; CinnamonSettingsSession *session = CINNAMON_SETTINGS_SESSION (user_data); /* is our session active */ result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("IsActive failed: %s", error->message); g_error_free (error); return; } g_variant_get (result, "(b)", &active); cinnamon_settings_session_set_state (session, active); /* watch for changes */ g_signal_connect (session->priv->proxy_session, "g-signal", G_CALLBACK (cinnamon_settings_session_proxy_signal_cb), session); g_variant_unref (result); } static void got_session_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CinnamonSettingsSession *session = CINNAMON_SETTINGS_SESSION (user_data); /* connect to session */ session->priv->proxy_session = g_dbus_proxy_new_for_bus_finish (res, &error); if (session->priv->proxy_session == NULL) { g_warning ("cannot connect to %s: %s", session->priv->session_id, error->message); g_error_free (error); return; } /* is our session active */ g_dbus_proxy_call (session->priv->proxy_session, "IsActive", NULL, G_DBUS_CALL_FLAGS_NONE, -1, session->priv->cancellable, is_active_cb, session); } static void got_session_path_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; CinnamonSettingsSession *session = CINNAMON_SETTINGS_SESSION (user_data); result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("Failed to get session for pid: %s", error->message); g_error_free (error); return; } g_variant_get (result, "(o)", &session->priv->session_id); g_debug ("ConsoleKit session ID: %s", session->priv->session_id); /* connect to session */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_NAME, session->priv->session_id, CONSOLEKIT_SESSION_INTERFACE, session->priv->cancellable, got_session_proxy_cb, session); g_variant_unref (result); } static void got_manager_proxy_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GDBusProxy *proxy_manager; GError *error = NULL; guint32 pid; CinnamonSettingsSession *session = CINNAMON_SETTINGS_SESSION (user_data); proxy_manager = g_dbus_proxy_new_for_bus_finish (res, &error); if (proxy_manager == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } /* get the session we are running in */ pid = getpid (); g_dbus_proxy_call (proxy_manager, "GetSessionForUnixProcess", g_variant_new ("(u)", pid), G_DBUS_CALL_FLAGS_NONE, -1, session->priv->cancellable, got_session_path_cb, session); g_object_unref (proxy_manager); } static void cinnamon_settings_session_init (CinnamonSettingsSession *session) { session->priv = CINNAMON_SETTINGS_SESSION_GET_PRIVATE (session); #ifdef HAVE_LOGIND if (access("/run/systemd/system/", F_OK) == 0) { // sd_booted () sd_pid_get_session (getpid(), &session->priv->session_id); session->priv->sd_source = sd_source_new (); g_source_set_callback (session->priv->sd_source, sessions_changed, session, NULL); g_source_attach (session->priv->sd_source, NULL); sessions_changed (session); g_debug ("Using logind"); } else #endif /* HAVE_LOGIND */ { g_debug ("Using consolekit"); session->priv->cancellable = g_cancellable_new (); /* connect to ConsoleKit */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_NAME, CONSOLEKIT_MANAGER_PATH, CONSOLEKIT_MANAGER_INTERFACE, session->priv->cancellable, got_manager_proxy_cb, session); } } static void cinnamon_settings_session_finalize (GObject *object) { CinnamonSettingsSession *session; session = CINNAMON_SETTINGS_SESSION (object); g_free (session->priv->session_id); if (session->priv->sd_source != NULL) { g_source_destroy (session->priv->sd_source); g_source_unref (session->priv->sd_source); } g_cancellable_cancel (session->priv->cancellable); if (session->priv->proxy_session != NULL) g_object_unref (session->priv->proxy_session); g_object_unref (session->priv->cancellable); G_OBJECT_CLASS (cinnamon_settings_session_parent_class)->finalize (object); } CinnamonSettingsSession * cinnamon_settings_session_new (void) { CinnamonSettingsSession *session; session = g_object_new (CINNAMON_TYPE_SETTINGS_SESSION, NULL); return CINNAMON_SETTINGS_SESSION (session); } cinnamon-settings-daemon-4.4.0/cinnamon-settings-daemon/cinnamon-settings-session.h000066400000000000000000000050661356401377300306330ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __CINNAMON_SETTINGS_SESSION_H #define __CINNAMON_SETTINGS_SESSION_H #include G_BEGIN_DECLS #define CINNAMON_TYPE_SETTINGS_SESSION (cinnamon_settings_session_get_type ()) #define CINNAMON_SETTINGS_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CINNAMON_TYPE_SETTINGS_SESSION, CinnamonSettingsSession)) #define CINNAMON_SETTINGS_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CINNAMON_TYPE_SETTINGS_SESSION, CinnamonSettingsSessionClass)) #define CINNAMON_IS_SETTINGS_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CINNAMON_TYPE_SETTINGS_SESSION)) #define CINNAMON_IS_SETTINGS_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CINNAMON_TYPE_SETTINGS_SESSION)) #define CINNAMON_SETTINGS_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CINNAMON_TYPE_SETTINGS_SESSION, CinnamonSettingsSessionClass)) #define CINNAMON_TYPE_SETTINGS_SESSION_STATE (cinnamon_settings_session_state_get_type()) typedef struct CinnamonSettingsSessionPrivate CinnamonSettingsSessionPrivate; typedef struct { GObject parent; CinnamonSettingsSessionPrivate *priv; } CinnamonSettingsSession; typedef struct { GObjectClass parent_class; } CinnamonSettingsSessionClass; typedef enum { CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN, CINNAMON_SETTINGS_SESSION_STATE_ACTIVE, CINNAMON_SETTINGS_SESSION_STATE_INACTIVE, } CinnamonSettingsSessionState; GType cinnamon_settings_session_get_type (void); GType cinnamon_settings_session_state_get_type (void); CinnamonSettingsSession *cinnamon_settings_session_new (void); CinnamonSettingsSessionState cinnamon_settings_session_get_state (CinnamonSettingsSession *session); G_END_DECLS #endif /* __CINNAMON_SETTINGS_SESSION_H */ cinnamon-settings-daemon-4.4.0/configure.ac000066400000000000000000000453461356401377300207330ustar00rootroot00000000000000AC_PREREQ([2.60]) AC_INIT([cinnamon-settings-daemon], [4.4.0], [https://github.com/linuxmint/cinnamon-settings-daemon/issues]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([cinnamon-settings-daemon/cinnamon-settings-session.c]) AM_INIT_AUTOMAKE([1.9 tar-ustar dist-xz no-dist-gzip check-news]) AM_MAINTAINER_MODE([enable]) m4_ifdef([AX_IS_RELEASE], [AX_IS_RELEASE([always])]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) m4_define([gsd_api_version_major],[3]) m4_define([gsd_api_version_minor],[0]) m4_define([gsd_api_version],[gsd_api_version_major.gsd_api_version_minor]) CSD_API_VERSION="gsd_api_version" AC_SUBST(CSD_API_VERSION) AC_STDC_HEADERS AC_PROG_CXX AM_PROG_CC_C_O AC_PROG_LIBTOOL AC_HEADER_STDC AC_SUBST(VERSION) AC_CONFIG_HEADERS([config.h]) IT_PROG_INTLTOOL([0.37.1]) GETTEXT_PACKAGE=cinnamon-settings-daemon AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Name of default gettext domain]) AM_GLIB_GNU_GETTEXT m4_ifdef([AX_COMPILER_FLAGS], [AX_COMPILER_FLAGS([WARN_CFLAGS],[WARN_LDFLAGS])]) dnl --------------------------------------------------------------------------- dnl - Dependencies dnl --------------------------------------------------------------------------- GLIB_REQUIRED_VERSION=2.37.3 GTK_REQUIRED_VERSION=3.9.10 GCONF_REQUIRED_VERSION=2.6.1 GIO_REQUIRED_VERSION=2.26.0 CINNAMON_DESKTOP_REQUIRED_VERSION=3.2.2 LIBNOTIFY_REQUIRED_VERSION=0.7.3 UPOWER_GLIB_REQUIRED_VERSION=0.9.11 PA_REQUIRED_VERSION=0.9.16 LIBWACOM_REQUIRED_VERSION=0.7 LIBRSVG_REQUIRED_VERSION=2.36.2 GTK_XINPUT_2_3_VERSION=3.7.8 #EXTRA_COMPILE_WARNINGS(yes) PKG_CHECK_MODULES(SETTINGS_DAEMON, glib-2.0 >= $GLIB_REQUIRED_VERSION gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-2.0 >= $GIO_REQUIRED_VERSION gmodule-2.0 gthread-2.0 cinnamon-desktop ) PKG_CHECK_MODULES(SETTINGS_PLUGIN, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-2.0 >= $GIO_REQUIRED_VERSION libnotify >= $LIBNOTIFY_REQUIRED_VERSION cinnamon-desktop x11 ) PKG_CHECK_MODULES(XI23, gtk+-3.0 >= $GTK_XINPUT_2_3_VERSION, have_xi_23=yes, have_xi_23=no) if test x$have_xi_23 = xyes ; then AC_DEFINE(XI_23, 1, [Defined if GTK version is higher than 3.7.8]) fi CSD_PLUGIN_LDFLAGS="-export_dynamic -module -avoid-version -no-undefined" case $host_os in darwin*) CSD_PLUGIN_LDFLAGS="${CSD_PLUGIN_LDFLAGS} -Wl,-bundle_loader,\$(top_builddir)/cinnamon-settings-daemon/cinnamon-settings-daemon" ;; esac AC_SUBST([CSD_PLUGIN_LDFLAGS]) AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) dnl ================================================================ dnl GSettings stuff dnl ================================================================ GLIB_GSETTINGS dnl --------------------------------------------------------------------------- dnl - Check for LCMS2 dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(LCMS, lcms2 >= 2.2, have_new_lcms=yes, have_new_lcms=no) if test x$have_new_lcms = xyes; then AC_DEFINE(HAVE_NEW_LCMS,1,[Got new lcms2]) else PKG_CHECK_MODULES(LCMS, lcms2) fi dnl --------------------------------------------------------------------------- dnl - Check for GLib 2.38 or more dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(NEW_GLIB, glib-2.0 >= 2.38.0, have_new_glib=yes, have_new_gib=no) if test x$have_new_glib = xyes; then AC_DEFINE(HAVE_NEW_GLIB,1,[Got new glib-2.0]) fi dnl --------------------------------------------------------------------------- dnl - Check for libnotify dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED_VERSION, [have_libnotify=yes], have_libnotify=no) if test "x$have_libnotify" = xno ; then AC_MSG_ERROR([libnotify is required to build cinnamon-settings-daemon]) fi AC_SUBST(LIBNOTIFY_CFLAGS) AC_SUBST(LIBNOTIFY_LIBS) dnl --------------------------------------------------------------------------- dnl - Check for D-Bus dnl --------------------------------------------------------------------------- dnl - Are we specifying a different dbus root ? AC_ARG_WITH(dbus-sys, [AC_HELP_STRING([--with-dbus-sys=], [where D-BUS system.d directory is])]) AC_ARG_WITH(dbus-services, [AC_HELP_STRING([--with-dbus-services=], [where D-BUS services directory is])]) if ! test -z "$with_dbus_sys" ; then DBUS_SYS_DIR="$with_dbus_sys" else DBUS_SYS_DIR='${sysconfdir}/dbus-1/system.d' fi AC_SUBST(DBUS_SYS_DIR) dnl --------------------------------------------------------------------------- dnl - GUdev integration (default enabled) dnl --------------------------------------------------------------------------- GUDEV_PKG="" AC_ARG_ENABLE(gudev, AS_HELP_STRING([--disable-gudev],[Disable GUdev support (not optional on Linux platforms)]), enable_gudev=$enableval) if test x$enable_gudev != xno; then PKG_CHECK_MODULES(GUDEV, gudev-1.0, have_gudev="yes", have_gudev="no") if test "x$have_gudev" = "xyes"; then AC_DEFINE(HAVE_GUDEV, 1, [define if GUdev is available]) GUDEV_PKG="gudev-1.0" else if test x$enable_gudev = xyes; then AC_MSG_ERROR([GUdev enabled but not found]) fi fi else have_gudev=no fi AM_CONDITIONAL(HAVE_GUDEV, test x$have_gudev = xyes) dnl --------------------------------------------------------------------------- dnl - common dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(COMMON, x11 kbproto xi) dnl --------------------------------------------------------------------------- dnl - automount dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(AUTOMOUNT, x11 kbproto) dnl --------------------------------------------------------------------------- dnl - background dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(BACKGROUND, x11 cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION) dnl --------------------------------------------------------------------------- dnl - mouse dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(MOUSE, x11 xi) dnl --------------------------------------------------------------------------- dnl - cursor dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(CURSOR, xfixes) dnl --------------------------------------------------------------------------- dnl - xsettings dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(XSETTINGS, fontconfig) dnl --------------------------------------------------------------------------- dnl - Keyboard plugin stuff dnl --------------------------------------------------------------------------- LIBGNOMEKBD_REQUIRED=3.6.0 PKG_CHECK_MODULES(KEYBOARD, [libgnomekbdui >= $LIBGNOMEKBD_REQUIRED libgnomekbd >= $LIBGNOMEKBD_REQUIRED libxklavier >= 5.0 kbproto]) dnl --------------------------------------------------------------------------- dnl - Housekeeping plugin stuff dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(GIOUNIX, [gio-unix-2.0]) dnl --------------------------------------------------------------------------- dnl - media-keys plugin stuff dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(MEDIA_KEYS, [gio-unix-2.0 libnotify libcanberra $GUDEV_PKG cvc >= $CINNAMON_DESKTOP_REQUIRED_VERSION cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION]) dnl --------------------------------------------------------------------------- dnl - xrandr plugin stuff dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(XRANDR, [cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION upower-glib >= $UPOWER_GLIB_REQUIRED_VERSION]) dnl --------------------------------------------------------------------------- dnl - orientation plugin stuff dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(ORIENTATION, [cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION]) dnl --------------------------------------------------------------------------- dnl - sound plugin stuff dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(SOUND, [libpulse >= $PA_REQUIRED_VERSION $GUDEV_PKG libpulse-mainloop-glib >= $PA_REQUIRED_VERSION] libcanberra) # --------------------------------------------------------------------------- # Power # --------------------------------------------------------------------------- PKG_CHECK_MODULES(POWER, upower-glib >= $UPOWER_GLIB_REQUIRED_VERSION cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION libcanberra-gtk3 libnotify x11 xext) if test x$have_gudev != xno; then PKG_CHECK_MODULES(BACKLIGHT_HELPER, glib-2.0 >= $GLIB_REQUIRED_VERSION gudev-1.0 ) fi dnl --------------------------------------------------------------------------- dnl - color dnl --------------------------------------------------------------------------- PKG_CHECK_MODULES(COLOR, [colord >= 0.1.27 cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION libcanberra-gtk3]) dnl --------------------------------------------------------------------------- dnl - wacom dnl --------------------------------------------------------------------------- build_wacom=false PKG_CHECK_MODULES(WACOM, [libwacom >= $LIBWACOM_REQUIRED_VERSION x11 xi xtst gudev-1.0 cinnamon-desktop xorg-wacom librsvg-2.0 >= $LIBRSVG_REQUIRED_VERSION gtk+-3.0 >= 3.8.0], [build_wacom="true" AC_DEFINE(HAVE_WACOM, 1, [Define if wacom is being build])], [build_wacom="false"]) AM_CONDITIONAL(BUILD_WACOM, test "x$build_wacom" = "xtrue") dnl ============================================== dnl smartcard section dnl ============================================== have_smartcard_support=false AC_ARG_ENABLE(smartcard-support, AC_HELP_STRING([--disable-smartcard-support], [turn off smartcard support]), [case "${enableval}" in yes) WANT_SMARTCARD_SUPPORT=yes ;; no) WANT_SMARTCARD_SUPPORT=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-smartcard-support) ;; esac], [WANT_SMARTCARD_SUPPORT=yes]) if test x$WANT_SMARTCARD_SUPPORT = xyes ; then NSS_REQUIRED_VERSION=3.11.2 PKG_CHECK_MODULES(NSS, nss >= $NSS_REQUIRED_VERSION, [have_smartcard_support=true AC_DEFINE(SMARTCARD_SUPPORT, 1, [Define if smartcard support should be enabled])], [have_smartcard_support=false]) fi AM_CONDITIONAL(SMARTCARD_SUPPORT, test "x$have_smartcard_support" = "xtrue") AC_SUBST(NSS_CFLAGS) AC_SUBST(NSS_LIBS) AC_ARG_WITH(nssdb, AC_HELP_STRING([--with-nssdb], [where system NSS database is])) NSS_DATABASE="" if test "x$have_smartcard_support" = "xtrue"; then if ! test -z "$with_nssdb" ; then NSS_DATABASE="$with_nssdb" else NSS_DATABASE="${sysconfdir}/pki/nssdb" fi else if ! test -z "$with_nssdb" ; then AC_MSG_WARN([nssdb specified when smartcard support is disabled]) fi fi AC_SUBST(NSS_DATABASE) dnl --------------------------------------------------------------------------- dnl - Check for D-Bus dnl --------------------------------------------------------------------------- dnl - Are we specifying a different dbus root ? AC_ARG_WITH(dbus-sys, [AC_HELP_STRING([--with-dbus-sys=], [where D-BUS system.d directory is])]) AC_ARG_WITH(dbus-services, [AC_HELP_STRING([--with-dbus-services=], [where D-BUS services directory is])]) if ! test -z "$with_dbus_sys" ; then DBUS_SYS_DIR="$with_dbus_sys" else DBUS_SYS_DIR='${sysconfdir}/dbus-1/system.d' fi AC_SUBST(DBUS_SYS_DIR) # --------------------------------------------------------------------------- # PolicyKit for the date & time mechanism # --------------------------------------------------------------------------- POLKIT_REQUIRED=0.97 DBUS_REQUIRED=1.1.2 # PolicyKit detection; defaults to 'auto' (use it if it's available) # POLKIT_CFLAGS= POLKIT_LIBS= AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit], [Enable PolicyKit support (auto)]), enable_polkit=$enableval, enable_polkit=auto) if test "x$enable_polkit" = "xno" ; then HAVE_POLKIT=no else HAVE_POLKIT=no PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= $POLKIT_REQUIRED dbus-1 >= $DBUS_REQUIRED dbus-glib-1, HAVE_POLKIT=yes, HAVE_POLKIT=no) if test "x$enable_polkit" = "xyes" -a "x$HAVE_POLKIT" = "xno" ; then AC_MSG_ERROR(PolicyKit support explicity enabled but not available) fi if test "x$HAVE_POLKIT" = "xyes" ; then AC_DEFINE(HAVE_POLKIT, 1, [Defined if PolicyKit support is enabled]) fi fi AM_CONDITIONAL(HAVE_POLKIT, test "x$HAVE_POLKIT" = "xyes") AC_SUBST(POLKIT_CFLAGS) AC_SUBST(POLKIT_LIBS) dnl ==================================================================== dnl Check for logind dnl ==================================================================== PKG_CHECK_MODULES(LOGIND, [libsystemd-login], [have_logind=yes], [ PKG_CHECK_MODULES(LOGIND, [libsystemd], [have_logind=yes], [have_logind=no]) ]) if test x$have_logind = xyes; then AC_DEFINE(HAVE_LOGIND, 1, [Define if logind is supported]) fi AC_SUBST(LOGIND_CFLAGS) AC_SUBST(LOGIND_LIBS) # --------------------------------------------------------------------------- # CUPS # --------------------------------------------------------------------------- AC_ARG_ENABLE(cups, AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),, enable_cups=yes) if test x"$enable_cups" != x"no" ; then AC_PROG_SED AC_PATH_PROG(CUPS_CONFIG, cups-config) if test x$CUPS_CONFIG = x; then AC_MSG_ERROR([cups-config not found but CUPS support requested]) fi CUPS_API_VERSION=`$CUPS_CONFIG --api-version` CUPS_API_MAJOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 1` CUPS_API_MINOR=`echo $ECHO_N $CUPS_API_VERSION | cut -d . -f 2` AC_CHECK_HEADERS([cups/cups.h cups/http.h cups/ipp.h],, AC_MSG_ERROR([CUPS headers not found but CUPS support requested])) if ! test $CUPS_API_MAJOR -gt 1 -o \ $CUPS_API_MAJOR -eq 1 -a $CUPS_API_MINOR -ge 4 ; then AC_MSG_ERROR([CUPS 1.4 or newer not found, but CUPS support requested]) fi CUPS_CFLAGS=`$CUPS_CONFIG --cflags | $SED -e 's/-O\w*//g' -e 's/-m\w*//g'` CUPS_LIBS=`$CUPS_CONFIG --libs` AC_SUBST(CUPS_CFLAGS) AC_SUBST(CUPS_LIBS) fi AM_CONDITIONAL(BUILD_PRINT_NOTIFICATIONS, [test x"$enable_cups" = x"yes"]) # --------------------------------------------------------------------------- # Enable Profiling # --------------------------------------------------------------------------- AC_ARG_ENABLE(profiling, [AC_HELP_STRING([--enable-profiling], [turn on profiling])], , enable_profiling=no) if test "x$enable_profiling" = "xyes"; then AC_DEFINE(ENABLE_PROFILING,1,[enable profiling]) fi # --------------------------------------------------------------------------- # Plugins # --------------------------------------------------------------------------- plugindir='$(libdir)/cinnamon-settings-daemon-gsd_api_version' AC_SUBST([plugindir]) PLUGIN_CFLAGS="-DG_LOG_DOMAIN=\"\\\"\$(plugin_name)-plugin\\\"\" -DPLUGIN_NAME=\"\\\"\$(plugin_name)\\\"\" " AC_SUBST(PLUGIN_CFLAGS) dnl --------------------------------------------------------------------------- dnl - Finish dnl --------------------------------------------------------------------------- # # Enable Debug # AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug], [turn on debugging])], , enable_debug=yes) if test "$enable_debug" = "yes"; then DEBUG_CFLAGS="-DG_ENABLE_DEBUG" else if test "x$enable_debug" = "xno"; then DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" else DEBUG_CFLAGS="" fi fi AC_SUBST(DEBUG_CFLAGS) CFLAGS="$CFLAGS -Wno-deprecated-declarations -Wno-deprecated -Wno-declaration-after-statement" AC_OUTPUT([ Makefile cinnamon-settings-daemon/Makefile files/Makefile plugins/Makefile plugins/a11y-keyboard/Makefile plugins/a11y-settings/Makefile plugins/automount/Makefile plugins/background/Makefile plugins/clipboard/Makefile plugins/color/Makefile plugins/common/Makefile plugins/cursor/Makefile plugins/datetime/Makefile plugins/dummy/Makefile plugins/power/Makefile plugins/housekeeping/Makefile plugins/keyboard/Makefile plugins/media-keys/Makefile plugins/mouse/Makefile plugins/orientation/Makefile plugins/print-notifications/Makefile plugins/screensaver-proxy/Makefile plugins/smartcard/Makefile plugins/sound/Makefile plugins/wacom/Makefile plugins/xrandr/Makefile plugins/xsettings/Makefile data/Makefile data/cinnamon-settings-daemon.pc data/org.cinnamon.settings-daemon.plugins.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.xsettings.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.power.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.color.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.media-keys.gschema.xml.in data/org.cinnamon.settings-daemon.peripherals.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.housekeeping.gschema.xml.in data/org.cinnamon.settings-daemon.peripherals.wacom.gschema.xml.in data/org.cinnamon.settings-daemon.plugins.xrandr.gschema.xml.in po/Makefile.in ]) dnl --------------------------------------------------------------------------- dnl - Show summary dnl --------------------------------------------------------------------------- echo " cinnamon-settings-daemon $VERSION ============================= prefix: ${prefix} exec_prefix: ${exec_prefix} libdir: ${libdir} bindir: ${bindir} sbindir: ${sbindir} sysconfdir: ${sysconfdir} sysconfsubdir: ${sysconfsubdir} localstatedir: ${localstatedir} plugindir: ${plugindir} datadir: ${datadir} source code location: ${srcdir} compiler: ${CC} cflags: ${CFLAGS} Maintainer mode: ${USE_MAINTAINER_MODE} dbus-1 system.d dir: ${DBUS_SYS_DIR} PolicyKit support: ${HAVE_POLKIT} Logind supported: ${have_logind} LCMS DICT support: ${have_new_lcms} Libnotify support: ${have_libnotify} Wacom support: ${build_wacom} Smartcard support: ${have_smartcard_support} Cups support: ${enable_cups} ${NSS_DATABASE:+\ System nssdb: ${NSS_DATABASE} }\ Profiling support: ${enable_profiling} " cinnamon-settings-daemon-4.4.0/data/000077500000000000000000000000001356401377300173425ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/data/Makefile.am000066400000000000000000000025531356401377300214030ustar00rootroot00000000000000NULL = apidir = $(includedir)/cinnamon-settings-daemon-$(CSD_API_VERSION)/cinnamon-settings-daemon api_DATA = csd-enums.h gsettings_ENUM_NAMESPACE = org.cinnamon.settings-daemon gsettings_ENUM_FILES = $(top_srcdir)/data/$(api_DATA) gsettings_SCHEMAS = \ org.cinnamon.settings-daemon.peripherals.gschema.xml \ org.cinnamon.settings-daemon.peripherals.wacom.gschema.xml \ org.cinnamon.settings-daemon.plugins.gschema.xml \ org.cinnamon.settings-daemon.plugins.power.gschema.xml \ org.cinnamon.settings-daemon.plugins.color.gschema.xml \ org.cinnamon.settings-daemon.plugins.media-keys.gschema.xml \ org.cinnamon.settings-daemon.plugins.xsettings.gschema.xml \ org.cinnamon.settings-daemon.plugins.housekeeping.gschema.xml \ org.cinnamon.settings-daemon.plugins.xrandr.gschema.xml @INTLTOOL_XML_NOMERGE_RULE@ @GSETTINGS_RULES@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cinnamon-settings-daemon.pc @INTLTOOL_XML_NOMERGE_RULE@ dbusservice_in_files = org.freedesktop.IBus.service.in EXTRA_DIST = \ $(man_MANS) \ $(convert_DATA) \ $(gsettings_SCHEMAS:.xml=.xml.in.in) \ $(gsettings_ENUM_FILES) \ cinnamon-settings-daemon.pc.in \ $(api_DATA) \ $(dbusservice_in_files) \ $(NULL) DISTCLEANFILES = \ $(gsettings_SCHEMAS) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in \ $(gsettings_SCHEMAS:.xml=.valid) cinnamon-settings-daemon-4.4.0/data/cinnamon-settings-daemon.pc.in000066400000000000000000000003551356401377300251770ustar00rootroot00000000000000prefix=@prefix@ includedir=@includedir@ Name: cinnamon-settings-daemon Description: cinnamon-settings-daemon specific enumarations Requires: glib-2.0 Version: @VERSION@ Cflags: -I${includedir}/cinnamon-settings-daemon-@CSD_API_VERSION@ cinnamon-settings-daemon-4.4.0/data/csd-enums.h000066400000000000000000000070351356401377300214160ustar00rootroot00000000000000/* * Copyright © 2010 Bastien Nocera * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * Authors: * Bastien Nocera */ #ifndef __csd_enums_h__ #define __csd_enums_h__ typedef enum { CSD_FONT_ANTIALIASING_MODE_NONE, CSD_FONT_ANTIALIASING_MODE_GRAYSCALE, CSD_FONT_ANTIALIASING_MODE_RGBA } CsdFontAntialiasingMode; typedef enum { CSD_FONT_HINTING_NONE, CSD_FONT_HINTING_SLIGHT, CSD_FONT_HINTING_MEDIUM, CSD_FONT_HINTING_FULL } CsdFontHinting; typedef enum { CSD_FONT_RGBA_ORDER_RGBA, CSD_FONT_RGBA_ORDER_RGB, CSD_FONT_RGBA_ORDER_BGR, CSD_FONT_RGBA_ORDER_VRGB, CSD_FONT_RGBA_ORDER_VBGR } CsdFontRgbaOrder; typedef enum { CSD_SMARTCARD_REMOVAL_ACTION_NONE, CSD_SMARTCARD_REMOVAL_ACTION_LOCK_SCREEN, CSD_SMARTCARD_REMOVAL_ACTION_FORCE_LOGOUT } CsdSmartcardRemovalAction; typedef enum { CSD_BELL_MODE_ON, CSD_BELL_MODE_OFF, CSD_BELL_MODE_CUSTOM } CsdBellMode; typedef enum { CSD_TOUCHPAD_HANDEDNESS_RIGHT, CSD_TOUCHPAD_HANDEDNESS_LEFT, CSD_TOUCHPAD_HANDEDNESS_MOUSE } CsdTouchpadHandedness; typedef enum { CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING, CSD_XRANDR_BOOT_BEHAVIOUR_CLONE, CSD_XRANDR_BOOT_BEHAVIOUR_DOCK, CSD_XRANDR_BOOT_BEHAVIOUR_FOLLOW_LID } CsdXrandrBootBehaviour; typedef enum { CSD_WACOM_ROTATION_NONE, CSD_WACOM_ROTATION_CW, CSD_WACOM_ROTATION_CCW, CSD_WACOM_ROTATION_HALF } CsdWacomRotation; typedef enum { CSD_WACOM_ACTION_TYPE_NONE, CSD_WACOM_ACTION_TYPE_CUSTOM, CSD_WACOM_ACTION_TYPE_SWITCH_MONITOR, CSD_WACOM_ACTION_TYPE_HELP } CsdWacomActionType; typedef enum { CSD_POWER_ACTION_BLANK, CSD_POWER_ACTION_SUSPEND, CSD_POWER_ACTION_SHUTDOWN, CSD_POWER_ACTION_HIBERNATE, CSD_POWER_ACTION_INTERACTIVE, CSD_POWER_ACTION_NOTHING } CsdPowerActionType; typedef enum { CSD_UPDATE_TYPE_ALL, CSD_UPDATE_TYPE_SECURITY, CSD_UPDATE_TYPE_NONE } CsdUpdateType; typedef enum { CSD_NUM_LOCK_STATE_UNKNOWN, CSD_NUM_LOCK_STATE_ON, CSD_NUM_LOCK_STATE_OFF } CsdNumLockState; typedef enum { CSD_INPUT_SOURCES_SWITCHER_OFF, CSD_INPUT_SOURCES_SWITCHER_SHIFT_L, CSD_INPUT_SOURCES_SWITCHER_ALT_L, CSD_INPUT_SOURCES_SWITCHER_CTRL_L, CSD_INPUT_SOURCES_SWITCHER_SHIFT_R, CSD_INPUT_SOURCES_SWITCHER_ALT_R, CSD_INPUT_SOURCES_SWITCHER_CTRL_R, CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_L, CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_R, CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_L, CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_R, CSD_INPUT_SOURCES_SWITCHER_SHIFT_L_SHIFT_R, CSD_INPUT_SOURCES_SWITCHER_ALT_L_ALT_R, CSD_INPUT_SOURCES_SWITCHER_CTRL_L_CTRL_R, CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT, CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT, CSD_INPUT_SOURCES_SWITCHER_ALT_CTRL, CSD_INPUT_SOURCES_SWITCHER_CAPS, CSD_INPUT_SOURCES_SWITCHER_SHIFT_CAPS, CSD_INPUT_SOURCES_SWITCHER_ALT_CAPS, CSD_INPUT_SOURCES_SWITCHER_CTRL_CAPS } CsdInputSourcesSwitcher; #endif /* __csd_enums_h__ */ cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.peripherals.gschema.xml.in.in000066400000000000000000000234661356401377300325240ustar00rootroot00000000000000 'none' <_summary>Smartcard removal action <_description>Set this to one of "none", "lock-screen", or "force-logout". The action will get performed when the smartcard used for log in is removed. true <_summary>Disable touchpad while typing <_description>Set this to TRUE if you have problems with accidentally hitting the touchpad while typing. 3 <_summary>Set scrolling mode on touchpad <_description>0 to 2, 0 is disabled, 1 is two-finger scrolling, 2 is edge scrolling, 3 is automatic selection false <_summary> <_description> true <_summary>Enable mouse clicks with touchpad <_description>Set this to TRUE to be able to send mouse clicks by tapping on the touchpad. 3 <_summary>Click action on clickpads <_description>0 through 2, 0 is single click action, 1 emulates mouse buttons in bottom corners, 2 is multi-finger click, 3 is automatic selection true <_summary>Enable touchpad <_description>Set this to TRUE to enable all touchpads. false <_summary>Disable the touchpad when an external mouse is connected <_description>Set this to TRUE to disable the touchpad when an external mouse is connected (only available with libinput) 'mouse' Touchpad button orientation Swap left and right mouse buttons for left-handed mice with 'left', 'right' for right-handed, 'mouse' to follow the mouse setting. false Custom Motion Acceleration Wheather or not to use a custom motion acceleration value. -1 Motion Acceleration Acceleration multiplier for mouse motion. A value of -1 is the system default. false Custom Motion Threshold Wheather or not to use a custom motion threshold value. -1 Motion Threshold Distance in pixels the pointer must move before accelerated mouse motion is activated. A value of -1 is the system default. true Natural scrolling Set this to TRUE to enable natural (reverse) scrolling for touchpads. true true 30 Key Repeat Interval Delay between repeats in milliseconds. 500 Initial Key Repeat Delay Initial key repeat delay in milliseconds. 0 'on' Possible values are "on", "off", and "custom". 400 100 '' Keyboard Bell Custom Filename File name of the bell sound to be played. true Remember NumLock state When set to true, GNOME will remember the state of the NumLock LED between sessions. 'unknown' NumLock state The remembered state of the NumLock LED. 'off' Modifiers-only input sources switcher shortcut false <_summary>Highlights the current location of the pointer when the Control key is pressed and released. false Mouse button orientation Swap left and right mouse buttons for left-handed mice. false Natural scrolling Set this to TRUE to enable natural (reverse) scrolling for mice. false Custom Motion Acceleration Wheather or not to use a custom motion acceleration value. -1 Motion Acceleration Acceleration multiplier for mouse motion. A value of -1 is the system default. false Custom Motion Threshold Wheather or not to use a custom motion threshold value. -1 Motion Threshold Distance in pixels the pointer must move before accelerated mouse motion is activated. A value of -1 is the system default. 400 <_summary>Double click time <_description> Length of a double click in milliseconds. 8 <_summary>Drag threshold <_description>Distance before a drag is started. true <_summary>Middle button emulation <_description>Enables middle mouse button emulation through simultaneous left and right button click. true <_summary>Whether the tablet's orientation is locked, or rotated automatically. '' <_summary>Device hotplug custom command <_description>Command to be run when a device is added or removed. cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.peripherals.wacom.gschema.xml.in.in000066400000000000000000000123661356401377300336260ustar00rootroot00000000000000 true <_summary>Wacom stylus absolute mode <_description>Enable this to set the tablet to absolute mode. [-1, -1, -1, -1] <_summary>Wacom tablet area <_description>Set this to x1, y1 and x2, y2 of the area usable by the tools. false <_summary>Wacom tablet aspect ratio <_description>Enable this to restrict the Wacom tablet area to match the aspect ratio of the output. true <_summary>Wacom tablet automatic rotation <_description>Enable this to automatically rotate the Wacom tablet area to match the rotation of the output. 'none' <_summary>Wacom tablet rotation <_description>Set this to 'none', 'cw' for 90 degree clockwise, 'half' for 180 degree, and 'ccw' for 90 degree counterclockwise. true <_summary>Wacom touch feature <_description>Enable this to move the cursor when the user touches the tablet. false <_summary>Wacom tablet PC feature <_description>Enable this to only report stylus events when the tip is pressed. ["", "", ""] <_summary>Wacom display mapping <_description>EDID information of monitor to map tablet to. Must be in the format [vendor, product, serial]. ["","",""] disables mapping. [0, 0, 100, 100] <_summary>Wacom stylus pressure curve <_description>Set this to x1, y1 and x2, y2 of the pressure curve applied to the stylus. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] <_summary>Wacom stylus button mapping <_description>Set this to the logical button mapping. -1 <_summary>Wacom stylus pressure threshold <_description>Set this to the pressure value at which a stylus click event is generated. [0, 0, 100, 100] <_summary>Wacom eraser pressure curve <_description>Set this to x1, y1 and x2, y2 of the pressure curve applied to the eraser. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] <_summary>Wacom eraser button mapping <_description>Set this to the logical button mapping. -1 <_summary>Wacom eraser pressure threshold <_description>Set this to the pressure value at which an eraser click event is generated. 'none' <_summary>Wacom button action type <_description>The type of action triggered by the button being pressed. '' <_summary>Key combination for the custom action <_description>The keyboard shortcut generated when the button is pressed for custom actions. ['', ''] <_summary>Key combinations for a touchring or touchstrip custom action <_description>The keyboard shortcuts generated when a touchring or touchstrip is used for custom actions (up followed by down). cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.plugins.color.gschema.xml.in.in000066400000000000000000000013611356401377300327720ustar00rootroot00000000000000 0 <_summary>The duration a display profile is valid <_description>This is the number of days after which the display color profile is considered invalid. 0 <_summary>The duration a printer profile is valid <_description>This is the number of days after which the printer color profile is considered invalid. cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.plugins.gschema.xml.in.in000066400000000000000000000012431356401377300316540ustar00rootroot00000000000000 org.cinnamon.settings-daemon.plugins.housekeeping.gschema.xml.in.in000066400000000000000000000031371356401377300342660ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/data [] <_summary>Mount paths to ignore <_description>Specify a list of mount paths to ignore when they run low on space. 0.05 <_summary>Free percentage notify threshold <_description>Percentage free space threshold for initial warning of low disk space. If the percentage free space drops below this, a warning will be shown. 0.01 <_summary>Subsequent free space percentage notify threshold <_description>Specify the percentage that the free disk space should reduce by before issuing a subsequent warning. 1 <_summary>Free space notify threshold <_description>Specify an amount in GB. If the amount of free space is more than this, no warning will be shown. 10 <_summary>Minimum notify period for repeated warnings <_description>Specify a time in minutes. Subsequent warnings for a volume will not appear more often than this period. org.cinnamon.settings-daemon.plugins.media-keys.gschema.xml.in.in000066400000000000000000000135051356401377300336300ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/data '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys '' <_summary>deprecated - moved to org.cinnamon.desktop.keybindings.media-keys cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.plugins.power.gschema.xml.in.in000066400000000000000000000224641356401377300330170ustar00rootroot00000000000000 30 The brightness of the screen when idle This is the laptop panel screen brightness used when the session is idle. false Dim the screen after a period of inactivity when on AC power If the screen should be dimmed to save power when the computer is idle when on AC power. true Dim the screen after a period of inactivity when on battery power If the screen should be dimmed to save power when the computer is idle when on battery power. 90 The default amount of time to dim the screen after idle The default amount of time to dim the screen after idle. 1800 Sleep timeout display when on AC The amount of time in seconds before the display turns off when the computer is on AC power. 1800 Sleep timeout display when on battery The amount of time in seconds before the display turns off when the computer is on battery power. 0 Sleep timeout computer when on AC The amount of time in seconds the computer on AC power needs to be inactive before it goes to sleep. A value of 0 means never. 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 0 Sleep timeout computer when on battery The amount of time in seconds the computer on battery power needs to be inactive before it goes to sleep. A value of 0 means never. 'suspend' Whether to hibernate, suspend or do nothing when inactive The type of sleeping that should be performed when the computer is inactive. 'suspend' Suspend button action The action to take when the system suspend button is pressed. 'hibernate' Hibernate button action The action to take when the system hibernate button is pressed. 'suspend' Power button action The action to take when the system power button is pressed. 'suspend' Laptop lid close action on battery The action to take when the laptop lid is closed and the laptop is on battery power. 'suspend' Laptop lid close action when on AC The action to take when the laptop lid is closed and the laptop is on AC power. false Laptop lid, when closed, will suspend even if there is an external monitor plugged in With no external monitors plugged in, closing a laptop's lid will suspend the machine (as set by the lid-close-battery-action and lid-close-ac-action keys). By default, however, closing the lid when an external monitor is present will not suspend the machine, so that one can keep working on that monitor (e.g. for docking stations or media viewers). Set this key to False to keep the default behavior, or to True to suspend the laptop whenever the lid is closed and regardless of external monitors. 'hibernate' Battery critical low action The action to take when the battery is critically low. 10 <_summary>Percentage considered low <_description>The percentage of the battery when it is considered low. Only valid when use-time-for-policy is false. 3 <_summary>Percentage considered critical <_description>The percentage of the battery when it is considered critical. Only valid when use-time-for-policy is false. 2 <_summary>Percentage action is taken <_description>The percentage of the battery when the critical action is performed. Only valid when use-time-for-policy is false. 1200 <_summary>The time remaining when low <_description>The time remaining in seconds of the battery when it is considered low. Only valid when use-time-for-policy is true. 300 <_summary>The time remaining when critical <_description>The time remaining in seconds of the battery when it is considered critical. Only valid when use-time-for-policy is true. 120 <_summary>The time remaining when action is taken <_description>The time remaining in seconds of the battery when critical action is taken. Only valid when use-time-for-policy is true. true <_summary>Whether to use time-based notifications <_description>If time based notifications should be used. If set to false, then the percentage change is used instead, which may fix a broken ACPI BIOS. false <_summary>If the computer should lock when entering suspend mode <_description>If the computer should lock during suspend - replaces ubuntu-lock-on-suspend false <_summary>Use the backlight helper application by default <_description>Setting this to true forces cinnamon-settings-daemon to use the backlight helper application to provide backlight control. This will usually fix backlight control problems on laptops where X11 picks the wrong interface, or uses an interface incorrectly. Adjust backlight-preference-order if the default selection logic still chooses the wrong interface. ['firmware','platform','raw'] <_summary>Search order for backlight control interfaces <_description>Controls the type of interfaces the backlight-helper will search for to control the backlight. This can be useful for working around systems with broken default backlight control behavior which provide multiple interfaces. If you are having problems, try setting 'raw' to a higher priority. true <_summary>Whether or not cinnamon-settings-daemon inhibits logind's handling of lid switch <_description>This setting should be true in all distributions and for all users. Only set it to false, if you want to prevent Cinnamon from handling lid switch events. In this case, you should not rely on Cinnamon's lid actions and use the logind ones instead. cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.plugins.xrandr.gschema.xml.in.in000066400000000000000000000025171356401377300331560ustar00rootroot00000000000000 '/etc/cinnamon-settings-daemon/xrandr/monitors.xml' <_summary>File for default configuration for RandR <_description>The XRandR plugin will look for a default configuration in the file specified by this key. This is similar to the ~/.config/monitors.xml that normally gets stored in users' home directories. If a user does not have such a file, or has one that does not match the user's setup of monitors, then the file specified by this key will be used instead. 'follow-lid' <_summary>Whether to turn off specific monitors after boot <_description>clone' will display the same thing on all monitors, 'dock' will switch off the internal monitor, 'do-nothing' will use the default Xorg behaviour (extend the desktop in recent versions). The default, 'follow-lid', will choose between 'do-nothing' and 'dock' depending on whether the lid is (respectively) open or closed. cinnamon-settings-daemon-4.4.0/data/org.cinnamon.settings-daemon.plugins.xsettings.gschema.xml.in.in000066400000000000000000000074201356401377300337060ustar00rootroot00000000000000 'rgba' <_summary>Antialiasing <_description>The type of antialiasing to use when rendering fonts. Possible values are: "none" for no antialiasing, "grayscale" for standard grayscale antialiasing, and "rgba" for subpixel antialiasing (LCD screens only). 'slight' <_summary>Hinting <_description>The type of hinting to use when rendering fonts. Possible values are: "none" for no hinting, "slight" for basic, "medium" for moderate, and "full" for maximum hinting (may cause distortion of letter forms). 'rgb' <_summary>RGBA order <_description>The order of subpixel elements on an LCD screen; only used when antialiasing is set to "rgba". Possible values are: "rgb" for red on left (most common), "bgr" for blue on left, "vrgb" for red on top, "vbgr" for red on bottom. [] <_summary>List of explicitly disabled GTK+ modules <_description>A list of strings representing the GTK+ modules that will not be loaded, even if enabled by default in their configuration. [] <_summary>List of explicitly enabled GTK+ modules <_description>A list of strings representing the GTK+ modules that will be loaded, usually in addition to conditional and forcibly disabled ones. {} A dictionary of XSETTINGS to override This dictionary maps XSETTINGS names to overrides values. The values must be either strings, signed int32s or (in the case of colors), 4-tuples of uint16 (red, green, blue, alpha; 65535 is fully opaque). false <_summary>Menus Have Icons <_description> Whether menus may display an icon next to a menu entry. false <_summary>Buttons Have Icons <_description> Whether buttons may display an icon in addition to the button text. true <_summary>Show the 'Input Methods' menu <_description> Whether the context menus of entries and text views should offer to change the input method. true <_summary>Show the 'Unicode Control Character' menu <_description> Whether the context menus of entries and text views should offer to insert control characters. true <_summary>Only show mnemonics on when the Alt key is pressed <_description> Whether mnemonics should be automatically shown and hidden when the user presses the Alt key. cinnamon-settings-daemon-4.4.0/data/org.freedesktop.IBus.service.in000066400000000000000000000001441356401377300252720ustar00rootroot00000000000000[D-BUS Service] Name=org.freedesktop.IBus Exec=@bindir@/ibus-daemon --replace --xim --panel disable cinnamon-settings-daemon-4.4.0/debian/000077500000000000000000000000001356401377300176535ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/debian/changelog000066400000000000000000000615311356401377300215330ustar00rootroot00000000000000cinnamon-settings-daemon (4.4.0) tricia; urgency=medium [ Michael Webster ] * automount: Add autorun dialog tester. (#263) * mouse manager: Expose libinput option to disable the touchpad when an external mouse is attached. * mouse manager: Simplify previous commit - get/set properties here already check for support, there's no need to pre-check. * mouse manager: set the 'disable touchpad with mouse' on devices at startup. * csd-input-helper.c: Use correct error_trap_pop function. * power helper - Try to use logind, then fallback to using consolekit, instead of using a gsettings key to decide. -- Clement Lefebvre Sat, 16 Nov 2019 16:37:55 +0100 cinnamon-settings-daemon (4.2.2) tina; urgency=medium [ Corbin Auriti ] * Fix Shutdown immediately not working - the easy way (#260) -- Clement Lefebvre Thu, 25 Jul 2019 10:22:37 +0200 cinnamon-settings-daemon (4.2.1) tina; urgency=medium [ Michael Webster ] * csd-power-manager.c: Define UP_DEVICE_LEVEL_NONE for ourselves if it's missing. UpDeviceLevel was new in 0.99.0. * csd-power-manager.c: Use gint instead of an enum type for compatibility with < 0.99.0 upower. -- Clement Lefebvre Wed, 10 Jul 2019 11:53:38 +0200 cinnamon-settings-daemon (4.2.0) tina; urgency=medium [ montagdude ] * Implement suspend/hibernate with ConsoleKit (#252) [ Clement Lefebvre ] * Power: Clean up unused code [ Mirko Girgenti ] * https://github.com/linuxmint/cinnamon-settings-daemon/issues/192 (#246) [ Clement Lefebvre ] * Disable natural-scroll by default for mice [ Michael Webster ] * csd-mouse-manager.c: Fix issues from bfa99478e0d996fe (Natural mouse scrolling). * misc: Use gdk_x11_display_error_trap_* instead of deprecated gdk_error_trap_*. * configure.ac: disable deprecation warnings entirely. * csd-power-manager.c: Check for a device battery-level property before attempting to access it. [ William Poetra Yoga ] * Prevent Segmentation Fault (#255) -- Clement Lefebvre Sun, 23 Jun 2019 15:37:44 +0200 cinnamon-settings-daemon (4.0.3) tessa; urgency=medium * Xrandr: Rotate touchscreens when applying a new configuration * Wacom: Disable automatic rotation by default and make it configurable * Wacom: Re-enable automatic rotation by default -- Clement Lefebvre Thu, 06 Dec 2018 13:21:34 +0000 cinnamon-settings-daemon (4.0.2) tessa; urgency=medium [ Clement Lefebvre ] * Set the GTK print preview to xreader * Revert "Set the GTK print preview to xreader" [ Alexander Drozdov ] * Handle AC remove while LID is closed (#244) -- Clement Lefebvre Mon, 19 Nov 2018 09:50:28 +0000 cinnamon-settings-daemon (4.0.1) tessa; urgency=medium [ Michael Webster ] * power/gpm-common.c: Don't fake a UPower enum in lesser upower versions, instead make an "unknown" device ok to display without a warning. Provide more support for gaming controllers as well when providing device state strings. [ Clement Lefebvre ] * l10n: Update POT -- Clement Lefebvre Mon, 12 Nov 2018 15:16:13 +0000 cinnamon-settings-daemon (4.0.0) tessa; urgency=medium [ Michael Webster ] * csd-power-helper: Implement optional hybrid-sleep for power and media-key plugins. * csd-power-manager.c: Lock the screensaver if demanded by settings prior to turning off the monitor and initiating suspend. * csd-power-manager.c: Fix conversion of absolute keyboard brightness back to percent, and fix signal handling of the keyboard backlight proxy. [ Jeremy Bicha ] * housekeeping: fix improper notify_notification_close() usage (#234) [ Michael Webster ] * csd-power-manager.c: Provide the BatteryLevel property over our Power interface (for showing course level when a device doesn't support percentages.) * power: Use generated interfaces for power, keyboard and screen services. This simplifies the code a bit, and more importantly, allows the proxies used in cinnamon to work properly with g-signal, etc.. for updates. * csd-power-manager.c: signal updates after each proxy initializes. * csd-power-manager: Add a GetStep method for the keyboard interface. This will allow our setting module and applet to better represent valid increments for the backlight level. [ Jason Hicks ] * Prevent log flooding when game controllers are detected [ Michael Webster ] * csd-power-manager.c: During lid action, only lock the screen if 'blank' is the selected action. If 'do nothing' is selected, then actually do nothing. [ cranes-bill ] * This will make NTP works on any Red Hat based system. (#238) [ Jackson Dearnley ] * csd-media-keys-manager.c: Execute default calculator application defined by schema (#240) [ Clement Lefebvre ] * l10n: Update POT * CI: Remove Mint 18 -- Clement Lefebvre Tue, 30 Oct 2018 14:51:25 +0000 cinnamon-settings-daemon (3.8.4) tara; urgency=medium * Power: Reconfigure idle timers when upower state changes -- Clement Lefebvre Fri, 22 Jun 2018 20:57:51 +0200 cinnamon-settings-daemon (3.8.3) tara; urgency=medium [ Michael Webster ] * csd-xsettings-manager.c: Handle any window button layout when adding the 'menu' item to CSD window controls, not just our default layout. -- Clement Lefebvre Fri, 08 Jun 2018 11:49:11 +0100 cinnamon-settings-daemon (3.8.2) tara; urgency=medium * CSD: Add menu to CSD windows when the layout is :minimize,maximize,close -- Clement Lefebvre Wed, 16 May 2018 18:40:48 +0100 cinnamon-settings-daemon (3.8.1) tara; urgency=medium [ Eli Schwartz ] * Remove vestigial manpage (#229) [ Marcin Mielniczuk ] * Fix the inhibit_lid_switch_enabled option being uninitialized while calling inhibit_lid_switch. (#231) -- Clement Lefebvre Sun, 06 May 2018 15:17:10 +0100 cinnamon-settings-daemon (3.8.0) tara; urgency=medium [ brownsr ] * housekeeping: replace gtk_stock items https://github.com/GNOME/gnome-settings-daemon/commit/92fc1c2f605561126e37dc9a69459d5ac66c1e90#diff-35dd745f84c1c68f9626401cda5ee45d * housekeeping: Fix deprecated GUnixMountMonitor calls https://github.com/GNOME/gnome-settings-daemon/commit/a7b82826bd716e50fae6668561117dfedc8873ec#diff-35dd745f84c1c68f9626401cda5ee45d * housekeeping: remove duplicated call https://github.com/GNOME/gnome-settings-daemon/commit/5ad0ff07b016cd920dbb84fbe6b2858aede725f7#diff-35dd745f84c1c68f9626401cda5ee45d [ Clement Lefebvre ] * README: Start describing plugins * Add more info to readme [ Simon Brown ] * sound: Remove empty constructor function (#200) * sound: Don't include unused GTK+ (#199) * Clipboard: various minor upstream fixes / cleanups (#198) [ Clement Lefebvre ] * Add more info to README [ Simon Brown ] * common: add break and scroll lock to whitelist (#201) [ Clement Lefebvre ] * Add more info to README * Add more info to README * Add more info to README [ Simon Brown ] * Housekeeping: various upstream fixes and cleanups (#202) [ Clement Lefebvre ] * Add CI configuration * Fix button layout for CSD windows * Fix titlebar click actions for CSD windows * README: Add info about xsettings * media-keys: Play volume_changed sound and display sound OSD according to the max sound volume. (#215) * Provide symlinks in /usr/bin to start the various CSD plugins. [ Michael Webster ] * csd-background-manager.c: Remove build conditional for AccountsService background support. GnomeBG will now determine during runtime whether to handle it or not. * csd-background-manager.c: Set the AccountsService user background at startup. [ brownsr ] * mouse: re-enable touchpad when no other pointing devices present https://github.com/GNOME/gnome-settings-daemon/commit/72b8df16a626cd6b638f3953b69f28e08bc39e59#diff-3144fcd94741d0a8ad93771b1f108efdR1138 * mouse: Stop idle start when stop() is called https://github.com/GNOME/gnome-settings-daemon/commit/9d6e80924ff9011dc2d8caa8a49a588ff4a318bd#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: simplify finalize call https://github.com/GNOME/gnome-settings-daemon/commit/7c268ddf2c0fea89ed053e55002fba65c523904a#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: simplify stop call https://github.com/GNOME/gnome-settings-daemon/commit/9e4e46a47fd385807f9cbae9d42ebcc312680a1e#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: replace dialogue by warning https://github.com/GNOME/gnome-settings-daemon/commit/3e337371249dace2613d4698d91f587621188c19#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: remove empty contructor and dispose functions https://github.com/GNOME/gnome-settings-daemon/commit/98df44761b4f0c70078df635aaa68adff6454380#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: wrap device button mapping into gdk_error_trap_push/pop https://github.com/GNOME/gnome-settings-daemon/commit/7a07cd12b862fa40ab5c38fee3dc264bb483a494#diff-f3eb78dbfdd1699b6580551f271aba41 * mouse: wrap pointer acceleration changes into a gdk_error_trap https://github.com/GNOME/gnome-settings-daemon/commit/8b78228a7e0abfc2c1561a275214da5d77cc7a93#diff-f3eb78dbfdd1699b6580551f271aba41 * locate-pointer: Remove support for multiple X screens https://github.com/GNOME/gnome-settings-daemon/commit/cf677a9c47d868b0bdae026b9d0db36df75f9dac#diff-f3eb78dbfdd1699b6580551f271aba41 gdk_display_get_n_screens is now hardcoded just to return 1, so take out the loop using it * locate-pointer: Replace deprecated gdk_window_get_pointer https://github.com/GNOME/gnome-settings-daemon/commit/41a023e58df6864e947849e558a4edb0c4057e20#diff-f3eb78dbfdd1699b6580551f271aba41 [ Michael Webster ] * Remove .pc folder (quilt-related) * csd-power: Lock the screensaver synchronously prior to suspending. [ Maximiliano Curia ] * Update gnome-power-manager's stats desktop name (#225) [ Fabio Fantoni ] * debian: wrap-and-sort -bst * update debian/copyright * Bump debhelper build-dep and compat to 10 and other small improvements [ Marcin Mielniczuk ] * Add an option to prevent handle-lid-switch from being inhibited. Closes (#219) [ Clement Lefebvre ] * Rename inhibit-lid-switch setting * Fix getting gsettings key from the wrong schema * l10n: Update POT file -- Clement Lefebvre Tue, 17 Apr 2018 13:13:39 +0100 cinnamon-settings-daemon (3.6.2) sylvia; urgency=medium [ JosephMcc ] * settings: Disable automatic screen orientation by default -- Clement Lefebvre Thu, 30 Nov 2017 13:50:44 +0000 cinnamon-settings-daemon (3.6.1) sylvia; urgency=medium * Power: Change default for sleep-display-ac/battery to 30 minutes -- Clement Lefebvre Thu, 09 Nov 2017 12:32:23 +0000 cinnamon-settings-daemon (3.6.0) sylvia; urgency=medium [ Albert Pool ] * Make touchpad settings compatible with libinput (#181) [ JosephMcc ] * Clean up the autorun dialog a bit (#194) [ Clement Lefebvre ] * Xrandr: Hold the session start while the plugin is loaded. [ Simon Brown ] * csd-xsettings-gtk: Avoid a potential GFile leak (#195) [ Clement Lefebvre ] * l10n: Update POT file -- Clement Lefebvre Mon, 23 Oct 2017 13:59:35 +0100 cinnamon-settings-daemon (3.5.0) sylvia; urgency=medium * Bump version number (unstable) -- Clement Lefebvre Thu, 07 Sep 2017 11:15:10 +0100 cinnamon-settings-daemon (3.4.2) sonya; urgency=medium [ Michael Webster ] * csd-color-manager.c: Make a device connect warning a debug message instead to reduce .xsession-errors clutter. * daemon-skeleton: Add a few upstream fixes for startup issues. -- Clement Lefebvre Tue, 20 Jun 2017 15:49:57 +0200 cinnamon-settings-daemon (3.4.1) sonya; urgency=medium [ Clement Lefebvre ] * Fix incorrect DBUS names [ JosephMcc ] * media-keys: Don't show the level in the screen lock OSD (#174) [ Clement Lefebvre ] * Make CSM wait for xsettings to be fully started before starting the WindowManager phase. -- Clement Lefebvre Tue, 23 May 2017 15:32:55 +0100 cinnamon-settings-daemon (3.4.0) sonya; urgency=medium [ monsta ] * mouse: add missing device closing [ leigh123linux ] * Increase cinnamon-desktop required version * power: Fix typo in UPower keyboard GDBus proxy name * Remove redundant aclocal as autoreconf calls it * fix Wmissing-include-dirs warning [ Elias Ojala ] * Fix typo in Finnish translation [ Clement Lefebvre ] * clipboard: Add test application * color: Add test application * common: Remove obsolete key parsing test program * color: Fix csd-test-color linkage * dummy: Add test application * main: Remove ability to start/stop individual plugins * plugins: Remove "test" from the stand-alone program names * common: Add verbose option to test-plugin.h * plugins: Rename sources of all test applications [ JosephMcc ] * mouse-plugin: Add new settings for mouse/touchpad [ Clement Lefebvre ] * sound: Rename the sound plugin for PulseAudio * plugins: Add desktop files for all the plugins * plugins: Stop building helpers as plugins * Remove refs to obsolete schemas * common: Remove use of SCHEMA_NAME * common: Report errors on startup in the helper skeleton * Fixed a couple of issues in previous commits * Use unique dbus names * common: Register plugins with the session manager * main: Remove gnome-settings-daemon binary * data: Adapt pkg-config file for API removal * build: Remove separate check for cinnamon-desktop * main: Remove cinnamon-settings-plugin.h * Add CSD plugin icons [ leigh123linux ] * Remove calls to g_type_init(), bump GLib required version * Fix redundant redeclarations * add makefile * add m4 to aclocal flags * fix fsf address [ Clement Lefebvre ] * Fix backgrounds in HiDPI * Don't kill plugins during CSM stop PHASE [ Leigh Scott ] * remove deprecated g_thread_init [ leigh123linux ] * Add detection for accountsservice background as it's ubuntu only [ brownsr ] * cinnamon-settings-session: remove an ISO C warning * csd-input-helper: remove compiler warnings [ Simon Brown ] * daemon-skeleton: remove ISO C compiler warnings (#170) * csd-color-manager: avoid compiler warnings (#172) * csd-locate-pointer: change a shadowed variable causing compiler warnings (#173) * csd-clipboard-manager: remove compiler warnings (#171) -- Clement Lefebvre Thu, 04 May 2017 13:35:21 +0100 cinnamon-settings-daemon (3.2.1) serena; urgency=medium [ leigh123linux ] * media-keys: Add Rotation lock support -- Clement Lefebvre Sat, 10 Dec 2016 11:57:53 +0000 cinnamon-settings-daemon (3.2.0) serena; urgency=medium [ brownsr ] * avoid compiler warning message about spurious comma * remove deprecated gdk_display_get_n_screens this is now hardcoded to return 1, so loops using this can be removed * remove deprecated function gdk_display_get_n_screens this only returns 1 now, so loops can be removed. * add precautionary test on default display being there * add precautionary test on existence of default display [ Jakub Adam ] * orientation: Use g_clear_* helpers * orientation: Remove empty constructor and dispose functions * orientation: Call stop from finalize * orientation: Port to iio-sensor-proxy * orientation: Use symbolic name for the GSettings key name * orientation: Fix screen lock not getting applied * Fix double free in is_wacom_tablet_device() [ leigh123linux ] * xsettings: Fix cursor-size changes being ignored * fix spelling mistakes [ brownsr ] * remove deprecated g_settings_list_schemas * replace deprecated gtk_icon_info_free with g_object_unref [ Peter Hutterer ] * common: don't create the Synaptics Off property if it doesn't exist * common: recognize libinput touchpads as touchpads * mouse: fix indentation * mouse: add helper function for fetching a property * mouse: rename helper to touchpad_set_bool * mouse: split into separate bool helpers * mouse: libinput - hook up tapping configuration * mouse: libinput - hook up natural scroll configuration * mouse: libinput - hook up scrolling settings * mouse: libinput - hook up click methods * mouse: libinput - hook up left-handed setting * mouse: libinput - hook up accel speed * mouse: libinput - hook up middle button emulation * mouse: libinput - hook up disable while typing [ Maximiliano Curia ] * Migrate away from gnome-common deprecated vars and macros * Build depend on autoconf-archive [ Clement Lefebvre ] * Xrandr plugin: Do not save configuration when RotateTo is called. [ Michael Webster ] * orientation plugin: Fix makefile, missing backslash - from previous build migration commit. [ brownsr ] * remove a couple of unused variables [ monsta ] * mouse: Fix critical warnings with touchpad settings -- Clement Lefebvre Mon, 07 Nov 2016 10:44:50 +0000 cinnamon-settings-daemon (3.0.1) sarah; urgency=medium * Touchpad: By default, disable the touchpad while typing -- Clement Lefebvre Tue, 10 May 2016 16:30:09 +0100 cinnamon-settings-daemon (3.0.0) sarah; urgency=medium [ Stephen Collins ] * Add dbus method to play sound event on specified channel [ Justin King-Lacroix ] * Corrected the icon shown in the OSD when the mic-mute button is used. [ Clement Lefebvre ] * Power plugin: Fixed CSD not notifying Cinnamon on device removal -- Clement Lefebvre Sat, 23 Apr 2016 16:17:45 +0100 cinnamon-settings-daemon (2.8.4) rosa; urgency=medium [ Michael Webster ] * power manager: prevent sleep properly when the session has a sleep (not idle) inhibitor active -- Clement Lefebvre Mon, 07 Mar 2016 17:10:45 +0000 cinnamon-settings-daemon (2.8.3) rosa; urgency=medium * Re-added code removed by mistake. -- Clement Lefebvre Thu, 26 Nov 2015 20:29:18 +0000 cinnamon-settings-daemon (2.8.2) rosa; urgency=medium [ Cindy Quach ] * Change the minimum height required to trigger HiDPI scaling. -- Clement Lefebvre Fri, 20 Nov 2015 17:17:13 +0000 cinnamon-settings-daemon (2.8.1) rosa; urgency=medium [ JosephMcc ] * clean up some unused functions and variables [ leigh123linux ] * csd-datetime forgets to authorize users -- Clement Lefebvre Mon, 09 Nov 2015 10:45:19 +0000 cinnamon-settings-daemon (2.8.0) rosa; urgency=medium [ leigh123linux ] * Change summary for motion-acceleration as it has nothing to do with single click * Stop using deprecated GSettings:schema property * print-notifications: Don't show error for job in progress * print-notifications: Close HTTP connections [ Mike Gerow ] * Pressing the mic-mute button now toggles the microphone's mute status [ Clement Lefebvre ] * Power plugin: Added vendor and model info to GetPrimaryDevice() and GetDevices() * [halfline] Xrandr plugin: don't ever show a dialog for xrandr failures * Xrandr: Catch-up with GSD 3.16 - set a title to the confirmation dialog https://bugzilla.gnome.org/show_bug.cgi?id=706128 * Xrandr: Catch-up with GSD 3.16 - Simplify layout of adjacent screens * Xrandr: Catch-up with GSD 3.16 - Add object path to the interface definition XML * Xrandr: Catch-up with GSD 3.16 - Avoid the GnomePnpIds object being created multiple times * Xrandr: Catch-up with GSD 3.16 - Add more debug to the rotate windows call * Xrandr: Catch-up with GSD 3.16 - Swap axes for tablets as well * Xrandr: Catch-up with GSD 3.16 - use default-monitors-setup for autoconfigure * Xrandr: Catch-up with GSD 3.16 - Add reasoning for GnomePnpIds instantiation * Catch-up with GSD 3.16 - Provide a helper function to close an XDevice safely * HiDPI: Don't scale when the physical size isn't properly encoded * Fix crash when a plugin failed to start * modernize code for handling SIGTERM * Unown our DBus name when cinnamon-session says "Stop" * Remove unused code * po: Fixed some refs to GNOME [ Fabio Fantoni ] * remove unused debian patches * update debian/copyright * remove unused maintscript * remove manpage from debian, the source one will be used instead * debian packaging improvements and fixes * update man with the one that was in debian folder -- Clement Lefebvre Fri, 16 Oct 2015 14:14:18 +0100 cinnamon-settings-daemon (2.6.3) rafaela; urgency=medium [ Clement Lefebvre ] * Revert "mouse: Enable two-finger scrolling by default" -- Clement Lefebvre Wed, 24 Jun 2015 19:26:31 +0200 cinnamon-settings-daemon (2.6.2) rafaela; urgency=medium [ leigh123linux ] * bump version to account for cinnamon-desktop systemd schema change * remove gsettings-desktop-schemas require as the c-s-d code doesn't need it * clean up -- Clement Lefebvre Wed, 27 May 2015 10:23:01 +0200 cinnamon-settings-daemon (2.6.1) rafaela; urgency=medium [ Clement Lefebvre ] * Replaced "use-systemd" with "settings-daemon-uses-logind" gsettings key [ leigh123linux ] * Fix broken KB shortcuts for suspend, hibernate and shutdown -- Clement Lefebvre Mon, 25 May 2015 10:37:48 +0200 cinnamon-settings-daemon (2.6.0) rafaela; urgency=medium * 2.6.0 -- Clement Lefebvre Tue, 19 May 2015 17:12:13 +0200 cinnamon-settings-daemon (2.5.0) unstable; urgency=medium * bump for development -- Michael Webster Sat, 11 Apr 2015 08:59:23 -0400 cinnamon-settings-daemon (2.4.3) rebecca; urgency=medium * Fixed power button asking what to do even when set to just do it -- Clement Lefebvre Mon, 10 Nov 2014 11:02:21 +0100 cinnamon-settings-daemon (2.4.2) rebecca; urgency=medium * Re-added media-keys keybindings schema to allow cinnamon-desktop migrate script to work -- Clement Lefebvre Sat, 08 Nov 2014 10:06:29 +0100 cinnamon-settings-daemon (2.4.1) rebecca; urgency=medium * Enable middle-click mouse emulation by default and support for single-button touchpads -- Clement Lefebvre Fri, 31 Oct 2014 16:04:10 +0100 cinnamon-settings-daemon (2.4.0) rebecca; urgency=medium * 2.4.0 -- Clement Lefebvre Thu, 30 Oct 2014 16:06:31 +0100 cinnamon-settings-daemon (2.3.0) unstable; urgency=medium * 2.3.0 -- Clement Lefebvre Fri, 27 Jun 2014 14:23:04 +0100 cinnamon-settings-daemon (2.2.4) qiana; urgency=medium * Replace Ctrl with Control so keybindings can parse it properly * Added missing wacom build dep for wacom module to be properly built -- Clement Lefebvre Sun, 08 Jun 2014 13:00:36 +0100 cinnamon-settings-daemon (2.2.3) qiana; urgency=medium * 2.2.3 -- Clement Lefebvre Mon, 12 May 2014 21:40:22 +0100 cinnamon-settings-daemon (2.2.2) qiana; urgency=medium * 2.2.2 -- Clement Lefebvre Thu, 01 May 2014 14:46:25 +0100 cinnamon-settings-daemon (2.2.1) qiana; urgency=medium * 2.2.1 -- Clement Lefebvre Mon, 14 Apr 2014 14:15:12 +0100 cinnamon-settings-daemon (2.2.0) qiana; urgency=medium * 2.2.0 -- Clement Lefebvre Sat, 12 Apr 2014 11:44:20 +0100 cinnamon-settings-daemon (2.0.8) petra; urgency=low * 2.0.8 -- Clement Lefebvre Mon, 25 Nov 2013 18:39:05 +0000 cinnamon-settings-daemon (2.0.7) petra; urgency=low * 2.0.7 -- Clement Lefebvre Thu, 07 Nov 2013 10:28:55 +0000 cinnamon-settings-daemon (2.0.6) petra; urgency=low * 2.0.6 -- Clement Lefebvre Sun, 03 Nov 2013 15:49:44 +0000 cinnamon-settings-daemon (2.0.5) petra; urgency=low * 2.0.5 -- Clement Lefebvre Fri, 25 Oct 2013 15:26:23 +0100 cinnamon-settings-daemon (2.0.4) petra; urgency=low * 2.0.4 -- Clement Lefebvre Thu, 24 Oct 2013 11:07:58 +0100 cinnamon-settings-daemon (2.0.3) petra; urgency=low * 2.0.3 -- Clement Lefebvre Fri, 18 Oct 2013 17:40:20 +0100 cinnamon-settings-daemon (2.0.2) petra; urgency=low * 2.0.2 -- Clement Lefebvre Fri, 18 Oct 2013 16:02:02 +0100 cinnamon-settings-daemon (2.0.1) petra; urgency=low * 2.0.1 -- Clement Lefebvre Wed, 02 Oct 2013 15:13:43 +0100 cinnamon-settings-daemon (2.0.0) petra; urgency=low * 2.0.0 -- Clement Lefebvre Wed, 02 Oct 2013 13:51:06 +0100 cinnamon-settings-daemon (1.9.1) petra; urgency=low * 1.9.1 -- Clement Lefebvre Mon, 30 Sep 2013 13:55:00 +0100 cinnamon-settings-daemon (1.0.0) olivia; urgency=low * Initial functionality with Cinnamon -- Michael Webster Fri, 24 May 2013 22:31:00 -0400 cinnamon-settings-daemon (0.0.1) olivia; urgency=low * Initial port from cinnamon-settings-daemon raring 3.6.4-0ubuntu8 -- Michael Webster Fri, 24 May 2013 17:41:00 -0400 cinnamon-settings-daemon-4.4.0/debian/cinnamon-settings-daemon-dev.install000066400000000000000000000001261356401377300267170ustar00rootroot00000000000000usr/include/cinnamon-settings-daemon* usr/lib/*/pkgconfig/cinnamon-settings-daemon.pc cinnamon-settings-daemon-4.4.0/debian/cinnamon-settings-daemon.install000066400000000000000000000007321356401377300261460ustar00rootroot00000000000000debian/source_cinnamon-settings-daemon.py /usr/share/apport/package-hooks etc/dbus-1/system.d/org.cinnamon.SettingsDaemon.DateTimeMechanism.conf etc/xdg/autostart/* usr/lib/*/cinnamon-settings-daemon*/*.so usr/lib/*/cinnamon-settings-daemon/ usr/share/applications/* usr/share/cinnamon-settings-daemon usr/share/dbus-1/*/org.cinnamon.SettingsDaemon.* usr/share/glib-2.0/*/org.cinnamon.settings-daemon.* usr/share/icons/*/*/*/csd* usr/share/polkit-1/*/org.cinnamon.settings* cinnamon-settings-daemon-4.4.0/debian/cinnamon-settings-daemon.links.in000066400000000000000000000051611356401377300262260ustar00rootroot00000000000000usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-a11y-keyboard usr/bin/csd-a11-keyboard usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-a11y-settings usr/bin/csd-a11y-settings usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-automount usr/bin/csd-automount usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-background usr/bin/csd-background usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-backlight-helper usr/bin/csd-backlight-helper usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-clipboard usr/bin/csd-clipboard usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-color usr/bin/csd-color usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-cursor usr/bin/csd-cursor usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-datetime-mechanism usr/bin/csd-datetime-mechanism usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-dummy usr/bin/csd-dummy usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-housekeeping usr/bin/csd-housekeeping usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-input-helper usr/bin/csd-input-helper usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-keyboard usr/bin/csd-keyboard usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-list-wacom usr/bin/csd-list-wacom usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-locate-pointer usr/bin/csd-locate-pointer usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-media-keys usr/bin/csd-media-keys usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-mouse usr/bin/csd-mouse usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-orientation usr/bin/csd-orientation usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-power usr/bin/csd-power usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-printer usr/bin/csd-printer usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-print-notifications usr/bin/csd-print-notifications usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-screensaver-proxy usr/bin/csd-screensaver-proxy usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-smartcard usr/bin/csd-smartcard usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-sound usr/bin/csd-sound usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-wacom usr/bin/csd-wacom usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-wacom-led-helper usr/bin/csd-wacom-led-helper usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-wacom-osd usr/bin/csd-wacom-osd usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-xrandr usr/bin/csd-xrandr usr/lib/@DEB_HOST_MULTIARCH@/cinnamon-settings-daemon/csd-xsettings usr/bin/csd-xsettings cinnamon-settings-daemon-4.4.0/debian/cinnamon-update-wallpaper-cache.c000066400000000000000000000040751356401377300261350ustar00rootroot00000000000000/* * Copyright (C) 2010 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License version 3.0 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by Didier Roche * * Bug: https://bugs.launchpad.net/bugs/530024 */ #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include static GOptionEntry entries[] = { { NULL } }; main (int argc, char *argv[]) { GOptionContext *context = NULL; GError *error = NULL; GdkScreen *screen; GdkRectangle rect; GnomeBG *bg; GSettings *settings; GdkPixbuf *pixbuf; gdk_init (&argc, &argv); context = g_option_context_new ("- refresh wallpaper cache"); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); g_option_context_free(context); g_error_free (error); return (1); } if (context) g_option_context_free (context); /* cache only the first monitor */ screen = gdk_screen_get_default (); gdk_screen_get_monitor_geometry (screen, 0, &rect); bg = gnome_bg_new (); settings = g_settings_new ("org.cinnamon.desktop.background"); gnome_bg_load_from_preferences (bg, settings); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, rect.width, rect.height); gnome_bg_draw (bg, pixbuf, screen, FALSE); g_object_unref (settings); return (0); } cinnamon-settings-daemon-4.4.0/debian/compat000066400000000000000000000000031356401377300210520ustar00rootroot0000000000000010 cinnamon-settings-daemon-4.4.0/debian/control000066400000000000000000000050411356401377300212560ustar00rootroot00000000000000Source: cinnamon-settings-daemon Section: x11 Priority: optional Maintainer: Linux Mint Build-Depends: autoconf-archive, automake, autotools-dev, debhelper (>= 10), docbook-xsl, intltool (>= 0.37.1), libcanberra-gtk3-dev, libcinnamon-desktop-dev (>= 3.4~), libcolord-dev (>= 0.1.27), libcups2-dev, libcvc-dev (>= 3.4~), libdbus-glib-1-dev (>= 0.88), libfontconfig1-dev, libglib2.0-dev (>= 2.37.3), libgnomekbd-dev (>= 3.6.0), libgtk-3-dev (>= 3.9.10), libgudev-1.0-dev [linux-any], liblcms2-dev, libnotify-dev (>= 0.7.0), libnss3-dev, libpolkit-gobject-1-dev, libpulse-dev (>= 0.9.16), librsvg2-dev, libsystemd-dev [linux-any], libupower-glib-dev (>= 0.9.11), libwacom-dev (>= 0.4) [linux-any], libx11-dev, libxext-dev, libxi-dev, libxklavier-dev, libxtst-dev, xserver-xorg-input-wacom [!s390x !hurd-any !kfreebsd-any], xsltproc, Standards-Version: 3.9.8 Homepage: http://cinnamon.linuxmint.com Package: cinnamon-settings-daemon Architecture: any Depends: cinnamon-desktop-data (>= 2.6.3), ${misc:Depends}, ${shlibs:Depends} Recommends: cinnamon-l10n, pulseaudio Suggests: cinnamon-screensaver, gnome-calculator | galculator | mate-calc, gnome-power-manager, gnome-screenshot, muffin | x-window-manager, tracker-gui | gnome-search-tool, x11-xserver-utils, Pre-Depends: ${misc:Pre-Depends} Breaks: banshee (<< 0.13.2+dfsg-7), gnome-color-manager (<< 3.0), gnome-screensaver (<< 2.28.0), gnome-session (<< 2.24), rhythmbox (<< 0.11.5), totem (<< 2.22.0), unity-greeter (<< 0.2.1-0ubuntu1), Description: daemon handling the Cinnamon session settings This package contains the daemon which is responsible for setting the various parameters of a Cinnamon session and the applications that run under it. It handles the following kinds of settings: . * Keyboard: layout, accessibility options, shortcuts, media keys * Clipboard management * Theming: background, icons, GTK+ applications * Cleanup of unused files * Mouse: cursors, speed, accessibility options * Startup of other daemons: screensaver, sound daemon * Typing break . It also sets various application settings through X resources and freedesktop.org XSETTINGS. Package: cinnamon-settings-daemon-dev Architecture: any Depends: libdbus-glib-1-dev (>= 0.74), libglib2.0-dev (>= 2.26.0), ${misc:Depends}, ${shlibs:Depends}, Description: Headers for building applications communicating with cinnamon-settings-daemon This package contains header files required to build applications that communicate with the Cinnamon settings daemon over D-Bus. cinnamon-settings-daemon-4.4.0/debian/copyright000066400000000000000000000235331356401377300216140ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cinnamon-settings-daemon Upstream-Contact: Linux Mint Project Source: https://github.com/linuxmint/cinnamon-settings-daemon.git Files: * Copyright: 2007, Anders Carlsson 2009, Bastien Nocera 2001-2012, Bastien Nocera 2008, Carlos Garnacho 2009, Chris Coulson 2007, David Zeuthen 1989-1991, Free Software Foundation, Inc 2008, Jens Granseuer 2006-2008, Lennart Poettering 2008, Lennart Poettering 2007, Matthias Clasen 2008, Michael J. Chudobiak 2006, Novell, Inc 2002-2005, Paolo Maggi 2006, Ray Strode 2006, Ray Strode 2008, Red Hat, Inc 2005-2011, Richard Hughes 2011, Ritesh Khadgaray 2007, Rodrigo Moya 2008, Sjoerd Simons 2008, Soren Sandmann 2004, Sun Microsystems, Inc 2001, Udaltsoft 2011, Vincent Untz 2008, William Jon McCann 2008, William Jon McCann 2005-2007, William Jon McCann 2001, Ximian, Inc 2007, AUTHOR 2004-2006, Adam Weinberger and the GNOME Foundation 2007, Aleś Navicki 2012, Bastien Nocera 2005, Canonical Ltd 2005, Canonical Ltd, and Rosetta Contributors 2005 Croatiann team 2010, Damyan Ivanov 1998-2009, Free Software Foundation Inc 2005, Free Software Foundation, Andhra Pradesh 1999-2008, Free Software Foundation, Inc 2011, Iranian Free Software Users Group (IFSUG.org) translation team 2009, Joshua Cummings 2006, Lukas Novotny 2007, Matthias Clasen 2008, Michael J. Chudobiak 2003-2006, Miloslav Trmac 2007, Novell 2011, Red Hat Inc 2011, Red Hat, Inc 2011, Richard Hughes 2010-2011, Richard Hughes 2008, Rosetta Contributors and Canonical Ltd 2008 2011, Rosetta Contributors and Canonical Ltd 2011 2012, Rosetta Contributors and Canonical Ltd 2012 2001, Roy-Magne Mo 2003-2005, Sharif FarsiWeb, Inc 2011-2012, Swecha Telugu Localisation Team 2009, The Gnome Foundation 2007-2011, The Gnome Project 2007, William Jon McCann 2001, Ximian, Inc 2004, Zuza Software Foundation 2004, Zuza Software Foundation (Translate.org.za) 1999-2012, cinnamon-settings-daemon 1999-2011, the author(s) of cinnamon-settings-daemon License: GPL-2+ Files: plugins/clipboard/list.c plugins/clipboard/list.h plugins/clipboard/xutils.c plugins/clipboard/xutils.h plugins/mouse/csd-locate-pointer.h plugins/xsettings/xsettings-common.c plugins/xsettings/xsettings-common.h plugins/xsettings/xsettings-manager.c plugins/xsettings/xsettings-manager.h Copyright: 2001, Jonathan Blandford 2001, Red Hat, Inc 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, and that the name of Red Hat not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Red Hat makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. . RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Files: plugins/keyboard/gkbd-configuration.c plugins/keyboard/gkbd-configuration.h plugins/media-keys/bus-watch-namespace.c plugins/media-keys/bus-watch-namespace.h Copyright: 2010-2013, Canonical Ltd 2009, Novell, Inc 2006-2007, William Jon McCann License: LGPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser 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. . On Debian systems, the complete text of the GNU Lesser General Public License version 2 can be found in `/usr/share/common-licenses/LGPL-2'. Files: plugins/media-keys/mpris-controller.c plugins/media-keys/mpris-controller.h Copyright: 2013, Intel Corporation License: LGPL-2.1 This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation. . This program is distributed in the hope 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 Lesser General Public License along with this program; if not, see . On Debian systems, the complete text of the GNU Lesser General Public License version 2.1 can be found in `/usr/share/common-licenses/LGPL-2.1'. Files: COPYING.LIB data/csd-enums.h Copyright: 2010, Bastien Nocera 1991-1999, Free Software Foundation, Inc License: LGPL-2.1+ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the complete text of the GNU Lesser General Public License version 2.1 can be found in `/usr/share/common-licenses/LGPL-2.1'. Files: po/Makefile.in.in Copyright: 2004-2008, Rodney Dawes 1995-1997, Ulrich Drepper 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. Files: debian/* Copyright: 2008, Sebastien Bacher 2014, Maximiliano Curia License: GPL-2+ Files: debian/cinnamon-update-wallpaper-cache.c Copyright: 2010, Canonical, Ltd License: GPL-3+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3.0 for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . On Debian systems, the complete text of the GNU General Public License version 3 can be found in `/usr/share/common-licenses/GPL-3'. 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. . You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. . On Debian systems, the complete text of the GNU General Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'. cinnamon-settings-daemon-4.4.0/debian/not-installed000066400000000000000000000004151356401377300223530ustar00rootroot00000000000000# Mmh, nah usr/share/cinnamon-settings-daemon-3.0/input-device-example.sh # We don't want the libtool nor static files usr/lib/*/cinnamon-settings-daemon-3.0/*.a usr/lib/*/cinnamon-settings-daemon-3.0/*.la # False positive usr/share/man/man1/cinnamon-settings-daemon.1 cinnamon-settings-daemon-4.4.0/debian/rules000077500000000000000000000017721356401377300207420ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) %: dh $@ override_dh_autoreconf: NOCONFIGURE=1 dh_autoreconf --as-needed ./autogen.sh override_dh_auto_configure: dh_auto_configure -- \ --libexecdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH)/cinnamon-settings-daemon override_dh_link: # Make *.links compatible with multiarch for in_file in debian/*.links.in; do \ out_file=$${in_file%.in}; \ sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/' \ "$${in_file}" > "$${out_file}"; \ done dh_link override_dh_install: dh_install --list-missing override_dh_makeshlibs: # Disabled, there are no shared libraries, but some plugins that cause this # to fail override_dh_auto_test: # Disable old test suite on build time override_dh_clean: # Remove autogenerated links for in_file in debian/*.links.in; do \ out_file=$${in_file%.in}; \ rm -f "$${out_file}"; \ done dh_clean cinnamon-settings-daemon-4.4.0/debian/source/000077500000000000000000000000001356401377300211535ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/debian/source/format000066400000000000000000000000151356401377300223620ustar00rootroot000000000000003.0 (native) cinnamon-settings-daemon-4.4.0/debian/source_cinnamon-settings-daemon.py000066400000000000000000000016471356401377300265160ustar00rootroot00000000000000import apport.packaging import re def add_info(report): if not 'Stacktrace' in report: return m = re.search(r'/usr/lib/([\w-]+/)?cinnamon-settings-daemon-3.0', report['Stacktrace']) if not m: return package = apport.packaging.get_file_package(m.group(0)) report.add_package_info(package) # the issue is not in the cinnamon-settings-daemon code so reassign for word in report['Stacktrace'].split(): # update the title to reflect the component and tab m = re.search(r'lib([\w-]+)\.so', word) if not m: continue component = m.group(1) report['Title'] = '[%s]: %s' % \ (component, report.get('Title', report.standard_title())) tags = ('%s ' % report['Tags']) if report.get('Tags', '') else '' report['Tags'] = tags + component break # Stop on the first .so that's the interesting one cinnamon-settings-daemon-4.4.0/files/000077500000000000000000000000001356401377300175335ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/Makefile.in000066400000000000000000000002761356401377300216050ustar00rootroot00000000000000all: clean: distclean: maintainer-clean: install: find . -mindepth 1 -maxdepth 1 -type d -exec cp -R {} $(DESTDIR)/ \; uninstall: find . -mindepth 1 -type f -exec rm $(DESTDIR)/{} \; cinnamon-settings-daemon-4.4.0/files/usr/000077500000000000000000000000001356401377300203445ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/000077500000000000000000000000001356401377300214465ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/000077500000000000000000000000001356401377300225615ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/000077500000000000000000000000001356401377300242205ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/000077500000000000000000000000001356401377300250055ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/000077500000000000000000000000001356401377300257505ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-a11y-keyboard.png000066400000000000000000000012711356401377300315770ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<6IDAT8?kTAwMv7#*!b(Q+R,+K|X ZXhLXE.F]RAɺ͝7) ifspGHȁCTZ@﫝906T_74fD3*%ҙ#u`,vWjdN 3+S-<\"t"1*hƹTk=N4,Ș:@Q.0> +9ϚmTKnH"A* =0Sתx07~"K Bβmc*3/qyN]Fc$& H` 7ʨ>(l^=N#sGK- |D3zW 1A_(%!"L6yd)4?x_}AQtio<~Bcnۿ'&E +*Nqw^tܼ=zVJx۔B4c/zZu6R~]xz0 Hf`X?3h~ij|m&7@)IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-a11y-settings.png000066400000000000000000000012711356401377300316370ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<6IDAT8?kTAwMv7#*!b(Q+R,+K|X ZXhLXE.F]RAɺ͝7) ifspGHȁCTZ@﫝906T_74fD3*%ҙ#u`,vWjdN 3+S-<\"t"1*hƹTk=N4,Ș:@Q.0> +9ϚmTKnH"A* =0Sתx07~"K Bβmc*3/qyN]Fc$& H` 7ʨ>(l^=N#sGK- |D3zW 1A_(%!"L6yd)4?x_}AQtio<~Bcnۿ'&E +*Nqw^tܼ=zVJx۔B4c/zZu6R~]xz0 Hf`X?3h~ij|m&7@)IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-automount.png000066400000000000000000000010501356401377300312540ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT81SA;>]K 6A0>` _XX,m,z% #Hܙ{<7A0ssν#CELl6n!@J ~?PjuA勢x \*yU81^srvOd Bh<^VšN){_͆dRKN*EQ+) !uuUe04,&mWWW,@c8gPQBcFQ×o}1Q@T3#DJvK=!ιqB}4x.Q0d@yfT/nSzX'yrv)߼}uonq'G98Wϳ'OdDΟ~H&A&IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-background.png000066400000000000000000000013111356401377300313400ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<FIDAT8o77efC2mB+^ڿ@JrP)dٙxlT;=Yl r}/,l"1ύQb,`;ӽƏo;d(r8xyc'sGr|okY C78LaW\^cSW(00.wac9T`[S@r 1b==,pבMʽfx!d9 pns4sgf1~3ޣOCg^p4A2{aL)VLU^2gԛ5~63k-8;inbnVZ)7H:hlfdS7jcqkXH ֲ+~xd]`d6$؟.?Ӛ' eж-GE/?OG#:O6(g 0EA $x0͟"rLeIwjT#*%^^{7'c]dIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-clipboard.png000066400000000000000000000014241356401377300311650ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8͋UWՉJkHfǠq0AqwB{. nN" A8I'3]ェz.Furdө:&|o sIQ b }%[ޓD1ZZW3 zQLRY"v-"Hku-]Src7nDW;w ζX-0JF`"^"_2>s}Oec yB r5ؽ8899ADxJN: A@ fM`0!C˹l0_@lz` !)9O]uD1Yn}|Ƀчg_N1!}c(0$%M2:sϚϿ~ypsW39E^QHG319kVPU "rŀ"NRa\nNh,&k%ض# J@K C g2P.kէy9SPIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-color.png000066400000000000000000000015711356401377300303470ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYskHtEXtSoftwarewww.inkscape.org<tEXtAuthorLapo Calamandreiߑ*IDAT8YHTqƿ8D$B4C)BD-E=E*T/(A=$bF5a Mn[ΌfΖ{9IP48sff~2L<̿XM3㊨N^G/V5b\X,*`YJsnsZ$\ v`0ejiۅcz0]!#~Jea.^kn] PFTے2bW0HHcr{M}|j~M C)΂E a0p<O<#:60<<,u$O4 T#d H+jREt2Ʊ',7; !r >Oa7BAI.YםhbPD] o( mX~1)@Baw&f gg$W&*b'&ib`@T @~ظޮ=ny2N-?z}_k]GL*4R 0LB!6)+[.nh1W@(C1'^$n/(@EZAٳ'bW Wi@f^:gB;$0is}Oec yB r5ؽ8899ADxJN: A@ fM`0!C˹l0_@lz` !)9O]uD1Yn}|Ƀчg_N1!}c(0$%M2:sϚϿ~ypsW39E^QHG319kVPU "rŀ"NRa\nNh,&k%ض# J@K C g2P.kէy9SPIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-datetime.png000066400000000000000000000012441356401377300310220ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<!IDAT8JQqV8jd >O7gAHH Bsoa"^~L`?U 'I{<v i6 ADigcc/@Zggg""looS% z=saHUUXk<CQt:8<#"cs!IS(4Mۈ9Q@Yt0!Y1i<==1bEU1h4eeeV:iyuXkY^^9G$4M1E fKE߳~d2h~# HYDQq3N kT~OHX`[U 8>f2Lߧn9^PJc(sQUVhaR;;;5 t9gkk6TNUus{nnn~SaVG-$ר8IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-housekeeping.png000066400000000000000000000011761356401377300317200ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8kTQs[׍1.ÒD$B `BNT"HW{k$ӝsf;BH_n4,0Jf_^E=r Wp9/\hwm@=Ĉ7'@Dxnӧsï>GXoyjdpf$"fU.+k$zgj@5+X,;w3OyN݀b=aۅ =n ݴD3ke,MTDpƘJI;ci."$sa1b1BTmO~!uoQIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-keyboard.png000066400000000000000000000012521356401377300310250ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<'IDAT8?K+Q{*Il`p%JXX&X&a We``sfΙu@Y`jś4 Щbب}шp{{Kt:VfFk-ɄpXhhk-"BߧlE^-5E`( :qCݮꃃ(D 06j5??999]$jl6)% P9s{ ___(ð!"8TALS,C)h4{t:Z1WWWi֚ 0K,#MS+ IDX.$Is=ZCQAU[pΑ9J)Jo cf0 Kz 9x||{v]jATI^/vAOx˷?<`?FԀ!Q1' IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-media-keys.png000066400000000000000000000012341356401377300312550ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8J[Qנ!zckDP>O½kǕ/+見"b%(XVP#ƛ{.bZf739#ס`jujZ5YLӴӕJe'''8$n8S}V<0tX[[}(H˝4crj/Է|1*n(Rp}}Mw8XY2I13Ci 5cL) ""y!y#"*QQI>ㆀxXk`ssc 硪q̱֎c Zi6Ev_{{|<)^:A֢y|Q7;˷*66>@U(xlRMSx@QapM/z9>q#",//'H0VSU|ߧVeqSV0$ CѼ,^SK 3Z<}V 31Q H9,[XXx#ȳ(o8??>%N:>bIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-mouse.png000066400000000000000000000013011356401377300303500ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<>IDAT8NSQs{b jOCp`S' ;)8h%AP ZKdJvrupx̬Tnl<.b.Ujph67YeFq/R+Z:qA$ZKK QƳ'ܺ @\sJ)W(h !Bߴ󁵵gWnZkB Du"x?E^r$g(1&h"P,1ibuDh)bc+;u&fz}4헔R10H4B̵'jqqtG\PU/+ivA,9ūo<R]0wQ~k`8,˺@?T*rLz]^)%R#@n)t:Y&m\:؅KvgR(Z@8~kQJo&xeqxxRBkx3k-ZZsY['akx4v=916rs70l'Iqp^L~${Ocs.1jIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-orientation.png000066400000000000000000000012141356401377300315560ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org< IDAT8NA9sfZ) CcXq5z =Å1# Q$!Jbi\w339cHŔhVպHᗅ L7S>}_6<1Fo:{ʲ;{ Dp*Z;b`RJXrw9b H H&@L\ePsu._j^eJg/P 1bQLLLBHE}bt:TUFs:SPթ:^=[ uʲOcsq**Q5#)%R5X.Eq<77ט611gsPUTUE|_0Ʒ? l*IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-power.png000066400000000000000000000014061356401377300303620ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8nWwAĀDd Kt<3Nf ÷ >::zuppdwwnKe3hܤ*>ZksNNN)`i/j4Mm$,|,Kq*4MH)%%vuoo.Hˀwti|xxF4쵸hme]Ww$|Gb^S _e?=j6*Yb28p;a.$1@,8Ǣ(N1*CVx,:+ B:Td-Kt :Fi& 20r%_yzgl3.p/v,IP"GEa,_yK"GH R^W tHeAYĀ bDR Pazl7 H#BR吨mן,*R۽znݻ+vzwȧ|yaӯ> /K_y)oh*K=i:ε;+IkE@Q“,?|~yMxtIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-print-notifications.png000066400000000000000000000013751356401377300332360ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<zIDAT8}AhGՍ15` *i)PHJՋޤ7'/MRCk*HVE+b$M|7Hfa}zkKC@լǘyCG'@]?NOJ2AT;;nΚR)98TG cMJ-BBA$Dibh1:. $Wj#UAU)ɀhW7 82mpW.5B Dyv]Li_ys_SfB$$Gٙzn(5< @AD TsQ;pgƟm h(x|ew'XUkIBM>Eej},bT\=g$nǃS7k:Gq7 vW㥱G ,_w^fdnY$M#ѽ[Ҍ͈fd03z?--.dfԈ1òU4|u`|e9  F\1 ˜b;Xu{%AQѼcdb◇@EUW5s;0#IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-printer.png000066400000000000000000000012631356401377300307120ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<0IDAT8NAfpEXH@(˼/x "B#DԠT( i`vzpEBt#9s}>9`y$pzj@("2?{U^VTy 8>>#HQ8v=%"&Let:eYb9!EQ`%Ix'8<& aEItXYY973PZmWXkh42 t˛_,%DCh(ADp&Z[[[j84M@=۪*LtG4E1_#y4M,{Ձ9Gj0((˒,ǼPysƘeYcssS.//f41kkklll3f2ooo㘪}Ad2E,K`a#p`<_!Dvwg33S%ڭ %4MS0P $iBݦׯqL$LNMʰ6 MSdYjq#^5Bp9*8\.t#:L@!(Aaey8ڊ'!I y>3 w`DfWR7)( xl}V%V꫔>tHOx= 5\S"4mZQ'e7Bk(zˏx#®$'딫8V`TTP:l7BkqqqV85aUUED~UxAxi4ЙI`'>s?|cIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-sound.png000066400000000000000000000013621356401377300303570ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<oIDAT8AkA;InHz%!J1"H񢽈/R/UЛG⡇JST(&3Ɏ@=?+Q.!B9sԏͺnYk+Zk|<1A@$dY4ZܒohD\fmmc*dpǗ?<$IX]]eoom CRu988@JI3aP(`AuDpq+n J)j^oCǔJ%NNNWJeppG/KR!O֚fp8V$W'8xza`d4M *Z#DOop PJbnnk-|~O[ѼNjg9n!(5=a1&ZKKK~z8Ə8:y˴Z-Gv`%ɠ\.#Ƶ9rUaIwZs(t:aDQDݦrxyx=c <6 |vME&$0vbxs*WJlX94+8D0P 7o5/IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-wacom.png000066400000000000000000000011541356401377300303340ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8NAݳ$) E*X'h(hPPR Yny+ ,tl%;_3+ARFATsxh8{WWWc{|| Vf,wWcLl c 3^/@y"B^_j0#2!iEoT眼Ʉ[FOOO怨{q{ĪxWmD8 ( *)~* i!jeeYrvvFߧ0Lj1я|~~=v&ڿkkY0v$IV >NlY'MSu[[[\__ce:Rι2˲XU^0/'I &ZaŌDb(ǍFc}myιe02 ̼/ "<_ IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-xrandr.png000066400000000000000000000012141356401377300305210ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org< IDAT8NA9sfZ) CcXq5z =Å1# Q$!Jbi\w339cHŔhVպHᗅ L7S>}_6<1Fo:{ʲ;{ Dp*Z;b`RJXrw9b H H&@L\ePsu._j^eJg/P 1bQLLLBHE}bt:TUFs:SPթ:^=[ uʲOcsq**Q5#)%R5X.Eq<77ט611gsPUTUE|_0Ʒ? l*IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/16x16/apps/csd-xsettings.png000066400000000000000000000012101356401377300312470ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsOO8tEXtSoftwarewww.inkscape.org<IDAT8MK#A" 2H<( g<=-`1 3]ճqŽX.:b ssww&βp8<~NXkZV} D{<*DG4( MS,*lmm1NQUBTUEe*Je8ʲmu]ci1u09i="+0N ,KTlC$ { Kb1jlw<9>>f6Q%z%l:r|׌f19D^eYv9==e45L "ch$cnnn0 qZ if=X,t:1ι78u1?888 "^__ !4E$Wd`uݘElF'/A{CD#IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/000077500000000000000000000000001356401377300247775ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/000077500000000000000000000000001356401377300257425ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-a11y-keyboard.png000066400000000000000000000021111356401377300315630ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8]Ue>gx&qj0d2ʠ4*.n躋 +!$J,Q 1lӆqӜ}bǹtw~~w}nb| vc>t YέV>7kmeCX1:!&j,8u8FZ!Ik Ag2ȩc9&&N ܕ59ZbYVvg5*֮Yx;keh+Z-g[3.L?; `s]t41^d5IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-a11y-settings.png000066400000000000000000000021111356401377300316230ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8]Ue>gx&qj0d2ʠ4*.n躋 +!$J,Q 1lӆqӜ}bǹtw~~w}nb| vc>t YέV>7kmeCX1:!&j,8u8FZ!Ik Ag2ȩc9&&N ܕ59ZbYVvg5*֮Yx;keh+Z-g[3.L?; `s]t41^d5IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-automount.png000066400000000000000000000015251356401377300312550ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8Mk$Usҕn&1 n0EfQAč+?~J\ $fS=u9.@Aݪ{0›M>bꟍ_!3CD""ffH666Y]]}j0R}?x4!H", Uh| w)vQ%vUuh4vB3c{{ܭp/$S}tt ysxxbfsCeڊœ96滙:DP> s4%xP^7b]Q\^^r}}$It:sNZ!{#"vT3NOO|4m_JRLZ s^Syd_g~/>}`hEQ|8sHIZZZjieIVc՗ ~zFEy|?d4ziIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-background.png000066400000000000000000000021441356401377300313370ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8MEޙ$2!q;FDąƽ?$tB!\?PL | vWw}YSojëexW@޾͛krֺȸf0cГ݀1'@Eƒx2=s&RiJ뚺/sJ ̺2_gzڃZȓY;ŔU;,{̥{x&Is{/zNw?{\_y>e=0ecjfW.s{T!2,K TH0g 6 *#C9!D3C"rip~CUNs|Ĩ䢪9:r3PCMKIa@)IUuNeU_j56[(-]#p)<#=qBU !vv8L}}u篎Y.=fK.ZKjҕڕBy2ovުu4| 6"bT33Y"TLXY'A` vyqL05`R\c5SK@V~cQjvES9 ב&31FH29glN PU#8IMG`Z0a T9%MJ 20)6ȱe65Hh!H"Q")%44b֝A0"DaI^+| #1n dcKKK}iovuu.V,_ 4r=Bv$FD9ͅٽi_zCPRMVfO8"߿A4NcoZUb:Tj=ؿOuᕾ9S3>@ūe_<~c9k_nf2ScfV.JѬ ԠAs+=6pf'AtޱIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-clipboard.png000066400000000000000000000024541356401377300311630ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8͏eVbʴ)*0Dn3\&!Ø 7FcF+MQB:e0 0L9s{ϧ-Wru]}ݏp7rW_ŅSˏ<ҕ(eT>VE1J[#PRI oUUQU~k-9gY^Ś롕!D0ySJYxpZ=ϥς(%T>Z} (E2A ՟.#Ր౳{l.\eN|cm+]*}h=r=?/GI?r p ߧ:{!~aV\hږiP rJL(QZeh CжztXK7-M[CD@yypl+>1f7.g?YY)%J)`A%J][J\9\jDiT̻<@WC fId{IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-color.png000066400000000000000000000025031356401377300303350ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsSSV\tEXtSoftwarewww.inkscape.org<tEXtAuthorLapo Calamandreiߑ*IDAT8{lSuǿ{o]ZtB 1& 1 E!1$N@dF`"Q"2uCYskv]?P0s>9sq*zYS EzI 3sPY~~wW0Up;!i,pMbm~lcz!w555,ax;T,xzRa00xZov+MZ ^+8L4 g!̲iU Zԓn ᄣ5%&).^pֈ剢iV$A<JZ3pFn4;zRX-6XgLpVVV$+,@ A ТuAE& NTT쪩9 <ϯ7>v '\E @D0 Wu!ܔK\KUij MћПmB4'4er 2M$K5 J|PU(|Zxl<N'@ I :)=eCwr.0 TM BIR, lyV_=!w:PՑ>Buo%vm+L]7r :|hQԜ&s>u moTI.'Ef!b,EI*Ö<̂g G^9_^~MMUG$7n93XbOx% : QDA$)UTY@ϯee]z* SaR[{J>ꏂf *YUR`7)4%z̙8RӞɫ : ŐL %R@ǼG}awOVE1J[#PRI oUUQU~k-9gY^Ś롕!D0ySJYxpZ=ϥς(%T>Z} (E2A ՟.#Ր౳{l.\eN|cm+]*}h=r=?/GI?r p ߧ:{!~aV\hږiP rJL(QZeh CжztXK7-M[CD@yypl+>1f7.g?YY)%J)`A%J][J\9\jDiT̻<@WC fId{IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-datetime.png000066400000000000000000000020351356401377300310130ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8OI]|@)y(( aHH))Je(ʨk-ȄGJȍPV9333$IB^T*˝nsyQ)?FZ lMZR*wHc$IZ1??{58G|usYcccc8::"yc( q̣Ghujvc9BR Ia(X\\djj߳;nXF}5OkR jJ y5{{{#qzzRͻE!pZkVWWi6!F^G6Ϋ(xϞ=wK8z>{1GԘy!BcZ4Z묵iá~o@/K|1~?IifIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-housekeeping.png000066400000000000000000000015761356401377300317160ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8Mh]Usy%yƈh6nV XѺtSu-[Rt#. RAPZ&XR ZԢhIj>9s:0{!YXt>$P5kW7xSvf-o4f[c5>p<Λ*wf;hE."&qOPκEČ %ثfÆ _6l\뽎NcDI͡E\ tfPhꎊ(-.)@L4]5jN8g>ptpUWqEVA")E})Vg3Ta:u<;sJTx2U&%-;@@%ePj͓3$3 k*`U4J^i2N''|Jf1/*hPQMF컛=HFt>Vg]m#Nu'h(*!L#=4uF~%(/'B3KH0B4Bʤ k|z:A+sV?EшȊht>Xm 7:y:n'p N:+n 묝:}Ya9O/!k8Vd@:\:- iG6BR jNG(N0  @a`nF $ NqN991bE3Li .v׀ο@:IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-keyboard.png000066400000000000000000000017661356401377300310310ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<sIDAT8J3IK4#:`KEp!B`p;1p@҅ *!"$QNڤkd19~{ުR'`~yuu?`㯱oB;~ӀXKAp4sy.PVTLIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-media-keys.png000066400000000000000000000017411356401377300312520ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<^IDAT8K$GU|jDWlYam/{ٻ?$z,+'HB6Ag0 BTWUΰ ,B}>SՂܯhss{;kkkPRexxxP7} Zc8::ZdNLLLq }8Cfgg㘛90dddӍ {fu.W}:q 1nKdjjr ~I"JI7`qx" k-} ZVחz?U4#!q1"j( E|ߧhdv_T${{{,,,pyyIV}">$ݤKY3֢)((IƘv}gii3fff% CY!}~E\/:9p12+v&>jWgQik-R˗_~pԀOaB"Wgl΃888e!R 7$ F^3by0L=z|Vic[(/Lʹt*|a߯j,h}tViм@~eiQJ }0(c v6I{CFq TZ3dA=m_!c Zq<[abŜ ۢU~o?[gq]1 Zzn\ګfkcn(1y6Ƙ3q?XŠ^}*V,7n,055EU`zŢ( $MUpUOq:']rV* FRL}SgN2AuZ>2 )-b7BGO@qS'*nch6=ő#1B *bR,mA$C川:.,sYNL%ؘ1焒LѤ+`iS9l4ySp"1YL/J?yf1]=pq"VAZLȲGe3)JܰǦFqxd.C066$33\~z \[x}9z:oX`Êett8O<9S]Zgkk k?@U1#y1BNS͢S3loBe; m5鴻dYNr,lj#ić5κ{c0= b FC|7X8b]RlĘ)Ssb*ZVŕ+ϱpC䄢(8>>@r!*J&"Z;@9ʥ{Q;_[[8qr.C: jeIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-power.png000066400000000000000000000023471356401377300303610ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<dIDAT8AvF;][v$bK09#AK>BNE-|5'` H쮼LOL~U9j UWOxB>yOYVeIQ~tz5?}_ܹsph4b41oX,fEj"@1Moyfm4jurrG~@obcםm$ 9z1FsBY]<ϙN!0 z_<EF_uWUwYu,K88Jy Ȁ9;u֗f:3kE92NUO۶Yݻ'̤F iΦ*px: 7T_oln_Sx mPխ̶ oB &jfr>>|ezH*ZLբE~O.XE:QdГ셔̭<9,cVwjyIgN["QkɒHj+:/U*ٌof)8%A7PLw)9W'11QfᜒxAEqDT"%H!\|k1yr^uIxyQL'JoGz~},Q2ϯ90gEKC v.Cd}>o=5eK`| .QxF_?p|õm^fc^&/Nqs.$Q$"^{6^tO o,Se"^] I.1)$D+=Ve'd*~ϔwwc37-ؙPS@Pg648`>d>eY)"&r|Q7n}7d;b]6.bQX*]#siӸ]皦I.G7#q1~e=۴a%dM1Q +!pr܁3 ?ݻpx̤i,L&]R%Mӈii&`!>}/j}gϱ8V`m:0_IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-print-notifications.png000066400000000000000000000021101356401377300332140ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8]UUk}utMӌM &:G/ CЃDO=DPD KD=ԃ%V` }@TA6i63w8ޙkP$Zp΁uk P̿ & | 7_ 9rS*3˿9|'^vuw=<55i>Zs8I$H3""£\7Acdhhvp࣓E/YB! 8\hCU0SLf]nƮr @Qyw āq)1@L S\Aؾc+{D -a />l&5 swTjF\PK>StbEC59H2cy&FQ% #f0m͊4 "y텧8 *zia4./73oe5nMս; ^ ^U U#bj,\\keǙN7_7Sӧ$MFGWP 3 8qb7n)^$KsY ffj fb(#fbʕCC2WS`;nIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-printer.png000066400000000000000000000020341356401377300307010ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8oG?3;9HFʉҺJBJ.]zTQ*tNHXn ĎH=3/'J+M}}Q Ljn޼˗ Jwׯ_9דwT 7NضmG!RܺuKe0,K677յkהж2` !EL.\]r,qѶ-iGk=OfpUB{|g0p8dmmgϞQ%Zk4Eks\{MUM~)2֒$ J)u 5"B$XkXk !B9%Fe-1qLUUyNǤi{ԩScX^^feecLO|̊IY7xֲvlPQ&MӾX۶9"_MB`6EݶyQ2H(LGLdYs,ԥK`0PEmK4TUEYuMedYF$LqǺkڶe:X,>4MV"¹sa:RUZk8ֽ|y.^=˗}1F#}$u{V[/ +$cqTUի;)1Xk<}EgEp5""\K3nFsEQ8y "]$@UU,K5۽o6y*o53uIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-screensaver-proxy.png000066400000000000000000000021671356401377300327240ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8oUU{sk+JH@)Zjbu"Q61qy !!ΈсhUJ+%A0m"s9}! Fdg-_['''':DDUSJSSS[}wޓ6eYFewm48}8`|Cr8Ueq]%1Fnaj0!gқ(gaM``A p͓yTU ƈ1k 8t)ƶiFbL\pwcOyUUF:cǎ/u4MvxӋΞE!U{/1F}8kxyy( >3ɲ}^K ֌\CCtY( b`3x)ZRJtWPUR¨5ٿo,{VWWY^JYzҳx"yG7Cʪ$uq`=s?ӏI27vNJP1, U8`}%( jҊ}Gq3 Y!HAeY \rBٗaJMQuVqΑR!I)j&czyvc<\mA:{dmm_./Sb?w !HmJ|6qx]#^KKPkSBL`T1X;ĩfx-yd,/slAQvwW+N)Igb$\:o F*0n&D%*ؔc$س4UUu)P:Icem*UPV}S;B =O<7|VQH"֪EDMSbqkbRy[7RJyNh?~j4#uЫcPU^śBS(ĉ@+lIꝕKꟆ[}IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-sound.png000066400000000000000000000023241356401377300303500ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<QIDAT8MhTW}$/̼ĉZMi Z]rEBWe% n]]I"hA1Ӣ ah$L:)L 3޻ׅyvQꁳ{YGܹ3~ܹ/((0 uu󙙙d ,_@j("_WbFZkXeYhwi&DQD!Dqضd2 \.STR8qq,,)H4M|2Ri6Zk2 SSSܸqyfk)0#)7"&BݻGTqNN0LOO322BPlEQ x HJihQJ>.\ [ܼb&*|~ѳE:wR 5RJ#E 2??OOO35 GgOS*8~8j4QJ(vwwӧ4 &F8:yI.C䘋mC^?cAl6,be/.K9Vܚ5%ER(R"C dr9^,`w |OB$h valoom[qbNq L^j y @DQ$r9VVVhB -ze/ߐR2>>&-+ᔱ8j5"<~Y?4/C|?=cǎyj+2Z 5iX^^19;:yh3a$r9^-SS8X(ufiik׮C\'1::Joo/KKKAyP>C1e3G-h4J%"W\m-<\JtޅK6^i$ՅyIaȓ'OҵR_|GGNR(d2cYR,`qq['8ibBaF6C7N0T*58dxM7ntL:IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-wacom.png000066400000000000000000000015021356401377300303230ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<IDAT8MKXssSj(uVCb@Bt!R+w.]hSR *^@YRMrB!='~H+(nllDR(,۶'511ƤUo[f8_XH=Z8N*N˲tww7~8hpyy֚I@)@(vnߒ10 VdYp]@~cWQ8d2G(qq\]]!ER'X٤VQ),--nrb Akkky (l `f\*8>>憽=8N,7 c̛qLTy2>lqZKXD<1e* bi...!ϓPJ!"IƒD*jB>ݒ, ]TUfgggjjA~?vRI)乶T* fffi | pR<~nVy^XDx2L: @k-\]kd2dlۖwOma>tuu}z7]&b~8>YZ:%i;o0IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-xrandr.png000066400000000000000000000017771356401377300305310ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<|IDAT8MkUs󾓯NbM"RmIuaRu& ?čD0 %d#_Pj6хqL h2Mfx\3χl_7o~佯inll]ZZ_l6Eq.cccLLL077 rH}rOܹ> ۢU~o?[gq]1 Zzn\ګfkcn(1y6Ƙ3q?XŠ^}*V,7n,055EU`zŢ( $MUpUOq:']rV* FRL}SgN2AuZ>2 )-b7BGO@qS'*nch6=ő#1B *bR,mA$C川:.,sYNL%ؘ1焒LѤ+`iS9l4ySp"1YL/J?yf1]=pq"VAZLȲGe3)JܰǦFqxd.C066$33\~z \[x}9z:oX`Êett8O<9S]Zgkk k?@U1#y1BNS͢S3loBe; m5鴻dYNr,lj#ić5κ{c0= b FC|7X8b]RlĘ)Ssb*ZVŕ+ϱpC䄢(8>>@r!*J&"Z;@9ʥ{Q;_[[8qr.C: jeIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/22x22/apps/csd-xsettings.png000066400000000000000000000017061356401377300312530ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs,,tEXtSoftwarewww.inkscape.org<CIDAT8N+IEnӗ16,!G`,Y ' #F|L@FHL@@&[<,^kk^%UժZ熛:>>l ğN/GGGF@[>o8PJpΑbshqQV"Rj,--Z^R*| RbE)2{{{h2QJ%J)RiJ4Mx-1~+t:8l}4qssycFaH.#Ih3A`Aι7ZC$Q sż"=kQJ xa6Mӿ OF#h6L GT*v988t͠z8{:JM'hZR1d3LzBs 2 sgu^nC[^z񝙭Zm=qPo;v7FKT/ptf![\ƞ#\$ "7^eë ![Ts@ 5qwF՘6,B+{oj5ܝBMKG' yM+h+azD"b=a48n[{Yww=s;Y׎Em/ϻ[Ѩn%8WÌ&Vr<ܺ^ jXnKE$XQ}M2puN2pe6<̾E ;+,lc&;>=Js=a3nI(Us[yl]twj\n^0<6'L9Ha;)MF4*Y0$=:zwCX G0t|$՘4ФAnj:j  830̩ZBqMXfT0M%R3"^tJdwCBQW|ȎYHFP{*QJ܍j׃,o4ZHְ)Zg5Sě V-ܹH}8-o8;WY{"_c^",*];jdUӴq弽 $T ܉ƹXƖs9# 5BWU9NdtgĬ`F)u?aD5,d! '"_:kc*<}L:5 q6W Q is?R099 L&ה ;#Z._Eoۓ-Ɩ7=`hp `dYֲgn_wKwȂAY&$@B{l|s 2 sgu^nC[^z񝙭Zm=qPo;v7FKT/ptf![\ƞ#\$ "7^eë ![Ts@ 5qwF՘6,B+{oj5ܝBMKG' yM+h+azD"b=a48n[{Yww=s;Y׎Em/ϻ[Ѩn%8WÌ&Vr<ܺ^ jXnKE$XQ}M2puN2pe6<̾E ;+,lc&;>=Js=a3nI(Us[yl]twj\n^0<6'L9Ha;)MF4*Y0$=:zwCX G0t|$՘4ФAnj:j  830̩ZBqMXfT0M%R3"^tJdwCBQW|ȎYHFP{*QJ܍j׃,o4ZHְ)Zg5Sě V-ܹH}8-o8;WY{"_c^",*];jdUӴq弽 $T ܉ƹXƖs9# 5BWU9NdtgĬ`F)u?aD5,d! '"_:kc*<}L:5 q6W Q is?R099 L&ה ;#Z._Eoۓ-Ɩ7=`hp `dYֲgn_wKwȂAY&$@B{l|5{OeWWW677;f|kk/0b}sXkF ƘZ{YEW q(# 9'Z$"$I{1  +@rY"RCZVh4Z_*BUV=RKeDU-JSvvv^,--199IU *4:Y++ @ve&$Q ") 8-Z\\1&AiPA$maaD|^1BE""qHk-il6:NK. |+]aUZER@ z^!t|ѫ) Cl=~<ݹ[cۘM7nצ(`5##bF$|ɇzs(MNX[?8XB[\QA"2Kf\G'~w~ߘ}36i3i5^we$IVDHxjbL'}}5k{?'06H<>6dH.nIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-background.png000066400000000000000000000022371356401377300313460ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATH˯eCU{{F7FuH)b&;0060AHCt:BB9vUUk8Sh>#!1*C Ĝ3fKi 1*('+fUrΈMȪJ)/\lFEOt5M>}Z9~>q=.EUQU^9É峑 .d{ hD%ZM ŤLLsa?)0+đ)1+}R2%"ZȖ[léSplnn;y a\IdBb@ *#,//s ֯osfyy]BLGHZD;M6̽%c/J hKp!x>q O~r6WqED;LN٤ɚ隆ՋX{1FsNN'ϼMN8>xcN]<[K,J$ Q$ʉ( Dk-J DAS"h? qXP5Ͽ:g~mU\$]O~s,a60C4bd{k7wgiiD\\9ŕǫ"DYqC|{ܼ( ZF\ʢ:GD@#1!Hʙr7nn26OWQ꺦kbӆ7o߾DZKUDEc&P ՐA8Ϗ*KÂy/ ^˼zuG>!Y搲`GY }U5%EQ,e5 G7޺˿ )eܺps`0b8p89`2CQeMz䲪E]= Cʉn0nKT*T>0m(xy[x g01,zs4wi:`8\D5Q hg-m3fIJo_o //O+R}"2mcȻvKߦԁngmpv{yk-YnF?J(Da06=##1F:;_mƙMp߿ȘT(%TT|VuvcO  "sْ7> t#P_˸&l%B(o-ɂq,}]x nxԳ 082|`:\}"{qk GayނXp3' <Ղ=R-qO+++L:AS Ҙa`GGx0j<ߒϜ<j!38I MTB&XGV #xjĐ_庲wi6TjjCP:;AlB LhbBc 0GeC` DKlK&vq0'''Jn F}1aFpP b6qLT{: ;( ">^'e~SP(4M rre%t[$5DY'W e|&;s]DRR-@/1?l6 3.nN*aQ#"bJ~20+VUu̹]R'%>uF}_'<0ԏ^CI ` Pq .OΔ[n_V\~K %%CS~j{\+ 9uɌ y?8)k baٱa{@_)bP qzlٵ=0""xyDD$ rtEa{p/}!DҵH[{}3FK8*ʊrk&YԈH \-NJʫWq@խϷswl̈́P$8I8w᧽+'Y#oHh$1M+*j47kk˫~ILL*-zrF)x% B!{Li铋 1WEiYq[̙S}F8tvp8WU?2w~856 xcXhIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-cursor.png000066400000000000000000000027411356401377300305440ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<^IDATHMeW~םיqz|ٌfcp%D"A֥يV&f!!8V3cwd_{}s\LO4[]-G}zo};s.k1`#9wWXg6g9LdGs5_|?Ik18ڣZeY!H'xs}ejXBGYd8c ŒI9a2Y@R%gX1=~MNr$)()Ƃ3dH *} 0 Đ]GU806#1D0B ڗ-UsL #"&RʈȑIU QZG >~>q=.EUQU^9É峑 .d{ hD%ZM ŤLLsa?)0+đ)1+}R2%"ZȖ[léSplnn;y a\IdBb@ *#,//s ֯osfyy]BLGHZD;M6̽%c/J hKp!x>q O~r6WqED;LN٤ɚ隆ՋX{1FsNN'ϼMN8>xcN]<[K,J$ Q$ʉ( Dk-J DAS"h? qXP5Ͽ:g~mU\$]O~s,a60C4bd{k7wgiiD\\9ŕǫ"DYqC|{ܼ( ZF\ʢ:GD@#1!Hʙr7nn26OWQ꺦kbӆ7o߾DZKUDEc&P ՐA8Ϗ*KÂy/ ^˼zuG>!Y搲`GY }U5%EQ,e5 G7޺˿ )eܺps`0b8p89`2CQeMz䲪E]= Cʉn0nKT*T>0m(xy[x g01,zs4wi:`8\D5Q hg-m3677~OVuvv594 pi=Ab8;ֲD{OEz=y"R #CD(CTիW>|VEE8rru.q.rffjsR ({>4%I*MS=@DԩS4MNt14y_Jv8qAP(x!RS׹y&F)._5YsJ ^~͋/d0011k8~8w!Iz>,>h4J)Dri1a2JYT*ǙRP.ً;09GǏ}J"BR_|ɹsqgϞenn'OU&|yZ^9bBsf'ȑ#s "#8z*Or=;F,,,HkmN[ eU{ ۷C\_gll :q @ Pz׃dhY{<1!I޾}KZeeejJ^ ,"*^0 bbbNpQ""BE,//$ .]9GN,0`V,XZki6(VZ-R| k-,'}d:.\ ^$ "bF&K:ryt:($_cZmv7ZlQj{s9s΋H~v8w HF W\= a2IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-housekeeping.png000066400000000000000000000017431356401377300317160ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<`IDATHMhe3|Fi4&bS/^`/ѓ(zxx= (- ҂V ii&Gvgi%ā?3&/=?Kh-ޝ=9ZJ|Vyw G%ս, 6 @ҐVٜ}X[e(ɴӐ $<ddc `80t&"u0B ,}yRs XEQj&fdl2ājIyT-;F`%D.zDNdhS$M ,8i5b - &'5Dv;RT~PHd8x5k/EnM!5Bo1>>:̷WŸEY3dJ+ 0!5:"ozr&} z9edjT QI}[d, b!θgL"%cCݩՅIC5hDUȈ`itK-+G{()_۬p %xd+$JD1"f.( !xE9o.6UX06+)-_^DG!t`łr7bU̬[e9w<3*~z{jiss|>pE9<<Z^?UJD}l͛7>~g ) )&% 'K)eit:{.BeYerzαKDQ֚ׯ_#6<<|hN(@a((z8C$1zhCK&1Z'W"1ėS~8hR!J%>$a:)2 q/sJ)1Q(( > aŎEZ3??˗/q!...Ŷfݣ\.EfȵZz1֚j>kkk?d;;;!J)1/˜`! Ct @)ea"V J1HbP}y)%${{{`'`0)@DʵiC <vu󧈈R RG] hZ۞x]}ah;Mh Sg)Brt$PU3IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-orientation.png000066400000000000000000000021351356401377300315570ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHk^Us$$fS$UQK ]/(( {XGRԊZҕXU4Ę}~4.l^yy#w>|nwHz_:ɓ'sssLOO#?!Ξ=}F;ʲĉ/|`{qN$$ |1Dyy|)%$e!"Ŗ-[nx7afeYR lڴ}Mu;)x $!(j"(!2cf 3k;FFG8yFGGZLΙ3fUv" Usg)>;9EQcA, "cA ة޵ ƈH;EU)%*T~+3w !?VW(˒K203bT*#ԩܻ r (+twWaH$f&M șڑ;&XO؈,ZU#ɌUxKVdE"v07\ [׋ʲlE^[vZ-[B+уC kłSehZxv%:E]!* uN{yt4;{{$SR3JU4(C#Cܽu3<203fkuygyŗ9}{4Fdi Z9 exKH2^:W_|y"c3l߾#ϲJ|D9U~T6SVJV|^t @Y's}P\2L{!C@&Wkr355o#  4Vn.4059IJwF_ZZZvw{lv fzoaqqw#Л}k0oVUB{WUz?眳Pۻ/.=zm OohXʿ:Շ'vIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-power.png000066400000000000000000000024611356401377300303620ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHˏGUΌ3cgL fa&,B D H^`?]KXdk9[ ";aŠ8><ÊN;T^=z٘fXkFXk2Ngo=P7y֭_\vNommMUUmkzxeٌhZlllIk̀vUUZKecZ3NifkV>s[@[m9gy )D)HR "b!HH)^8s|m>.]faqa@/r?[wM3EO xƿ9N 2pIO?KNJ~B eK'ٵ_ ["JLȴ_#)H4"_Ho>G/(eŅ#N0i"BL´z~瞤!pPܧ?|Nlz*E)%$ (AA#d)I`dQQnU+p AAŻs5PJNJPJȔ>^l^a_IJx C '_{"0d:҂ںBPdI曻o)%Əx;KSւ6B h%nw'TcO3l tf@d"F0"Ņ'ys4&[9Ώ)R5ڀ@eܫl mq EmO0ؑgf=sJ DTf B\IFd-ob]pԼP+#(1Zh)PUh&LKxXq/0xd )@_XPB%-`6&@5fq"y\ ؾy\N˗agg5ш( ev{ʖ{p8ݻyqss< .䔛L&ed2!2^O{޽Ƙ)R j<SLSөZct4iK Tuާn}.֔\ NIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-print-notifications.png000066400000000000000000000022671356401377300332350ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<4IDATHOU?~o63F!J68E%ߢ6EZaPThQb 4 VP-JIQS3oyޟQqSgs9+"2@6m\ȣm.OבϜ"^-;fuΛ; ˁVyw[G,Wrr%E5Cri7#D1b䓧t}gd9 j(XY)JA Qrǂ"`HWQ<nLAD!!!R$o! JjE 9GKSkg?k4Kj13j`׎-?pY,Dj* (so=)2'wp[O4UM EvTh+b~׷ue"Zyڴf{ᑡh62<4塱{[F5-0qAQ4kR;F7ҵocWshoBD&dBauT*N.c1ל)]W4ST j98?sοiW.]F4Eл޹~;=yE$rAe־hM--:F;'18*A8z\9×F{٩[ѠXY ZS@o}y۾[JYM1Ư>_|r"-u<7;`4@Z0(NRΛù y cf7V̚2GKqfppl+l8UQKn1a1bJ8y^ 3!㣹 iKy4AA֡^P( zݝ^}*频0k;cLjHtKݙ3zy|׻N.[bX"Ҽ%@óm ݩowҶyϜ>K5β֖OP 3Ξ8TT|&!Pj]IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-printer.png000066400000000000000000000021321356401377300307040ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHk\Gw޼7oW/]!8C ƅ+qciҤJCZ \&`H!R+ PBU0 Rޮ}Lh&l8$ͻsϽg۷nc><æ}\n޼s?R<ǻw~9q۶>śquz8pέm[99dkkonn$Id<l6C2e:h4b!X&h~kkˇu)"^Z#"sBibRd"I,xի}!ٌir=& I&I;r /_ٳg,KUU1N8wϟҥK}nܸA8hCN 0^+#"ܺu $I MSe ѨoWOBkMeTU`0)rGGwAH9NǗe9DWU8tNYUUN1EYs0[I1X@(V/1Ccr̃IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-screensaver-proxy.png000066400000000000000000000024351356401377300327260ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHݏk3(#`!dѦA 7ڐhpe^xc`zݤ $%ahLafr3{ﵷ9Mt%oYk=~fC;V]!SSS>umɓ'o߾?Zv5ޯ,w̙>|C!fffD[=q+%~&'R}TUs^yR(ٳg71F駧*㜃{R4::{@p/Rj0̌c@YJ)8z.sՁ88yϱp}ҋ"ƈs39gP@RJQ@u8~qk}l7)EVWWv%nmU#LXx9RH)afxo11Bsfz ^y/cP7$1]MJOD`fsFS!~ {B8ty#}8MJ#"XH]"u޽$FȅE:/_gaa6jdkt4A }02i@dvfٙ%D~Ƴ V"o}9OURu^*[UDU.%T^PQQ.ؾ]:j8UTBXYaeeKPڻ5" ך9yv?_xc #cN2EZUK4DpO8sԕt8<$ǘ:v\ mj !! ^WӽÁ'&ޭdK8p`ܹsض,˗ ԩSBEBOy뺜npc QڀȲLcI)RA'''a߾}lllA37Z'{*ޞ)JnJ:!ZkRbEN^!XX$n(0$aw (1qt:r]֫g ?rKs8r'b+?#MSfffxmc2ZkFJIq4O %%k qQ2;###ض6RB/(2`0v9t duMRYE'OP/ woH,,,v ! V! BX]]e4 VVVxŸ9wSirEFi Rp6NP/Bd3yX뺬1??O^gii|tvf$2|رcLOO8J%F*{<6zRjhRrNCbnn3g1aKZ-ǡRܬxƘ/yzhTeQVV3>>:aEZ z?/>C(:(zNaH}|ߧ\.$ R+W T* L[h!Wt*n"<8@޽{y>^TvLKRX5w4 K.<~|u` ρp|IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-wacom.png000066400000000000000000000016471356401377300303410ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<$IDATHKkYܛ5$EB BҨ `(BlL?tZ<AXDd?F2(!3x?y9k P}'BY^^1C"0ZK5"]ץLdf Zkfffg/\j}} |ZkM¶m9=='`u] \keYi󴵵Rx/lۦT*q||L(b{{ߏ8\E, :::FRSEP222S7 Xee2r߂Yd2ITX,bY"bDkBH$HRF8&p0J*\eqq]b;;;444mK0RhI$iƘ&zimm@ -"<Wcj6KKK399Iww7DQ(>33J)Uq/;C2$N3>>N$!C}}Dpttq׮+xEL&|(?3x\|>]]]LLLP(Ԕ{֘<0$ qyyYqa&@\W*I]]ݫD,x*,j} O-7"_Zr-xxxS#]XXjfwwwe9><<#\m@U7oxLhZ1{IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-xrandr.png000066400000000000000000000021351356401377300305220ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHk^Us$$fS$UQK ]/(( {XGRԊZҕXU4Ę}~4.l^yy#w>|nwHz_:ɓ'sssLOO#?!Ξ=}F;ʲĉ/|`{qN$$ |1Dyy|)%$e!"Ŗ-[nx7afeYR lڴ}Mu;)x $!(j"(!2cf 3k;FFG8yFGGZLΙ3fUv" Usg)>;9EQcA, "cA ة޵ ƈH;EU)%*T~+3w !?VW(˒K203bT*#ԩܻ r (+twWaH$f&M șڑ;&XO؈,ZU#ɌUxKVdE"v07\ [׋ʲlE^[vZ-[B+уC kłSehZxv%:E]!* uN{yt4;{{$SR3JU4(C#Cܽu3<203fkuygyŗ9}{4Fdi Z9 exKH2^:W_|y"c3l߾#ϲJ|D9U~T6SVJV|^t @Y's}P\2L{!C@&Wkr355o#  4Vn.4059IJwF_ZZZvw{lv fzoaqqw#Л}k0oVUB{WUz?眳Pۻ/.=zm OohXʿ:Շ'vIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/24x24/apps/csd-xsettings.png000066400000000000000000000020171356401377300312530ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYsvv}ՂtEXtSoftwarewww.inkscape.org<IDATHOK3Ww&R@Z*~@W ŕ]; ;i wx[xB{039y9% voog~o6?*ޑWN1ɻ\\\|)xR___ǝNJ2J)r_1QrX(B b֚d֚h ^Z--R|>yc8pcZ3 aii'1(0!vcL6a&>R:J)ARg0$c'86Pq#t,E)Z.Rʌ4@z \emmx28KM AtR2QJa >[[[yzRf$"K)GbC.//Y__OZqp8$")ֹRZy^BGhB$Y""ZgaaV`0HfFtSJ AFdcLՠR.x||}f(8-2i?XR"Helnnֱ9 0Ni4yF=+++x Af5?YtuuyaHZ͈ote]Ru݄5viZr]7v"Zkfggi6S3cv96=l2`̟77*RJygQJ~¿{eF@.'D4BER)iglFQYz~xxxJml֠5En/-c Q(rttt:ZqayuG%&^˖itc]x!J\R3 f 5c mzTxųv>(ն%kNڶ`8$ qyO x A̠Fz6IE}m|^V_SUU"DR J,iw8JhT"bx 9":< ]* " EP1p"eTkĦNؽ0cʼnP!" x ˖itc]x!J\R3 f 5c mzTxųv>(ն%kNڶ`8$ qyO x A̠Fz6IE}m|^V_SUU"DR J,iw8JhT"bx 9":< ]* " EP1p"eTkĦNؽ0cʼnP!" x $I[n}vOX Zzx׀_?a94SכQ^υ9<,!a)Iv9sXkg6 uP%"33`۷8y(@Ykgb@kR5ܹCbVf, x766X[[cnnu رcE8{777vj5~!KKKP0j30i0{{{t:sqL 8n[$4}N]f@?c iR`0խUΝ;Rʨ`Rk}aaO\WhCB$!J``x`{.N? ԩS,//cȟx;cvvv*)7  PG$ig\ urjaȌ'Np…W"R1uXkS:_WrDAYM;W1~,x@i5㷧*@ʞ].q1Z;IjRo8~n Pa:)WA򧏿+R6PBR KKipn,ˀţVj`Z`+W%L8(Ɗ @a17 [h5Fo_7"mDJ(sb?%=DФ4LBo>t [4"3oqX El83+| ||Hبרͅ&6+9~F:HHz)I?&%Dat W! w/a7 " ^>&\>s6x^%aGB/R@ w7~x3U6w,F=]Q ²if?`8y; !o/lgrk6 ||۷7co 0؝AvVDY~V7Qd&kktȿFyY@PUZkT C-:jƳEf/L]\0UT_'vdbSe9*!4X'j^eXÔ%:U-%w[G;2!xR@ȃDM6_%a/j$Ø 2!UHu 9O:6C(ا}$^\d݀N*`f!LcNbSCٗ=u|qw<^heݤTuUPkݔZVV*G &Rs|A c )Y hm7/s.u (ր4(GYf\-_ V.$_Sz vF=3 +PUhuviqҐ)$Jt>UK0RH'Rʡ=gnlD| 0$HiNcd`mq-RNDuIG!(KacFFHednJ>F)u&ߘz­;Ld{8̍l|9}X<$W R ND\%sh]Lh'vEU@HhV'e(lSr3pcViՅ,SBH ZdR1v3BY~iNUWBhrį^ U h_wumLƳu]cd61f3bu&ϿC1жZ|7{}M,kk ׇ{gMom?}Gs Xz zI7rIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-clipboard.png000066400000000000000000000041761356401377300311700ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXŗۯ]Usu{sZi9-Pʡ\j-ň(7}7}Wㅈ(1F$@-A˥z;g_Zs{&q&{eeϵ7qY^{d} 0|oc_LbLGC-c0&F1`DACݗo._"س}xw}R 1DQc\uEjh Wek~1~^LQ PAT(PWAD(W:EIP9G (E_a1DCb1ƢPt83WŠ** JQH*{` h-kXK֦"Ennl$飴Z9n qS+IaKZxk\=HT_}XkZk=7^=]1a(wO>v>uk-!4 ׌t72a KkPm‚b6U\#ĕvUes~E&`TKK 0Y t9zB!^PiufT5[" "['gXynՒ)eYp*i1sM'q~0m.[[exέq}{n.VWSI]N1FQ܀5SO*TuqVhwZғ$jHDݜ}9*Mϥ(~*OQUV03s@@{Bx_`x{{nb9K9ȁTXdIL%mmff:4҄,I$vD%,i(:4+~w?NOsp/0G߭-yп8\V>PdւW-QIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-color.png000066400000000000000000000044021356401377300303370ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs tEXtSoftwarewww.inkscape.org<tEXtAuthorLapo Calamandreiߑ*\IDATXWip}3;;j%VqC #s:IUP@R$@lU&qv(8qlBQ$. 9"@ׂ]]LOlY?yf =.=OΝ;޾h6G}뗙aoyzV3X/ZyEK_^e@o6C'?>[p:rWW3t5&,'NB2D:ayZ[ox;W@v[ a,(lnO}}[ɜNvP] `KNΎD"Z}響!, /düo_Lk>/>F1)9w48AW@%`XUW45վ&N:'+6pg=! `1"aFyE0{ ֛Z$=PV~vwvv i'aj[!JI0: BM 4 蠱^@pzI,&Ccvu6:=;ڵ@VVi Z & I'@:+B- Bg tvp GKK(kQ 0~8*d?Z9L7 VDLC&n6{>tΝ |+.W{Usڲx/H["Xxπ*HT )4)q_~tH 0LocIR|>Xb^QBL3E4ڒ T8#0Զ"5@BFcݵk[ 8NG>݆ɉz7oPY]4 RL͋”)NrV=,_0QDHf1Wkjr\`#v{JSJ% :-- f!ԧ s. f (&Ulpż+aETTYQ5hyXo:}gmP9rbK mѻE)mi 9Бꀿ*${A x<SI V ;} /мkNm v xό "t&n"ٿՊȝuntt.t&kʣ4غ-rooof̙37\1>;?V-}h Wq/AW̙_(~ᕏT^kR>y飴Z9n qS+IaKZxk\=HT_}XkZk=7^=]1a(wO>v>uk-!4 ׌t72a KkPm‚b6U\#ĕvUes~E&`TKK 0Y t9zB!^PiufT5[" "['gXynՒ)eYp*i1sM'q~0m.[[exέq}{n.VWSI]N1FQ܀5SO*TuqVhwZғ$jHDݜ}9*Mϥ(~*OQUV03s@@{Bx_`x{{nb9K9ȁTXdIL%mmff:4҄,I$vD%,i(:4+~w?NOsp/0G߭-yп8\V>PdւW-QIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-datetime.png000066400000000000000000000032631356401377300310210ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<0IDATXŗkk]$7ݡqa2bG".A.rA.B"Rѕو 2j4Ff"ItEY*́<= g+ 8fx@`ׯj躎\p.n߾y9s%={7/h[!( :u50\.>}GR,YZZĉ0mc|odQ]^^X,r 4Mò,2㰸iT*4SSS,--1>>͛7Y]]%Q0 $u *G?ZqPP(JMfW( tvvf퍧)D H$(IS\O>|>OVkiH!qVVV0 &, 'OG$I޽{ J<T*I"!eB.GOJJD4M|˄aȕ+Wr\t={pؾDE(;::Ȳ{`L&C&! C 4MT*1664xvߵA@*²,fx++r9,uݸiGGGQ\.ccc4 2ȲOP"((JV*aHjL},qllli=de%Ab$I7v8Nh`f?l[k}mbb4l6⏿unwq< e yޟiSZKE-e=HBOe{l'6-D榫!|=W_ΪL~=OYxg_m;XeہݬZN q{D*G<4aZlD#UEm[i3kXD<ʥ/uPV#+B=u+SL^eqΓJ &\' >!5`Av[%¯_QWa`8ȶa"Q(U(d1#j7qzm{-kqTkj˩rM4H{g̊ 灋IZF  @_(ǙIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-keyboard.png000066400000000000000000000031541356401377300310240ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXŗoK]ݱcb@$"&ʊf{H5K6(k@B FA%E JLC@;n] ]t;G:wwNf =>8>ٳRf2z?\໱/ o޽ Ryԩs@, ψm۽A?V,cR 8lJ)R,xɲ,)˄akRP.f1 C._ÇA-~Ԁ8jLNN222BB)ar9ܹ͛7iZeYH)ƍ4[j H$g$ (ضMZŶm<#cBjsssZ-Zlll`N|ZF€R(mJa $"H)) yAXyloo.mEJ))]8CfbbZeY(47oޠBJeY@&u]6hiO~@ضJ)|g``k׮鵕bHX@AضS5@$,޽cjjJWR0 Y]]ezzL&+9c'~u777\.Oe}ӧXbK Ķmhm['5cY.Z!B à^w= ^߀}{Mo`h@T{#k V&IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-media-keys.png000066400000000000000000000027061356401377300312560ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<CIDATXŗkW?j$}iIjm J(V `>*!">>>Q(IT !"FnܝM=p̹|M>+ w3B (ݺuC}yw=׵ZS"gqqW!; no߾O'.{3">+>˲ c z9۝@el!8LWLJ,| c0;;˥KBl6IԽ7 `׮]!e>xX0֔e,-Ç] @22 $Iرc$IqSuF֗_q$Byir4Mő <f6A`իWTFG] !8 ,w%y1i R ;w)SSSeiq6+!RJx".\^#DJܸqN͛7i6H)1-%%Hm>{~ܹ1(PJbffЄ)7߄<{ݻw[hZZ- `hhIL57ys 0MS?Ne|ct:NS߻G_ؐOqQn#{* ܾM$4s’/1!2hB J%__gn' Q)zbiZQmB_S9f$\ޞn)mkgi ٌL瘔[榛;rYvA0LkM`"CiyJ)ƨLNNEgzzamLOrY;V<`nnqy^ͷp[ Ð8YYYZf޽!]ۚ%ui޽Ǐh4((ؿK x+:%?N&JJ™3g'NG8YkME]%,((V166ֽLDʼ5 :ζ )Iqid \V^-m$dNc d_ TAXV? nm4Hz07>>aRvh<}߭Ryn=*dg~x?~j/!s0F_ )MwIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-mouse.png000066400000000000000000000026471356401377300303620ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<$IDATXŗϏ?U{w3^ nA\PB%Q`N@|!C, 1D !^#;c:vwzw^Uqw*QTꑦ޷>W6U49h;wwǏRy#/7Ç[_'8qw3^?|/ fzYx _+:ȷ<)G,?Ҫ{ɓ:rzpoacra1?_\Oګpde֧PI ں#1FB \[Wx~_s/kᅬso9כK"51PkF\N? KKK>}ueKSf!TjSF2(U 'U{Rb*C c 0hUVJk @YBP1tNL5=Y|SN)E*i8<ht}~%D Zk~`0Y1@!ss(M ~_\uDݫ}=z<'q JQ뷽9X "0QnߟSeE℗_>Fc ~g_B꣔}31C`$)ȭRQ7M,.Gj=sncX -b:fIJ);u Jh`2~9z"nj.7o-:pQz۽EQta9߾)1# S(>YU{0U9Dw50 k1mnvvW &Ӷ֎DbOʟ J3ƌFѿx`SDE[d^-gGWV+߸5WY99 ";Zt0mll,Y%&#Ngc)@et@\sW'qpVg7ns!+"~B} nwBU6)$I:omy?]Z%lBj9~8ˌ1j^!R^bBʸu}8'򘯦}7@!KLepSЀ[H!R?KՑ֙C_ir~I T_Rj>F~Rczӏ7vT(K(-Z8X~<suk` poXMhb_)c%IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-orientation.png000066400000000000000000000027511356401377300315610ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<fIDATXŖˏW[ӏqq"@#/XE Hl! ;DBl@R$$+A ("2,20#i,nUM6Bx;]ꪞ:}gGUVϴ/_ڵky>t<@?+?Op}T׾Ǖ+W!m@geok43;1 ̺r47u7_}A 1Fbo|ܸ*"W4ux|e677Y__W^9a֜9L ghDpxxC H:kTBѧP}ˀ`~o3i-_"1BHBa}~ APtHknﲐ2}Pa 1-jԡ*c:ae>B֣ڧ,Kʪ%UUb{SǦ%!Yb@oۨ EQP%UY,咪8{,ŢořKE1uCh DR, `6QKb E3Ww >M@wZM+64U>{#EDDQZ $Os->5QȊc= ?σ0u Y ˂#\Ҟ#U Ǻ PC$*fƩSӧQQ)EmLj 3ι_qbvmd] S({ҷɗ(ppQ03[c~ŋIZZZz~ppΙ3qv|s.$IeYՒʗx)¨X21web1'հ @NE9s4ŲD1L'S)S|;7[ow [ZY7$B,Gǜ4uR]2y֡Qq\ˀt<X/XXSAU[MG!F$"m3G.~OU{ +:UੂTQyt~?i0Hίޡ,kƚ]ϓϱ])<Ǚ1=\=9 d2YFO?żL& FK^ lwΑey9^^G_9z,#˲Ζh1Ln/݆"e`D(8}0d xcIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-power.png000066400000000000000000000035711356401377300303630ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXˏWުd:Ǐ!!VDJ9,# $ o HA""R"B Q2k#3]UUu=YTu=vW}oW_o Hʲ*b_VeIQ՝;w7=8-_y啟gYubrE#M3:Q^}ڵ^z͛7F#~jEܿ,,X,8S5/^{9=4M[o(~tzyww(1I9GUUEb 29Y9G]qg2lε]ǿ|Xŕ$I뚲,(,ˍu]wx*,#@r\n<0|gp(`Zu]EsN:)n]׈&IAkA.\W}p1LuPU=zdׄ8x>}S@ݲ֭[>?չl?[3;.N~7u -i'* -u_@F+9 B;מو\7 =s $޸EJْ)Ȑ}TJ 'c?!'OPWƅIv+L(*gU'oo(bFx!(Jy0Z+мsB`׀ޱ`Yr E|)嚱< -b6a\#ĂkU3f_{B oO:e- ڲ_DjZ\=̓_ <5.L9O9>2O;ΪbP ([mnUĮHa)wSGނ,4Z7?c@T]STLV mfD߼A>qUki3:aki/lXlˀmz%2 5 D'|>Ğe1h<(rj(Fe(" "_L}2 <c {8`Q}޻Q:e:2=e4xvξ [ Z c+D*((>csGzVc&a6T6eFϨƈQZߖ);=@:FGh8j $&$Ź^<vVuEߎLY2AUe_9JozUmlLP̢ᅟO\Ν;nx0f4X,HY1#MS<'MSbK\Y!9wuqB/%pF#LDݩg=3V8e~,It{Bi~Mm{0qxܼp8d8N )k-k-"rjbӔ>l6+pom6vxxXt !mfh '**EIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-print-notifications.png000066400000000000000000000031631356401377300332270ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATX_w?fP6 ]0"jm41>M46FEӤ}C}PXkTTZ46AH4V]B@l nw²woug{ݻ'{g~3s{U$WS< cǎ{̽{mb־bq>W<]v_vEa <TʉWB\ܖm 0Y[cnǎ;H h! Ex߱ta8Qu붾߲iywo0+KzuGDǾٙɠ SEB Q`ncffXvmx HFgg)&TA @DT@Mɸ2<{rwfgg+ @ɀx6 XEU4SDd@2}C``fq6RK/g-5ʿƽjBCXFt!$$UP>6 * d2_:pz׿O^qm߲KSo[?3:{moQ#mQpoa4D_ᆵ}GV\5:{ǖmݼ"Z@?ߌdo򬫻+LM{nj S]\UɃ;~Coz=C^|jtlYʱF':[Ɓ~ ǧUk]/}хtMn P-UA;ACi4.&g[ozm@}|˻ng483y?4P_F'y}zxeHy0Gx_='w߾O}壧w#4d`f190KXŌBF†7Nxnߑ{hĪnN^ہ"<0#  fy^rc'^V1s8Y Ez+fdk3#^RSMwnaǰŸW,I TXQBtNk5m!ՈcXN-ox,ZVw]|5bJCȄ<b$SuL zj8f)BsWw9yaYPptx?/`ZPZMUuȇ;X˲-"/jS'O- ꍣ[]%oVf[>qY"Pjww_v|֡=j9XT$"qZS402l@] P;sss'(αKȑS@OJ_ !4lo$@t:ξ}>QP9,..WSD[oZ!:ʷc={._Ƴ~3CUe9O^=ׯ@D8vl =@ 0@fqmv @sP2 >U* nuY̦"pG}Sӻh6,,D3 =!TRoM48y>D5N΍Fnǭw_! |Q nN>qÜ:u;Z~sc}Sx bd`PC9{D ,"s_dlAedYFcyye:y9q䧟`i˛ъ󨁗MbҦ>{8C B!>,b玽>j:]ͪr 00e,14b!`Ŵ";S%gXJ>\JB^ Hqj 50QL˺VJSAt 9N>#+Yea$2"0㜉wg؄VVVcccR%v;=a.JcnCsss4 gf;㸺Z$IHzN$j5jQU9WnVJ;}\ `~8Y~\@. XO4{*pIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-sound.png000066400000000000000000000040361356401377300303540ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXŗ[lgf;ޫwY,cp*$R@@r)K+*UTU&C U5TUPBPHEM R [{gv朙> <Fhw;gu8oM]׳:!K\)eݼyz7@ØQYpᛣPq|yy\.R*~|aDӴh =m=nnR~yh40Mt:i8 mc&D 6BA h"9JC0J))JtuuQ.1 ]ףRJz}t lƶmn߾Y/<"p>+aJ{Yg@F <2ccc8/E.hl^!ϓ^ƪ*$R 6EfffOj;::pׯSTk\?_~ DM`&R//|r-[ӧ00*W*ػw/8.]T*L&Y!򻟜}F7 6L&~V^M:fϞ=VJ%<qbppbH&a||G憅h-~! !\0 /frreYXŝ;wfѢER)۷A=JP"a*I&,Y˲@4떔FE* !r jD"bN/T*E2DJo$ 2LtQ}?* Gu%q8aqzt#K=睦iyz[@1;|5kl4M3~:69dh^Xx26ib9fi/$IENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-wacom.png000066400000000000000000000024441356401377300303330ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXŗOSY?^[SĆEIcCB’0.ݘ1 &" 1ꂕ15lƿa6%a1"FPDikiNZi}YW~Pf=={)_yرӧ,jUJ!hLB$TB!D!1Fk1ԧc<)e)%޽ʕ+@ z{{o޼9ֶNR񷰤K$#ccc5  Z`;`A~`y{]XJrjbȋ/ZU_\AbؖICT"8=== ,l1 ^z9%@. wB@.# Dxu]޿Ǐ'N`-7.TR֚L&ãGB1!@m)H| ϟ?Ç s,뫿M>,P)z*& .ZmƘmB$333\~"X,R.<cm,@G\x099IWWݣyh/CZk$ 144ٳgqBAZ۷MxwﲸH>'oTk͇m9B"f\@)nO]skk+m7C,B)dٖ{Pҿ, (VCcm!`'^۶>~k׮i/ N)rE ($oݺ̙_`Fcqq۪L\֯_^|8?-@Uq0d<ْʸ TodIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-xrandr.png000066400000000000000000000027511356401377300305240ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<fIDATXŖˏW[ӏqq"@#/XE Hl! ;DBl@R$$+A ("2,20#i,nUM6Bx;]ꪞ:}gGUVϴ/_ڵky>t<@?+?Op}T׾Ǖ+W!m@geok43;1 ̺r47u7_}A 1Fbo|ܸ*"W4ux|e677Y__W^9a֜9L ghDpxxC H:kTBѧP}ˀ`~o3i-_"1BHBa}~ APtHknﲐ2}Pa 1-jԡ*c:ae>B֣ڧ,Kʪ%UUb{SǦ%!Yb@oۨ EQP%UY,咪8{,ŢořKE1uCh DR, `6QKb E3Ww >M@wZM+64U>{#EDDQZ $Os->5QȊc= ?σ0u Y ˂#\Ҟ#U Ǻ PC$*fƩSӧQQ)EmLj 3ι_qbvmd] S({ҷɗ(ppQ03[c~ŋIZZZz~ppΙ3qv|s.$IeYՒʗx)¨X21web1'հ @NE9s4ŲD1L'S)S|;7[ow [ZY7$B,Gǜ4uR]2y֡Qq\ˀt<X/XXSAU[MG!F$"m3G.~OU{ +:UੂTQyt~?i0Hίޡ,kƚ]ϓϱ])<Ǚ1=\=9 d2YFO?żL& FK^ lwΑey9^^G_9z,#˲Ζh1Ln/݆"e`D(8}0d xcIENDB`cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/32x32/apps/csd-xsettings.png000066400000000000000000000025451356401377300312570ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDATXŗ?hIZK$K,%X$%\i[VHW+RpM\"8CB\ęCvH%ْv5s5ZqH}9 !R^Z}TlF&GLd3-It8Z vm~vml:'鬔NY^^Zv#Q4c3&ٳgZ-.^ȕ+WyfO\6L2qG-h4"˙9c=?~6;O0o޼asshN#3xZqA뺆2"z1ۼ~FAXȀƧކ:L&˖q( J88!(D!]~64<8fRȻL &ԡ(DmlO.wH)#U) C  S󘝝d?{>WBwۯMJucMMMl6j(#T  0ͦua ._ ֯o߾=L\.GPh4~)͂}1繹9i7^7\]]hR @L;{$JNT$p\ cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-a11y-settings.svg000066400000000000000000000247511356401377300326430ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-automount.svg000066400000000000000000000511671356401377300322660ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-background.svg000066400000000000000000001205501356401377300323430ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-clipboard.svg000066400000000000000000000407341356401377300321700ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-color.svg000066400000000000000000003076251356401377300313540ustar00rootroot00000000000000 image/svg+xml Lapo Calamandrei keyboard keys configure cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-cursor.svg000066400000000000000000000407341356401377300315460ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-datetime.svg000066400000000000000000001277601356401377300320320ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-housekeeping.svg000066400000000000000000001061271356401377300327160ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-keyboard.svg000066400000000000000000001103051356401377300320210ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-media-keys.svg000066400000000000000000001221031356401377300322500ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-mouse.svg000066400000000000000000000277701356401377300313660ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-orientation.svg000066400000000000000000000243601356401377300325610ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-power.svg000066400000000000000000000304511356401377300313600ustar00rootroot00000000000000 csd-print-notifications.svg000066400000000000000000002153751356401377300341620ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-printer.svg000066400000000000000000006574471356401377300317330ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-screensaver-proxy.svg000066400000000000000000000660531356401377300337320ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-sound.svg000066400000000000000000000353551356401377300313640ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-wacom.svg000066400000000000000000002213751356401377300313410ustar00rootroot00000000000000 image/svg+xml cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-xrandr.svg000066400000000000000000000243601356401377300315240ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/files/usr/share/icons/hicolor/scalable/apps/csd-xsettings.svg000066400000000000000000000347171356401377300322650ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/makepot000077500000000000000000000002671356401377300200240ustar00rootroot00000000000000#!/bin/bash xgettext --language=C --keyword=_ --keyword=N_ --output=cinnamon-settings-daemon.pot cinnamon-settings-daemon/*.c cinnamon-settings-daemon/*.h plugins/*/*.c plugins/*/*.h cinnamon-settings-daemon-4.4.0/plugins/000077500000000000000000000000001356401377300201125ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/Makefile.am000066400000000000000000000012711356401377300221470ustar00rootroot00000000000000NULL = enabled_plugins = \ a11y-keyboard \ a11y-settings \ automount \ background \ clipboard \ color \ cursor \ dummy \ datetime \ power \ housekeeping \ keyboard \ media-keys \ mouse \ orientation \ screensaver-proxy \ sound \ xrandr \ xsettings \ $(NULL) disabled_plugins = $(NULL) if BUILD_WACOM enabled_plugins += wacom else disabled_plugins += wacom endif if SMARTCARD_SUPPORT enabled_plugins += smartcard else disabled_plugins += smartcard endif if BUILD_PRINT_NOTIFICATIONS enabled_plugins += print-notifications else disabled_plugins += print-notifications endif SUBDIRS = common $(enabled_plugins) DIST_SUBDIRS = $(SUBDIRS) $(disabled_plugins) cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/000077500000000000000000000000001356401377300224635ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/Makefile.am000066400000000000000000000040151356401377300245170ustar00rootroot00000000000000NULL = plugin_name = a11y-keyboard AM_CFLAGS = $(WARN_CFLAGS) gtkbuilderdir = $(pkgdatadir) gtkbuilder_DATA = \ csd-a11y-preferences-dialog.ui \ $(NULL) noinst_PROGRAMS = test-a11y-preferences-dialog libexec_PROGRAMS = csd-a11y-keyboard csd_a11y_keyboard_SOURCES = \ csd-a11y-keyboard-manager.h \ csd-a11y-keyboard-manager.c \ csd-a11y-preferences-dialog.c \ csd-a11y-preferences-dialog.h \ main.c csd_a11y_keyboard_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ $(PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(APPINDICATOR_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_a11y_keyboard_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(LIBNOTIFY_LIBS) \ $(APPINDICATOR_LIBS) \ $(SETTINGS_PLUGIN_LIBS) test_a11y_preferences_dialog_SOURCES = \ csd-a11y-preferences-dialog.c \ csd-a11y-preferences-dialog.h \ test-a11y-preferences-dialog.c \ $(NULL) test_a11y_preferences_dialog_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) test_a11y_preferences_dialog_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) test_a11y_preferences_dialog_LDADD = \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(NULL) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-a11y-keyboard.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-a11y-keyboard.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(gtkbuilder_DATA) \ $(desktop_in_files) \ $(NULL) CLEANFILES = \ $(desktop_DATA) \ $(NULL) DISTCLEANFILES = \ $(desktop_DATA) \ $(NULL) cinnamon-settings-daemon-a11y-keyboard.desktop.in000066400000000000000000000003671356401377300336620ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - a11y-keyboard Exec=@libexecdir@/csd-a11y-keyboard OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/csd-a11y-keyboard-manager.c000066400000000000000000001326611356401377300273700ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-a11y-keyboard-manager.h" #include "csd-a11y-preferences-dialog.h" #define KEYBOARD_A11Y_SCHEMA "org.cinnamon.desktop.a11y.keyboard" #define NOTIFICATION_TIMEOUT 30 #define CSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerPrivate)) struct CsdA11yKeyboardManagerPrivate { guint start_idle_id; int xkbEventBase; GdkDeviceManager *device_manager; guint device_added_id; gboolean stickykeys_shortcut_val; gboolean slowkeys_shortcut_val; GtkWidget *stickykeys_alert; GtkWidget *slowkeys_alert; GtkWidget *preferences_dialog; GtkStatusIcon *status_icon; GSettings *settings; NotifyNotification *notification; }; static void csd_a11y_keyboard_manager_finalize (GObject *object); static void csd_a11y_keyboard_manager_ensure_status_icon (CsdA11yKeyboardManager *manager); static void set_server_from_gsettings (CsdA11yKeyboardManager *manager); G_DEFINE_TYPE (CsdA11yKeyboardManager, csd_a11y_keyboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void device_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdA11yKeyboardManager *manager) { if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) set_server_from_gsettings (manager); } static void set_devicepresence_handler (CsdA11yKeyboardManager *manager) { GdkDeviceManager *device_manager; device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); if (device_manager == NULL) return; manager->priv->device_manager = device_manager; manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (device_added_cb), manager); } static gboolean xkb_enabled (CsdA11yKeyboardManager *manager) { int opcode, errorBase, major, minor; if (!XkbQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &opcode, &manager->priv->xkbEventBase, &errorBase, &major, &minor)) return FALSE; if (!XkbUseExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor)) return FALSE; return TRUE; } static XkbDescRec * get_xkb_desc_rec (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; Status status = Success; gdk_x11_display_error_trap_push (gdk_display_get_default ()); desc = XkbGetMap (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbAllMapComponentsMask, XkbUseCoreKbd); if (desc != NULL) { desc->ctrls = NULL; status = XkbGetControls (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbAllControlsMask, desc); } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); g_return_val_if_fail (desc != NULL, NULL); g_return_val_if_fail (desc->ctrls != NULL, NULL); g_return_val_if_fail (status == Success, NULL); return desc; } static int get_int (GSettings *settings, char const *key) { int res = g_settings_get_int (settings, key); if (res <= 0) { res = 1; } return res; } static gboolean set_int (GSettings *settings, char const *key, int val) { int prev_val; prev_val = g_settings_get_int (settings, key); g_settings_set_int (settings, key, val); if (val != prev_val) { g_debug ("%s changed", key); } return val != prev_val; } static gboolean set_bool (GSettings *settings, char const *key, int val) { gboolean bval = (val != 0); gboolean prev_val; prev_val = g_settings_get_boolean (settings, key); g_settings_set_boolean (settings, key, bval ? TRUE : FALSE); if (bval != prev_val) { g_debug ("%s changed", key); return TRUE; } return (bval != prev_val); } static unsigned long set_clear (gboolean flag, unsigned long value, unsigned long mask) { if (flag) { return value | mask; } return value & ~mask; } static gboolean set_ctrl_from_gsettings (XkbDescRec *desc, GSettings *settings, char const *key, unsigned long mask) { gboolean result = g_settings_get_boolean (settings, key); desc->ctrls->enabled_ctrls = set_clear (result, desc->ctrls->enabled_ctrls, mask); return result; } static void set_server_from_gsettings (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; gboolean enable_accessX; GSettings *settings; cinnamon_settings_profile_start (NULL); desc = get_xkb_desc_rec (manager); if (!desc) { return; } settings = manager->priv->settings; /* general */ enable_accessX = g_settings_get_boolean (settings, "enable"); desc->ctrls->enabled_ctrls = set_clear (enable_accessX, desc->ctrls->enabled_ctrls, XkbAccessXKeysMask); if (set_ctrl_from_gsettings (desc, settings, "timeout-enable", XkbAccessXTimeoutMask)) { desc->ctrls->ax_timeout = get_int (settings, "disable-timeout"); /* disable only the master flag via the server we will disable * the rest on the rebound without affecting GSettings state * don't change the option flags at all. */ desc->ctrls->axt_ctrls_mask = XkbAccessXKeysMask | XkbAccessXFeedbackMask; desc->ctrls->axt_ctrls_values = 0; desc->ctrls->axt_opts_mask = 0; } desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "feature-state-change-beep"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); /* bounce keys */ if (set_ctrl_from_gsettings (desc, settings, "bouncekeys-enable", XkbBounceKeysMask)) { desc->ctrls->debounce_delay = get_int (settings, "bouncekeys-delay"); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "bouncekeys-beep-reject"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask); } /* mouse keys */ if (set_ctrl_from_gsettings (desc, settings, "mousekeys-enable", XkbMouseKeysMask | XkbMouseKeysAccelMask)) { desc->ctrls->mk_interval = 100; /* msec between mousekey events */ desc->ctrls->mk_curve = 50; /* We store pixels / sec, XKB wants pixels / event */ desc->ctrls->mk_max_speed = get_int (settings, "mousekeys-max-speed") / (1000 / desc->ctrls->mk_interval); if (desc->ctrls->mk_max_speed <= 0) desc->ctrls->mk_max_speed = 1; desc->ctrls->mk_time_to_max = get_int (settings, /* events before max */ "mousekeys-accel-time") / desc->ctrls->mk_interval; if (desc->ctrls->mk_time_to_max <= 0) desc->ctrls->mk_time_to_max = 1; desc->ctrls->mk_delay = get_int (settings, /* ms before 1st event */ "mousekeys-init-delay"); } /* slow keys */ if (set_ctrl_from_gsettings (desc, settings, "slowkeys-enable", XkbSlowKeysMask)) { desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-press"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-accept"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-reject"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask); desc->ctrls->slow_keys_delay = get_int (settings, "slowkeys-delay"); /* anything larger than 500 seems to loose all keyboard input */ if (desc->ctrls->slow_keys_delay > 500) desc->ctrls->slow_keys_delay = 500; } /* sticky keys */ if (set_ctrl_from_gsettings (desc, settings, "stickykeys-enable", XkbStickyKeysMask)) { desc->ctrls->ax_options |= XkbAX_LatchToLockMask; desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "stickykeys-two-key-off"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "stickykeys-modifier-beep"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask); } /* g_debug ("CHANGE to : 0x%x", desc->ctrls->enabled_ctrls); g_debug ("CHANGE to : 0x%x (2)", desc->ctrls->ax_options); */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); XkbSetControls (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask | XkbMouseKeysAccelMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask | XkbAccessXFeedbackMask | XkbControlsEnabledMask, desc); XkbFreeKeyboard (desc, XkbAllComponentsMask, True); XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); cinnamon_settings_profile_end (NULL); } static gboolean ax_response_callback (CsdA11yKeyboardManager *manager, GtkWindow *parent, gint response_id, guint revert_controls_mask, gboolean enabled) { GSettings *settings; GdkScreen *screen; GError *err; settings = manager->priv->settings; switch (response_id) { case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_REJECT: case GTK_RESPONSE_CANCEL: /* we're reverting, so we invert sense of 'enabled' flag */ g_debug ("cancelling AccessX request"); if (revert_controls_mask == XkbStickyKeysMask) { g_settings_set_boolean (settings, "stickykeys-enable", !enabled); } else if (revert_controls_mask == XkbSlowKeysMask) { g_settings_set_boolean (settings, "slowkeys-enable", !enabled); } set_server_from_gsettings (manager); break; case GTK_RESPONSE_HELP: if (!parent) screen = gdk_screen_get_default (); else screen = gtk_widget_get_screen (GTK_WIDGET (parent)); err = NULL; if (!gtk_show_uri (screen, "help:gnome-help/a11y", gtk_get_current_event_time(), &err)) { GtkWidget *error_dialog = gtk_message_dialog_new (parent, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("There was an error displaying help: %s"), err->message); g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_window_set_resizable (GTK_WINDOW (error_dialog), FALSE); gtk_widget_show (error_dialog); g_error_free (err); } return FALSE; default: break; } return TRUE; } static void ax_stickykeys_response (GtkDialog *dialog, gint response_id, CsdA11yKeyboardManager *manager) { if (ax_response_callback (manager, GTK_WINDOW (dialog), response_id, XkbStickyKeysMask, manager->priv->stickykeys_shortcut_val)) { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void ax_slowkeys_response (GtkDialog *dialog, gint response_id, CsdA11yKeyboardManager *manager) { if (ax_response_callback (manager, GTK_WINDOW (dialog), response_id, XkbSlowKeysMask, manager->priv->slowkeys_shortcut_val)) { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void maybe_show_status_icon (CsdA11yKeyboardManager *manager) { gboolean show; /* for now, show if accessx is enabled */ show = g_settings_get_boolean (manager->priv->settings, "enable"); if (!show && manager->priv->status_icon == NULL) return; csd_a11y_keyboard_manager_ensure_status_icon (manager); gtk_status_icon_set_visible (manager->priv->status_icon, show); } static void on_notification_closed (NotifyNotification *notification, CsdA11yKeyboardManager *manager) { g_object_unref (manager->priv->notification); manager->priv->notification = NULL; } static void on_slow_keys_action (NotifyNotification *notification, const char *action, CsdA11yKeyboardManager *manager) { gboolean res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = ax_response_callback (manager, NULL, response_id, XkbSlowKeysMask, manager->priv->slowkeys_shortcut_val); if (res) { notify_notification_close (manager->priv->notification, NULL); } } static void on_sticky_keys_action (NotifyNotification *notification, const char *action, CsdA11yKeyboardManager *manager) { gboolean res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = ax_response_callback (manager, NULL, response_id, XkbStickyKeysMask, manager->priv->stickykeys_shortcut_val); if (res) { notify_notification_close (manager->priv->notification, NULL); } } static gboolean ax_slowkeys_warning_post_bubble (CsdA11yKeyboardManager *manager, gboolean enabled) { gboolean res; const char *title; const char *message; GError *error; title = enabled ? _("Slow Keys Turned On") : _("Slow Keys Turned Off"); message = _("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) { return FALSE; } if (manager->priv->slowkeys_alert != NULL) { gtk_widget_destroy (manager->priv->slowkeys_alert); } if (manager->priv->notification != NULL) { notify_notification_close (manager->priv->notification, NULL); } csd_a11y_keyboard_manager_ensure_status_icon (manager); manager->priv->notification = notify_notification_new (title, message, "preferences-desktop-accessibility-symbolic"); notify_notification_set_app_name (manager->priv->notification, _("Universal Access")); notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_set_hint (manager->priv->notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_add_action (manager->priv->notification, "reject", enabled ? _("Turn Off") : _("Turn On"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); notify_notification_add_action (manager->priv->notification, "accept", enabled ? _("Leave On") : _("Leave Off"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); g_signal_connect (manager->priv->notification, "closed", G_CALLBACK (on_notification_closed), manager); error = NULL; res = notify_notification_show (manager->priv->notification, &error); if (! res) { g_warning ("CsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->priv->notification, NULL); } return res; } static void ax_slowkeys_warning_post_dialog (CsdA11yKeyboardManager *manager, gboolean enabled) { const char *title; const char *message; title = enabled ? _("Slow Keys Turned On") : _("Slow Keys Turned Off"); message = _("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); if (manager->priv->slowkeys_alert != NULL) { gtk_widget_show (manager->priv->slowkeys_alert); return; } manager->priv->slowkeys_alert = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->slowkeys_alert), "%s", message); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), GTK_STOCK_HELP, GTK_RESPONSE_HELP); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), enabled ? _("_Turn Off") : _("_Turn On"), GTK_RESPONSE_REJECT); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), enabled ? _("_Leave On") : _("_Leave Off"), GTK_RESPONSE_ACCEPT); gtk_window_set_title (GTK_WINDOW (manager->priv->slowkeys_alert), ""); gtk_window_set_icon_name (GTK_WINDOW (manager->priv->slowkeys_alert), "preferences-desktop-accessibility"); gtk_dialog_set_default_response (GTK_DIALOG (manager->priv->slowkeys_alert), GTK_RESPONSE_ACCEPT); g_signal_connect (manager->priv->slowkeys_alert, "response", G_CALLBACK (ax_slowkeys_response), manager); gtk_widget_show (manager->priv->slowkeys_alert); g_object_add_weak_pointer (G_OBJECT (manager->priv->slowkeys_alert), (gpointer*) &manager->priv->slowkeys_alert); } static void ax_slowkeys_warning_post (CsdA11yKeyboardManager *manager, gboolean enabled) { manager->priv->slowkeys_shortcut_val = enabled; /* alway try to show something */ if (! ax_slowkeys_warning_post_bubble (manager, enabled)) { ax_slowkeys_warning_post_dialog (manager, enabled); } } static gboolean ax_stickykeys_warning_post_bubble (CsdA11yKeyboardManager *manager, gboolean enabled) { #if 1 gboolean res; const char *title; const char *message; GError *error; title = enabled ? _("Sticky Keys Turned On") : _("Sticky Keys Turned Off"); message = enabled ? _("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) { return FALSE; } if (manager->priv->slowkeys_alert != NULL) { gtk_widget_destroy (manager->priv->slowkeys_alert); } if (manager->priv->notification != NULL) { notify_notification_close (manager->priv->notification, NULL); } csd_a11y_keyboard_manager_ensure_status_icon (manager); manager->priv->notification = notify_notification_new (title, message, "preferences-desktop-accessibility-symbolic"); notify_notification_set_app_name (manager->priv->notification, _("Universal Access")); notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_set_hint (manager->priv->notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_add_action (manager->priv->notification, "reject", enabled ? _("Turn Off") : _("Turn On"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); notify_notification_add_action (manager->priv->notification, "accept", enabled ? _("Leave On") : _("Leave Off"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); g_signal_connect (manager->priv->notification, "closed", G_CALLBACK (on_notification_closed), manager); error = NULL; res = notify_notification_show (manager->priv->notification, &error); if (! res) { g_warning ("CsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->priv->notification, NULL); } return res; #endif /* 1 */ } static void ax_stickykeys_warning_post_dialog (CsdA11yKeyboardManager *manager, gboolean enabled) { const char *title; const char *message; title = enabled ? _("Sticky Keys Turned On") : _("Sticky Keys Turned Off"); message = enabled ? _("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->priv->stickykeys_alert != NULL) { gtk_widget_show (manager->priv->stickykeys_alert); return; } manager->priv->stickykeys_alert = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->stickykeys_alert), "%s", message); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), GTK_STOCK_HELP, GTK_RESPONSE_HELP); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), enabled ? _("_Turn Off") : _("_Turn On"), GTK_RESPONSE_REJECT); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), enabled ? _("_Leave On") : _("_Leave Off"), GTK_RESPONSE_ACCEPT); gtk_window_set_title (GTK_WINDOW (manager->priv->stickykeys_alert), ""); gtk_window_set_icon_name (GTK_WINDOW (manager->priv->stickykeys_alert), "preferences-desktop-accessibility"); gtk_dialog_set_default_response (GTK_DIALOG (manager->priv->stickykeys_alert), GTK_RESPONSE_ACCEPT); g_signal_connect (manager->priv->stickykeys_alert, "response", G_CALLBACK (ax_stickykeys_response), manager); gtk_widget_show (manager->priv->stickykeys_alert); g_object_add_weak_pointer (G_OBJECT (manager->priv->stickykeys_alert), (gpointer*) &manager->priv->stickykeys_alert); } static void ax_stickykeys_warning_post (CsdA11yKeyboardManager *manager, gboolean enabled) { manager->priv->stickykeys_shortcut_val = enabled; /* alway try to show something */ if (! ax_stickykeys_warning_post_bubble (manager, enabled)) { ax_stickykeys_warning_post_dialog (manager, enabled); } } static void set_gsettings_from_server (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; gboolean changed = FALSE; gboolean slowkeys_changed; gboolean stickykeys_changed; GSettings *settings; desc = get_xkb_desc_rec (manager); if (! desc) { return; } /* Create a new one, so that only those settings * are delayed */ settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); g_settings_delay (settings); /* fprintf (stderr, "changed to : 0x%x\n", desc->ctrls->enabled_ctrls); fprintf (stderr, "changed to : 0x%x (2)\n", desc->ctrls->ax_options); */ changed |= set_bool (settings, "enable", desc->ctrls->enabled_ctrls & XkbAccessXKeysMask); changed |= set_bool (settings, "feature-state-change-beep", desc->ctrls->ax_options & (XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask)); changed |= set_bool (settings, "timeout-enable", desc->ctrls->enabled_ctrls & XkbAccessXTimeoutMask); changed |= set_int (settings, "disable-timeout", desc->ctrls->ax_timeout); changed |= set_bool (settings, "bouncekeys-enable", desc->ctrls->enabled_ctrls & XkbBounceKeysMask); changed |= set_int (settings, "bouncekeys-delay", desc->ctrls->debounce_delay); changed |= set_bool (settings, "bouncekeys-beep-reject", desc->ctrls->ax_options & XkbAX_BKRejectFBMask); changed |= set_bool (settings, "mousekeys-enable", desc->ctrls->enabled_ctrls & XkbMouseKeysMask); changed |= set_int (settings, "mousekeys-max-speed", desc->ctrls->mk_max_speed * (1000 / desc->ctrls->mk_interval)); /* NOTE : mk_time_to_max is measured in events not time */ changed |= set_int (settings, "mousekeys-accel-time", desc->ctrls->mk_time_to_max * desc->ctrls->mk_interval); changed |= set_int (settings, "mousekeys-init-delay", desc->ctrls->mk_delay); slowkeys_changed = set_bool (settings, "slowkeys-enable", desc->ctrls->enabled_ctrls & XkbSlowKeysMask); changed |= set_bool (settings, "slowkeys-beep-press", desc->ctrls->ax_options & XkbAX_SKPressFBMask); changed |= set_bool (settings, "slowkeys-beep-accept", desc->ctrls->ax_options & XkbAX_SKAcceptFBMask); changed |= set_bool (settings, "slowkeys-beep-reject", desc->ctrls->ax_options & XkbAX_SKRejectFBMask); changed |= set_int (settings, "slowkeys-delay", desc->ctrls->slow_keys_delay); stickykeys_changed = set_bool (settings, "stickykeys-enable", desc->ctrls->enabled_ctrls & XkbStickyKeysMask); changed |= set_bool (settings, "stickykeys-two-key-off", desc->ctrls->ax_options & XkbAX_TwoKeysMask); changed |= set_bool (settings, "stickykeys-modifier-beep", desc->ctrls->ax_options & XkbAX_StickyKeysFBMask); if (!changed && stickykeys_changed ^ slowkeys_changed) { /* * sticky or slowkeys has changed, singly, without our intervention. * 99% chance this is due to a keyboard shortcut being used. * we need to detect via this hack until we get * XkbAXN_AXKWarning notifications working (probable XKB bug), * at which time we can directly intercept such shortcuts instead. * See cb_xkb_event_filter () below. */ /* sanity check: are keyboard shortcuts available? */ if (desc->ctrls->enabled_ctrls & XkbAccessXKeysMask) { if (slowkeys_changed) { ax_slowkeys_warning_post (manager, desc->ctrls->enabled_ctrls & XkbSlowKeysMask); } else { ax_stickykeys_warning_post (manager, desc->ctrls->enabled_ctrls & XkbStickyKeysMask); } } } XkbFreeKeyboard (desc, XkbAllComponentsMask, True); g_settings_apply (settings); g_object_unref (settings); } static GdkFilterReturn cb_xkb_event_filter (GdkXEvent *xevent, GdkEvent *ignored1, CsdA11yKeyboardManager *manager) { XEvent *xev = (XEvent *) xevent; XkbEvent *xkbEv = (XkbEvent *) xevent; /* 'event_type' is set to zero on notifying us of updates in * response to client requests (including our own) and non-zero * to notify us of key/mouse events causing changes (like * pressing shift 5 times to enable sticky keys). * * We only want to update GSettings when it's in response to an * explicit user input event, so require a non-zero event_type. */ if (xev->xany.type == (manager->priv->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbControlsNotify && xkbEv->ctrls.event_type != 0) { g_debug ("XKB state changed"); set_gsettings_from_server (manager); } else if (xev->xany.type == (manager->priv->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbAccessXNotify) { if (xkbEv->accessx.detail == XkbAXN_AXKWarning) { g_debug ("About to turn on an AccessX feature from the keyboard!"); /* * TODO: when XkbAXN_AXKWarnings start working, we need to * invoke ax_keys_warning_dialog_run here instead of in * set_gsettings_from_server(). */ } } return GDK_FILTER_CONTINUE; } static void keyboard_callback (GSettings *settings, const char *key, CsdA11yKeyboardManager *manager) { set_server_from_gsettings (manager); maybe_show_status_icon (manager); } static gboolean start_a11y_keyboard_idle_cb (CsdA11yKeyboardManager *manager) { guint event_mask; g_debug ("Starting a11y_keyboard manager"); cinnamon_settings_profile_start (NULL); if (!xkb_enabled (manager)) goto out; manager->priv->settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (keyboard_callback), manager); set_devicepresence_handler (manager); event_mask = XkbControlsNotifyMask; event_mask |= XkbAccessXNotifyMask; /* make default when AXN_AXKWarning works */ /* be sure to init before starting to monitor the server */ set_server_from_gsettings (manager); XkbSelectEvents (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, event_mask, event_mask); gdk_window_add_filter (NULL, (GdkFilterFunc) cb_xkb_event_filter, manager); maybe_show_status_icon (manager); out: cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_a11y_keyboard_manager_start (CsdA11yKeyboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_a11y_keyboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_a11y_keyboard_manager_stop (CsdA11yKeyboardManager *manager) { CsdA11yKeyboardManagerPrivate *p = manager->priv; g_debug ("Stopping a11y_keyboard manager"); if (p->start_idle_id != 0) { g_source_remove (p->start_idle_id); p->start_idle_id = 0; } if (p->device_manager != NULL) { g_signal_handler_disconnect (p->device_manager, p->device_added_id); p->device_manager = NULL; } if (p->status_icon) { gtk_status_icon_set_visible (p->status_icon, FALSE); p->status_icon = NULL; } if (p->settings != NULL) { g_signal_handlers_disconnect_by_func (p->settings, keyboard_callback, manager); g_object_unref (p->settings); p->settings = NULL; } gdk_window_remove_filter (NULL, (GdkFilterFunc) cb_xkb_event_filter, manager); if (p->slowkeys_alert != NULL) { gtk_widget_destroy (p->slowkeys_alert); p->slowkeys_alert = NULL; } if (p->stickykeys_alert != NULL) { gtk_widget_destroy (p->stickykeys_alert); p->stickykeys_alert = NULL; } p->slowkeys_shortcut_val = FALSE; p->stickykeys_shortcut_val = FALSE; } static GObject * csd_a11y_keyboard_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11yKeyboardManager *a11y_keyboard_manager; a11y_keyboard_manager = CSD_A11Y_KEYBOARD_MANAGER (G_OBJECT_CLASS (csd_a11y_keyboard_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_keyboard_manager); } static void csd_a11y_keyboard_manager_class_init (CsdA11yKeyboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_keyboard_manager_constructor; object_class->finalize = csd_a11y_keyboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdA11yKeyboardManagerPrivate)); } static void on_preferences_dialog_response (GtkDialog *dialog, int response, CsdA11yKeyboardManager *manager) { g_signal_handlers_disconnect_by_func (dialog, on_preferences_dialog_response, manager); gtk_widget_destroy (GTK_WIDGET (dialog)); manager->priv->preferences_dialog = NULL; } static void on_status_icon_activate (GtkStatusIcon *status_icon, CsdA11yKeyboardManager *manager) { if (manager->priv->preferences_dialog == NULL) { manager->priv->preferences_dialog = csd_a11y_preferences_dialog_new (); g_signal_connect (manager->priv->preferences_dialog, "response", G_CALLBACK (on_preferences_dialog_response), manager); gtk_window_present (GTK_WINDOW (manager->priv->preferences_dialog)); } else { g_signal_handlers_disconnect_by_func (manager->priv->preferences_dialog, on_preferences_dialog_response, manager); gtk_widget_destroy (GTK_WIDGET (manager->priv->preferences_dialog)); manager->priv->preferences_dialog = NULL; } } static void on_status_icon_popup_menu (GtkStatusIcon *status_icon, guint button, guint activate_time, CsdA11yKeyboardManager *manager) { on_status_icon_activate (status_icon, manager); } static void csd_a11y_keyboard_manager_ensure_status_icon (CsdA11yKeyboardManager *manager) { cinnamon_settings_profile_start (NULL); if (!manager->priv->status_icon) { manager->priv->status_icon = gtk_status_icon_new_from_icon_name ("preferences-desktop-accessibility"); gtk_status_icon_set_name (manager->priv->status_icon, "a11y-keyboard"); g_signal_connect (manager->priv->status_icon, "activate", G_CALLBACK (on_status_icon_activate), manager); g_signal_connect (manager->priv->status_icon, "popup-menu", G_CALLBACK (on_status_icon_popup_menu), manager); } cinnamon_settings_profile_end (NULL); } static void csd_a11y_keyboard_manager_init (CsdA11yKeyboardManager *manager) { manager->priv = CSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE (manager); } static void csd_a11y_keyboard_manager_finalize (GObject *object) { CsdA11yKeyboardManager *a11y_keyboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_KEYBOARD_MANAGER (object)); a11y_keyboard_manager = CSD_A11Y_KEYBOARD_MANAGER (object); g_return_if_fail (a11y_keyboard_manager->priv != NULL); if (a11y_keyboard_manager->priv->start_idle_id != 0) { g_source_remove (a11y_keyboard_manager->priv->start_idle_id); a11y_keyboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_a11y_keyboard_manager_parent_class)->finalize (object); } CsdA11yKeyboardManager * csd_a11y_keyboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_A11Y_KEYBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_A11Y_KEYBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/csd-a11y-keyboard-manager.h000066400000000000000000000047501356401377300273720ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_A11Y_KEYBOARD_MANAGER_H #define __CSD_A11Y_KEYBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_KEYBOARD_MANAGER (csd_a11y_keyboard_manager_get_type ()) #define CSD_A11Y_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManager)) #define CSD_A11Y_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerClass)) #define CSD_IS_A11Y_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER)) #define CSD_IS_A11Y_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_KEYBOARD_MANAGER)) #define CSD_A11Y_KEYBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerClass)) typedef struct CsdA11yKeyboardManagerPrivate CsdA11yKeyboardManagerPrivate; typedef struct { GObject parent; CsdA11yKeyboardManagerPrivate *priv; } CsdA11yKeyboardManager; typedef struct { GObjectClass parent_class; } CsdA11yKeyboardManagerClass; GType csd_a11y_keyboard_manager_get_type (void); CsdA11yKeyboardManager *csd_a11y_keyboard_manager_new (void); gboolean csd_a11y_keyboard_manager_start (CsdA11yKeyboardManager *manager, GError **error); void csd_a11y_keyboard_manager_stop (CsdA11yKeyboardManager *manager); G_END_DECLS #endif /* __CSD_A11Y_KEYBOARD_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.c000066400000000000000000000421541356401377300277130ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "csd-a11y-preferences-dialog.h" #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" #define CSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogPrivate)) #define GTKBUILDER_UI_FILE "csd-a11y-preferences-dialog.ui" #define INTERFACE_SCHEMA "org.cinnamon.desktop.interface" #define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" #define KEYBOARD_A11Y_SCHEMA "org.cinnamon.desktop.a11y.keyboard" #define KEY_STICKY_KEYS_ENABLED "stickykeys-enable" #define KEY_BOUNCE_KEYS_ENABLED "bouncekeys-enable" #define KEY_SLOW_KEYS_ENABLED "slowkeys-enable" #define KEY_AT_SCHEMA "org.cinnamon.desktop.a11y.applications" #define KEY_AT_SCREEN_KEYBOARD_ENABLED "screen-keyboard-enabled" #define KEY_AT_SCREEN_MAGNIFIER_ENABLED "screen-magnifier-enabled" #define KEY_AT_SCREEN_READER_ENABLED "screen-reader-enabled" #define DPI_FACTOR_LARGE 1.25 #define DPI_FACTOR_LARGER 1.5 #define DPI_FACTOR_LARGEST 2.0 #define KEY_GTK_THEME "gtk-theme" #define KEY_ICON_THEME "icon-theme" #define KEY_METACITY_THEME "theme" #define HIGH_CONTRAST_THEME "HighContrast" struct CsdA11yPreferencesDialogPrivate { GtkWidget *large_print_checkbutton; GtkWidget *high_contrast_checkbutton; GSettings *a11y_settings; GSettings *interface_settings; GSettings *apps_settings; }; enum { PROP_0, }; static void csd_a11y_preferences_dialog_finalize (GObject *object); G_DEFINE_TYPE (CsdA11yPreferencesDialog, csd_a11y_preferences_dialog, GTK_TYPE_DIALOG) static GObject * csd_a11y_preferences_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11yPreferencesDialog *a11y_preferences_dialog; a11y_preferences_dialog = CSD_A11Y_PREFERENCES_DIALOG (G_OBJECT_CLASS (csd_a11y_preferences_dialog_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_preferences_dialog); } static void csd_a11y_preferences_dialog_class_init (CsdA11yPreferencesDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_preferences_dialog_constructor; object_class->finalize = csd_a11y_preferences_dialog_finalize; g_type_class_add_private (klass, sizeof (CsdA11yPreferencesDialogPrivate)); } static void on_response (CsdA11yPreferencesDialog *dialog, gint response_id) { switch (response_id) { default: break; } } static gboolean config_get_large_print (CsdA11yPreferencesDialog *dialog, gboolean *is_writable) { gboolean ret; gdouble factor; factor = g_settings_get_double (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); ret = (factor > 1.0); *is_writable = g_settings_is_writable (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); return ret; } static void config_set_large_print (CsdA11yPreferencesDialog *dialog, gboolean enabled) { if (enabled) g_settings_set_double (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR, DPI_FACTOR_LARGER); else g_settings_reset (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); } static gboolean config_get_high_contrast (CsdA11yPreferencesDialog *dialog) { gboolean ret; char *gtk_theme; ret = FALSE; gtk_theme = g_settings_get_string (dialog->priv->interface_settings, KEY_GTK_THEME); if (gtk_theme != NULL && g_str_equal (gtk_theme, HIGH_CONTRAST_THEME)) { ret = TRUE; } g_free (gtk_theme); return ret; } static void config_set_high_contrast (gboolean enabled) { GSettings *settings; GSettings *wm_settings; settings = g_settings_new ("org.cinnamon.desktop.interface"); wm_settings = g_settings_new ("org.cinnamon.desktop.wm.preferences"); if (enabled) { g_settings_set_string (settings, KEY_GTK_THEME, HIGH_CONTRAST_THEME); g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); /* there isn't a high contrast metacity theme afaik */ } else { g_settings_reset (settings, KEY_GTK_THEME); g_settings_reset (settings, KEY_ICON_THEME); g_settings_reset (wm_settings, KEY_METACITY_THEME); } g_object_unref (settings); g_object_unref (wm_settings); } static gboolean config_have_at_gsettings_condition (const char *condition) { GDBusProxy *sm_proxy; GDBusConnection *connection; GError *error; GVariant *res; gboolean is_handled; error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (connection == NULL) { g_warning ("Unable to connect to session bus: %s", error->message); g_error_free (error); return FALSE; } sm_proxy = g_dbus_proxy_new_sync (connection, 0, NULL, SM_DBUS_NAME, SM_DBUS_PATH, SM_DBUS_INTERFACE, NULL, &error); if (sm_proxy == NULL) { g_warning ("Unable to get proxy for %s: %s", SM_DBUS_NAME, error->message); g_error_free (error); return FALSE; } is_handled = FALSE; res = g_dbus_proxy_call_sync (sm_proxy, "IsAutostartConditionHandled", g_variant_new ("(s)", condition), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (! res) { g_warning ("Unable to call IsAutostartConditionHandled (%s): %s", condition, error->message); } if (g_variant_is_of_type (res, G_VARIANT_TYPE_BOOLEAN)) { is_handled = g_variant_get_boolean (res); } g_object_unref (sm_proxy); g_variant_unref (res); return is_handled; } static void on_high_contrast_checkbutton_toggled (GtkToggleButton *button, CsdA11yPreferencesDialog *dialog) { config_set_high_contrast (gtk_toggle_button_get_active (button)); } static void on_large_print_checkbutton_toggled (GtkToggleButton *button, CsdA11yPreferencesDialog *dialog) { config_set_large_print (dialog, gtk_toggle_button_get_active (button)); } static void ui_set_high_contrast (CsdA11yPreferencesDialog *dialog, gboolean enabled) { gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->high_contrast_checkbutton)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->high_contrast_checkbutton), enabled); } } static void ui_set_large_print (CsdA11yPreferencesDialog *dialog, gboolean enabled) { gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->large_print_checkbutton)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->large_print_checkbutton), enabled); } } static void setup_dialog (CsdA11yPreferencesDialog *dialog, GtkBuilder *builder) { GtkWidget *widget; gboolean enabled; gboolean is_writable; GSettings *settings; dialog->priv->a11y_settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); settings = dialog->priv->a11y_settings; dialog->priv->interface_settings = g_settings_new (INTERFACE_SCHEMA); dialog->priv->apps_settings = g_settings_new (KEY_AT_SCHEMA); /* Sticky keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "sticky_keys_checkbutton")); g_settings_bind (settings, KEY_STICKY_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_STICKY_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* Bounce keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "bounce_keys_checkbutton")); g_settings_bind (settings, KEY_BOUNCE_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_BOUNCE_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* Slow keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "slow_keys_checkbutton")); g_settings_bind (settings, KEY_SLOW_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_SLOW_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* High contrast */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_checkbutton")); g_settings_bind_writable (dialog->priv->interface_settings, KEY_GTK_THEME, G_OBJECT (widget), "sensitive", TRUE); dialog->priv->high_contrast_checkbutton = widget; g_signal_connect (widget, "toggled", G_CALLBACK (on_high_contrast_checkbutton_toggled), dialog); enabled = config_get_high_contrast (dialog); ui_set_high_contrast (dialog, enabled); /* On-screen keyboard */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_keyboard_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_KEYBOARD_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_KEYBOARD_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_KEYBOARD_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Screen reader */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_reader_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_READER_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_READER_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_READER_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Screen magnifier */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_magnifier_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_MAGNIFIER_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_MAGNIFIER_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_MAGNIFIER_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Large print */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "large_print_checkbutton")); dialog->priv->large_print_checkbutton = widget; g_signal_connect (widget, "toggled", G_CALLBACK (on_large_print_checkbutton_toggled), dialog); enabled = config_get_large_print (dialog, &is_writable); ui_set_large_print (dialog, enabled); if (! is_writable) { gtk_widget_set_sensitive (widget, FALSE); } } static void csd_a11y_preferences_dialog_init (CsdA11yPreferencesDialog *dialog) { static const gchar *ui_file_path = GTKBUILDERDIR "/" GTKBUILDER_UI_FILE; gchar *objects[] = {"main_box", NULL}; GError *error = NULL; GtkBuilder *builder; dialog->priv = CSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE (dialog); builder = gtk_builder_new (); gtk_builder_set_translation_domain (builder, PACKAGE); if (gtk_builder_add_objects_from_file (builder, ui_file_path, objects, &error) == 0) { g_warning ("Could not load A11Y-UI: %s", error->message); g_error_free (error); } else { GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (builder, "main_box")); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), widget); gtk_container_set_border_width (GTK_CONTAINER (widget), 12); setup_dialog (dialog, builder); } g_object_unref (builder); gtk_container_set_border_width (GTK_CONTAINER (dialog), 12); gtk_window_set_title (GTK_WINDOW (dialog), _("Universal Access Preferences")); gtk_window_set_icon_name (GTK_WINDOW (dialog), "preferences-desktop-accessibility"); g_object_set (dialog, "resizable", FALSE, NULL); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_signal_connect (dialog, "response", G_CALLBACK (on_response), dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); } static void csd_a11y_preferences_dialog_finalize (GObject *object) { CsdA11yPreferencesDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_PREFERENCES_DIALOG (object)); dialog = CSD_A11Y_PREFERENCES_DIALOG (object); g_return_if_fail (dialog->priv != NULL); g_object_unref (dialog->priv->a11y_settings); g_object_unref (dialog->priv->interface_settings); g_object_unref (dialog->priv->apps_settings); G_OBJECT_CLASS (csd_a11y_preferences_dialog_parent_class)->finalize (object); } GtkWidget * csd_a11y_preferences_dialog_new (void) { GObject *object; object = g_object_new (CSD_TYPE_A11Y_PREFERENCES_DIALOG, NULL); return GTK_WIDGET (object); } cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.h000066400000000000000000000044161356401377300277170ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 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 __CSD_A11Y_PREFERENCES_DIALOG_H #define __CSD_A11Y_PREFERENCES_DIALOG_H #include #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_PREFERENCES_DIALOG (csd_a11y_preferences_dialog_get_type ()) #define CSD_A11Y_PREFERENCES_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialog)) #define CSD_A11Y_PREFERENCES_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogClass)) #define CSD_IS_A11Y_PREFERENCES_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG)) #define CSD_IS_A11Y_PREFERENCES_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_PREFERENCES_DIALOG)) #define CSD_A11Y_PREFERENCES_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogClass)) typedef struct CsdA11yPreferencesDialogPrivate CsdA11yPreferencesDialogPrivate; typedef struct { GtkDialog parent; CsdA11yPreferencesDialogPrivate *priv; } CsdA11yPreferencesDialog; typedef struct { GtkDialogClass parent_class; } CsdA11yPreferencesDialogClass; GType csd_a11y_preferences_dialog_get_type (void); GtkWidget * csd_a11y_preferences_dialog_new (void); G_END_DECLS #endif /* __CSD_A11Y_PREFERENCES_DIALOG_H */ cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.ui000066400000000000000000000261171356401377300301070ustar00rootroot00000000000000 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 Universal Access Preferences center-on-parent preferences-desktop-accessibility dialog False True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 10 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 preferences-desktop-accessibility 6 0 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 6 Use on-screen _keyboard True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 0 Use screen _reader True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 1 Use screen _magnifier True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 2 Enhance _contrast in colors True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 3 Make _text larger and easier to read True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 4 _Press keyboard shortcuts one key at a time (Sticky Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 5 _Ignore duplicate keypresses (Bounce Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 6 Press and _hold keys to accept them (Slow Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 7 False False 1 1 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK end gtk-close True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False False 0 False end 0 button1 cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/main.c000066400000000000000000000010541356401377300235530ustar00rootroot00000000000000#define NEW csd_a11y_keyboard_manager_new #define START csd_a11y_keyboard_manager_start #define STOP csd_a11y_keyboard_manager_stop #define MANAGER CsdA11yKeyboardManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-a11y-keyboard-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/a11y-keyboard/test-a11y-preferences-dialog.c000066400000000000000000000031751356401377300301210ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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. * * */ #include "config.h" #include #include #include #include "csd-a11y-preferences-dialog.h" static void test_window (void) { GtkWidget *window; window = csd_a11y_preferences_dialog_new (); gtk_dialog_run (GTK_DIALOG (window)); } int main (int argc, char **argv) { GError *error = NULL; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { fprintf (stderr, "%s", error->message); g_error_free (error); exit (1); } test_window (); return 0; } cinnamon-settings-daemon-4.4.0/plugins/a11y-settings/000077500000000000000000000000001356401377300225235ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/a11y-settings/Makefile.am000066400000000000000000000017321356401377300245620ustar00rootroot00000000000000plugin_name = a11y-settings libexec_PROGRAMS = csd-a11y-settings csd_a11y_settings_SOURCES = \ csd-a11y-settings-manager.h \ csd-a11y-settings-manager.c \ main.c csd_a11y_settings_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_a11y_settings_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-a11y-settings.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-a11y-settings.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-a11y-settings.desktop.in000066400000000000000000000003671356401377300337620ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/a11y-settings[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - a11y-settings Exec=@libexecdir@/csd-a11y-settings OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/a11y-settings/csd-a11y-settings-manager.c000066400000000000000000000411561356401377300274660ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-a11y-settings-manager.h" #define CSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerPrivate)) struct CsdA11ySettingsManagerPrivate { GSettings *interface_settings; GSettings *a11y_apps_settings; GSettings *wm_settings; GSettings *sound_settings; GHashTable *bind_table; }; enum { PROP_0, }; static void csd_a11y_settings_manager_class_init (CsdA11ySettingsManagerClass *klass); static void csd_a11y_settings_manager_init (CsdA11ySettingsManager *a11y_settings_manager); static void csd_a11y_settings_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdA11ySettingsManager, csd_a11y_settings_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; typedef struct { GSettings *settings; gchar *key; } SettingsData; static void settings_data_free (SettingsData *data) { g_object_unref (data->settings); g_free (data->key); } static void bound_key_changed (GSettings *settings, gchar *key, SettingsData *data) { g_signal_handlers_block_matched (G_SETTINGS (data->settings), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, bound_key_changed, NULL); g_settings_set_value (data->settings, data->key, g_settings_get_value (settings, key)); g_signal_handlers_unblock_matched (G_SETTINGS (data->settings), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, bound_key_changed, NULL); } static void bind_keys (CsdA11ySettingsManager *manager, const gchar *schema_id_a, const gchar *key_a, const gchar *schema_id_b, const gchar *key_b) { GSettingsSchemaSource *source = g_settings_schema_source_get_default (); /* We assume any schema_id_a will exist (since it's our's) */ GSettingsSchema *schema = g_settings_schema_source_lookup (source, schema_id_b, FALSE); if (!schema) return; if (!g_settings_schema_has_key (schema, key_b)) return; g_settings_schema_unref (schema); if (!manager->priv->bind_table) { manager->priv->bind_table = g_hash_table_new_full (g_direct_hash, g_str_equal, g_free, g_object_unref); } GSettings *a_settings = NULL; GSettings *b_settings = NULL; a_settings = g_hash_table_lookup (manager->priv->bind_table, schema_id_a); if (!a_settings) { a_settings = g_settings_new (schema_id_a); g_hash_table_insert (manager->priv->bind_table, g_strdup (schema_id_a), a_settings); } b_settings = g_hash_table_lookup (manager->priv->bind_table, schema_id_b); if (!b_settings) { b_settings = g_settings_new (schema_id_b); g_hash_table_insert (manager->priv->bind_table, g_strdup (schema_id_b), b_settings); } /* initial sync */ g_settings_set_value (b_settings, key_b, g_settings_get_value (a_settings, key_a)); gchar *detailed_signal_a = g_strdup_printf ("changed::%s", key_a); gchar *detailed_signal_b = g_strdup_printf ("changed::%s", key_b); SettingsData *data_a = g_slice_new(SettingsData); SettingsData *data_b = g_slice_new(SettingsData); data_a->settings = g_object_ref (a_settings); data_a->key = g_strdup (key_a); data_b->settings = g_object_ref (b_settings); data_b->key = g_strdup (key_b); g_signal_connect_data (a_settings, detailed_signal_a, G_CALLBACK (bound_key_changed), data_b, (GClosureNotify) settings_data_free, 0); g_signal_connect_data (b_settings, detailed_signal_b, G_CALLBACK (bound_key_changed), data_a, (GClosureNotify) settings_data_free, 0); g_free (detailed_signal_a); g_free (detailed_signal_b); } #define CINNAMON_A11Y_APP_SCHEMA "org.cinnamon.desktop.a11y.applications" #define CINNAMON_DESKTOP_SCHEMA "org.cinnamon.desktop.interface" #define CINNAMON_A11Y_MOUSE_SCHEMA "org.cinnamon.desktop.a11y.mouse" #define GNOME_A11Y_APP_SCHEMA "org.gnome.desktop.a11y.applications" #define GNOME_DESKTOP_SCHEMA "org.gnome.desktop.interface" #define GNOME_A11Y_MOUSE_SCHEMA "org.gnome.desktop.a11y.mouse" static void bind_cinnamon_gnome_a11y_settings (CsdA11ySettingsManager *manager) { bind_keys (manager, CINNAMON_A11Y_APP_SCHEMA, "screen-keyboard-enabled", GNOME_A11Y_APP_SCHEMA, "screen-keyboard-enabled"); bind_keys (manager, CINNAMON_A11Y_APP_SCHEMA, "screen-reader-enabled", GNOME_A11Y_APP_SCHEMA, "screen-reader-enabled"); bind_keys (manager, CINNAMON_DESKTOP_SCHEMA, "toolkit-accessibility", GNOME_DESKTOP_SCHEMA, "toolkit-accessibility"); bind_keys (manager, CINNAMON_A11Y_MOUSE_SCHEMA, "secondary-click-enabled", GNOME_A11Y_MOUSE_SCHEMA, "secondary-click-enabled"); bind_keys (manager, CINNAMON_A11Y_MOUSE_SCHEMA, "secondary-click-time", GNOME_A11Y_MOUSE_SCHEMA, "secondary-click-time"); bind_keys (manager, CINNAMON_A11Y_MOUSE_SCHEMA, "dwell-click-enabled", GNOME_A11Y_MOUSE_SCHEMA, "dwell-click-enabled"); bind_keys (manager, CINNAMON_A11Y_MOUSE_SCHEMA, "dwell-threshold", GNOME_A11Y_MOUSE_SCHEMA, "dwell-threshold"); bind_keys (manager, CINNAMON_A11Y_MOUSE_SCHEMA, "dwell-time", GNOME_A11Y_MOUSE_SCHEMA, "dwell-time"); } static void hash_table_foreach_disconnect (gpointer key, gpointer value, gpointer user_data) { g_signal_handlers_disconnect_matched (G_SETTINGS (value), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, bound_key_changed, NULL); } static void unbind_cinnamon_gnome_a11y_settings (CsdA11ySettingsManager *manager) { g_hash_table_foreach (manager->priv->bind_table, (GHFunc) hash_table_foreach_disconnect, manager); g_clear_pointer (&manager->priv->bind_table, g_hash_table_destroy); } static void on_notification_closed (NotifyNotification *notification, CsdA11ySettingsManager *manager) { g_object_unref (notification); } static void on_notification_action_clicked (NotifyNotification *notification, const char *action, CsdA11ySettingsManager *manager) { g_spawn_command_line_async ("cinnamon-settings universal-access", NULL); } static void apps_settings_changed (GSettings *settings, const char *key, CsdA11ySettingsManager *manager) { gboolean screen_reader, keyboard; if (g_str_equal (key, "screen-reader-enabled") == FALSE && g_str_equal (key, "screen-keyboard-enabled") == FALSE) return; g_debug ("screen reader or OSK enablement changed"); screen_reader = g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-reader-enabled"); keyboard = g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-keyboard-enabled"); if (screen_reader || keyboard) { g_debug ("Enabling toolkit-accessibility, screen reader or OSK enabled"); g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", TRUE); } else if (screen_reader == FALSE && keyboard == FALSE) { g_debug ("Disabling toolkit-accessibility, screen reader and OSK disabled"); g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", FALSE); } if (screen_reader) { gchar *orca_path = g_find_program_in_path ("orca"); if (orca_path == NULL) { NotifyNotification *notification = notify_notification_new (_("Screen reader not found."), _("Please install the 'orca' package."), "preferences-desktop-accessibility"); notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL); notify_notification_add_action (notification, "open-cinnamon-settings", _("Open accessibility settings"), (NotifyActionCallback) on_notification_action_clicked, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), manager); GError *error = NULL; gboolean res = notify_notification_show (notification, &error); if (!res) { g_warning ("CsdA11ySettingsManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (notification, NULL); } } g_free (orca_path); } } static void bell_settings_changed (GSettings *settings, const char *key, CsdA11ySettingsManager *manager) { gboolean visual, audible; if (g_str_equal (key, "visual-bell") == FALSE && g_str_equal (key, "audible-bell") == FALSE) return; g_debug ("event feedback settings changed"); visual = g_settings_get_boolean (manager->priv->wm_settings, "visual-bell"); audible = g_settings_get_boolean (manager->priv->wm_settings, "audible-bell"); if (visual || audible) { g_debug ("Enabling event-sounds, visible or audible feedback enabled"); g_settings_set_boolean (manager->priv->sound_settings, "event-sounds", TRUE); } else if (visual == FALSE && audible == FALSE) { g_debug ("Disabling event-sounds, visible and audible feedback disabled"); g_settings_set_boolean (manager->priv->sound_settings, "event-sounds", FALSE); } } gboolean csd_a11y_settings_manager_start (CsdA11ySettingsManager *manager, GError **error) { g_debug ("Starting a11y_settings manager"); cinnamon_settings_profile_start (NULL); manager->priv->interface_settings = g_settings_new ("org.cinnamon.desktop.interface"); manager->priv->a11y_apps_settings = g_settings_new ("org.cinnamon.desktop.a11y.applications"); manager->priv->wm_settings = g_settings_new ("org.cinnamon.desktop.wm.preferences"); manager->priv->sound_settings = g_settings_new ("org.cinnamon.desktop.sound"); g_signal_connect (G_OBJECT (manager->priv->a11y_apps_settings), "changed", G_CALLBACK (apps_settings_changed), manager); g_signal_connect (G_OBJECT (manager->priv->wm_settings), "changed", G_CALLBACK (bell_settings_changed), manager); /* If any of the screen reader or on-screen keyboard are enabled, * make sure a11y is enabled for the toolkits. * We don't do the same thing for the reverse so it's possible to * enable AT-SPI for the toolkits without using an a11y app */ if (g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-keyboard-enabled") || g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-reader-enabled")) g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", TRUE); if (g_settings_get_boolean (manager->priv->wm_settings, "audible-bell") || g_settings_get_boolean (manager->priv->wm_settings, "visual-bell")) g_settings_set_boolean (manager->priv->sound_settings, "event-sounds", TRUE); else g_settings_set_boolean (manager->priv->sound_settings, "event-sounds", FALSE); /* Some accessibility applications (like orca) are hardcoded to look at the gnome a11y applications schema - mirror them */ bind_cinnamon_gnome_a11y_settings (manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_a11y_settings_manager_stop (CsdA11ySettingsManager *manager) { unbind_cinnamon_gnome_a11y_settings (manager); g_clear_object (&manager->priv->interface_settings); g_clear_object (&manager->priv->a11y_apps_settings); g_clear_object (&manager->priv->wm_settings); g_clear_object (&manager->priv->sound_settings); g_debug ("Stopping a11y_settings manager"); } static GObject * csd_a11y_settings_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11ySettingsManager *a11y_settings_manager; a11y_settings_manager = CSD_A11Y_SETTINGS_MANAGER (G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_settings_manager); } static void csd_a11y_settings_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->dispose (object); } static void csd_a11y_settings_manager_class_init (CsdA11ySettingsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_settings_manager_constructor; object_class->dispose = csd_a11y_settings_manager_dispose; object_class->finalize = csd_a11y_settings_manager_finalize; g_type_class_add_private (klass, sizeof (CsdA11ySettingsManagerPrivate)); } static void csd_a11y_settings_manager_init (CsdA11ySettingsManager *manager) { manager->priv = CSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE (manager); manager->priv->bind_table = NULL; } static void csd_a11y_settings_manager_finalize (GObject *object) { CsdA11ySettingsManager *a11y_settings_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_SETTINGS_MANAGER (object)); a11y_settings_manager = CSD_A11Y_SETTINGS_MANAGER (object); g_return_if_fail (a11y_settings_manager->priv != NULL); G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->finalize (object); } CsdA11ySettingsManager * csd_a11y_settings_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_A11Y_SETTINGS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_A11Y_SETTINGS_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/a11y-settings/csd-a11y-settings-manager.h000066400000000000000000000047441356401377300274750ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_A11Y_SETTINGS_MANAGER_H #define __CSD_A11Y_SETTINGS_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_SETTINGS_MANAGER (csd_a11y_settings_manager_get_type ()) #define CSD_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManager)) #define CSD_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerClass)) #define CSD_IS_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER)) #define CSD_IS_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_SETTINGS_MANAGER)) #define CSD_A11Y_SETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerClass)) typedef struct CsdA11ySettingsManagerPrivate CsdA11ySettingsManagerPrivate; typedef struct { GObject parent; CsdA11ySettingsManagerPrivate *priv; } CsdA11ySettingsManager; typedef struct { GObjectClass parent_class; } CsdA11ySettingsManagerClass; GType csd_a11y_settings_manager_get_type (void); CsdA11ySettingsManager *csd_a11y_settings_manager_new (void); gboolean csd_a11y_settings_manager_start (CsdA11ySettingsManager *manager, GError **error); void csd_a11y_settings_manager_stop (CsdA11ySettingsManager *manager); G_END_DECLS #endif /* __CSD_A11Y_SETTINGS_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/a11y-settings/main.c000066400000000000000000000010541356401377300236130ustar00rootroot00000000000000#define NEW csd_a11y_settings_manager_new #define START csd_a11y_settings_manager_start #define STOP csd_a11y_settings_manager_stop #define MANAGER CsdA11ySettingsManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-a11y-settings-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/automount/000077500000000000000000000000001356401377300221455ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/automount/Makefile.am000066400000000000000000000037341356401377300242100ustar00rootroot00000000000000NULL = plugin_name = automount libexec_PROGRAMS = csd-automount AM_CFLAGS = $(WARN_CFLAGS) csd_automount_SOURCES = \ main.c \ csd-automount-manager.h \ csd-automount-manager.c \ csd-autorun.c \ csd-autorun.h \ $(NULL) csd_automount_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_automount_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LOGIND_CFLAGS) \ $(AUTOMOUNT_CFLAGS) $(AM_CFLAGS) csd_automount_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(LOGIND_LIBS) \ $(AUTOMOUNT_LIBS) \ $(NULL) test_automount_dialog_SOURCES = test-automount-dialog.c \ csd-autorun.c \ $(NULL) test_automount_dialog_LDADD = $(AUTOMOUNT_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(NULL) test_automount_dialog_CFLAGS = $(AUTOMOUNT_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(NULL) noinst_PROGRAMS=test-automount-dialog desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-automount.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) applicationsdir = $(datadir)/applications applications_in_files = csd-automount.desktop.in applications_DATA = $(applications_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-automount.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ csd-automount.desktop: $(applications_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) \ $(applications_in_files) \ $(NULL) CLEANFILES = \ $(desktop_DATA) \ $(applications_DATA) \ $(NULL) DISTCLEANFILES = \ $(desktop_DATA) \ $(applications_DATA) \ $(NULL) cinnamon-settings-daemon-4.4.0/plugins/automount/cinnamon-settings-daemon-automount.desktop.in000066400000000000000000000003571356401377300331040ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - automount Exec=@libexecdir@/csd-automount OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/automount/csd-automount-manager.c000066400000000000000000000413361356401377300265320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Red Hat, 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 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 * * Author: Tomas Bzatek */ #include "config.h" #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-automount-manager.h" #include "csd-autorun.h" #define CSD_AUTOMOUNT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerPrivate)) struct CsdAutomountManagerPrivate { GSettings *settings; GVolumeMonitor *volume_monitor; unsigned int automount_idle_id; CinnamonSettingsSession *session; gboolean session_is_active; gboolean screensaver_active; guint ss_watch_id; GDBusProxy *ss_proxy; GList *volume_queue; }; G_DEFINE_TYPE (CsdAutomountManager, csd_automount_manager, G_TYPE_OBJECT) static GtkDialog * show_error_dialog (const char *primary_text, const char *secondary_text) { GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", ""); g_object_set (dialog, "text", primary_text, "secondary-text", secondary_text, NULL); gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); return GTK_DIALOG (dialog); } static void startup_volume_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { g_volume_mount_finish (G_VOLUME (source_object), res, NULL); } static void automount_all_volumes (CsdAutomountManager *manager) { GList *volumes, *l; GMount *mount; GVolume *volume; if (g_settings_get_boolean (manager->priv->settings, "automount")) { /* automount all mountable volumes at start-up */ volumes = g_volume_monitor_get_volumes (manager->priv->volume_monitor); for (l = volumes; l != NULL; l = l->next) { volume = l->data; if (!g_volume_should_automount (volume) || !g_volume_can_mount (volume)) { continue; } mount = g_volume_get_mount (volume); if (mount != NULL) { g_object_unref (mount); continue; } /* pass NULL as GMountOperation to avoid user interaction */ g_volume_mount (volume, 0, NULL, NULL, startup_volume_mount_cb, NULL); } g_list_free_full (volumes, g_object_unref); } } static gboolean automount_all_volumes_idle_cb (gpointer data) { CsdAutomountManager *manager = CSD_AUTOMOUNT_MANAGER (data); automount_all_volumes (manager); manager->priv->automount_idle_id = 0; return FALSE; } static void volume_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GMountOperation *mount_op = user_data; GError *error; char *primary; char *name; error = NULL; csd_allow_autorun_for_volume_finish (G_VOLUME (source_object)); if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) { if (error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED) { name = g_volume_get_name (G_VOLUME (source_object)); primary = g_strdup_printf (_("Unable to mount %s"), name); g_free (name); show_error_dialog (primary, error->message); g_free (primary); } g_error_free (error); } g_object_unref (mount_op); } static void do_mount_volume (GVolume *volume) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (NULL); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); csd_allow_autorun_for_volume (volume); g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, mount_op); } static void check_volume_queue (CsdAutomountManager *manager) { GList *l; GVolume *volume; if (manager->priv->screensaver_active) return; l = manager->priv->volume_queue; while (l != NULL) { volume = l->data; do_mount_volume (volume); manager->priv->volume_queue = g_list_remove (manager->priv->volume_queue, volume); g_object_unref (volume); l = l->next; } manager->priv->volume_queue = NULL; } static void check_screen_lock_and_mount (CsdAutomountManager *manager, GVolume *volume) { if (!manager->priv->session_is_active) return; if (manager->priv->screensaver_active) { /* queue the volume, to mount it after the screensaver state changed */ g_debug ("Queuing volume %p", volume); manager->priv->volume_queue = g_list_prepend (manager->priv->volume_queue, g_object_ref (volume)); } else { /* mount it immediately */ do_mount_volume (volume); } } static void volume_removed_callback (GVolumeMonitor *monitor, GVolume *volume, CsdAutomountManager *manager) { g_debug ("Volume %p removed, removing from the queue", volume); /* clear it from the queue, if present */ manager->priv->volume_queue = g_list_remove (manager->priv->volume_queue, volume); } static void volume_added_callback (GVolumeMonitor *monitor, GVolume *volume, CsdAutomountManager *manager) { if (g_settings_get_boolean (manager->priv->settings, "automount") && g_volume_should_automount (volume) && g_volume_can_mount (volume)) { check_screen_lock_and_mount (manager, volume); } else { /* Allow csd_autorun() to run. When the mount is later * added programmatically (i.e. for a blank CD), * csd_autorun() will be called by mount_added_callback(). */ csd_allow_autorun_for_volume (volume); csd_allow_autorun_for_volume_finish (volume); } } static void autorun_show_window (GMount *mount, gpointer user_data) { GFile *location; char *uri; GError *error; char *primary; char *name; location = g_mount_get_root (mount); uri = g_file_get_uri (location); error = NULL; /* use default folder handler */ g_debug("Opening %s", uri); if (g_str_has_prefix (uri, "afc://")) { // AFC (Apple File Conduit, which runs on iPhone and other Apple devices) doesn't always work well // Observed on an iOS 4 device it would work the first time the device was connected, and then indefinitely hang after that // Even a simple 'ls /run/user/$USER/gvfs' would hang forever // It is unacceptable for CSD to hang, so we're treating AFC differently (asynchronously) g_debug("AFC protocol detected, opening asynchronously!"); char * command = g_strdup_printf("timeout 10s xdg-open %s", uri); g_debug("Executing command '%s'", command); system(command); g_debug("Command was executed, moving on.."); g_free(command); } else { if (! gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error)) { name = g_mount_get_name (mount); primary = g_strdup_printf (_("Unable to open a folder for %s"), name); g_free (name); show_error_dialog (primary, error->message); g_free (primary); g_error_free (error); } } g_free (uri); g_object_unref (location); } static void mount_added_callback (GVolumeMonitor *monitor, GMount *mount, CsdAutomountManager *manager) { /* don't autorun if the session is not active */ if (!manager->priv->session_is_active) { return; } csd_autorun (mount, manager->priv->settings, autorun_show_window, manager); } static void session_state_changed (CinnamonSettingsSession *session, GParamSpec *pspec, gpointer user_data) { CsdAutomountManager *manager = user_data; CsdAutomountManagerPrivate *p = manager->priv; if (cinnamon_settings_session_get_state (session) == CINNAMON_SETTINGS_SESSION_STATE_ACTIVE) { p->session_is_active = TRUE; } else { p->session_is_active = FALSE; } if (!p->session_is_active) { if (p->volume_queue != NULL) { g_list_free_full (p->volume_queue, g_object_unref); p->volume_queue = NULL; } } } static void do_initialize_session (CsdAutomountManager *manager) { manager->priv->session = cinnamon_settings_session_new (); g_signal_connect (manager->priv->session, "notify::state", G_CALLBACK (session_state_changed), manager); session_state_changed (manager->priv->session, NULL, manager); } #define SCREENSAVER_NAME "org.cinnamon.ScreenSaver" #define SCREENSAVER_PATH "/org/cinnamon/ScreenSaver" #define SCREENSAVER_INTERFACE "org.cinnamon.ScreenSaver" static void screensaver_signal_callback (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdAutomountManager *manager = user_data; if (g_strcmp0 (signal_name, "ActiveChanged") == 0) { g_variant_get (parameters, "(b)", &manager->priv->screensaver_active); g_debug ("Screensaver active changed to %d", manager->priv->screensaver_active); check_volume_queue (manager); } } static void screensaver_get_active_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { CsdAutomountManager *manager = user_data; GDBusProxy *proxy = manager->priv->ss_proxy; GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (proxy, res, &error); if (error != NULL) { g_warning ("Can't call GetActive() on the ScreenSaver object: %s", error->message); g_error_free (error); return; } g_variant_get (result, "(b)", &manager->priv->screensaver_active); g_variant_unref (result); g_debug ("Screensaver GetActive() returned %d", manager->priv->screensaver_active); } static void screensaver_proxy_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { CsdAutomountManager *manager = user_data; GError *error = NULL; GDBusProxy *ss_proxy; ss_proxy = g_dbus_proxy_new_finish (res, &error); if (error != NULL) { g_warning ("Can't get proxy for the ScreenSaver object: %s", error->message); g_error_free (error); return; } g_debug ("ScreenSaver proxy ready"); manager->priv->ss_proxy = ss_proxy; g_signal_connect (ss_proxy, "g-signal", G_CALLBACK (screensaver_signal_callback), manager); g_dbus_proxy_call (ss_proxy, "GetActive", NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, screensaver_get_active_ready_cb, manager); } static void screensaver_appeared_callback (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { CsdAutomountManager *manager = user_data; g_debug ("ScreenSaver name appeared"); manager->priv->screensaver_active = FALSE; g_dbus_proxy_new (connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, name, SCREENSAVER_PATH, SCREENSAVER_INTERFACE, NULL, screensaver_proxy_ready_cb, manager); } static void screensaver_vanished_callback (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdAutomountManager *manager = user_data; g_debug ("ScreenSaver name vanished"); manager->priv->screensaver_active = FALSE; if (manager->priv->ss_proxy != NULL) { g_object_unref (manager->priv->ss_proxy); manager->priv->ss_proxy = NULL; } /* in this case force a clear of the volume queue, without * mounting them. */ if (manager->priv->volume_queue != NULL) { g_list_free_full (manager->priv->volume_queue, g_object_unref); manager->priv->volume_queue = NULL; } } static void do_initialize_screensaver (CsdAutomountManager *manager) { CsdAutomountManagerPrivate *p = manager->priv; p->ss_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, SCREENSAVER_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE, screensaver_appeared_callback, screensaver_vanished_callback, manager, NULL); } static void setup_automounter (CsdAutomountManager *manager) { do_initialize_session (manager); do_initialize_screensaver (manager); manager->priv->volume_monitor = g_volume_monitor_get (); g_signal_connect_object (manager->priv->volume_monitor, "mount-added", G_CALLBACK (mount_added_callback), manager, 0); g_signal_connect_object (manager->priv->volume_monitor, "volume-added", G_CALLBACK (volume_added_callback), manager, 0); g_signal_connect_object (manager->priv->volume_monitor, "volume-removed", G_CALLBACK (volume_removed_callback), manager, 0); manager->priv->automount_idle_id = g_idle_add_full (G_PRIORITY_LOW, automount_all_volumes_idle_cb, manager, NULL); } gboolean csd_automount_manager_start (CsdAutomountManager *manager, GError **error) { g_debug ("Starting automounting manager"); cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new ("org.cinnamon.desktop.media-handling"); setup_automounter (manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_automount_manager_stop (CsdAutomountManager *manager) { CsdAutomountManagerPrivate *p = manager->priv; g_debug ("Stopping automounting manager"); if (p->session != NULL) { g_object_unref (p->session); p->session = NULL; } if (p->volume_monitor != NULL) { g_object_unref (p->volume_monitor); p->volume_monitor = NULL; } if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->ss_proxy != NULL) { g_object_unref (p->ss_proxy); p->ss_proxy = NULL; } g_bus_unwatch_name (p->ss_watch_id); if (p->volume_queue != NULL) { g_list_free_full (p->volume_queue, g_object_unref); p->volume_queue = NULL; } if (p->automount_idle_id != 0) { g_source_remove (p->automount_idle_id); p->automount_idle_id = 0; } } static void csd_automount_manager_class_init (CsdAutomountManagerClass *klass) { g_type_class_add_private (klass, sizeof (CsdAutomountManagerPrivate)); } static void csd_automount_manager_init (CsdAutomountManager *manager) { manager->priv = CSD_AUTOMOUNT_MANAGER_GET_PRIVATE (manager); } CsdAutomountManager * csd_automount_manager_new (void) { return CSD_AUTOMOUNT_MANAGER (g_object_new (CSD_TYPE_AUTOMOUNT_MANAGER, NULL)); } cinnamon-settings-daemon-4.4.0/plugins/automount/csd-automount-manager.h000066400000000000000000000046161356401377300265370ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Red Hat, 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 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 * * Author: Tomas Bzatek */ #ifndef __CSD_AUTOMOUNT_MANAGER_H #define __CSD_AUTOMOUNT_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_AUTOMOUNT_MANAGER (csd_automount_manager_get_type ()) #define CSD_AUTOMOUNT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManager)) #define CSD_AUTOMOUNT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerClass)) #define CSD_IS_AUTOMOUNT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_AUTOMOUNT_MANAGER)) #define CSD_IS_AUTOMOUNT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_AUTOMOUNT_MANAGER)) #define CSD_AUTOMOUNT_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerClass)) typedef struct CsdAutomountManagerPrivate CsdAutomountManagerPrivate; typedef struct { GObject parent; CsdAutomountManagerPrivate *priv; } CsdAutomountManager; typedef struct { GObjectClass parent_class; } CsdAutomountManagerClass; GType csd_automount_manager_get_type (void); CsdAutomountManager * csd_automount_manager_new (void); gboolean csd_automount_manager_start (CsdAutomountManager *manager, GError **error); void csd_automount_manager_stop (CsdAutomountManager *manager); G_END_DECLS #endif /* __CSD_AUTOMOUNT_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/automount/csd-automount.desktop.in000066400000000000000000000010641356401377300267500ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Files Name[am]=ፋይሎች Name[bg]=Файлове Name[ca]=Arxius Name[cs]=Soubory Name[da]=Filer Name[de]=Dateien Name[es]=Archivos Name[eu]=Fitxategiak Name[fr]=Fichiers Name[hr]=Nemo Name[hu]=Fájlok Name[ko]=파일 Name[lt]=Failai Name[nl]=Bestanden Name[pl]=Pliki Name[pt]=Ficheiros Name[pt_BR]=Arquivos Name[pt_PT]=Ficheiros Name[ru]=Файлы Name[sv]=Filer Name[tr]=Dosyalar Name[uk]=Файли Name[zh_CN]=文件 Name[zh_HK]=檔案 Icon=folder Exec=@libexecdir@/csd-automount OnlyShowIn=X-Cinnamon; NoDisplay=true cinnamon-settings-daemon-4.4.0/plugins/automount/csd-autorun.c000066400000000000000000000717511356401377300245700ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * csd-automount.c: helpers for automounting hotplugged volumes * * Copyright (C) 2008, 2010 Red Hat, Inc. * * Nautilus 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: David Zeuthen * Cosimo Cecchi */ #include #include #include #include #include #include #include #include #include "csd-autorun.h" static gboolean should_autorun_mount (GMount *mount); #define CUSTOM_ITEM_ASK "csd-item-ask" #define CUSTOM_ITEM_DO_NOTHING "csd-item-do-nothing" #define CUSTOM_ITEM_OPEN_FOLDER "csd-item-open-folder" typedef struct { GtkWidget *dialog; GMount *mount; gboolean should_eject; gboolean selected_ignore; gboolean selected_open_folder; GAppInfo *selected_app; gboolean remember; char *x_content_type; CsdAutorunOpenWindow open_window_func; gpointer user_data; } AutorunDialogData; static int csd_autorun_g_strv_find (char **strv, const char *find_me) { guint index; g_return_val_if_fail (find_me != NULL, -1); for (index = 0; strv[index] != NULL; ++index) { if (strcmp (strv[index], find_me) == 0) { return index; } } return -1; } #define ICON_SIZE_STANDARD 48 static gint get_icon_size_for_stock_size (GtkIconSize size) { gint w, h; if (gtk_icon_size_lookup (size, &w, &h)) { return MAX (w, h); } return ICON_SIZE_STANDARD; } static GdkPixbuf * render_icon (GIcon *icon, gint icon_size) { GdkPixbuf *pixbuf; GtkIconInfo *info; pixbuf = NULL; if (G_IS_THEMED_ICON (icon)) { gchar const * const *names; info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), icon, icon_size, 0); if (info) { pixbuf = gtk_icon_info_load_icon (info, NULL); g_object_unref (info); } if (pixbuf == NULL) { names = g_themed_icon_get_names (G_THEMED_ICON (icon)); pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), *names, icon_size, 0, NULL); } } else if (G_IS_FILE_ICON (icon)) { GFile *icon_file; gchar *path; icon_file = g_file_icon_get_file (G_FILE_ICON (icon)); path = g_file_get_path (icon_file); pixbuf = gdk_pixbuf_new_from_file_at_size (path, icon_size, icon_size, NULL); g_free (path); g_object_unref (G_OBJECT (icon_file)); } return pixbuf; } static void csd_autorun_get_preferences (const char *x_content_type, gboolean *pref_start_app, gboolean *pref_ignore, gboolean *pref_open_folder) { GSettings *settings; char **x_content_start_app; char **x_content_ignore; char **x_content_open_folder; g_return_if_fail (pref_start_app != NULL); g_return_if_fail (pref_ignore != NULL); g_return_if_fail (pref_open_folder != NULL); settings = g_settings_new ("org.cinnamon.desktop.media-handling"); *pref_start_app = FALSE; *pref_ignore = FALSE; *pref_open_folder = FALSE; x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app"); x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore"); x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder"); if (x_content_start_app != NULL) { *pref_start_app = csd_autorun_g_strv_find (x_content_start_app, x_content_type) != -1; } if (x_content_ignore != NULL) { *pref_ignore = csd_autorun_g_strv_find (x_content_ignore, x_content_type) != -1; } if (x_content_open_folder != NULL) { *pref_open_folder = csd_autorun_g_strv_find (x_content_open_folder, x_content_type) != -1; } g_strfreev (x_content_ignore); g_strfreev (x_content_start_app); g_strfreev (x_content_open_folder); g_object_unref (settings); } static char ** remove_elem_from_str_array (char **v, const char *s) { GPtrArray *array; guint idx; array = g_ptr_array_new (); for (idx = 0; v[idx] != NULL; idx++) { if (g_strcmp0 (v[idx], s) == 0) { continue; } g_ptr_array_add (array, v[idx]); } g_ptr_array_add (array, NULL); g_free (v); return (char **) g_ptr_array_free (array, FALSE); } static char ** add_elem_to_str_array (char **v, const char *s) { GPtrArray *array; guint idx; array = g_ptr_array_new (); for (idx = 0; v[idx] != NULL; idx++) { g_ptr_array_add (array, v[idx]); } g_ptr_array_add (array, g_strdup (s)); g_ptr_array_add (array, NULL); g_free (v); return (char **) g_ptr_array_free (array, FALSE); } static void csd_autorun_set_preferences (const char *x_content_type, gboolean pref_start_app, gboolean pref_ignore, gboolean pref_open_folder) { GSettings *settings; char **x_content_start_app; char **x_content_ignore; char **x_content_open_folder; g_assert (x_content_type != NULL); settings = g_settings_new ("org.cinnamon.desktop.media-handling"); x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app"); x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore"); x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder"); x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type); if (pref_start_app) { x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-start-app", (const gchar * const*) x_content_start_app); x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type); if (pref_ignore) { x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-ignore", (const gchar * const*) x_content_ignore); x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type); if (pref_open_folder) { x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-open-folder", (const gchar * const*) x_content_open_folder); g_strfreev (x_content_open_folder); g_strfreev (x_content_ignore); g_strfreev (x_content_start_app); g_object_unref (settings); } static void custom_item_activated_cb (GtkAppChooserButton *button, const gchar *item, gpointer user_data) { gchar *content_type; AutorunDialogData *data = user_data; content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button)); if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) { csd_autorun_set_preferences (content_type, FALSE, FALSE, FALSE); data->selected_open_folder = FALSE; data->selected_ignore = FALSE; } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) { csd_autorun_set_preferences (content_type, FALSE, FALSE, TRUE); data->selected_open_folder = TRUE; data->selected_ignore = FALSE; } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) { csd_autorun_set_preferences (content_type, FALSE, TRUE, FALSE); data->selected_open_folder = FALSE; data->selected_ignore = TRUE; } g_free (content_type); } static void combo_box_changed_cb (GtkComboBox *combo_box, gpointer user_data) { GAppInfo *info; AutorunDialogData *data = user_data; info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); if (info == NULL) return; if (data->selected_app != NULL) { g_object_unref (data->selected_app); data->selected_app = NULL; } data->selected_app = info; } static void prepare_combo_box (GtkWidget *combo_box, AutorunDialogData *data) { GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box); GIcon *icon; gboolean pref_ask; gboolean pref_start_app; gboolean pref_ignore; gboolean pref_open_folder; GAppInfo *info; gchar *content_type; content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser)); gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (combo_box), TRUE); /* fetch preferences for this content type */ csd_autorun_get_preferences (content_type, &pref_start_app, &pref_ignore, &pref_open_folder); pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); /* append the separator only if we have >= 1 apps in the chooser */ if (info != NULL) { gtk_app_chooser_button_append_separator (app_chooser); g_object_unref (info); } icon = g_themed_icon_new ("dialog-question"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK, _("Ask what to do"), icon); g_object_unref (icon); icon = g_themed_icon_new ("window-close"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING, _("Do Nothing"), icon); g_object_unref (icon); icon = g_themed_icon_new ("folder-open"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER, _("Open Folder"), icon); g_object_unref (icon); gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE); if (pref_ask) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK); } else if (pref_ignore) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING); } else if (pref_open_folder) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER); } g_signal_connect (app_chooser, "changed", G_CALLBACK (combo_box_changed_cb), data); g_signal_connect (app_chooser, "custom-item-activated", G_CALLBACK (custom_item_activated_cb), data); g_free (content_type); } static gboolean is_shift_pressed (void) { gboolean ret; XkbStateRec state; Bool status; ret = FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); status = XkbGetState (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, &state); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); if (status == Success) { ret = state.mods & ShiftMask; } return ret; } enum { AUTORUN_DIALOG_RESPONSE_EJECT = 0 }; static void csd_autorun_launch_for_mount (GMount *mount, GAppInfo *app_info) { GFile *root; GdkAppLaunchContext *launch_context; GError *error; gboolean result; GList *list; gchar *uri_scheme; gchar *uri; root = g_mount_get_root (mount); list = g_list_append (NULL, root); launch_context = gdk_app_launch_context_new (); error = NULL; result = g_app_info_launch (app_info, list, G_APP_LAUNCH_CONTEXT (launch_context), &error); g_object_unref (launch_context); if (!result) { if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED) { uri = g_file_get_uri (root); uri_scheme = g_uri_parse_scheme (uri); /* FIXME: Present user a dialog to choose another app when the last one failed to handle a file */ g_warning ("Cannot open location: %s\n", error->message); g_free (uri_scheme); g_free (uri); } else { g_warning ("Cannot open app: %s\n", error->message); } g_error_free (error); } g_list_free (list); g_object_unref (root); } static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data); static void autorun_dialog_destroy (AutorunDialogData *data) { g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount), G_CALLBACK (autorun_dialog_mount_unmounted), data); gtk_widget_destroy (GTK_WIDGET (data->dialog)); if (data->selected_app != NULL) { g_object_unref (data->selected_app); } g_object_unref (data->mount); g_free (data->x_content_type); g_free (data); } static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data) { /* remove the dialog if the media is unmounted */ autorun_dialog_destroy (data); } static void unmount_mount_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; char *primary; gboolean unmounted; gboolean should_eject; GtkWidget *dialog; should_eject = user_data != NULL; error = NULL; if (should_eject) { unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error); } else { unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object), res, &error); } if (! unmounted) { if (error->code != G_IO_ERROR_FAILED_HANDLED) { if (should_eject) { primary = g_strdup_printf (_("Unable to eject %p"), source_object); } else { primary = g_strdup_printf (_("Unable to unmount %p"), source_object); } dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", primary); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); g_free (primary); } } if (error != NULL) { g_error_free (error); } } static void do_unmount (GMount *mount, gboolean should_eject, GtkWindow *window) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (window); if (should_eject) { g_mount_eject_with_operation (mount, 0, mount_op, NULL, unmount_mount_callback, (gpointer) 1); } else { g_mount_unmount_with_operation (mount, 0, mount_op, NULL, unmount_mount_callback, (gpointer) 0); } g_object_unref (mount_op); } static void autorun_dialog_response (GtkDialog *dialog, gint response, AutorunDialogData *data) { switch (response) { case AUTORUN_DIALOG_RESPONSE_EJECT: do_unmount (data->mount, data->should_eject, GTK_WINDOW (dialog)); break; case GTK_RESPONSE_NONE: /* window was closed */ break; case GTK_RESPONSE_CANCEL: break; case GTK_RESPONSE_OK: /* do the selected action */ if (data->remember) { /* make sure we don't ask again */ csd_autorun_set_preferences (data->x_content_type, TRUE, data->selected_ignore, data->selected_open_folder); if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) { g_app_info_set_as_default_for_type (data->selected_app, data->x_content_type, NULL); } } else { /* make sure we do ask again */ csd_autorun_set_preferences (data->x_content_type, FALSE, FALSE, FALSE); } if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) { csd_autorun_launch_for_mount (data->mount, data->selected_app); } else if (!data->selected_ignore && data->selected_open_folder) { if (data->open_window_func != NULL) data->open_window_func (data->mount, data->user_data); } break; } autorun_dialog_destroy (data); } static void autorun_always_toggled (GtkToggleButton *togglebutton, AutorunDialogData *data) { data->remember = gtk_toggle_button_get_active (togglebutton); } static gboolean combo_box_enter_ok (GtkWidget *togglebutton, GdkEventKey *event, GtkDialog *dialog) { if (event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_Return) { gtk_dialog_response (dialog, GTK_RESPONSE_OK); return TRUE; } return FALSE; } /* returns TRUE if a folder window should be opened */ static gboolean do_autorun_for_content_type (GMount *mount, const char *x_content_type, CsdAutorunOpenWindow open_window_func, gpointer user_data) { AutorunDialogData *data; GtkWidget *dialog; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *label; GtkWidget *combo_box; GtkWidget *always_check_button; GtkWidget *eject_button; GtkWidget *image; char *markup; char *content_description; char *mount_name; GIcon *icon; GdkPixbuf *pixbuf; int icon_size; gboolean user_forced_dialog; gboolean pref_ask; gboolean pref_start_app; gboolean pref_ignore; gboolean pref_open_folder; char *media_greeting; gboolean ret; ret = FALSE; mount_name = NULL; if (g_content_type_is_a (x_content_type, "x-content/win32-software")) { /* don't pop up the dialog anyway if the content type says * windows software. */ goto out; } user_forced_dialog = is_shift_pressed (); csd_autorun_get_preferences (x_content_type, &pref_start_app, &pref_ignore, &pref_open_folder); pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; if (user_forced_dialog) { goto show_dialog; } if (!pref_ask && !pref_ignore && !pref_open_folder) { GAppInfo *app_info; app_info = g_app_info_get_default_for_type (x_content_type, FALSE); if (app_info != NULL) { csd_autorun_launch_for_mount (mount, app_info); } goto out; } if (pref_open_folder) { ret = TRUE; goto out; } if (pref_ignore) { goto out; } show_dialog: mount_name = g_mount_get_name (mount); dialog = gtk_dialog_new (); gtk_window_set_default_size (GTK_WINDOW (dialog), 450, -1); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); icon = g_mount_get_icon (mount); icon_size = get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG); image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); pixbuf = render_icon (icon, icon_size); gtk_widget_set_halign (image, GTK_ALIGN_CENTER); gtk_widget_set_valign (image, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0); /* also use the icon on the dialog */ gtk_window_set_title (GTK_WINDOW (dialog), mount_name); gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); g_object_unref (icon); if (pixbuf) { g_object_unref (pixbuf); } vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); label = gtk_label_new (NULL); /* Customize greeting for well-known x-content types */ if (strcmp (x_content_type, "x-content/audio-cdda") == 0) { media_greeting = _("You have just inserted an Audio CD."); } else if (strcmp (x_content_type, "x-content/audio-dvd") == 0) { media_greeting = _("You have just inserted an Audio DVD."); } else if (strcmp (x_content_type, "x-content/video-dvd") == 0) { media_greeting = _("You have just inserted a Video DVD."); } else if (strcmp (x_content_type, "x-content/video-vcd") == 0) { media_greeting = _("You have just inserted a Video CD."); } else if (strcmp (x_content_type, "x-content/video-svcd") == 0) { media_greeting = _("You have just inserted a Super Video CD."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank CD."); } else if (strcmp (x_content_type, "x-content/blank-dvd") == 0) { media_greeting = _("You have just inserted a blank DVD."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank Blu-Ray disc."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank HD DVD."); } else if (strcmp (x_content_type, "x-content/image-photocd") == 0) { media_greeting = _("You have just inserted a Photo CD."); } else if (strcmp (x_content_type, "x-content/image-picturecd") == 0) { media_greeting = _("You have just inserted a Picture CD."); } else if (strcmp (x_content_type, "x-content/image-dcf") == 0) { media_greeting = _("You have just inserted a medium with digital photos."); } else if (strcmp (x_content_type, "x-content/audio-player") == 0) { media_greeting = _("You have just inserted a digital audio player."); } else if (g_content_type_is_a (x_content_type, "x-content/software")) { media_greeting = _("You have just inserted a medium with software intended to be automatically started."); } else { /* fallback to generic greeting */ media_greeting = _("You have just inserted a medium."); } markup = g_strdup_printf ("%s %s", media_greeting, _("Choose what application to launch.")); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); label = gtk_label_new (NULL); content_description = g_content_type_get_description (x_content_type); markup = g_strdup_printf (_("Select how to open \"%s\" and whether to perform this action in the future for other media of type \"%s\"."), mount_name, content_description); g_free (content_description); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); data = g_new0 (AutorunDialogData, 1); data->dialog = dialog; data->mount = g_object_ref (mount); data->remember = !pref_ask; data->selected_ignore = pref_ignore; data->x_content_type = g_strdup (x_content_type); data->selected_app = g_app_info_get_default_for_type (x_content_type, FALSE); data->open_window_func = open_window_func; data->user_data = user_data; combo_box = gtk_app_chooser_button_new (x_content_type); prepare_combo_box (combo_box, data); g_signal_connect (G_OBJECT (combo_box), "key-press-event", G_CALLBACK (combo_box_enter_ok), dialog); gtk_box_pack_start (GTK_BOX (vbox), combo_box, TRUE, TRUE, 0); always_check_button = gtk_check_button_new_with_mnemonic (_("_Always perform this action")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (always_check_button), data->remember); g_signal_connect (G_OBJECT (always_check_button), "toggled", G_CALLBACK (autorun_always_toggled), data); gtk_box_pack_start (GTK_BOX (vbox), always_check_button, TRUE, TRUE, 0); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Ok"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); if (g_mount_can_eject (mount)) { eject_button = gtk_button_new_with_mnemonic (_("_Eject")); data->should_eject = TRUE; } else { eject_button = gtk_button_new_with_mnemonic (_("_Unmount")); data->should_eject = FALSE; } gtk_dialog_add_action_widget (GTK_DIALOG (dialog), eject_button, AUTORUN_DIALOG_RESPONSE_EJECT); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), eject_button, TRUE); /* show the dialog */ gtk_widget_show_all (dialog); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (autorun_dialog_response), data); g_signal_connect (G_OBJECT (data->mount), "unmounted", G_CALLBACK (autorun_dialog_mount_unmounted), data); out: g_free (mount_name); return ret; } typedef struct { GMount *mount; CsdAutorunOpenWindow open_window_func; gpointer user_data; GSettings *settings; } AutorunData; static void autorun_guessed_content_type_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; char **guessed_content_type; AutorunData *data = user_data; gboolean open_folder; open_folder = FALSE; error = NULL; guessed_content_type = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, &error); g_object_set_data_full (source_object, "csd-content-type-cache", g_strdupv (guessed_content_type), (GDestroyNotify)g_strfreev); if (error != NULL) { g_warning ("Unable to guess content type for mount: %s", error->message); g_error_free (error); } else { if (guessed_content_type != NULL && g_strv_length (guessed_content_type) > 0) { int n; for (n = 0; guessed_content_type[n] != NULL; n++) { if (do_autorun_for_content_type (data->mount, guessed_content_type[n], data->open_window_func, data->user_data)) { open_folder = TRUE; } } g_strfreev (guessed_content_type); } else { if (g_settings_get_boolean (data->settings, "automount-open")) { open_folder = TRUE; } } } /* only open the folder once.. */ if (open_folder && data->open_window_func != NULL) { data->open_window_func (data->mount, data->user_data); } g_object_unref (data->mount); g_object_unref (data->settings); g_free (data); } void csd_autorun (GMount *mount, GSettings *settings, CsdAutorunOpenWindow open_window_func, gpointer user_data) { AutorunData *data; if (!should_autorun_mount (mount) || g_settings_get_boolean (settings, "autorun-never")) { return; } data = g_new0 (AutorunData, 1); data->mount = g_object_ref (mount); data->open_window_func = open_window_func; data->user_data = user_data; data->settings = g_object_ref (settings); g_mount_guess_content_type (mount, FALSE, NULL, autorun_guessed_content_type_callback, data); } static gboolean remove_allow_volume (gpointer data) { GVolume *volume = data; g_object_set_data (G_OBJECT (volume), "csd-allow-autorun", NULL); return FALSE; } void csd_allow_autorun_for_volume (GVolume *volume) { g_object_set_data (G_OBJECT (volume), "csd-allow-autorun", GINT_TO_POINTER (1)); } #define INHIBIT_AUTORUN_SECONDS 10 void csd_allow_autorun_for_volume_finish (GVolume *volume) { if (g_object_get_data (G_OBJECT (volume), "csd-allow-autorun") != NULL) { g_timeout_add_seconds_full (0, INHIBIT_AUTORUN_SECONDS, remove_allow_volume, g_object_ref (volume), g_object_unref); } } static gboolean should_skip_native_mount_root (GFile *root) { char *path; gboolean should_skip; /* skip any mounts in hidden directory hierarchies */ path = g_file_get_path (root); should_skip = strstr (path, "/.") != NULL; g_free (path); return should_skip; } static gboolean should_autorun_mount (GMount *mount) { GFile *root; GVolume *enclosing_volume; gboolean ignore_autorun; ignore_autorun = TRUE; enclosing_volume = g_mount_get_volume (mount); if (enclosing_volume != NULL) { if (g_object_get_data (G_OBJECT (enclosing_volume), "csd-allow-autorun") != NULL) { ignore_autorun = FALSE; g_object_set_data (G_OBJECT (enclosing_volume), "csd-allow-autorun", NULL); } } if (ignore_autorun) { if (enclosing_volume != NULL) { g_object_unref (enclosing_volume); } return FALSE; } root = g_mount_get_root (mount); /* only do autorun on local files or files where g_volume_should_automount() returns TRUE */ ignore_autorun = TRUE; if ((g_file_is_native (root) && !should_skip_native_mount_root (root)) || (enclosing_volume != NULL && g_volume_should_automount (enclosing_volume))) { ignore_autorun = FALSE; } if (enclosing_volume != NULL) { g_object_unref (enclosing_volume); } g_object_unref (root); return !ignore_autorun; } void csd_autorun_for_content_type (GMount *mount, const gchar *content_type, CsdAutorunOpenWindow *callback, gpointer user_data) { do_autorun_for_content_type (mount, content_type, callback, user_data); }cinnamon-settings-daemon-4.4.0/plugins/automount/csd-autorun.h000066400000000000000000000036051356401377300245660ustar00rootroot00000000000000/* * csd-automount.h:helpers for automounting hotplugged volumes * * Copyright (C) 2008 Red Hat, Inc. * * Nautilus 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: David Zeuthen * Cosimo Cecchi */ /* TODO: * * - unmount all the media we've automounted on shutdown * - finish x-content / * types * - finalize the semi-spec * - add probing/sniffing code * - implement missing features * - "Open Folder when mounted" * - Autorun spec (e.g. $ROOT/.autostart) * */ #ifndef __CSD_AUTORUN_H__ #define __CSD_AUTORUN_H__ #include #include typedef void (*CsdAutorunOpenWindow) (GMount *mount, gpointer user_data); void csd_autorun (GMount *mount, GSettings *settings, CsdAutorunOpenWindow open_window_func, gpointer user_data); void csd_autorun_for_content_type (GMount *mount, const gchar *content_type, CsdAutorunOpenWindow *callback, gpointer user_data); void csd_allow_autorun_for_volume (GVolume *volume); void csd_allow_autorun_for_volume_finish (GVolume *volume); #endif /* __CSD_AUTORUN_H__ */ cinnamon-settings-daemon-4.4.0/plugins/automount/main.c000066400000000000000000000010321356401377300232310ustar00rootroot00000000000000#define NEW csd_automount_manager_new #define START csd_automount_manager_start #define STOP csd_automount_manager_stop #define MANAGER CsdAutomountManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE FALSE #include "csd-automount-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/automount/test-automount-dialog.c000066400000000000000000000042251356401377300265610ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * save-session.c - Small program to talk to session manager. Copyright (C) 1998 Tom Tromey Copyright (C) 2008 Red Hat, 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, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #include #include #include #include #include #include #include #include "csd-autorun.h" static void autorun_show_window (GMount *mount, gpointer user_data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GVolumeMonitor *monitor; GError *error; GList *mounts, *l; int conflicting_options; error = NULL; if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { g_warning ("Unable to start: %s", error->message); g_error_free (error); exit (1); } if (argc != 2) { g_print ("Need one argument as content type\n"); exit (1); } monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (monitor); if (mounts) { GMount *mount = G_MOUNT (mounts->data); csd_autorun_for_content_type (mount, argv[1], (CsdAutorunOpenWindow) autorun_show_window, NULL); } gtk_main (); gtk_main_quit (); return 0; } cinnamon-settings-daemon-4.4.0/plugins/background/000077500000000000000000000000001356401377300222315ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/background/Makefile.am000066400000000000000000000023741356401377300242730ustar00rootroot00000000000000NULL = plugin_name = background libexec_PROGRAMS = csd-background AM_CFLAGS = $(WARN_CFLAGS) csd_background_SOURCES = \ main.c \ csd-background-manager.h \ csd-background-manager.c \ $(NULL) csd_background_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_background_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(BACKGROUND_CFLAGS) \ $(AM_CFLAGS) csd_background_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(BACKGROUND_LIBS) \ $(NULL) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-background.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-background.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) \ $(NULL) CLEANFILES = \ $(desktop_DATA) \ $(NULL) DISTCLEANFILES = \ $(desktop_DATA) \ $(NULL) cinnamon-settings-daemon-4.4.0/plugins/background/cinnamon-settings-daemon-background.desktop.in000066400000000000000000000003611356401377300332470ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - background Exec=@libexecdir@/csd-background OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/background/csd-background-manager.c000066400000000000000000000324711356401377300267020ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 William Jon McCann * Copyright 2007 Red Hat, 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 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 #include #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include "cinnamon-settings-profile.h" #include "csd-background-manager.h" #define CSD_BACKGROUND_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerPrivate)) struct CsdBackgroundManagerPrivate { GSettings *settings; GnomeBG *bg; GnomeBGCrossfade *fade; GDBusProxy *proxy; guint proxy_signal_id; }; static void csd_background_manager_finalize (GObject *object); static void setup_bg (CsdBackgroundManager *manager); static void connect_screen_signals (CsdBackgroundManager *manager); G_DEFINE_TYPE (CsdBackgroundManager, csd_background_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void on_crossfade_finished (CsdBackgroundManager *manager) { g_object_unref (manager->priv->fade); manager->priv->fade = NULL; } static void draw_background (CsdBackgroundManager *manager, gboolean use_crossfade) { GdkDisplay *display; cinnamon_settings_profile_start (NULL); display = gdk_display_get_default (); if (display) { GdkScreen *screen; GdkWindow *root_window; cairo_surface_t *surface; screen = gdk_display_get_screen (display, 0); root_window = gdk_screen_get_root_window (screen); surface = gnome_bg_create_surface (manager->priv->bg, root_window, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE); if (FALSE) { /* use_crossfade - buggy now? need to look at cinnamon-desktop */ if (manager->priv->fade != NULL) { g_object_unref (manager->priv->fade); } manager->priv->fade = gnome_bg_set_surface_as_root_with_crossfade (screen, surface); g_signal_connect_swapped (manager->priv->fade, "finished", G_CALLBACK (on_crossfade_finished), manager); } else { gnome_bg_set_surface_as_root (screen, surface); } cairo_surface_destroy (surface); } cinnamon_settings_profile_end (NULL); } static void on_bg_transitioned (GnomeBG *bg, CsdBackgroundManager *manager) { draw_background (manager, FALSE); } static gboolean settings_change_event_cb (GSettings *settings, gpointer keys, gint n_keys, CsdBackgroundManager *manager) { gnome_bg_load_from_preferences (manager->priv->bg, manager->priv->settings); gnome_bg_set_accountsservice_background (gnome_bg_get_filename (manager->priv->bg)); return FALSE; } static void on_screen_size_changed (GdkScreen *screen, CsdBackgroundManager *manager) { draw_background (manager, FALSE); } static void watch_bg_preferences (CsdBackgroundManager *manager) { g_signal_connect (manager->priv->settings, "change-event", G_CALLBACK (settings_change_event_cb), manager); } static void on_bg_changed (GnomeBG *bg, CsdBackgroundManager *manager) { draw_background (manager, TRUE); } static void setup_bg (CsdBackgroundManager *manager) { if (manager->priv->bg != NULL) return; manager->priv->bg = gnome_bg_new (); g_signal_connect (manager->priv->bg, "changed", G_CALLBACK (on_bg_changed), manager); g_signal_connect (manager->priv->bg, "transitioned", G_CALLBACK (on_bg_transitioned), manager); connect_screen_signals (manager); watch_bg_preferences (manager); gnome_bg_load_from_preferences (manager->priv->bg, manager->priv->settings); gnome_bg_set_accountsservice_background (gnome_bg_get_filename (manager->priv->bg)); } static void setup_bg_and_draw_background (CsdBackgroundManager *manager) { setup_bg (manager); draw_background (manager, FALSE); } static void disconnect_session_manager_listener (CsdBackgroundManager *manager) { if (manager->priv->proxy && manager->priv->proxy_signal_id) { g_signal_handler_disconnect (manager->priv->proxy, manager->priv->proxy_signal_id); manager->priv->proxy_signal_id = 0; } } static void on_session_manager_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdBackgroundManager *manager = CSD_BACKGROUND_MANAGER (user_data); if (g_strcmp0 (signal_name, "SessionRunning") == 0) { setup_bg_and_draw_background (manager); disconnect_session_manager_listener (manager); } } static void draw_background_after_session_loads (CsdBackgroundManager *manager) { GError *error = NULL; GDBusProxyFlags flags; GVariant *var = NULL; gboolean running = FALSE; flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; manager->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, flags, NULL, /* GDBusInterfaceInfo */ "org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", NULL, /* GCancellable */ &error); if (manager->priv->proxy == NULL) { g_warning ("Could not listen to session manager: %s", error->message); g_error_free (error); return; } var = g_dbus_proxy_call_sync (manager->priv->proxy, "IsSessionRunning", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); if (var != NULL) { g_variant_get (var, "(b)", &running); g_variant_unref (var); } if (running) { setup_bg_and_draw_background (manager); } else { manager->priv->proxy_signal_id = g_signal_connect (manager->priv->proxy, "g-signal", G_CALLBACK (on_session_manager_signal), manager); } } static void disconnect_screen_signals (CsdBackgroundManager *manager) { GdkDisplay *display; display = gdk_display_get_default (); if (display) { GdkScreen *screen; screen = gdk_display_get_screen (display, 0); g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_size_changed), manager); } } static void connect_screen_signals (CsdBackgroundManager *manager) { GdkDisplay *display; display = gdk_display_get_default (); if (display) { GdkScreen *screen; screen = gdk_display_get_screen (display, 0); g_signal_connect (screen, "monitors-changed", G_CALLBACK (on_screen_size_changed), manager); g_signal_connect (screen, "size-changed", G_CALLBACK (on_screen_size_changed), manager); } } gboolean csd_background_manager_start (CsdBackgroundManager *manager, GError **error) { g_debug ("Starting background manager"); cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new ("org.cinnamon.desktop.background"); draw_background_after_session_loads (manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_background_manager_stop (CsdBackgroundManager *manager) { CsdBackgroundManagerPrivate *p = manager->priv; g_debug ("Stopping background manager"); disconnect_screen_signals (manager); if (manager->priv->proxy) { disconnect_session_manager_listener (manager); g_object_unref (manager->priv->proxy); } g_signal_handlers_disconnect_by_func (manager->priv->settings, settings_change_event_cb, manager); if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->bg != NULL) { g_object_unref (p->bg); p->bg = NULL; } } static GObject * csd_background_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdBackgroundManager *background_manager; background_manager = CSD_BACKGROUND_MANAGER (G_OBJECT_CLASS (csd_background_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (background_manager); } static void csd_background_manager_class_init (CsdBackgroundManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_background_manager_constructor; object_class->finalize = csd_background_manager_finalize; g_type_class_add_private (klass, sizeof (CsdBackgroundManagerPrivate)); } static void csd_background_manager_init (CsdBackgroundManager *manager) { manager->priv = CSD_BACKGROUND_MANAGER_GET_PRIVATE (manager); } static void csd_background_manager_finalize (GObject *object) { CsdBackgroundManager *background_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_BACKGROUND_MANAGER (object)); background_manager = CSD_BACKGROUND_MANAGER (object); g_return_if_fail (background_manager->priv != NULL); G_OBJECT_CLASS (csd_background_manager_parent_class)->finalize (object); } CsdBackgroundManager * csd_background_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_BACKGROUND_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_BACKGROUND_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/background/csd-background-manager.h000066400000000000000000000046261356401377300267100ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_BACKGROUND_MANAGER_H #define __CSD_BACKGROUND_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_BACKGROUND_MANAGER (csd_background_manager_get_type ()) #define CSD_BACKGROUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManager)) #define CSD_BACKGROUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerClass)) #define CSD_IS_BACKGROUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_BACKGROUND_MANAGER)) #define CSD_IS_BACKGROUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_BACKGROUND_MANAGER)) #define CSD_BACKGROUND_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerClass)) typedef struct CsdBackgroundManagerPrivate CsdBackgroundManagerPrivate; typedef struct { GObject parent; CsdBackgroundManagerPrivate *priv; } CsdBackgroundManager; typedef struct { GObjectClass parent_class; } CsdBackgroundManagerClass; GType csd_background_manager_get_type (void); CsdBackgroundManager * csd_background_manager_new (void); gboolean csd_background_manager_start (CsdBackgroundManager *manager, GError **error); void csd_background_manager_stop (CsdBackgroundManager *manager); G_END_DECLS #endif /* __CSD_BACKGROUND_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/background/main.c000066400000000000000000000010361356401377300233210ustar00rootroot00000000000000#define NEW csd_background_manager_new #define START csd_background_manager_start #define STOP csd_background_manager_stop #define MANAGER CsdBackgroundManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-background-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/clipboard/000077500000000000000000000000001356401377300220515ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/clipboard/Makefile.am000066400000000000000000000020671356401377300241120ustar00rootroot00000000000000NULL = plugin_name = clipboard AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-clipboard csd_clipboard_SOURCES = \ main.c \ csd-clipboard-manager.h \ csd-clipboard-manager.c \ xutils.h \ xutils.c \ list.h \ list.c \ $(NULL) csd_clipboard_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_clipboard_CPPFLAGS = \ $(PLUGIN_CFLAGS) \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_clipboard_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la $(NULL) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-clipboard.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-clipboard.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) \ $(NULL) CLEANFILES = \ $(desktop_DATA) \ $(NULL) DISTCLEANFILES = \ $(desktop_DATA) \ $(NULL) cinnamon-settings-daemon-4.4.0/plugins/clipboard/cinnamon-settings-daemon-clipboard.desktop.in000066400000000000000000000003571356401377300327140ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - clipboard Exec=@libexecdir@/csd-clipboard OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/clipboard/csd-clipboard-manager.c000066400000000000000000001153361356401377300263440ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Matthias Clasen * Copyright (C) 2007 Anders Carlsson * Copyright (C) 2007 Rodrigo Moya * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xutils.h" #include "list.h" #include "cinnamon-settings-profile.h" #include "csd-clipboard-manager.h" #define CSD_CLIPBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerPrivate)) struct CsdClipboardManagerPrivate { guint start_idle_id; Display *display; Window window; Time timestamp; List *contents; List *conversions; Window requestor; Atom property; Time time; }; typedef struct { unsigned char *data; unsigned long length; Atom target; Atom type; int format; int refcount; } TargetData; typedef struct { Atom target; TargetData *data; Atom property; Window requestor; int offset; } IncrConversion; static void csd_clipboard_manager_finalize (GObject *object); static void clipboard_manager_watch_cb (CsdClipboardManager *manager, Window window, Bool is_start, long mask, void *cb_data); G_DEFINE_TYPE (CsdClipboardManager, csd_clipboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; /* We need to use reference counting for the target data, since we may * need to keep the data around after losing the CLIPBOARD ownership * to complete incremental transfers. */ static TargetData * target_data_ref (TargetData *data) { data->refcount++; return data; } static void target_data_unref (TargetData *data) { data->refcount--; if (data->refcount == 0) { free (data->data); free (data); } } static void conversion_free (IncrConversion *rdata) { if (rdata->data) { target_data_unref (rdata->data); } free (rdata); } static void send_selection_notify (CsdClipboardManager *manager, Bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = True; notify.display = manager->priv->display; notify.requestor = manager->priv->requestor; notify.selection = XA_CLIPBOARD_MANAGER; notify.target = XA_SAVE_TARGETS; notify.property = success ? manager->priv->property : None; notify.time = manager->priv->time; gdk_x11_display_error_trap_push (gdk_display_get_default ()); XSendEvent (manager->priv->display, manager->priv->requestor, False, NoEventMask, (XEvent *)¬ify); XSync (manager->priv->display, False); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } static void finish_selection_request (CsdClipboardManager *manager, XEvent *xev, Bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = True; notify.display = xev->xselectionrequest.display; notify.requestor = xev->xselectionrequest.requestor; notify.selection = xev->xselectionrequest.selection; notify.target = xev->xselectionrequest.target; notify.property = success ? xev->xselectionrequest.property : None; notify.time = xev->xselectionrequest.time; gdk_x11_display_error_trap_push (gdk_display_get_default ()); XSendEvent (xev->xselectionrequest.display, xev->xselectionrequest.requestor, False, NoEventMask, (XEvent *) ¬ify); XSync (manager->priv->display, False); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } static gsize clipboard_bytes_per_item (int format) { switch (format) { case 8: return sizeof (char); case 16: return sizeof (short); case 32: return sizeof (long); default: ; } return 0; } static void free_contents (CsdClipboardManager *manager) { list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL); list_free (manager->priv->contents); manager->priv->contents = NULL; } static void save_targets (CsdClipboardManager *manager, Atom *save_targets, int nitems) { int nout, i; Atom *multiple; TargetData *tdata; multiple = (Atom *) malloc (2 * nitems * sizeof (Atom)); nout = 0; for (i = 0; i < nitems; i++) { if (save_targets[i] != XA_TARGETS && save_targets[i] != XA_MULTIPLE && save_targets[i] != XA_DELETE && save_targets[i] != XA_INSERT_PROPERTY && save_targets[i] != XA_INSERT_SELECTION && save_targets[i] != XA_PIXMAP) { tdata = (TargetData *) malloc (sizeof (TargetData)); tdata->data = NULL; tdata->length = 0; tdata->target = save_targets[i]; tdata->type = None; tdata->format = 0; tdata->refcount = 1; manager->priv->contents = list_prepend (manager->priv->contents, tdata); multiple[nout++] = save_targets[i]; multiple[nout++] = save_targets[i]; } } XFree (save_targets); XChangeProperty (manager->priv->display, manager->priv->window, XA_MULTIPLE, XA_ATOM_PAIR, 32, PropModeReplace, (const unsigned char *) multiple, nout); free (multiple); XConvertSelection (manager->priv->display, XA_CLIPBOARD, XA_MULTIPLE, XA_MULTIPLE, manager->priv->window, manager->priv->time); } static int find_content_target (TargetData *tdata, Atom target) { return tdata->target == target; } static int find_content_type (TargetData *tdata, Atom type) { return tdata->type == type; } static int find_conversion_requestor (IncrConversion *rdata, XEvent *xev) { return (rdata->requestor == xev->xproperty.window && rdata->property == xev->xproperty.atom); } static void get_property (TargetData *tdata, CsdClipboardManager *manager) { Atom type; int format; unsigned long length; unsigned long remaining; unsigned char *data; XGetWindowProperty (manager->priv->display, manager->priv->window, tdata->target, 0, 0x1FFFFFFF, True, AnyPropertyType, &type, &format, &length, &remaining, &data); if (type == None) { manager->priv->contents = list_remove (manager->priv->contents, tdata); free (tdata); } else if (type == XA_INCR) { tdata->type = type; tdata->length = 0; XFree (data); } else { tdata->type = type; tdata->data = data; tdata->length = length * clipboard_bytes_per_item (format); tdata->format = format; } } static Bool receive_incrementally (CsdClipboardManager *manager, XEvent *xev) { List *list; TargetData *tdata; Atom type; int format; unsigned long length, nitems, remaining; unsigned char *data; if (xev->xproperty.window != manager->priv->window) return False; list = list_find (manager->priv->contents, (ListFindFunc) find_content_target, (void *) xev->xproperty.atom); if (!list) return False; tdata = (TargetData *) list->data; if (tdata->type != XA_INCR) return False; XGetWindowProperty (xev->xproperty.display, xev->xproperty.window, xev->xproperty.atom, 0, 0x1FFFFFFF, True, AnyPropertyType, &type, &format, &nitems, &remaining, &data); length = nitems * clipboard_bytes_per_item (format); if (length == 0) { tdata->type = type; tdata->format = format; if (!list_find (manager->priv->contents, (ListFindFunc) find_content_type, (void *)XA_INCR)) { /* all incremental transfers done */ send_selection_notify (manager, True); manager->priv->requestor = None; } XFree (data); } else { if (!tdata->data) { tdata->data = data; tdata->length = length; } else { tdata->data = realloc (tdata->data, tdata->length + length + 1); memcpy (tdata->data + tdata->length, data, length + 1); tdata->length += length; XFree (data); } } return True; } static Bool send_incrementally (CsdClipboardManager *manager, XEvent *xev) { List *list; IncrConversion *rdata; unsigned long length; unsigned long items; unsigned char *data; gsize bytes_per_item; list = list_find (manager->priv->conversions, (ListFindFunc) find_conversion_requestor, xev); if (list == NULL) return False; rdata = (IncrConversion *) list->data; bytes_per_item = clipboard_bytes_per_item (rdata->data->format); if (bytes_per_item == 0) return False; data = rdata->data->data + rdata->offset; length = rdata->data->length - rdata->offset; if (length > SELECTION_MAX_SIZE) length = SELECTION_MAX_SIZE; rdata->offset += length; items = length / bytes_per_item; XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, rdata->data->type, rdata->data->format, PropModeAppend, data, items); if (length == 0) { clipboard_manager_watch_cb (manager, rdata->requestor, False, PropertyChangeMask, NULL); manager->priv->conversions = list_remove (manager->priv->conversions, rdata); conversion_free (rdata); } return True; } static void convert_clipboard_manager (CsdClipboardManager *manager, XEvent *xev) { Atom type = None; int format; unsigned long nitems; unsigned long remaining; Atom *targets = NULL; if (xev->xselectionrequest.target == XA_SAVE_TARGETS) { if (manager->priv->requestor != None || manager->priv->contents != NULL) { /* We're in the middle of a conversion request, or own * the CLIPBOARD already */ finish_selection_request (manager, xev, False); } else { gdk_x11_display_error_trap_push (gdk_display_get_default ()); clipboard_manager_watch_cb (manager, xev->xselectionrequest.requestor, True, StructureNotifyMask, NULL); XSelectInput (manager->priv->display, xev->xselectionrequest.requestor, StructureNotifyMask); XSync (manager->priv->display, False); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != Success) return; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (xev->xselectionrequest.property != None) { XGetWindowProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != Success) { if (targets) XFree (targets); return; } } manager->priv->requestor = xev->xselectionrequest.requestor; manager->priv->property = xev->xselectionrequest.property; manager->priv->time = xev->xselectionrequest.time; if (type == None) XConvertSelection (manager->priv->display, XA_CLIPBOARD, XA_TARGETS, XA_TARGETS, manager->priv->window, manager->priv->time); else save_targets (manager, targets, nitems); } } else if (xev->xselectionrequest.target == XA_TIMESTAMP) { XChangeProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &manager->priv->timestamp, 1); finish_selection_request (manager, xev, True); } else if (xev->xselectionrequest.target == XA_TARGETS) { int n_targets = 0; Atom tgets[3]; tgets[n_targets++] = XA_TARGETS; tgets[n_targets++] = XA_TIMESTAMP; tgets[n_targets++] = XA_SAVE_TARGETS; XChangeProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) tgets, n_targets); finish_selection_request (manager, xev, True); } else finish_selection_request (manager, xev, False); } static void convert_clipboard_target (IncrConversion *rdata, CsdClipboardManager *manager) { TargetData *tdata; Atom *targets; int n_targets; List *list; unsigned long items; XWindowAttributes atts; if (rdata->target == XA_TARGETS) { n_targets = list_length (manager->priv->contents) + 2; targets = (Atom *) malloc (n_targets * sizeof (Atom)); n_targets = 0; targets[n_targets++] = XA_TARGETS; targets[n_targets++] = XA_MULTIPLE; for (list = manager->priv->contents; list; list = list->next) { tdata = (TargetData *) list->data; targets[n_targets++] = tdata->target; } XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, n_targets); free (targets); } else { gsize bytes_per_item; /* Convert from stored CLIPBOARD data */ list = list_find (manager->priv->contents, (ListFindFunc) find_content_target, (void *) rdata->target); /* We got a target that we don't support */ if (!list) return; tdata = (TargetData *)list->data; if (tdata->type == XA_INCR) { /* we haven't completely received this target yet */ rdata->property = None; return; } bytes_per_item = clipboard_bytes_per_item (tdata->format); if (bytes_per_item == 0) return; rdata->data = target_data_ref (tdata); items = tdata->length / bytes_per_item; if (tdata->length <= SELECTION_MAX_SIZE) XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, tdata->type, tdata->format, PropModeReplace, tdata->data, items); else { /* start incremental transfer */ rdata->offset = 0; gdk_x11_display_error_trap_push (gdk_display_get_default ()); XGetWindowAttributes (manager->priv->display, rdata->requestor, &atts); clipboard_manager_watch_cb (manager, rdata->requestor, True, PropertyChangeMask, NULL); XSelectInput (manager->priv->display, rdata->requestor, atts.your_event_mask | PropertyChangeMask); XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, XA_INCR, 32, PropModeReplace, (unsigned char *) &items, 1); XSync (manager->priv->display, False); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } } } static void collect_incremental (IncrConversion *rdata, CsdClipboardManager *manager) { if (rdata->offset >= 0) manager->priv->conversions = list_prepend (manager->priv->conversions, rdata); else { if (rdata->data) { target_data_unref (rdata->data); rdata->data = NULL; } free (rdata); } } static void convert_clipboard (CsdClipboardManager *manager, XEvent *xev) { List *list; List *conversions; IncrConversion *rdata; Atom type; int format; unsigned long i, nitems; unsigned long remaining; Atom *multiple; conversions = NULL; type = None; if (xev->xselectionrequest.target == XA_MULTIPLE) { XGetWindowProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM_PAIR, &type, &format, &nitems, &remaining, (unsigned char **) &multiple); if (type != XA_ATOM_PAIR || nitems == 0) { if (multiple) free (multiple); return; } for (i = 0; i < nitems; i += 2) { rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = multiple[i]; rdata->property = multiple[i+1]; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } } else { multiple = NULL; rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = xev->xselectionrequest.target; rdata->property = xev->xselectionrequest.property; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } list_foreach (conversions, (Callback) convert_clipboard_target, manager); if (conversions->next == NULL && ((IncrConversion *) conversions->data)->property == None) { finish_selection_request (manager, xev, False); } else { if (multiple) { i = 0; for (list = conversions; list; list = list->next) { rdata = (IncrConversion *)list->data; multiple[i++] = rdata->target; multiple[i++] = rdata->property; } XChangeProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM_PAIR, 32, PropModeReplace, (unsigned char *) multiple, nitems); } finish_selection_request (manager, xev, True); } list_foreach (conversions, (Callback) collect_incremental, manager); list_free (conversions); if (multiple) free (multiple); } static Bool clipboard_manager_process_event (CsdClipboardManager *manager, XEvent *xev) { Atom type; int format; unsigned long nitems; unsigned long remaining; Atom *targets; targets = NULL; switch (xev->xany.type) { case DestroyNotify: if (xev->xdestroywindow.window == manager->priv->requestor) { free_contents (manager); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } break; case PropertyNotify: if (xev->xproperty.state == PropertyNewValue) { return receive_incrementally (manager, xev); } else { return send_incrementally (manager, xev); } case SelectionClear: if (xev->xany.window != manager->priv->window) return False; if (xev->xselectionclear.selection == XA_CLIPBOARD_MANAGER) { /* We lost the manager selection */ if (manager->priv->contents) { free_contents(manager); XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD, None, manager->priv->time); } return True; } if (xev->xselectionclear.selection == XA_CLIPBOARD) { /* We lost the clipboard selection */ free_contents(manager); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; return True; } break; case SelectionNotify: if (xev->xany.window != manager->priv->window) return False; if (xev->xselection.selection == XA_CLIPBOARD) { /* a CLIPBOARD conversion is done */ if (xev->xselection.property == XA_TARGETS) { XGetWindowProperty (xev->xselection.display, xev->xselection.requestor, xev->xselection.property, 0, 0x1FFFFFFF, True, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); save_targets (manager, targets, nitems); } else if (xev->xselection.property == XA_MULTIPLE) { List *tmp; tmp = list_copy (manager->priv->contents); list_foreach (tmp, (Callback) get_property, manager); list_free (tmp); manager->priv->time = xev->xselection.time; XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD, manager->priv->window, manager->priv->time); if (manager->priv->property != None) XChangeProperty (manager->priv->display, manager->priv->requestor, manager->priv->property, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XA_NULL, 1); if (!list_find (manager->priv->contents, (ListFindFunc)find_content_type, (void *)XA_INCR)) { /* all transfers done */ send_selection_notify (manager, True); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } } else if (xev->xselection.property == None) { send_selection_notify (manager, False); free_contents (manager); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } return True; } break; case SelectionRequest: if (xev->xany.window != manager->priv->window) { return False; } if (xev->xselectionrequest.selection == XA_CLIPBOARD_MANAGER) { convert_clipboard_manager (manager, xev); return True; } else if (xev->xselectionrequest.selection == XA_CLIPBOARD) { convert_clipboard (manager, xev); return True; } break; default: ; } return False; } static GdkFilterReturn clipboard_manager_event_filter (GdkXEvent *xevent, GdkEvent *event, CsdClipboardManager *manager) { if (clipboard_manager_process_event (manager, (XEvent *)xevent)) { return GDK_FILTER_REMOVE; } else { return GDK_FILTER_CONTINUE; } } static void clipboard_manager_watch_cb (CsdClipboardManager *manager, Window window, Bool is_start, long mask, void *cb_data) { GdkWindow *gdkwin; GdkDisplay *display; display = gdk_display_get_default (); gdkwin = gdk_x11_window_lookup_for_display (display, window); if (is_start) { if (gdkwin == NULL) { gdkwin = gdk_x11_window_foreign_new_for_display (display, window); } else { g_object_ref (gdkwin); } gdk_window_add_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); } else { if (gdkwin == NULL) { return; } gdk_window_remove_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); g_object_unref (gdkwin); } } static gboolean start_clipboard_idle_cb (CsdClipboardManager *manager) { XClientMessageEvent xev; cinnamon_settings_profile_start (NULL); init_atoms (manager->priv->display); /* check if there is a clipboard manager running */ if (XGetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER)) { g_warning ("Clipboard manager is already running."); return FALSE; } manager->priv->contents = NULL; manager->priv->conversions = NULL; manager->priv->requestor = None; manager->priv->window = XCreateSimpleWindow (manager->priv->display, DefaultRootWindow (manager->priv->display), 0, 0, 10, 10, 0, WhitePixel (manager->priv->display, DefaultScreen (manager->priv->display)), WhitePixel (manager->priv->display, DefaultScreen (manager->priv->display))); clipboard_manager_watch_cb (manager, manager->priv->window, True, PropertyChangeMask, NULL); XSelectInput (manager->priv->display, manager->priv->window, PropertyChangeMask); manager->priv->timestamp = get_server_time (manager->priv->display, manager->priv->window); XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER, manager->priv->window, manager->priv->timestamp); /* Check to see if we managed to claim the selection. If not, * we treat it as if we got it then immediately lost it */ if (XGetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER) == manager->priv->window) { xev.type = ClientMessage; xev.window = DefaultRootWindow (manager->priv->display); xev.message_type = XA_MANAGER; xev.format = 32; xev.data.l[0] = manager->priv->timestamp; xev.data.l[1] = XA_CLIPBOARD_MANAGER; xev.data.l[2] = manager->priv->window; xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (manager->priv->display, DefaultRootWindow (manager->priv->display), False, StructureNotifyMask, (XEvent *)&xev); } else { clipboard_manager_watch_cb (manager, manager->priv->window, False, 0, NULL); /* FIXME: manager->priv->terminate (manager->priv->cb_data); */ } cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_clipboard_manager_start (CsdClipboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_clipboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_clipboard_manager_stop (CsdClipboardManager *manager) { g_debug ("Stopping clipboard manager"); if (manager->priv->window != None) { clipboard_manager_watch_cb (manager, manager->priv->window, FALSE, 0, NULL); XDestroyWindow (manager->priv->display, manager->priv->window); manager->priv->window = None; } if (manager->priv->conversions != NULL) { list_foreach (manager->priv->conversions, (Callback) conversion_free, NULL); list_free (manager->priv->conversions); manager->priv->conversions = NULL; } if (manager->priv->contents != NULL) { free_contents (manager); } } static void csd_clipboard_manager_class_init (CsdClipboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_clipboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdClipboardManagerPrivate)); } static void csd_clipboard_manager_init (CsdClipboardManager *manager) { manager->priv = CSD_CLIPBOARD_MANAGER_GET_PRIVATE (manager); manager->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); } static void csd_clipboard_manager_finalize (GObject *object) { CsdClipboardManager *clipboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CLIPBOARD_MANAGER (object)); clipboard_manager = CSD_CLIPBOARD_MANAGER (object); g_return_if_fail (clipboard_manager->priv != NULL); csd_clipboard_manager_stop(clipboard_manager); if (clipboard_manager->priv->start_idle_id !=0) { g_source_remove (clipboard_manager->priv->start_idle_id); clipboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_clipboard_manager_parent_class)->finalize (object); } CsdClipboardManager * csd_clipboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_CLIPBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_CLIPBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/clipboard/csd-clipboard-manager.h000066400000000000000000000045631356401377300263500ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_CLIPBOARD_MANAGER_H #define __CSD_CLIPBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_CLIPBOARD_MANAGER (csd_clipboard_manager_get_type ()) #define CSD_CLIPBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManager)) #define CSD_CLIPBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerClass)) #define CSD_IS_CLIPBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CLIPBOARD_MANAGER)) #define CSD_IS_CLIPBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CLIPBOARD_MANAGER)) #define CSD_CLIPBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerClass)) typedef struct CsdClipboardManagerPrivate CsdClipboardManagerPrivate; typedef struct { GObject parent; CsdClipboardManagerPrivate *priv; } CsdClipboardManager; typedef struct { GObjectClass parent_class; } CsdClipboardManagerClass; GType csd_clipboard_manager_get_type (void); CsdClipboardManager * csd_clipboard_manager_new (void); gboolean csd_clipboard_manager_start (CsdClipboardManager *manager, GError **error); void csd_clipboard_manager_stop (CsdClipboardManager *manager); G_END_DECLS #endif /* __CSD_CLIPBOARD_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/clipboard/list.c000066400000000000000000000055041356401377300231740ustar00rootroot00000000000000/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #include #include void list_foreach (List *list, Callback func, void *user_data) { while (list) { func (list->data, user_data); list = list->next; } } List * list_prepend (List *list, void *data) { List *link; link = (List *) malloc (sizeof (List)); link->next = list; link->data = data; return link; } void list_free (List *list) { while (list) { List *next = list->next; free (list); list = next; } } List * list_find (List *list, ListFindFunc func, void *user_data) { List *tmp; for (tmp = list; tmp; tmp = tmp->next) { if ((*func) (tmp->data, user_data)) break; } return tmp; } List * list_remove (List *list, void *data) { List *tmp, *prev; prev = NULL; for (tmp = list; tmp; tmp = tmp->next) { if (tmp->data == data) { if (prev) prev->next = tmp->next; else list = tmp->next; free (tmp); break; } prev = tmp; } return list; } int list_length (List *list) { List *tmp; int length; length = 0; for (tmp = list; tmp; tmp = tmp->next) length++; return length; } List * list_copy (List *list) { List *new_list = NULL; if (list) { List *last; new_list = (List *) malloc (sizeof (List)); new_list->data = list->data; new_list->next = NULL; last = new_list; list = list->next; while (list) { last->next = (List *) malloc (sizeof (List)); last = last->next; last->data = list->data; list = list->next; } last->next = NULL; } return new_list; } cinnamon-settings-daemon-4.4.0/plugins/clipboard/list.h000066400000000000000000000035661356401377300232070ustar00rootroot00000000000000/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #ifndef LIST_H #define LIST_H typedef struct _List List; typedef void (*Callback) (void *data, void *user_data); struct _List { void *data; List *next; }; typedef int (*ListFindFunc) (void *data, void *user_data); void list_foreach (List *list, Callback func, void *user_data); List *list_prepend (List *list, void *data); void list_free (List *list); List *list_find (List *list, ListFindFunc func, void *user_data); List *list_remove (List *list, void *data); int list_length (List *list); List *list_copy (List *list); #endif /* LIST_H */ cinnamon-settings-daemon-4.4.0/plugins/clipboard/main.c000066400000000000000000000010311356401377300231340ustar00rootroot00000000000000#define NEW csd_clipboard_manager_new #define START csd_clipboard_manager_start #define STOP csd_clipboard_manager_stop #define MANAGER CsdClipboardManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-clipboard-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/clipboard/xutils.c000066400000000000000000000067561356401377300235630ustar00rootroot00000000000000/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #include #include "xutils.h" Atom XA_ATOM_PAIR; Atom XA_CLIPBOARD_MANAGER; Atom XA_CLIPBOARD; Atom XA_DELETE; Atom XA_INCR; Atom XA_INSERT_PROPERTY; Atom XA_INSERT_SELECTION; Atom XA_MANAGER; Atom XA_MULTIPLE; Atom XA_NULL; Atom XA_SAVE_TARGETS; Atom XA_TARGETS; Atom XA_TIMESTAMP; unsigned long SELECTION_MAX_SIZE = 0; void init_atoms (Display *display) { unsigned long max_request_size; if (SELECTION_MAX_SIZE > 0) return; XA_ATOM_PAIR = XInternAtom (display, "ATOM_PAIR", False); XA_CLIPBOARD_MANAGER = XInternAtom (display, "CLIPBOARD_MANAGER", False); XA_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False); XA_DELETE = XInternAtom (display, "DELETE", False); XA_INCR = XInternAtom (display, "INCR", False); XA_INSERT_PROPERTY = XInternAtom (display, "INSERT_PROPERTY", False); XA_INSERT_SELECTION = XInternAtom (display, "INSERT_SELECTION", False); XA_MANAGER = XInternAtom (display, "MANAGER", False); XA_MULTIPLE = XInternAtom (display, "MULTIPLE", False); XA_NULL = XInternAtom (display, "NULL", False); XA_SAVE_TARGETS = XInternAtom (display, "SAVE_TARGETS", False); XA_TARGETS = XInternAtom (display, "TARGETS", False); XA_TIMESTAMP = XInternAtom (display, "TIMESTAMP", False); max_request_size = XExtendedMaxRequestSize (display); if (max_request_size == 0) max_request_size = XMaxRequestSize (display); SELECTION_MAX_SIZE = max_request_size - 100; if (SELECTION_MAX_SIZE > 262144) SELECTION_MAX_SIZE = 262144; } typedef struct { Window window; Atom timestamp_prop_atom; } TimeStampInfo; static Bool timestamp_predicate (Display *display, XEvent *xevent, XPointer arg) { TimeStampInfo *info = (TimeStampInfo *)arg; if (xevent->type == PropertyNotify && xevent->xproperty.window == info->window && xevent->xproperty.atom == info->timestamp_prop_atom) return True; return False; } Time get_server_time (Display *display, Window window) { unsigned char c = 'a'; XEvent xevent; TimeStampInfo info; info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False); info.window = window; XChangeProperty (display, window, info.timestamp_prop_atom, info.timestamp_prop_atom, 8, PropModeReplace, &c, 1); XIfEvent (display, &xevent, timestamp_predicate, (XPointer)&info); return xevent.xproperty.time; } cinnamon-settings-daemon-4.4.0/plugins/clipboard/xutils.h000066400000000000000000000033401356401377300235520ustar00rootroot00000000000000/* * Copyright © 2004 Red Hat, Inc. * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Matthias Clasen, Red Hat, Inc. */ #ifndef X_UTILS_H #define X_UTILS_H #include extern Atom XA_ATOM_PAIR; extern Atom XA_CLIPBOARD_MANAGER; extern Atom XA_CLIPBOARD; extern Atom XA_DELETE; extern Atom XA_INCR; extern Atom XA_INSERT_PROPERTY; extern Atom XA_INSERT_SELECTION; extern Atom XA_MANAGER; extern Atom XA_MULTIPLE; extern Atom XA_NULL; extern Atom XA_SAVE_TARGETS; extern Atom XA_TARGETS; extern Atom XA_TIMESTAMP; extern unsigned long SELECTION_MAX_SIZE; void init_atoms (Display *display); Time get_server_time (Display *display, Window window); #endif /* X_UTILS_H */ cinnamon-settings-daemon-4.4.0/plugins/color/000077500000000000000000000000001356401377300212305ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/color/Makefile.am000066400000000000000000000034251356401377300232700ustar00rootroot00000000000000plugin_name = color AM_CFLAGS = $(WARN_CFLAGS) check_PROGRAMS = \ gcm-self-test gcm_self_test_CPPFLAGS = \ -DTESTDATADIR=\""$(top_srcdir)/plugins/color/test-data"\" \ $(AM_CPPFLAGS) gcm_self_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(COLOR_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(AM_CFLAGS) gcm_self_test_SOURCES = \ gcm-dmi.c \ gcm-dmi.h \ gcm-edid.c \ gcm-edid.h \ gcm-self-test.c gcm_self_test_LDADD = \ $(COLOR_LIBS) \ $(LCMS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ -lm TESTS = gcm-self-test libexec_PROGRAMS = csd-color csd_color_SOURCES = \ gcm-profile-store.c \ gcm-profile-store.h \ gcm-dmi.c \ gcm-dmi.h \ gcm-edid.c \ gcm-edid.h \ csd-color-manager.c \ csd-color-manager.h \ main.c csd_color_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(COLOR_CFLAGS) \ $(LCMS_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) csd_color_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DBINDIR=\"$(bindir)\" \ $(AM_CPPFLAGS) csd_color_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(COLOR_LIBS) \ $(LCMS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(LIBNOTIFY_LIBS) \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la -lm desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-color.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-color.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) \ test-data/Lenovo-T61-Internal.bin \ test-data/LG-L225W-External.bin CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/color/cinnamon-settings-daemon-color.desktop.in000066400000000000000000000003471356401377300312510ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - color Exec=@libexecdir@/csd-color OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/color/csd-color-manager.c000066400000000000000000002526511356401377300247040ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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 #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-color-manager.h" #include "gcm-profile-store.h" #include "gcm-dmi.h" #include "gcm-edid.h" #define CSD_COLOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManagerPrivate)) #define GCM_SESSION_NOTIFY_TIMEOUT 30000 /* ms */ #define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold" #define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold" struct CsdColorManagerPrivate { CinnamonSettingsSession *session; CdClient *client; GSettings *settings; GcmProfileStore *profile_store; GcmDmi *dmi; GnomeRRScreen *x11_screen; GHashTable *edid_cache; GdkWindow *gdk_window; CinnamonSettingsSessionState session_state; GHashTable *device_assign_hash; }; enum { PROP_0, }; static void csd_color_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdColorManager, csd_color_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; /* see http://www.oyranos.org/wiki/index.php?title=ICC_Profiles_in_X_Specification_0.3 */ #define GCM_ICC_PROFILE_IN_X_VERSION_MAJOR 0 #define GCM_ICC_PROFILE_IN_X_VERSION_MINOR 3 typedef struct { guint32 red; guint32 green; guint32 blue; } GnomeRROutputClutItem; GQuark csd_color_manager_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("csd_color_manager_error"); return quark; } static GcmEdid * gcm_session_get_output_edid (CsdColorManager *manager, GnomeRROutput *output, GError **error) { const guint8 *data; gsize size; GcmEdid *edid = NULL; gboolean ret; /* can we find it in the cache */ edid = g_hash_table_lookup (manager->priv->edid_cache, gnome_rr_output_get_name (output)); if (edid != NULL) { g_object_ref (edid); goto out; } /* parse edid */ data = gnome_rr_output_get_edid_data (output, &size); if (data == NULL || size == 0) { g_set_error_literal (error, GNOME_RR_ERROR, GNOME_RR_ERROR_UNKNOWN, "unable to get EDID for output"); goto out; } edid = gcm_edid_new (); ret = gcm_edid_parse (edid, data, size, error); if (!ret) { g_object_unref (edid); edid = NULL; goto out; } /* add to cache */ g_hash_table_insert (manager->priv->edid_cache, g_strdup (gnome_rr_output_get_name (output)), g_object_ref (edid)); out: return edid; } static gboolean gcm_session_screen_set_icc_profile (CsdColorManager *manager, const gchar *filename, GError **error) { gboolean ret; gchar *data = NULL; gsize length; guint version_data; CsdColorManagerPrivate *priv = manager->priv; g_return_val_if_fail (filename != NULL, FALSE); g_debug ("setting root window ICC profile atom from %s", filename); /* get contents of file */ ret = g_file_get_contents (filename, &data, &length, error); if (!ret) goto out; /* set profile property */ gdk_property_change (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) data, length); /* set version property */ version_data = GCM_ICC_PROFILE_IN_X_VERSION_MAJOR * 100 + GCM_ICC_PROFILE_IN_X_VERSION_MINOR * 1; gdk_property_change (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) &version_data, 1); out: g_free (data); return ret; } static gchar * gcm_session_get_output_id (CsdColorManager *manager, GnomeRROutput *output) { const gchar *name; const gchar *serial; const gchar *vendor; GcmEdid *edid = NULL; GString *device_id; GError *error = NULL; /* all output devices are prefixed with this */ device_id = g_string_new ("xrandr"); /* get the output EDID if possible */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_debug ("no edid for %s [%s], falling back to connection name", gnome_rr_output_get_name (output), error->message); g_error_free (error); g_string_append_printf (device_id, "-%s", gnome_rr_output_get_name (output)); goto out; } /* check EDID data is okay to use */ vendor = gcm_edid_get_vendor_name (edid); name = gcm_edid_get_monitor_name (edid); serial = gcm_edid_get_serial_number (edid); if (vendor == NULL && name == NULL && serial == NULL) { g_debug ("edid invalid for %s, falling back to connection name", gnome_rr_output_get_name (output)); g_string_append_printf (device_id, "-%s", gnome_rr_output_get_name (output)); goto out; } /* use EDID data */ if (vendor != NULL) g_string_append_printf (device_id, "-%s", vendor); if (name != NULL) g_string_append_printf (device_id, "-%s", name); if (serial != NULL) g_string_append_printf (device_id, "-%s", serial); out: if (edid != NULL) g_object_unref (edid); return g_string_free (device_id, FALSE); } static GnomeRROutput * gcm_session_get_output_by_edid_checksum (GnomeRRScreen *screen, const gchar *edid_md5, GError **error) { const guint8 *data; gchar *checksum; GnomeRROutput *output = NULL; GnomeRROutput **outputs; gsize size; guint i; outputs = gnome_rr_screen_list_outputs (screen); if (outputs == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to get outputs"); goto out; } /* find the output */ for (i = 0; outputs[i] != NULL && output == NULL; i++) { /* get edid */ data = gnome_rr_output_get_edid_data (outputs[i], &size); if (data == NULL || size < 0x6c) continue; checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, 0x6c); if (g_strcmp0 (checksum, edid_md5) == 0) output = outputs[i]; g_free (checksum); } if (output == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "no connected output with that edid hash"); } out: return output; } typedef struct { CsdColorManager *manager; CdProfile *profile; CdDevice *device; guint32 output_id; } GcmSessionAsyncHelper; static void gcm_session_async_helper_free (GcmSessionAsyncHelper *helper) { if (helper->manager != NULL) g_object_unref (helper->manager); if (helper->profile != NULL) g_object_unref (helper->profile); if (helper->device != NULL) g_object_unref (helper->device); g_free (helper); } static void gcm_session_profile_assign_add_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device = CD_DEVICE (object); gboolean ret; GError *error = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; /* add the profile to the device */ ret = cd_device_add_profile_finish (device, res, &error); if (!ret) { /* this will fail if the profile is already added */ g_debug ("failed to assign auto-edid profile to device %s: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } /* phew! */ g_debug ("successfully assigned %s to %s", cd_profile_get_object_path (helper->profile), cd_device_get_object_path (device)); out: gcm_session_async_helper_free (helper); } static void gcm_session_profile_assign_device_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device = CD_DEVICE (object); gboolean ret; GError *error = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; /* get properties */ ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_warning ("cannot connect to device: %s", error->message); g_error_free (error); gcm_session_async_helper_free (helper); goto out; } /* add the profile to the device */ cd_device_add_profile (device, CD_DEVICE_RELATION_SOFT, helper->profile, NULL, gcm_session_profile_assign_add_profile_cb, helper); out: return; } static void gcm_session_profile_assign_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdClient *client = CD_CLIENT (object); CdDevice *device = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; GError *error = NULL; device = cd_client_find_device_finish (client, res, &error); if (device == NULL) { g_warning ("not found device which should have been added: %s", error->message); g_error_free (error); gcm_session_async_helper_free (helper); goto out; } /* get properties */ cd_device_connect (device, NULL, gcm_session_profile_assign_device_connect_cb, helper); out: if (device != NULL) g_object_unref (device); } static void gcm_session_profile_assign_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile = CD_PROFILE (object); const gchar *edid_md5; gboolean ret; gchar *device_id = NULL; GcmSessionAsyncHelper *helper; GError *error = NULL; GHashTable *metadata = NULL; GnomeRROutput *output = NULL; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); /* get properties */ ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("cannot connect to profile: %s", error->message); g_error_free (error); goto out; } /* does the profile have EDID metadata? */ metadata = cd_profile_get_metadata (profile); edid_md5 = g_hash_table_lookup (metadata, CD_PROFILE_METADATA_EDID_MD5); if (edid_md5 == NULL) goto out; /* get the GnomeRROutput for the edid */ output = gcm_session_get_output_by_edid_checksum (manager->priv->x11_screen, edid_md5, &error); if (output == NULL) { g_debug ("edid hash %s ignored: %s", edid_md5, error->message); g_error_free (error); goto out; } /* get the CdDevice for this ID */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->manager = g_object_ref (manager); helper->profile = g_object_ref (profile); device_id = gcm_session_get_output_id (manager, output); cd_client_find_device (manager->priv->client, device_id, NULL, gcm_session_profile_assign_find_device_cb, helper); out: g_free (device_id); if (metadata != NULL) g_hash_table_unref (metadata); } static void gcm_session_profile_added_assign_cb (CdClient *client, CdProfile *profile, CsdColorManager *manager) { cd_profile_connect (profile, NULL, gcm_session_profile_assign_profile_connect_cb, manager); } static cmsBool _cmsWriteTagTextAscii (cmsHPROFILE lcms_profile, cmsTagSignature sig, const gchar *text) { cmsBool ret; cmsMLU *mlu = cmsMLUalloc (0, 1); cmsMLUsetASCII (mlu, "EN", "us", text); ret = cmsWriteTag (lcms_profile, sig, mlu); cmsMLUfree (mlu); return ret; } static gboolean gcm_utils_mkdir_for_filename (const gchar *filename, GError **error) { gboolean ret = FALSE; GFile *file; GFile *parent_dir = NULL; /* get parent directory */ file = g_file_new_for_path (filename); parent_dir = g_file_get_parent (file); if (parent_dir == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "could not get parent dir %s", filename); goto out; } /* ensure desination does not already exist */ ret = g_file_query_exists (parent_dir, NULL); if (ret) goto out; ret = g_file_make_directory_with_parents (parent_dir, NULL, error); if (!ret) goto out; out: if (file != NULL) g_object_unref (file); if (parent_dir != NULL) g_object_unref (parent_dir); return ret; } #ifdef HAVE_NEW_LCMS static wchar_t * utf8_to_wchar_t (const char *src) { size_t len; size_t converted; wchar_t *buf = NULL; len = mbstowcs (NULL, src, 0); if (len == (size_t) -1) { g_warning ("Invalid UTF-8 in string %s", src); goto out; } len += 1; buf = g_malloc (sizeof (wchar_t) * len); converted = mbstowcs (buf, src, len - 1); g_assert (converted != (size_t)-1); buf[converted] = '\0'; out: return buf; } static cmsBool _cmsDictAddEntryAscii (cmsHANDLE dict, const gchar *key, const gchar *value) { cmsBool ret = FALSE; wchar_t *mb_key = NULL; wchar_t *mb_value = NULL; mb_key = utf8_to_wchar_t (key); if (mb_key == NULL) goto out; mb_value = utf8_to_wchar_t (value); if (mb_value == NULL) goto out; ret = cmsDictAddEntry (dict, mb_key, mb_value, NULL, NULL); out: g_free (mb_key); g_free (mb_value); return ret; } #endif /* HAVE_NEW_LCMS */ static gboolean gcm_apply_create_icc_profile_for_edid (CsdColorManager *manager, GcmEdid *edid, const gchar *filename, GError **error) { const CdColorYxy *tmp; cmsCIExyYTRIPLE chroma; cmsCIExyY white_point; cmsHPROFILE lcms_profile = NULL; cmsToneCurve *transfer_curve[3] = { NULL, NULL, NULL }; const gchar *data; gboolean ret = FALSE; gchar *str; gfloat edid_gamma; gfloat localgamma; #ifdef HAVE_NEW_LCMS cmsHANDLE dict = NULL; #endif CsdColorManagerPrivate *priv = manager->priv; /* ensure the per-user directory exists */ ret = gcm_utils_mkdir_for_filename (filename, error); if (!ret) goto out; /* copy color data from our structures */ tmp = gcm_edid_get_red (edid); chroma.Red.x = tmp->x; chroma.Red.y = tmp->y; tmp = gcm_edid_get_green (edid); chroma.Green.x = tmp->x; chroma.Green.y = tmp->y; tmp = gcm_edid_get_blue (edid); chroma.Blue.x = tmp->x; chroma.Blue.y = tmp->y; tmp = gcm_edid_get_white (edid); white_point.x = tmp->x; white_point.y = tmp->y; white_point.Y = 1.0; /* estimate the transfer function for the gamma */ localgamma = gcm_edid_get_gamma (edid); transfer_curve[0] = transfer_curve[1] = transfer_curve[2] = cmsBuildGamma (NULL, localgamma); /* create our generated profile */ lcms_profile = cmsCreateRGBProfile (&white_point, &chroma, transfer_curve); if (lcms_profile == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to create profile"); goto out; } cmsSetColorSpace (lcms_profile, cmsSigRgbData); cmsSetPCS (lcms_profile, cmsSigXYZData); cmsSetHeaderRenderingIntent (lcms_profile, INTENT_PERCEPTUAL); cmsSetDeviceClass (lcms_profile, cmsSigDisplayClass); /* copyright */ ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigCopyrightTag, /* deliberately not translated */ "This profile is free of known copyright restrictions."); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write copyright"); goto out; } /* set model */ data = gcm_edid_get_monitor_name (edid); if (data == NULL) data = gcm_dmi_get_name (priv->dmi); if (data == NULL) data = "Unknown monitor"; ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigDeviceModelDescTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write model"); goto out; } /* write title */ ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigProfileDescriptionTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write description"); goto out; } /* get manufacturer */ data = gcm_edid_get_vendor_name (edid); if (data == NULL) data = gcm_dmi_get_vendor (priv->dmi); if (data == NULL) data = "Unknown vendor"; ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigDeviceMfgDescTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write manufacturer"); goto out; } #ifdef HAVE_NEW_LCMS /* just create a new dict */ dict = cmsDictAlloc (NULL); /* set the framework creator metadata */ _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_PRODUCT, PACKAGE_NAME); _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_BINARY, PACKAGE_NAME); _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_VERSION, PACKAGE_VERSION); /* set the data source so we don't ever prompt the user to * recalibrate (as the EDID data won't have changed) */ _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_DATA_SOURCE, CD_PROFILE_METADATA_DATA_SOURCE_EDID); /* set 'ICC meta Tag for Monitor Profiles' data */ _cmsDictAddEntryAscii (dict, "EDID_md5", gcm_edid_get_checksum (edid)); data = gcm_edid_get_monitor_name (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_model", data); data = gcm_edid_get_serial_number (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_serial", data); data = gcm_edid_get_pnp_id (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_mnft", data); data = gcm_edid_get_vendor_name (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_manufacturer", data); edid_gamma = gcm_edid_get_gamma (edid); if (edid_gamma > 0.0 && edid_gamma < 10.0) { str = g_strdup_printf ("%f", edid_gamma); _cmsDictAddEntryAscii (dict, "EDID_gamma", str); g_free (str); } /* also add the primaries */ str = g_strdup_printf ("%f", chroma.Red.x); _cmsDictAddEntryAscii (dict, "EDID_red_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Red.y); _cmsDictAddEntryAscii (dict, "EDID_red_y", str); g_free (str); str = g_strdup_printf ("%f", chroma.Green.x); _cmsDictAddEntryAscii (dict, "EDID_green_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Green.y); _cmsDictAddEntryAscii (dict, "EDID_green_y", str); g_free (str); str = g_strdup_printf ("%f", chroma.Blue.x); _cmsDictAddEntryAscii (dict, "EDID_blue_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Blue.y); _cmsDictAddEntryAscii (dict, "EDID_blue_y", str); g_free (str); /* write new tag */ ret = cmsWriteTag (lcms_profile, cmsSigMetaTag, dict); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write profile metadata"); goto out; } #endif /* HAVE_NEW_LCMS */ /* write profile id */ ret = cmsMD5computeID (lcms_profile); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write profile id"); goto out; } /* save, TODO: get error */ cmsSaveProfileToFile (lcms_profile, filename); ret = TRUE; out: #ifdef HAVE_NEW_LCMS if (dict != NULL) cmsDictFree (dict); #endif if (*transfer_curve != NULL) cmsFreeToneCurve (*transfer_curve); return ret; } static GPtrArray * gcm_session_generate_vcgt (CdProfile *profile, guint size) { GnomeRROutputClutItem *tmp; GPtrArray *array = NULL; const cmsToneCurve **vcgt; cmsFloat32Number in; guint i; const gchar *filename; cmsHPROFILE lcms_profile = NULL; /* invalid size */ if (size == 0) goto out; /* not an actual profile */ filename = cd_profile_get_filename (profile); if (filename == NULL) goto out; /* open file */ lcms_profile = cmsOpenProfileFromFile (filename, "r"); if (lcms_profile == NULL) goto out; /* get tone curves from profile */ vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag); if (vcgt == NULL || vcgt[0] == NULL) { g_debug ("profile does not have any VCGT data"); goto out; } /* create array */ array = g_ptr_array_new_with_free_func (g_free); for (i = 0; i < size; i++) { in = (gdouble) i / (gdouble) (size - 1); tmp = g_new0 (GnomeRROutputClutItem, 1); tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * (gdouble) 0xffff; tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * (gdouble) 0xffff; tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * (gdouble) 0xffff; g_ptr_array_add (array, tmp); } out: if (lcms_profile != NULL) cmsCloseProfile (lcms_profile); return array; } static guint cinnamon_rr_output_get_gamma_size (GnomeRROutput *output) { GnomeRRCrtc *crtc; gint len = 0; crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) return 0; gnome_rr_crtc_get_gamma (crtc, &len, NULL, NULL, NULL); return (guint) len; } static gboolean gcm_session_output_set_gamma (GnomeRROutput *output, GPtrArray *array, GError **error) { gboolean ret = TRUE; guint16 *red = NULL; guint16 *green = NULL; guint16 *blue = NULL; guint i; GnomeRROutputClutItem *data; GnomeRRCrtc *crtc; /* no length? */ if (array->len == 0) { ret = FALSE; g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "no data in the CLUT array"); goto out; } /* convert to a type X understands */ red = g_new (guint16, array->len); green = g_new (guint16, array->len); blue = g_new (guint16, array->len); for (i = 0; i < array->len; i++) { data = g_ptr_array_index (array, i); red[i] = data->red; green[i] = data->green; blue[i] = data->blue; } /* send to LUT */ crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { ret = FALSE; g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to get ctrc for %s", gnome_rr_output_get_name (output)); goto out; } gnome_rr_crtc_set_gamma (crtc, array->len, red, green, blue); out: g_free (red); g_free (green); g_free (blue); return ret; } static gboolean gcm_session_device_set_gamma (GnomeRROutput *output, CdProfile *profile, GError **error) { gboolean ret = FALSE; guint size; GPtrArray *clut = NULL; /* create a lookup table */ size = cinnamon_rr_output_get_gamma_size (output); if (size == 0) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "gamma size is zero"); goto out; } clut = gcm_session_generate_vcgt (profile, size); if (clut == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to generate vcgt"); goto out; } /* apply the vcgt to this output */ ret = gcm_session_output_set_gamma (output, clut, error); if (!ret) goto out; out: if (clut != NULL) g_ptr_array_unref (clut); return ret; } static gboolean gcm_session_device_reset_gamma (GnomeRROutput *output, GError **error) { gboolean ret; guint i; guint size; guint32 value; GPtrArray *clut; GnomeRROutputClutItem *data; /* create a linear ramp */ g_debug ("falling back to dummy ramp"); clut = g_ptr_array_new_with_free_func (g_free); size = cinnamon_rr_output_get_gamma_size (output); if (size == 0) { ret = FALSE; g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "gamma size is zero"); goto out; } for (i = 0; i < size; i++) { value = (i * 0xffff) / (size - 1); data = g_new0 (GnomeRROutputClutItem, 1); data->red = value; data->green = value; data->blue = value; g_ptr_array_add (clut, data); } /* apply the vcgt to this output */ ret = gcm_session_output_set_gamma (output, clut, error); if (!ret) goto out; out: g_ptr_array_unref (clut); return ret; } static GnomeRROutput * gcm_session_get_x11_output_by_id (CsdColorManager *manager, const gchar *device_id, GError **error) { gchar *output_id; GnomeRROutput *output = NULL; GnomeRROutput **outputs = NULL; guint i; CsdColorManagerPrivate *priv = manager->priv; /* search all X11 outputs for the device id */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to get outputs"); goto out; } for (i = 0; outputs[i] != NULL && output == NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; output_id = gcm_session_get_output_id (manager, outputs[i]); if (g_strcmp0 (output_id, device_id) == 0) output = outputs[i]; g_free (output_id); } if (output == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to find output %s", device_id); } out: return output; } /* this function is more complicated than it should be, due to the * fact that XOrg sometimes assigns no primary devices when using * "xrandr --auto" or when the version of RANDR is < 1.3 */ static gboolean gcm_session_use_output_profile_for_screen (CsdColorManager *manager, GnomeRROutput *output) { gboolean has_laptop = FALSE; gboolean has_primary = FALSE; GnomeRROutput **outputs; GnomeRROutput *connected = NULL; guint i; /* do we have any screens marked as primary */ outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen); if (outputs == NULL || outputs[0] == NULL) { g_warning ("failed to get outputs"); return FALSE; } for (i = 0; outputs[i] != NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; if (connected == NULL) connected = outputs[i]; if (gnome_rr_output_get_is_primary (outputs[i])) has_primary = TRUE; if (gnome_rr_output_is_laptop (outputs[i])) has_laptop = TRUE; } /* we have an assigned primary device, are we that? */ if (has_primary) return gnome_rr_output_get_is_primary (output); /* choosing the internal panel is probably sane */ if (has_laptop) return gnome_rr_output_is_laptop (output); /* we have to choose one, so go for the first connected device */ if (connected != NULL) return gnome_rr_output_get_id (connected) == gnome_rr_output_get_id (output); return FALSE; } /* TODO: remove when we can dep on a released version of colord */ #ifndef CD_PROFILE_METADATA_SCREEN_BRIGHTNESS #define CD_PROFILE_METADATA_SCREEN_BRIGHTNESS "SCREEN_brightness" #endif #define CSD_DBUS_SERVICE "org.cinnamon.SettingsDaemon.Power" #define CSD_DBUS_INTERFACE_POWER_SCREEN "org.cinnamon.SettingsDaemon.Power.Screen" #define CSD_DBUS_PATH_POWER "/org/cinnamon/SettingsDaemon/Power" static void gcm_session_set_output_percentage_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GDBusConnection *connection = G_DBUS_CONNECTION (source_object); GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (connection, res, &error); if (retval == NULL) { g_warning ("failed to set output brightness: %s", error->message); g_error_free (error); return; } g_variant_unref (retval); } static void gcm_session_set_output_percentage (guint percentage) { GDBusConnection *connection; /* get a ref to the existing bus connection */ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); if (connection == NULL) return; g_dbus_connection_call (connection, CSD_DBUS_SERVICE, CSD_DBUS_PATH_POWER, CSD_DBUS_INTERFACE_POWER_SCREEN, "SetPercentage", g_variant_new ("(u)", percentage), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, gcm_session_set_output_percentage_cb, NULL); g_object_unref (connection); } static void gcm_session_device_assign_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile = CD_PROFILE (object); const gchar *brightness_profile; const gchar *filename; gboolean ret; GError *error = NULL; GnomeRROutput *output; guint brightness_percentage; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; CsdColorManager *manager = CSD_COLOR_MANAGER (helper->manager); /* get properties */ ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("failed to connect to profile: %s", error->message); g_error_free (error); goto out; } /* get the filename */ filename = cd_profile_get_filename (profile); g_assert (filename != NULL); /* get the output (can't save in helper as GnomeRROutput isn't * a GObject, just a pointer */ output = gnome_rr_screen_get_output_by_id (manager->priv->x11_screen, helper->output_id); if (output == NULL) goto out; /* if output is a laptop screen and the profile has a * calibration brightness then set this new brightness */ brightness_profile = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_SCREEN_BRIGHTNESS); if (gnome_rr_output_is_laptop (output) && brightness_profile != NULL) { /* the percentage is stored in the profile metadata as * a string, not ideal, but it's all we have... */ brightness_percentage = atoi (brightness_profile); gcm_session_set_output_percentage (brightness_percentage); } /* set the _ICC_PROFILE atom */ ret = gcm_session_use_output_profile_for_screen (manager, output); if (ret) { ret = gcm_session_screen_set_icc_profile (manager, filename, &error); if (!ret) { g_warning ("failed to set screen _ICC_PROFILE: %s", error->message); g_clear_error (&error); } } /* create a vcgt for this icc file */ ret = cd_profile_get_has_vcgt (profile); if (ret) { ret = gcm_session_device_set_gamma (output, profile, &error); if (!ret) { g_warning ("failed to set %s gamma tables: %s", cd_device_get_id (helper->device), error->message); g_error_free (error); goto out; } } else { ret = gcm_session_device_reset_gamma (output, &error); if (!ret) { g_warning ("failed to reset %s gamma tables: %s", cd_device_get_id (helper->device), error->message); g_error_free (error); goto out; } } out: gcm_session_async_helper_free (helper); } static void gcm_session_device_assign_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDeviceKind kind; CdProfile *profile = NULL; gboolean ret; gchar *autogen_filename = NULL; gchar *autogen_path = NULL; GcmEdid *edid = NULL; GnomeRROutput *output = NULL; GError *error = NULL; const gchar *xrandr_id; GcmSessionAsyncHelper *helper; CdDevice *device = CD_DEVICE (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); CsdColorManagerPrivate *priv = manager->priv; /* remove from assign array */ g_hash_table_remove (manager->priv->device_assign_hash, cd_device_get_object_path (device)); /* get properties */ ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_debug ("failed to connect to device: %s", error->message); g_error_free (error); goto out; } /* check we care */ kind = cd_device_get_kind (device); if (kind != CD_DEVICE_KIND_DISPLAY) goto out; g_debug ("need to assign display device %s", cd_device_get_id (device)); /* get the GnomeRROutput for the device id */ xrandr_id = cd_device_get_id (device); output = gcm_session_get_x11_output_by_id (manager, xrandr_id, &error); if (output == NULL) { g_warning ("no %s device found: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } /* create profile from device edid if it exists */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_warning ("unable to get EDID for %s: %s", cd_device_get_id (device), error->message); g_clear_error (&error); } else { autogen_filename = g_strdup_printf ("edid-%s.icc", gcm_edid_get_checksum (edid)); autogen_path = g_build_filename (g_get_user_data_dir (), "icc", autogen_filename, NULL); if (g_file_test (autogen_path, G_FILE_TEST_EXISTS)) { g_debug ("auto-profile edid %s exists", autogen_path); } else { g_debug ("auto-profile edid does not exist, creating as %s", autogen_path); ret = gcm_apply_create_icc_profile_for_edid (manager, edid, autogen_path, &error); if (!ret) { g_warning ("failed to create profile from EDID data: %s", error->message); g_clear_error (&error); } } } /* get the default profile for the device */ profile = cd_device_get_default_profile (device); if (profile == NULL) { g_debug ("%s has no default profile to set", cd_device_get_id (device)); /* the default output? */ if (gnome_rr_output_get_is_primary (output)) { gdk_property_delete (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE")); gdk_property_delete (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION")); } /* reset, as we want linear profiles for profiling */ ret = gcm_session_device_reset_gamma (output, &error); if (!ret) { g_warning ("failed to reset %s gamma tables: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } goto out; } /* get properties */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->output_id = gnome_rr_output_get_id (output); helper->manager = g_object_ref (manager); helper->device = g_object_ref (device); cd_profile_connect (profile, NULL, gcm_session_device_assign_profile_connect_cb, helper); out: g_free (autogen_filename); g_free (autogen_path); if (edid != NULL) g_object_unref (edid); if (profile != NULL) g_object_unref (profile); } static void gcm_session_device_assign (CsdColorManager *manager, CdDevice *device) { const gchar *key; gpointer found; /* are we already assigning this device */ key = cd_device_get_object_path (device); found = g_hash_table_lookup (manager->priv->device_assign_hash, key); if (found != NULL) { g_debug ("assign for %s already in progress", key); return; } g_hash_table_insert (manager->priv->device_assign_hash, g_strdup (key), GINT_TO_POINTER (TRUE)); cd_device_connect (device, NULL, gcm_session_device_assign_connect_cb, manager); } static void gcm_session_device_added_assign_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { gcm_session_device_assign (manager, device); } static void gcm_session_device_changed_assign_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { g_debug ("%s changed", cd_device_get_object_path (device)); gcm_session_device_assign (manager, device); } static void gcm_session_create_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; device = cd_client_create_device_finish (CD_CLIENT (object), res, &error); if (device == NULL) { if (error->domain != CD_CLIENT_ERROR || error->code != CD_CLIENT_ERROR_ALREADY_EXISTS) { g_warning ("failed to create device: %s", error->message); } g_error_free (error); return; } g_object_unref (device); } static void gcm_session_add_x11_output (CsdColorManager *manager, GnomeRROutput *output) { const gchar *model = NULL; const gchar *serial = NULL; const gchar *vendor = NULL; gboolean ret; gchar *device_id = NULL; GcmEdid *edid; GError *error = NULL; GHashTable *device_props = NULL; CsdColorManagerPrivate *priv = manager->priv; /* try to get edid */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_warning ("failed to get edid: %s", error->message); g_clear_error (&error); } /* prefer DMI data for the internal output */ ret = gnome_rr_output_is_laptop (output); if (ret) { model = gcm_dmi_get_name (priv->dmi); vendor = gcm_dmi_get_vendor (priv->dmi); } /* use EDID data if we have it */ if (edid != NULL) { if (model == NULL) model = gcm_edid_get_monitor_name (edid); if (vendor == NULL) vendor = gcm_edid_get_vendor_name (edid); if (serial == NULL) serial = gcm_edid_get_serial_number (edid); } /* ensure mandatory fields are set */ if (model == NULL) model = gnome_rr_output_get_name (output); if (vendor == NULL) vendor = "unknown"; if (serial == NULL) serial = "unknown"; device_id = gcm_session_get_output_id (manager, output); g_debug ("output %s added", device_id); device_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_KIND, (gpointer) cd_device_kind_to_string (CD_DEVICE_KIND_DISPLAY)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODE, (gpointer) cd_device_mode_to_string (CD_DEVICE_MODE_PHYSICAL)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_COLORSPACE, (gpointer) cd_colorspace_to_string (CD_COLORSPACE_RGB)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_VENDOR, (gpointer) vendor); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODEL, (gpointer) model); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_SERIAL, (gpointer) serial); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_XRANDR_NAME, (gpointer) gnome_rr_output_get_name (output)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY, gnome_rr_output_get_is_primary (output) ? (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_PRIMARY : (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_SECONDARY); /* set this so we can call the device a 'Laptop Screen' in the * control center main panel */ if (gnome_rr_output_is_laptop (output)) { g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_EMBEDDED, NULL); } cd_client_create_device (priv->client, device_id, CD_OBJECT_SCOPE_TEMP, device_props, NULL, gcm_session_create_device_cb, manager); g_free (device_id); if (device_props != NULL) g_hash_table_unref (device_props); if (edid != NULL) g_object_unref (edid); } static void cinnamon_rr_screen_output_added_cb (GnomeRRScreen *screen, GnomeRROutput *output, CsdColorManager *manager) { gcm_session_add_x11_output (manager, output); } static void gcm_session_screen_removed_delete_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; /* deleted device */ ret = cd_client_delete_device_finish (CD_CLIENT (object), res, &error); if (!ret) { g_warning ("failed to delete device: %s", error->message); g_error_free (error); } } static void gcm_session_screen_removed_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CdDevice *device; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); device = cd_client_find_device_finish (manager->priv->client, res, &error); if (device == NULL) { g_warning ("failed to find device: %s", error->message); g_error_free (error); return; } g_debug ("output %s found, and will be removed", cd_device_get_object_path (device)); cd_client_delete_device (manager->priv->client, device, NULL, gcm_session_screen_removed_delete_device_cb, manager); g_object_unref (device); } static void cinnamon_rr_screen_output_removed_cb (GnomeRRScreen *screen, GnomeRROutput *output, CsdColorManager *manager) { g_debug ("output %s removed", gnome_rr_output_get_name (output)); g_hash_table_remove (manager->priv->edid_cache, gnome_rr_output_get_name (output)); cd_client_find_device_by_property (manager->priv->client, CD_DEVICE_METADATA_XRANDR_NAME, gnome_rr_output_get_name (output), NULL, gcm_session_screen_removed_find_device_cb, manager); } static void gcm_session_get_devices_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; GPtrArray *array; guint i; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); array = cd_client_get_devices_finish (CD_CLIENT (object), res, &error); if (array == NULL) { g_warning ("failed to get devices: %s", error->message); g_error_free (error); goto out; } for (i = 0; i < array->len; i++) { device = g_ptr_array_index (array, i); gcm_session_device_assign (manager, device); } out: if (array != NULL) g_ptr_array_unref (array); } static void gcm_session_profile_gamma_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdClient *client = CD_CLIENT (object); CdDevice *device = NULL; GError *error = NULL; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); device = cd_client_find_device_by_property_finish (client, res, &error); if (device == NULL) { g_warning ("could not find device: %s", error->message); g_error_free (error); goto out; } /* get properties */ cd_device_connect (device, NULL, gcm_session_device_assign_connect_cb, manager); out: if (device != NULL) g_object_unref (device); } /* We have to reset the gamma tables each time as if the primary output * has changed then different crtcs are going to be used. * See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */ static void cinnamon_rr_screen_output_changed_cb (GnomeRRScreen *screen, CsdColorManager *manager) { GnomeRROutput **outputs; CsdColorManagerPrivate *priv = manager->priv; guint i; /* get X11 outputs */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_warning ("failed to get outputs"); return; } for (i = 0; outputs[i] != NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; /* get CdDevice for this output */ cd_client_find_device_by_property (manager->priv->client, CD_DEVICE_METADATA_XRANDR_NAME, gnome_rr_output_get_name (outputs[i]), NULL, gcm_session_profile_gamma_find_device_cb, manager); } } static void gcm_session_client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; GnomeRROutput **outputs; guint i; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); CsdColorManagerPrivate *priv = manager->priv; /* connected */ g_debug ("connected to colord"); ret = cd_client_connect_finish (manager->priv->client, res, &error); if (!ret) { g_warning ("failed to connect to colord: %s", error->message); g_error_free (error); return; } /* is there an available colord instance? */ ret = cd_client_get_has_server (manager->priv->client); if (!ret) { g_warning ("There is no colord server available"); goto out; } /* add profiles */ gcm_profile_store_search (priv->profile_store); /* add screens */ gnome_rr_screen_refresh (priv->x11_screen, &error); if (error != NULL) { g_warning ("failed to refresh: %s", error->message); g_error_free (error); goto out; } /* get X11 outputs */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_warning ("failed to get outputs"); goto out; } for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_connected (outputs[i])) gcm_session_add_x11_output (manager, outputs[i]); } /* only connect when colord is awake */ g_signal_connect (priv->x11_screen, "output-connected", G_CALLBACK (cinnamon_rr_screen_output_added_cb), manager); g_signal_connect (priv->x11_screen, "output-disconnected", G_CALLBACK (cinnamon_rr_screen_output_removed_cb), manager); g_signal_connect (priv->x11_screen, "changed", G_CALLBACK (cinnamon_rr_screen_output_changed_cb), manager); g_signal_connect (priv->client, "profile-added", G_CALLBACK (gcm_session_profile_added_assign_cb), manager); g_signal_connect (priv->client, "device-added", G_CALLBACK (gcm_session_device_added_assign_cb), manager); g_signal_connect (priv->client, "device-changed", G_CALLBACK (gcm_session_device_changed_assign_cb), manager); /* set for each device that already exist */ cd_client_get_devices (priv->client, NULL, gcm_session_get_devices_cb, manager); out: return; } gboolean csd_color_manager_start (CsdColorManager *manager, GError **error) { CsdColorManagerPrivate *priv = manager->priv; gboolean ret = FALSE; g_debug ("Starting color manager"); cinnamon_settings_profile_start (NULL); /* coldplug the list of screens */ priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (priv->x11_screen == NULL) goto out; cd_client_connect (priv->client, NULL, gcm_session_client_connect_cb, manager); /* success */ ret = TRUE; out: cinnamon_settings_profile_end (NULL); return ret; } void csd_color_manager_stop (CsdColorManager *manager) { g_debug ("Stopping color manager"); g_return_if_fail (manager->priv != NULL); if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->client != NULL) { g_object_unref (manager->priv->client); manager->priv->client = NULL; } if (manager->priv->profile_store != NULL) { g_object_unref (manager->priv->profile_store); manager->priv->profile_store = NULL; } if (manager->priv->dmi != NULL) { g_object_unref (manager->priv->dmi); manager->priv->dmi = NULL; } if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->edid_cache != NULL) { g_hash_table_destroy (manager->priv->edid_cache); manager->priv->edid_cache = NULL; } if (manager->priv->device_assign_hash != NULL) { g_hash_table_destroy (manager->priv->device_assign_hash); manager->priv->device_assign_hash = NULL; } if (manager->priv->x11_screen != NULL) g_object_unref (manager->priv->x11_screen); manager->priv->x11_screen = NULL; } static void gcm_session_exec_control_center (CsdColorManager *manager) { gboolean ret; GError *error = NULL; GAppInfo *app_info; GdkAppLaunchContext *launch_context; /* setup the launch context so the startup notification is correct */ launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ()); app_info = g_app_info_create_from_commandline (BINDIR "/cinnamon-settings color", "cinnamon-settings", G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION, &error); if (app_info == NULL) { g_warning ("failed to create application info: %s", error->message); g_error_free (error); goto out; } /* launch cinnamon-settings */ ret = g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error); if (!ret) { g_warning ("failed to launch cinnamon-settings: %s", error->message); g_error_free (error); goto out; } out: g_object_unref (launch_context); if (app_info != NULL) g_object_unref (app_info); } static void gcm_session_notify_cb (NotifyNotification *notification, gchar *action, gpointer user_data) { CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); if (g_strcmp0 (action, "recalibrate") == 0) { notify_notification_close (notification, NULL); gcm_session_exec_control_center (manager); } } static void closed_cb (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static gboolean gcm_session_notify_recalibrate (CsdColorManager *manager, const gchar *title, const gchar *message, CdDeviceKind kind) { gboolean ret; GError *error = NULL; NotifyNotification *notification; CsdColorManagerPrivate *priv = manager->priv; /* show a bubble */ notification = notify_notification_new (title, message, "preferences-color"); notify_notification_set_timeout (notification, GCM_SESSION_NOTIFY_TIMEOUT); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); notify_notification_set_app_name (notification, _("Color")); /* TRANSLATORS: button: this is to open GCM */ notify_notification_add_action (notification, "recalibrate", _("Recalibrate now"), gcm_session_notify_cb, priv, NULL); g_signal_connect (notification, "closed", G_CALLBACK (closed_cb), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); } return ret; } static gchar * gcm_session_device_get_title (CdDevice *device) { const gchar *vendor; const gchar *model; model = cd_device_get_model (device); vendor = cd_device_get_vendor (device); if (model != NULL && vendor != NULL) return g_strdup_printf ("%s - %s", vendor, model); if (vendor != NULL) return g_strdup (vendor); if (model != NULL) return g_strdup (model); return g_strdup (cd_device_get_id (device)); } static void gcm_session_notify_device (CsdColorManager *manager, CdDevice *device) { CdDeviceKind kind; const gchar *title; gchar *device_title = NULL; gchar *message; guint threshold; glong since; CsdColorManagerPrivate *priv = manager->priv; /* TRANSLATORS: this is when the device has not been recalibrated in a while */ title = _("Recalibration required"); device_title = gcm_session_device_get_title (device); /* check we care */ kind = cd_device_get_kind (device); if (kind == CD_DEVICE_KIND_DISPLAY) { /* get from GSettings */ threshold = g_settings_get_uint (priv->settings, GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD); /* TRANSLATORS: this is when the display has not been recalibrated in a while */ message = g_strdup_printf (_("The display '%s' should be recalibrated soon."), device_title); } else { /* get from GSettings */ threshold = g_settings_get_uint (priv->settings, GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD); /* TRANSLATORS: this is when the printer has not been recalibrated in a while */ message = g_strdup_printf (_("The printer '%s' should be recalibrated soon."), device_title); } /* check if we need to notify */ since = (g_get_real_time () - cd_device_get_modified (device)) / G_USEC_PER_SEC; if (threshold > since) gcm_session_notify_recalibrate (manager, title, message, kind); g_free (device_title); g_free (message); } static void gcm_session_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { const gchar *filename; gboolean ret; gchar *basename = NULL; const gchar *data_source; GError *error = NULL; CdProfile *profile = CD_PROFILE (object); GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; CsdColorManager *manager = CSD_COLOR_MANAGER (helper->manager); ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("failed to connect to profile: %s", error->message); g_error_free (error); goto out; } /* ensure it's a profile generated by us */ data_source = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_DATA_SOURCE); if (data_source == NULL) { /* existing profiles from gnome-color-manager < 3.1 * won't have the extra metadata values added */ filename = cd_profile_get_filename (profile); if (filename == NULL) goto out; basename = g_path_get_basename (filename); if (!g_str_has_prefix (basename, "GCM")) { g_debug ("not a GCM profile for %s: %s", cd_device_get_id (helper->device), filename); goto out; } /* ensure it's been created from a calibration, rather than from * auto-EDID */ } else if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_CALIB) != 0) { g_debug ("not a calib profile for %s", cd_device_get_id (helper->device)); goto out; } /* handle device */ gcm_session_notify_device (manager, helper->device); out: gcm_session_async_helper_free (helper); g_free (basename); } static void gcm_session_device_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdDeviceKind kind; CdProfile *profile = NULL; CdDevice *device = CD_DEVICE (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); GcmSessionAsyncHelper *helper; ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_warning ("failed to connect to device: %s", error->message); g_error_free (error); goto out; } /* check we care */ kind = cd_device_get_kind (device); if (kind != CD_DEVICE_KIND_DISPLAY && kind != CD_DEVICE_KIND_PRINTER) goto out; /* ensure we have a profile */ profile = cd_device_get_default_profile (device); if (profile == NULL) { g_debug ("no profile set for %s", cd_device_get_id (device)); goto out; } /* connect to the profile */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->manager = g_object_ref (manager); helper->device = g_object_ref (device); cd_profile_connect (profile, NULL, gcm_session_profile_connect_cb, helper); out: if (profile != NULL) g_object_unref (profile); } static void gcm_session_device_added_notify_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { /* connect to the device to get properties */ cd_device_connect (device, NULL, gcm_session_device_connect_cb, manager); } static gchar * gcm_session_get_precooked_md5 (cmsHPROFILE lcms_profile) { cmsUInt8Number profile_id[16]; gboolean md5_precooked = FALSE; guint i; gchar *md5 = NULL; /* check to see if we have a pre-cooked MD5 */ cmsGetHeaderProfileID (lcms_profile, profile_id); for (i = 0; i < 16; i++) { if (profile_id[i] != 0) { md5_precooked = TRUE; break; } } if (!md5_precooked) goto out; /* convert to a hex string */ md5 = g_new0 (gchar, 32 + 1); for (i = 0; i < 16; i++) g_snprintf (md5 + i*2, 3, "%02x", profile_id[i]); out: return md5; } static gchar * gcm_session_get_md5_for_filename (const gchar *filename, GError **error) { gboolean ret; gchar *checksum = NULL; gchar *data = NULL; gsize length; cmsHPROFILE lcms_profile = NULL; /* get the internal profile id, if it exists */ lcms_profile = cmsOpenProfileFromFile (filename, "r"); if (lcms_profile == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to load: not an ICC profile"); goto out; } checksum = gcm_session_get_precooked_md5 (lcms_profile); if (checksum != NULL) goto out; /* generate checksum */ ret = g_file_get_contents (filename, &data, &length, error); if (!ret) goto out; checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) data, length); out: g_free (data); if (lcms_profile != NULL) cmsCloseProfile (lcms_profile); return checksum; } static void gcm_session_create_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile; GError *error = NULL; CdClient *client = CD_CLIENT (object); profile = cd_client_create_profile_finish (client, res, &error); if (profile == NULL) { if (error->domain != CD_CLIENT_ERROR || error->code != CD_CLIENT_ERROR_ALREADY_EXISTS) g_warning ("%s", error->message); g_error_free (error); return; } g_object_unref (profile); } static void gcm_session_profile_store_added_cb (GcmProfileStore *profile_store, const gchar *filename, CsdColorManager *manager) { gchar *checksum = NULL; gchar *profile_id = NULL; GError *error = NULL; GHashTable *profile_props = NULL; CsdColorManagerPrivate *priv = manager->priv; g_debug ("profile %s added", filename); /* generate ID */ checksum = gcm_session_get_md5_for_filename (filename, &error); if (checksum == NULL) { g_debug ("failed to get profile checksum for %s: %s", filename, error->message); g_error_free (error); goto out; } profile_id = g_strdup_printf ("icc-%s", checksum); profile_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (profile_props, (gpointer) CD_PROFILE_PROPERTY_FILENAME, (gpointer) filename); g_hash_table_insert (profile_props, (gpointer) CD_PROFILE_METADATA_FILE_CHECKSUM, (gpointer) checksum); cd_client_create_profile (priv->client, profile_id, CD_OBJECT_SCOPE_TEMP, profile_props, NULL, gcm_session_create_profile_cb, manager); out: g_free (checksum); g_free (profile_id); if (profile_props != NULL) g_hash_table_unref (profile_props); } static void gcm_session_delete_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdClient *client = CD_CLIENT (object); ret = cd_client_delete_profile_finish (client, res, &error); if (!ret) { g_warning ("%s", error->message); g_error_free (error); } } static void gcm_session_find_profile_by_filename_cb (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CdProfile *profile; CdClient *client = CD_CLIENT (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); profile = cd_client_find_profile_by_filename_finish (client, res, &error); if (profile == NULL) { g_warning ("%s", error->message); g_error_free (error); goto out; } /* remove it from colord */ cd_client_delete_profile (manager->priv->client, profile, NULL, gcm_session_delete_profile_cb, manager); out: if (profile != NULL) g_object_unref (profile); } static void gcm_session_profile_store_removed_cb (GcmProfileStore *profile_store, const gchar *filename, CsdColorManager *manager) { /* find the ID for the filename */ g_debug ("filename %s removed", filename); cd_client_find_profile_by_filename (manager->priv->client, filename, NULL, gcm_session_find_profile_by_filename_cb, manager); } static void gcm_session_sensor_added_cb (CdClient *client, CdSensor *sensor, CsdColorManager *manager) { ca_context_play (ca_gtk_context_get (), 0, CA_PROP_EVENT_ID, "device-added", /* TRANSLATORS: this is the application name */ CA_PROP_APPLICATION_NAME, _("Cinnamon Settings Daemon Color Plugin"), /* TRANSLATORS: this is a sound description */ CA_PROP_EVENT_DESCRIPTION, _("Color calibration device added"), NULL); /* open up the color prefs window */ gcm_session_exec_control_center (manager); } static void gcm_session_sensor_removed_cb (CdClient *client, CdSensor *sensor, CsdColorManager *manager) { ca_context_play (ca_gtk_context_get (), 0, CA_PROP_EVENT_ID, "device-removed", /* TRANSLATORS: this is the application name */ CA_PROP_APPLICATION_NAME, _("Cinnamon Settings Daemon Color Plugin"), /* TRANSLATORS: this is a sound description */ CA_PROP_EVENT_DESCRIPTION, _("Color calibration device removed"), NULL); } static void gcm_session_active_changed_cb (CinnamonSettingsSession *session, GParamSpec *pspec, CsdColorManager *manager) { CinnamonSettingsSessionState state_new; CsdColorManagerPrivate *priv = manager->priv; /* not yet connected to the daemon */ if (!cd_client_get_connected (priv->client)) return; /* When doing the fast-user-switch into a new account, load the * new users chosen profiles. * * If this is the first time the CinnamonSettingsSession has been * loaded, then we'll get a change from unknown to active * and we want to avoid reprobing the devices for that. */ state_new = cinnamon_settings_session_get_state (session); if (priv->session_state != CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN && state_new == CINNAMON_SETTINGS_SESSION_STATE_ACTIVE) { g_debug ("Done switch to new account, reload devices"); cd_client_get_devices (manager->priv->client, NULL, gcm_session_get_devices_cb, manager); } priv->session_state = state_new; } static void csd_color_manager_class_init (CsdColorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_color_manager_finalize; g_type_class_add_private (klass, sizeof (CsdColorManagerPrivate)); } static void csd_color_manager_init (CsdColorManager *manager) { CsdColorManagerPrivate *priv; priv = manager->priv = CSD_COLOR_MANAGER_GET_PRIVATE (manager); /* track the active session */ priv->session = cinnamon_settings_session_new (); priv->session_state = cinnamon_settings_session_get_state (priv->session); g_signal_connect (priv->session, "notify::state", G_CALLBACK (gcm_session_active_changed_cb), manager); /* set the _ICC_PROFILE atoms on the root screen */ priv->gdk_window = gdk_screen_get_root_window (gdk_screen_get_default ()); /* parsing the EDID is expensive */ priv->edid_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* we don't want to assign devices multiple times at startup */ priv->device_assign_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* use DMI data for internal panels */ priv->dmi = gcm_dmi_new (); priv->settings = g_settings_new ("org.cinnamon.settings-daemon.plugins.color"); priv->client = cd_client_new (); g_signal_connect (priv->client, "device-added", G_CALLBACK (gcm_session_device_added_notify_cb), manager); g_signal_connect (priv->client, "sensor-added", G_CALLBACK (gcm_session_sensor_added_cb), manager); g_signal_connect (priv->client, "sensor-removed", G_CALLBACK (gcm_session_sensor_removed_cb), manager); /* have access to all user profiles */ priv->profile_store = gcm_profile_store_new (); g_signal_connect (priv->profile_store, "added", G_CALLBACK (gcm_session_profile_store_added_cb), manager); g_signal_connect (priv->profile_store, "removed", G_CALLBACK (gcm_session_profile_store_removed_cb), manager); } static void csd_color_manager_finalize (GObject *object) { g_return_if_fail (object != NULL); G_OBJECT_CLASS (csd_color_manager_parent_class)->finalize (object); } CsdColorManager * csd_color_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_COLOR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_COLOR_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/color/csd-color-manager.h000066400000000000000000000047701356401377300247060ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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 __CSD_COLOR_MANAGER_H #define __CSD_COLOR_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_COLOR_MANAGER (csd_color_manager_get_type ()) #define CSD_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManager)) #define CSD_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_COLOR_MANAGER, CsdColorManagerClass)) #define CSD_IS_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_COLOR_MANAGER)) #define CSD_IS_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_COLOR_MANAGER)) #define CSD_COLOR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManagerClass)) #define CSD_COLOR_MANAGER_ERROR (csd_color_manager_error_quark ()) typedef struct CsdColorManagerPrivate CsdColorManagerPrivate; typedef struct { GObject parent; CsdColorManagerPrivate *priv; } CsdColorManager; typedef struct { GObjectClass parent_class; } CsdColorManagerClass; enum { CSD_COLOR_MANAGER_ERROR_FAILED }; GType csd_color_manager_get_type (void); GQuark csd_color_manager_error_quark (void); CsdColorManager * csd_color_manager_new (void); gboolean csd_color_manager_start (CsdColorManager *manager, GError **error); void csd_color_manager_stop (CsdColorManager *manager); G_END_DECLS #endif /* __CSD_COLOR_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/color/gcm-dmi.c000066400000000000000000000120631356401377300227130ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "gcm-dmi.h" static void gcm_dmi_finalize (GObject *object); #define GCM_DMI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_DMI, GcmDmiPrivate)) struct _GcmDmiPrivate { gchar *name; gchar *version; gchar *vendor; }; static gpointer gcm_dmi_object = NULL; G_DEFINE_TYPE (GcmDmi, gcm_dmi, G_TYPE_OBJECT) static gchar * gcm_dmi_get_from_filename (const gchar *filename) { gboolean ret; GError *error = NULL; gchar *data = NULL; /* get the contents */ ret = g_file_get_contents (filename, &data, NULL, &error); if (!ret) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) g_warning ("failed to get contents of %s: %s", filename, error->message); g_error_free (error); } /* process the random chars and trailing spaces */ if (data != NULL) { g_strdelimit (data, "\t_", ' '); g_strdelimit (data, "\n\r", '\0'); g_strchomp (data); } /* don't return an empty string */ if (data != NULL && data[0] == '\0') { g_free (data); data = NULL; } return data; } static gchar * gcm_dmi_get_from_filenames (const gchar * const * filenames) { guint i; gchar *tmp = NULL; /* try each one in preference order */ for (i = 0; filenames[i] != NULL; i++) { tmp = gcm_dmi_get_from_filename (filenames[i]); if (tmp != NULL) break; } return tmp; } const gchar * gcm_dmi_get_name (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->name; } const gchar * gcm_dmi_get_version (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->version; } const gchar * gcm_dmi_get_vendor (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->vendor; } static void gcm_dmi_class_init (GcmDmiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_dmi_finalize; g_type_class_add_private (klass, sizeof (GcmDmiPrivate)); } static void gcm_dmi_init (GcmDmi *dmi) { #if defined(__linux__) const gchar *sysfs_name[] = { "/sys/class/dmi/id/product_name", "/sys/class/dmi/id/board_name", NULL}; const gchar *sysfs_version[] = { "/sys/class/dmi/id/product_version", "/sys/class/dmi/id/chassis_version", "/sys/class/dmi/id/board_version", NULL}; const gchar *sysfs_vendor[] = { "/sys/class/dmi/id/sys_vendor", "/sys/class/dmi/id/chassis_vendor", "/sys/class/dmi/id/board_vendor", NULL}; #else #warning Please add dmi support for your OS const gchar *sysfs_name[] = { NULL }; const gchar *sysfs_version[] = { NULL }; const gchar *sysfs_vendor[] = { NULL }; #endif dmi->priv = GCM_DMI_GET_PRIVATE (dmi); /* get all the possible data now */ dmi->priv->name = gcm_dmi_get_from_filenames (sysfs_name); dmi->priv->version = gcm_dmi_get_from_filenames (sysfs_version); dmi->priv->vendor = gcm_dmi_get_from_filenames (sysfs_vendor); } static void gcm_dmi_finalize (GObject *object) { GcmDmi *dmi = GCM_DMI (object); g_free (dmi->priv->name); g_free (dmi->priv->version); g_free (dmi->priv->vendor); G_OBJECT_CLASS (gcm_dmi_parent_class)->finalize (object); } GcmDmi * gcm_dmi_new (void) { if (gcm_dmi_object != NULL) { g_object_ref (gcm_dmi_object); } else { gcm_dmi_object = g_object_new (GCM_TYPE_DMI, NULL); g_object_add_weak_pointer (gcm_dmi_object, &gcm_dmi_object); } return GCM_DMI (gcm_dmi_object); } cinnamon-settings-daemon-4.4.0/plugins/color/gcm-dmi.h000066400000000000000000000042261356401377300227220ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2010 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_DMI_H #define __GCM_DMI_H #include G_BEGIN_DECLS #define GCM_TYPE_DMI (gcm_dmi_get_type ()) #define GCM_DMI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_DMI, GcmDmi)) #define GCM_DMI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_DMI, GcmDmiClass)) #define GCM_IS_DMI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_DMI)) #define GCM_IS_DMI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_DMI)) #define GCM_DMI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_DMI, GcmDmiClass)) typedef struct _GcmDmiPrivate GcmDmiPrivate; typedef struct _GcmDmi GcmDmi; typedef struct _GcmDmiClass GcmDmiClass; struct _GcmDmi { GObject parent; GcmDmiPrivate *priv; }; struct _GcmDmiClass { GObjectClass parent_class; }; GType gcm_dmi_get_type (void); GcmDmi *gcm_dmi_new (void); const gchar *gcm_dmi_get_name (GcmDmi *dmi); const gchar *gcm_dmi_get_version (GcmDmi *dmi); const gchar *gcm_dmi_get_vendor (GcmDmi *dmi); G_END_DECLS #endif /* __GCM_DMI_H */ cinnamon-settings-daemon-4.4.0/plugins/color/gcm-edid.c000066400000000000000000000343251356401377300230540ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Soren Sandmann * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include "gcm-edid.h" static void gcm_edid_finalize (GObject *object); #define GCM_EDID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_EDID, GcmEdidPrivate)) struct _GcmEdidPrivate { gchar *monitor_name; gchar *vendor_name; gchar *serial_number; gchar *eisa_id; gchar *checksum; gchar *pnp_id; guint width; guint height; gfloat gamma; CdColorYxy *red; CdColorYxy *green; CdColorYxy *blue; CdColorYxy *white; GnomePnpIds *pnp_ids; }; G_DEFINE_TYPE (GcmEdid, gcm_edid, G_TYPE_OBJECT) #define GCM_EDID_OFFSET_PNPID 0x08 #define GCM_EDID_OFFSET_SERIAL 0x0c #define GCM_EDID_OFFSET_SIZE 0x15 #define GCM_EDID_OFFSET_GAMMA 0x17 #define GCM_EDID_OFFSET_DATA_BLOCKS 0x36 #define GCM_EDID_OFFSET_LAST_BLOCK 0x6c #define GCM_EDID_OFFSET_EXTENSION_BLOCK_COUNT 0x7e #define GCM_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc #define GCM_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff #define GCM_DESCRIPTOR_COLOR_MANAGEMENT_DATA 0xf9 #define GCM_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe #define GCM_DESCRIPTOR_COLOR_POINT 0xfb GQuark gcm_edid_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("gcm_edid_error"); return quark; } const gchar * gcm_edid_get_monitor_name (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->monitor_name; } const gchar * gcm_edid_get_vendor_name (GcmEdid *edid) { GcmEdidPrivate *priv = edid->priv; g_return_val_if_fail (GCM_IS_EDID (edid), NULL); if (priv->vendor_name == NULL) priv->vendor_name = gnome_pnp_ids_get_pnp_id (priv->pnp_ids, priv->pnp_id); return priv->vendor_name; } const gchar * gcm_edid_get_serial_number (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->serial_number; } const gchar * gcm_edid_get_eisa_id (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->eisa_id; } const gchar * gcm_edid_get_checksum (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->checksum; } const gchar * gcm_edid_get_pnp_id (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->pnp_id; } guint gcm_edid_get_width (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0); return edid->priv->width; } guint gcm_edid_get_height (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0); return edid->priv->height; } gfloat gcm_edid_get_gamma (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0.0f); return edid->priv->gamma; } const CdColorYxy * gcm_edid_get_red (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->red; } const CdColorYxy * gcm_edid_get_green (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->green; } const CdColorYxy * gcm_edid_get_blue (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->blue; } const CdColorYxy * gcm_edid_get_white (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->white; } void gcm_edid_reset (GcmEdid *edid) { GcmEdidPrivate *priv = edid->priv; g_return_if_fail (GCM_IS_EDID (edid)); /* free old data */ g_free (priv->monitor_name); g_free (priv->vendor_name); g_free (priv->serial_number); g_free (priv->eisa_id); g_free (priv->checksum); /* do not deallocate, just blank */ priv->pnp_id[0] = '\0'; /* set to default values */ priv->monitor_name = NULL; priv->vendor_name = NULL; priv->serial_number = NULL; priv->eisa_id = NULL; priv->checksum = NULL; priv->width = 0; priv->height = 0; priv->gamma = 0.0f; } static gint gcm_edid_get_bit (gint in, gint bit) { return (in & (1 << bit)) >> bit; } /** * gcm_edid_get_bits: **/ static gint gcm_edid_get_bits (gint in, gint begin, gint end) { gint mask = (1 << (end - begin + 1)) - 1; return (in >> begin) & mask; } /** * gcm_edid_decode_fraction: **/ static gdouble gcm_edid_decode_fraction (gint high, gint low) { gdouble result = 0.0; gint i; high = (high << 2) | low; for (i = 0; i < 10; ++i) result += gcm_edid_get_bit (high, i) * pow (2, i - 10); return result; } static gchar * gcm_edid_parse_string (const guint8 *data) { gchar *text; guint i; guint replaced = 0; /* this is always 12 bytes, but we can't guarantee it's null * terminated or not junk. */ text = g_strndup ((const gchar *) data, 12); /* remove insane newline chars */ g_strdelimit (text, "\n\r", '\0'); /* remove spaces */ g_strchomp (text); /* nothing left? */ if (text[0] == '\0') { g_free (text); text = NULL; goto out; } /* ensure string is printable */ for (i = 0; text[i] != '\0'; i++) { if (!g_ascii_isprint (text[i])) { text[i] = '-'; replaced++; } } /* if the string is junk, ignore the string */ if (replaced > 4) { g_free (text); text = NULL; goto out; } out: return text; } gboolean gcm_edid_parse (GcmEdid *edid, const guint8 *data, gsize length, GError **error) { gboolean ret = TRUE; guint i; GcmEdidPrivate *priv = edid->priv; guint32 serial; gchar *tmp; /* check header */ if (length < 128) { g_set_error_literal (error, GCM_EDID_ERROR, GCM_EDID_ERROR_FAILED_TO_PARSE, "EDID length is too small"); ret = FALSE; goto out; } if (data[0] != 0x00 || data[1] != 0xff) { g_set_error_literal (error, GCM_EDID_ERROR, GCM_EDID_ERROR_FAILED_TO_PARSE, "Failed to parse EDID header"); ret = FALSE; goto out; } /* free old data */ gcm_edid_reset (edid); /* decode the PNP ID from three 5 bit words packed into 2 bytes * /--08--\/--09--\ * 7654321076543210 * |\---/\---/\---/ * R C1 C2 C3 */ priv->pnp_id[0] = 'A' + ((data[GCM_EDID_OFFSET_PNPID+0] & 0x7c) / 4) - 1; priv->pnp_id[1] = 'A' + ((data[GCM_EDID_OFFSET_PNPID+0] & 0x3) * 8) + ((data[GCM_EDID_OFFSET_PNPID+1] & 0xe0) / 32) - 1; priv->pnp_id[2] = 'A' + (data[GCM_EDID_OFFSET_PNPID+1] & 0x1f) - 1; /* maybe there isn't a ASCII serial number descriptor, so use this instead */ serial = (guint32) data[GCM_EDID_OFFSET_SERIAL+0]; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+1] * 0x100; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+2] * 0x10000; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+3] * 0x1000000; if (serial > 0) priv->serial_number = g_strdup_printf ("%" G_GUINT32_FORMAT, serial); /* get the size */ priv->width = data[GCM_EDID_OFFSET_SIZE+0]; priv->height = data[GCM_EDID_OFFSET_SIZE+1]; /* we don't care about aspect */ if (priv->width == 0 || priv->height == 0) { priv->width = 0; priv->height = 0; } /* get gamma */ if (data[GCM_EDID_OFFSET_GAMMA] == 0xff) { priv->gamma = 1.0f; } else { priv->gamma = ((gfloat) data[GCM_EDID_OFFSET_GAMMA] / 100) + 1; } /* get color red */ priv->red->x = gcm_edid_decode_fraction (data[0x1b], gcm_edid_get_bits (data[0x19], 6, 7)); priv->red->y = gcm_edid_decode_fraction (data[0x1c], gcm_edid_get_bits (data[0x19], 5, 4)); /* get color green */ priv->green->x = gcm_edid_decode_fraction (data[0x1d], gcm_edid_get_bits (data[0x19], 2, 3)); priv->green->y = gcm_edid_decode_fraction (data[0x1e], gcm_edid_get_bits (data[0x19], 0, 1)); /* get color blue */ priv->blue->x = gcm_edid_decode_fraction (data[0x1f], gcm_edid_get_bits (data[0x1a], 6, 7)); priv->blue->y = gcm_edid_decode_fraction (data[0x20], gcm_edid_get_bits (data[0x1a], 4, 5)); /* get color white */ priv->white->x = gcm_edid_decode_fraction (data[0x21], gcm_edid_get_bits (data[0x1a], 2, 3)); priv->white->y = gcm_edid_decode_fraction (data[0x22], gcm_edid_get_bits (data[0x1a], 0, 1)); /* parse EDID data */ for (i = GCM_EDID_OFFSET_DATA_BLOCKS; i <= GCM_EDID_OFFSET_LAST_BLOCK; i += 18) { /* ignore pixel clock data */ if (data[i] != 0) continue; if (data[i+2] != 0) continue; /* any useful blocks? */ if (data[i+3] == GCM_DESCRIPTOR_DISPLAY_PRODUCT_NAME) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->monitor_name); priv->monitor_name = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->serial_number); priv->serial_number = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_COLOR_MANAGEMENT_DATA) { g_warning ("failing to parse color management data"); } else if (data[i+3] == GCM_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->eisa_id); priv->eisa_id = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_COLOR_POINT) { if (data[i+3+9] != 0xff) { /* extended EDID block(1) which contains * a better gamma value */ priv->gamma = ((gfloat) data[i+3+9] / 100) + 1; } if (data[i+3+14] != 0xff) { /* extended EDID block(2) which contains * a better gamma value */ priv->gamma = ((gfloat) data[i+3+9] / 100) + 1; } } } /* calculate checksum */ priv->checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, length); out: return ret; } static void gcm_edid_class_init (GcmEdidClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_edid_finalize; g_type_class_add_private (klass, sizeof (GcmEdidPrivate)); } static void gcm_edid_init (GcmEdid *edid) { edid->priv = GCM_EDID_GET_PRIVATE (edid); edid->priv->pnp_ids = gnome_pnp_ids_new (); edid->priv->pnp_id = g_new0 (gchar, 4); edid->priv->red = cd_color_yxy_new (); edid->priv->green = cd_color_yxy_new (); edid->priv->blue = cd_color_yxy_new (); edid->priv->white = cd_color_yxy_new (); } static void gcm_edid_finalize (GObject *object) { GcmEdid *edid = GCM_EDID (object); GcmEdidPrivate *priv = edid->priv; g_free (priv->monitor_name); g_free (priv->vendor_name); g_free (priv->serial_number); g_free (priv->eisa_id); g_free (priv->checksum); g_free (priv->pnp_id); cd_color_yxy_free (priv->white); cd_color_yxy_free (priv->red); cd_color_yxy_free (priv->green); cd_color_yxy_free (priv->blue); g_object_unref (priv->pnp_ids); G_OBJECT_CLASS (gcm_edid_parent_class)->finalize (object); } GcmEdid * gcm_edid_new (void) { GcmEdid *edid; edid = g_object_new (GCM_TYPE_EDID, NULL); return GCM_EDID (edid); } cinnamon-settings-daemon-4.4.0/plugins/color/gcm-edid.h000066400000000000000000000072531356401377300230610ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2010 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_EDID_H #define __GCM_EDID_H #include #include G_BEGIN_DECLS #define GCM_TYPE_EDID (gcm_edid_get_type ()) #define GCM_EDID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_EDID, GcmEdid)) #define GCM_EDID_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_EDID, GcmEdidClass)) #define GCM_IS_EDID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_EDID)) #define GCM_IS_EDID_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_EDID)) #define GCM_EDID_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_EDID, GcmEdidClass)) #define GCM_EDID_ERROR (gcm_edid_error_quark ()) typedef struct _GcmEdidPrivate GcmEdidPrivate; typedef struct _GcmEdid GcmEdid; typedef struct _GcmEdidClass GcmEdidClass; struct _GcmEdid { GObject parent; GcmEdidPrivate *priv; }; struct _GcmEdidClass { GObjectClass parent_class; }; enum { GCM_EDID_ERROR_FAILED_TO_PARSE }; GType gcm_edid_get_type (void); GQuark gcm_edid_error_quark (void); GcmEdid *gcm_edid_new (void); void gcm_edid_reset (GcmEdid *edid); gboolean gcm_edid_parse (GcmEdid *edid, const guint8 *data, gsize length, GError **error); const gchar *gcm_edid_get_monitor_name (GcmEdid *edid); const gchar *gcm_edid_get_vendor_name (GcmEdid *edid); const gchar *gcm_edid_get_serial_number (GcmEdid *edid); const gchar *gcm_edid_get_eisa_id (GcmEdid *edid); const gchar *gcm_edid_get_checksum (GcmEdid *edid); const gchar *gcm_edid_get_pnp_id (GcmEdid *edid); guint gcm_edid_get_width (GcmEdid *edid); guint gcm_edid_get_height (GcmEdid *edid); gfloat gcm_edid_get_gamma (GcmEdid *edid); const CdColorYxy *gcm_edid_get_red (GcmEdid *edid); const CdColorYxy *gcm_edid_get_green (GcmEdid *edid); const CdColorYxy *gcm_edid_get_blue (GcmEdid *edid); const CdColorYxy *gcm_edid_get_white (GcmEdid *edid); G_END_DECLS #endif /* __GCM_EDID_H */ cinnamon-settings-daemon-4.4.0/plugins/color/gcm-profile-store.c000066400000000000000000000453471356401377300247470ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "gcm-profile-store.h" static void gcm_profile_store_finalize (GObject *object); #define GCM_PROFILE_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStorePrivate)) struct _GcmProfileStorePrivate { GPtrArray *filename_array; GPtrArray *directory_array; GCancellable *cancellable; }; enum { SIGNAL_ADDED, SIGNAL_REMOVED, SIGNAL_CHANGED, SIGNAL_LAST }; static guint signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE (GcmProfileStore, gcm_profile_store, G_TYPE_OBJECT) static void gcm_profile_store_search_path (GcmProfileStore *profile_store, const gchar *path, guint depth); static void gcm_profile_store_process_child (GcmProfileStore *profile_store, const gchar *path, GFileInfo *info); #define GCM_PROFILE_STORE_MAX_RECURSION_LEVELS 2 typedef struct { gchar *path; GFileMonitor *monitor; guint depth; } GcmProfileStoreDirHelper; static void gcm_profile_store_helper_free (GcmProfileStoreDirHelper *helper) { g_free (helper->path); if (helper->monitor != NULL) g_object_unref (helper->monitor); g_free (helper); } static const gchar * gcm_profile_store_find_filename (GcmProfileStore *profile_store, const gchar *filename) { const gchar *tmp; guint i; GPtrArray *array = profile_store->priv->filename_array; for (i=0; ilen; i++) { tmp = g_ptr_array_index (array, i); if (g_strcmp0 (filename, tmp) == 0) return tmp; } return NULL; } static GcmProfileStoreDirHelper * gcm_profile_store_find_directory (GcmProfileStore *profile_store, const gchar *path) { GcmProfileStoreDirHelper *tmp; guint i; GPtrArray *array = profile_store->priv->directory_array; for (i=0; ilen; i++) { tmp = g_ptr_array_index (array, i); if (g_strcmp0 (path, tmp->path) == 0) return tmp; } return NULL; } static gboolean gcm_profile_store_remove_profile (GcmProfileStore *profile_store, const gchar *filename) { gboolean ret = FALSE; const gchar *tmp; gchar *filename_dup = NULL; GcmProfileStorePrivate *priv = profile_store->priv; /* find exact pointer */ tmp = gcm_profile_store_find_filename (profile_store, filename); if (tmp == NULL) goto out; /* dup so we can emit the signal */ filename_dup = g_strdup (tmp); ret = g_ptr_array_remove (priv->filename_array, (gpointer)tmp); if (!ret) { g_warning ("failed to remove %s", filename); goto out; } /* emit a signal */ g_debug ("emit removed: %s", filename_dup); g_signal_emit (profile_store, signals[SIGNAL_REMOVED], 0, filename_dup); out: g_free (filename_dup); return ret; } static void gcm_profile_store_add_profile (GcmProfileStore *profile_store, const gchar *filename) { GcmProfileStorePrivate *priv = profile_store->priv; /* add to list */ g_ptr_array_add (priv->filename_array, g_strdup (filename)); /* emit a signal */ g_debug ("emit add: %s", filename); g_signal_emit (profile_store, signals[SIGNAL_ADDED], 0, filename); } static void gcm_profile_store_created_query_info_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GFileInfo *info; GError *error = NULL; gchar *path; GFile *file = G_FILE (source_object); GFile *parent; GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); info = g_file_query_info_finish (file, res, &error); if (info == NULL) { g_warning ("failed to get info about deleted file: %s", error->message); g_error_free (error); return; } parent = g_file_get_parent (file); path = g_file_get_path (parent); gcm_profile_store_process_child (profile_store, path, info); g_free (path); g_object_unref (info); g_object_unref (parent); } static void gcm_profile_store_remove_from_prefix (GcmProfileStore *profile_store, const gchar *prefix) { guint i; const gchar *path; GcmProfileStorePrivate *priv = profile_store->priv; for (i = 0; i < priv->filename_array->len; i++) { path = g_ptr_array_index (priv->filename_array, i); if (g_str_has_prefix (path, prefix)) { g_debug ("auto-removed %s as path removed", path); gcm_profile_store_remove_profile (profile_store, path); } } } static void gcm_profile_store_file_monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GcmProfileStore *profile_store) { gchar *path = NULL; gchar *parent_path = NULL; const gchar *tmp; GcmProfileStoreDirHelper *helper; /* profile was deleted */ if (event_type == G_FILE_MONITOR_EVENT_DELETED) { /* we can either have two things here, a directory or a * file. We can't call g_file_query_info_async() as the * inode doesn't exist anymore */ path = g_file_get_path (file); tmp = gcm_profile_store_find_filename (profile_store, path); if (tmp != NULL) { /* is a file */ gcm_profile_store_remove_profile (profile_store, path); goto out; } /* is a directory, urgh. Remove all profiles there. */ gcm_profile_store_remove_from_prefix (profile_store, path); helper = gcm_profile_store_find_directory (profile_store, path); if (helper != NULL) { g_ptr_array_remove (profile_store->priv->directory_array, helper); } goto out; } /* only care about created objects */ if (event_type == G_FILE_MONITOR_EVENT_CREATED) { g_file_query_info_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_LOW, NULL, gcm_profile_store_created_query_info_cb, profile_store); goto out; } out: g_free (path); g_free (parent_path); } static void gcm_profile_store_process_child (GcmProfileStore *profile_store, const gchar *path, GFileInfo *info) { gchar *full_path = NULL; const gchar *name; GcmProfileStoreDirHelper *helper; /* check we're not in a loop */ helper = gcm_profile_store_find_directory (profile_store, path); if (helper == NULL) goto out; if (helper->depth > GCM_PROFILE_STORE_MAX_RECURSION_LEVELS) { g_warning ("recursing more than %i levels deep is insane", GCM_PROFILE_STORE_MAX_RECURSION_LEVELS); goto out; } /* make the compete path */ name = g_file_info_get_name (info); full_path = g_build_filename (path, name, NULL); /* if a directory */ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { gcm_profile_store_search_path (profile_store, full_path, helper->depth + 1); goto out; } /* ignore temp files */ if (g_strrstr (full_path, ".goutputstream") != NULL) { g_debug ("ignoring gvfs temporary file"); goto out; } /* is a file */ gcm_profile_store_add_profile (profile_store, full_path); out: g_free (full_path); } static void gcm_profile_store_next_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GList *files; GList *f; GError *error = NULL; GFileInfo *info; GFile *file; gchar *path; GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object); GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); files = g_file_enumerator_next_files_finish (enumerator, res, &error); if (files == NULL) { /* special value, meaning "no more files to process" */ return; } if (error != NULL) { g_warning ("failed to get data about enumerated directory: %s", error->message); g_error_free (error); return; } /* get each file */ file = g_file_enumerator_get_container (enumerator); path = g_file_get_path (file); for (f = files; f != NULL; f = f->next) { info = G_FILE_INFO (f->data); gcm_profile_store_process_child (profile_store, path, info); } /* continue to get the rest of the data in chunks */ g_file_enumerator_next_files_async (enumerator, 5, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_next_files_cb, user_data); g_free (path); g_list_foreach (files, (GFunc) g_object_unref, NULL); g_list_free (files); } static void gcm_profile_store_enumerate_children_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GFileEnumerator *enumerator; GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, &error); if (enumerator == NULL) { GcmProfileStoreDirHelper *helper; gchar *path = NULL; path = g_file_get_path (G_FILE (source_object)); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) g_debug ("failed to enumerate directory %s: %s", path, error->message); else g_warning ("failed to enumerate directory %s: %s", path, error->message); helper = gcm_profile_store_find_directory (profile_store, path); if (helper) g_ptr_array_remove (profile_store->priv->directory_array, helper); g_error_free (error); g_free (path); return; } /* get the first chunk of data */ g_file_enumerator_next_files_async (enumerator, 5, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_next_files_cb, user_data); g_object_unref (enumerator); } static void gcm_profile_store_search_path (GcmProfileStore *profile_store, const gchar *path, guint depth) { GFile *file = NULL; GError *error = NULL; GcmProfileStoreDirHelper *helper; file = g_file_new_for_path (path); /* add an inotify watch if not already added */ helper = gcm_profile_store_find_directory (profile_store, path); if (helper == NULL) { helper = g_new0 (GcmProfileStoreDirHelper, 1); helper->depth = depth; helper->path = g_strdup (path); helper->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &error); if (helper->monitor == NULL) { g_debug ("failed to monitor path: %s", error->message); g_error_free (error); gcm_profile_store_helper_free (helper); goto out; } g_signal_connect (helper->monitor, "changed", G_CALLBACK(gcm_profile_store_file_monitor_changed_cb), profile_store); g_ptr_array_add (profile_store->priv->directory_array, helper); } /* get contents of directory */ g_file_enumerate_children_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_enumerate_children_cb, profile_store); out: g_object_unref (file); } static gboolean gcm_profile_store_mkdir_with_parents (const gchar *filename, GCancellable *cancellable, GError **error) { gboolean ret; GFile *file; /* ensure destination exists */ file = g_file_new_for_path (filename); ret = g_file_make_directory_with_parents (file, cancellable, error); g_object_unref (file); return ret; } gboolean gcm_profile_store_search (GcmProfileStore *profile_store) { gchar *path; gboolean ret; GError *error = NULL; /* get Linux per-user profiles */ path = g_build_filename (g_get_user_data_dir (), "icc", NULL); ret = gcm_profile_store_mkdir_with_parents (path, profile_store->priv->cancellable, &error); if (!ret && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_warning ("failed to create directory on startup: %s", error->message); } else { gcm_profile_store_search_path (profile_store, path, 0); } g_free (path); g_clear_error (&error); /* get per-user profiles from obsolete location */ path = g_build_filename (g_get_home_dir (), ".color", "icc", NULL); gcm_profile_store_search_path (profile_store, path, 0); g_free (path); return TRUE; } static void gcm_profile_store_class_init (GcmProfileStoreClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_profile_store_finalize; signals[SIGNAL_ADDED] = g_signal_new ("added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcmProfileStoreClass, added), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals[SIGNAL_REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcmProfileStoreClass, removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_type_class_add_private (klass, sizeof (GcmProfileStorePrivate)); } static void gcm_profile_store_init (GcmProfileStore *profile_store) { profile_store->priv = GCM_PROFILE_STORE_GET_PRIVATE (profile_store); profile_store->priv->cancellable = g_cancellable_new (); profile_store->priv->filename_array = g_ptr_array_new_with_free_func (g_free); profile_store->priv->directory_array = g_ptr_array_new_with_free_func ((GDestroyNotify) gcm_profile_store_helper_free); } static void gcm_profile_store_finalize (GObject *object) { GcmProfileStore *profile_store = GCM_PROFILE_STORE (object); GcmProfileStorePrivate *priv = profile_store->priv; g_cancellable_cancel (profile_store->priv->cancellable); g_object_unref (profile_store->priv->cancellable); g_ptr_array_unref (priv->filename_array); g_ptr_array_unref (priv->directory_array); G_OBJECT_CLASS (gcm_profile_store_parent_class)->finalize (object); } GcmProfileStore * gcm_profile_store_new (void) { GcmProfileStore *profile_store; profile_store = g_object_new (GCM_TYPE_PROFILE_STORE, NULL); return GCM_PROFILE_STORE (profile_store); } cinnamon-settings-daemon-4.4.0/plugins/color/gcm-profile-store.h000066400000000000000000000046731356401377300247510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_PROFILE_STORE_H #define __GCM_PROFILE_STORE_H #include G_BEGIN_DECLS #define GCM_TYPE_PROFILE_STORE (gcm_profile_store_get_type ()) #define GCM_PROFILE_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStore)) #define GCM_PROFILE_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_PROFILE_STORE, GcmProfileStoreClass)) #define GCM_IS_PROFILE_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_PROFILE_STORE)) #define GCM_IS_PROFILE_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_PROFILE_STORE)) #define GCM_PROFILE_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStoreClass)) typedef struct _GcmProfileStorePrivate GcmProfileStorePrivate; typedef struct _GcmProfileStore GcmProfileStore; typedef struct _GcmProfileStoreClass GcmProfileStoreClass; struct _GcmProfileStore { GObject parent; GcmProfileStorePrivate *priv; }; struct _GcmProfileStoreClass { GObjectClass parent_class; void (* added) (const gchar *filename); void (* removed) (const gchar *filename); }; GType gcm_profile_store_get_type (void); GcmProfileStore *gcm_profile_store_new (void); gboolean gcm_profile_store_search (GcmProfileStore *profile_store); G_END_DECLS #endif /* __GCM_PROFILE_STORE_H */ cinnamon-settings-daemon-4.4.0/plugins/color/gcm-self-test.c000066400000000000000000000077461356401377300240640ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "gcm-edid.h" #include "gcm-dmi.h" static void gcm_test_dmi_func (void) { GcmDmi *dmi; dmi = gcm_dmi_new (); g_assert (dmi != NULL); g_assert (gcm_dmi_get_name (dmi) != NULL); g_assert (gcm_dmi_get_vendor (dmi) != NULL); g_object_unref (dmi); } static void gcm_test_edid_func (void) { GcmEdid *edid; gchar *data; gboolean ret; GError *error = NULL; gsize length = 0; edid = gcm_edid_new (); g_assert (edid != NULL); /* LG 21" LCD panel */ ret = g_file_get_contents (TESTDATADIR "/LG-L225W-External.bin", &data, &length, &error); g_assert_no_error (error); g_assert (ret); ret = gcm_edid_parse (edid, (const guint8 *) data, length, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpstr (gcm_edid_get_monitor_name (edid), ==, "L225W"); g_assert_cmpstr (gcm_edid_get_vendor_name (edid), ==, "Goldstar Company Ltd"); g_assert_cmpstr (gcm_edid_get_serial_number (edid), ==, "34398"); g_assert_cmpstr (gcm_edid_get_eisa_id (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_checksum (edid), ==, "0bb44865bb29984a4bae620656c31368"); g_assert_cmpstr (gcm_edid_get_pnp_id (edid), ==, "GSM"); g_assert_cmpint (gcm_edid_get_height (edid), ==, 30); g_assert_cmpint (gcm_edid_get_width (edid), ==, 47); g_assert_cmpfloat (gcm_edid_get_gamma (edid), >=, 2.2f - 0.01); g_assert_cmpfloat (gcm_edid_get_gamma (edid), <, 2.2f + 0.01); g_free (data); /* Lenovo T61 internal Panel */ ret = g_file_get_contents (TESTDATADIR "/Lenovo-T61-Internal.bin", &data, &length, &error); g_assert_no_error (error); g_assert (ret); ret = gcm_edid_parse (edid, (const guint8 *) data, length, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpstr (gcm_edid_get_monitor_name (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_vendor_name (edid), ==, "IBM France"); g_assert_cmpstr (gcm_edid_get_serial_number (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_eisa_id (edid), ==, "LTN154P2-L05"); g_assert_cmpstr (gcm_edid_get_checksum (edid), ==, "e1865128c7cd5e5ed49ecfc8102f6f9c"); g_assert_cmpstr (gcm_edid_get_pnp_id (edid), ==, "IBM"); g_assert_cmpint (gcm_edid_get_height (edid), ==, 21); g_assert_cmpint (gcm_edid_get_width (edid), ==, 33); g_assert_cmpfloat (gcm_edid_get_gamma (edid), >=, 2.2f - 0.01); g_assert_cmpfloat (gcm_edid_get_gamma (edid), <, 2.2f + 0.01); g_free (data); g_object_unref (edid); } int main (int argc, char **argv) { gtk_init (&argc, &argv); g_test_init (&argc, &argv, NULL); g_test_add_func ("/color/dmi", gcm_test_dmi_func); g_test_add_func ("/color/edid", gcm_test_edid_func); return g_test_run (); } cinnamon-settings-daemon-4.4.0/plugins/color/main.c000066400000000000000000000010051356401377300223140ustar00rootroot00000000000000#define NEW csd_color_manager_new #define START csd_color_manager_start #define STOP csd_color_manager_stop #define MANAGER CsdColorManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-color-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/color/test-data/000077500000000000000000000000001356401377300231165ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/color/test-data/LG-L225W-External.bin000066400000000000000000000002001356401377300264330ustar00rootroot00000000000000mcV^ /x%UI'PTk@qO|.`@0 6(!90b'@h6(8KS L225W tcinnamon-settings-daemon-4.4.0/plugins/color/test-data/Lenovo-T61-Internal.bin000066400000000000000000000002001356401377300271640ustar00rootroot00000000000000$M(!x uUO&!PT/`@ @K'`@ @K 2 (LX3LTN154P2-L05 cinnamon-settings-daemon-4.4.0/plugins/common/000077500000000000000000000000001356401377300214025ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/common/Makefile.am000066400000000000000000000015231356401377300234370ustar00rootroot00000000000000plugin_name = common noinst_LTLIBRARIES = libcommon.la AM_CFLAGS = $(WARN_CFLAGS) libcommon_la_SOURCES = \ csd-keygrab.c \ csd-keygrab.h \ csd-input-helper.c \ csd-input-helper.h \ csd-power-helper.c \ csd-power-helper.h libcommon_la_CPPFLAGS = \ $(AM_CPPFLAGS) libcommon_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(COMMON_CFLAGS) \ $(AM_CFLAGS) libcommon_la_LDFLAGS = \ $(WARN_LDFLAGS) \ $(CSD_PLUGIN_LDFLAGS) libcommon_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(COMMON_LIBS) libexec_PROGRAMS = csd-input-helper csd_input_helper_SOURCES = test-input-helper.c csd_input_helper_LDADD = libcommon.la csd_input_helper_CFLAGS = $(libcommon_la_CFLAGS) scriptsdir = $(datadir)/cinnamon-settings-daemon-@CSD_API_VERSION@ scripts_DATA = input-device-example.sh EXTRA_DIST = $(scripts_DATA) daemon-skeleton.h cinnamon-settings-daemon-4.4.0/plugins/common/csd-input-helper.c000066400000000000000000000422461356401377300247410ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera * * 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 #include #include #include #include #include "csd-input-helper.h" #define INPUT_DEVICES_SCHEMA "org.cinnamon.settings-daemon.peripherals.input-devices" #define KEY_HOTPLUG_COMMAND "hotplug-command" typedef gboolean (* InfoIdentifyFunc) (XDeviceInfo *device_info); typedef gboolean (* DeviceIdentifyFunc) (XDevice *xdevice); gboolean device_set_property (XDevice *xdevice, const char *device_name, PropertyHelper *property) { int rc; unsigned long i; Atom prop; Atom realtype; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property->name, False); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, property->nitems, False, AnyPropertyType, &realtype, &realformat, &nitems, &bytes_after, &data); if (rc != Success || realtype != (Atom)property->type || realformat != property->format || nitems < (unsigned long)property->nitems) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); g_warning ("Error reading property \"%s\" for \"%s\"", property->name, device_name); return FALSE; } for (i = 0; i < nitems; i++) { switch (property->format) { case 8: data[i] = property->data.c[i]; break; case 32: ((long*)data)[i] = property->data.i[i]; break; default: g_warning("device_set_property: default case"); break; } } XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, realtype, realformat, PropModeReplace, data, nitems); XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error in setting \"%s\" for \"%s\"", property->name, device_name); return FALSE; } return TRUE; } static gboolean supports_xinput_devices_with_opcode (int *opcode) { gint op_code, event, error; gboolean retval; retval = XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XInputExtension", &op_code, &event, &error); if (opcode) *opcode = op_code; return retval; } gboolean supports_xinput_devices (void) { return supports_xinput_devices_with_opcode (NULL); } gboolean supports_xtest (void) { gint op_code, event, error; gboolean retval; retval = XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XTEST", &op_code, &event, &error); return retval; } gboolean supports_xinput2_devices (int *opcode) { int major, minor; if (supports_xinput_devices_with_opcode (opcode) == FALSE) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); major = 2; #ifdef XI_23 minor = 3; #else minor = 0; #endif if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); #ifndef XI_23 /* try for 2.2, maybe gtk has already announced 2.2 support */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); major = 2; minor = 2; if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return FALSE; } #else return FALSE; #endif } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); if ((major * 1000 + minor) < (2000)) return FALSE; return TRUE; } gboolean device_is_touchpad (XDevice *xdevice) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; const char *names[] = { "libinput Tapping Enabled", /* we don't check on the type being XI_TOUCHPAD here, * but having a "Synaptics Off" property should be enough */ "Synaptics Off", NULL, }; const char **name = names; do { prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), *name, True); if (prop) { gdk_x11_display_error_trap_push (gdk_display_get_default ()); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); XFree (data); return TRUE; } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } name++; } while (*name); return FALSE; } gboolean device_info_is_touchpad (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHPAD, False)); } gboolean device_info_is_touchscreen (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHSCREEN, False)); } gboolean device_info_is_tablet (XDeviceInfo *device_info) { /* Note that this doesn't match Wacom tablets */ return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TABLET, False)); } gboolean device_info_is_mouse (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_MOUSE, False)); } static gboolean device_type_is_present (InfoIdentifyFunc info_func, DeviceIdentifyFunc device_func) { XDeviceInfo *device_info; gint n_devices,i; gboolean retval; if (supports_xinput_devices () == FALSE) return TRUE; retval = FALSE; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; for (i = 0; i < n_devices; i++) { XDevice *device; /* Check with the device info first */ retval = (info_func) (&device_info[i]); if (retval == FALSE) continue; /* If we only have an info func, we're done checking */ if (device_func == NULL) break; gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) continue; retval = (device_func) (device); if (retval) { xdevice_close (device); break; } xdevice_close (device); } XFreeDeviceList (device_info); return retval; } gboolean touchscreen_is_present (void) { return device_type_is_present (device_info_is_touchscreen, NULL); } gboolean touchpad_is_present (void) { return device_type_is_present (device_info_is_touchpad, device_is_touchpad); } gboolean mouse_is_present (void) { return device_type_is_present (device_info_is_mouse, NULL); } char * xdevice_get_device_node (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; char *ret; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Node", False); if (!prop) return NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return NULL; } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) goto out; if (nitems == 0) goto out; if (act_type != XA_STRING) goto out; /* Unknown string format */ if (act_format != 8) goto out; ret = g_strdup ((char *) data); XFree (data); return ret; out: XFree (data); return NULL; } #define TOOL_ID_FORMAT_SIZE 32 static int get_id_for_index (guchar *data, guint idx) { guchar *ptr; int id; ptr = data; ptr += TOOL_ID_FORMAT_SIZE / 8 * idx; id = *((int32_t*)ptr); id = id & 0xfffff; return id; } #define STYLUS_DEVICE_ID 0x02 #define ERASER_DEVICE_ID 0x0A int xdevice_get_last_tool_id (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; int id; id = -1; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False); if (!prop) return -1; data = NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); goto out; } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) goto out; if (nitems != 4 && nitems != 5) goto out; if (act_type != XA_INTEGER) goto out; if (act_format != TOOL_ID_FORMAT_SIZE) goto out; /* item 0 = tablet ID * item 1 = old device serial number (== last tool in proximity) * item 2 = old hardware serial number (including tool ID) * item 3 = current serial number (0 if no tool in proximity) * item 4 = current tool ID (since Feb 2012) * * Get the current tool ID first, if available, then the old one */ id = 0x0; if (nitems == 5) id = get_id_for_index (data, 4); if (id == 0x0) id = get_id_for_index (data, 2); /* That means that no tool was set down yet */ if (id == STYLUS_DEVICE_ID || id == ERASER_DEVICE_ID) id = 0x0; out: if (data != NULL) XFree (data); return id; } gboolean set_device_enabled (int device_id, gboolean enabled) { Atom prop; guchar value; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Enabled", False); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); value = enabled ? 1 : 0; XIChangeProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_id, prop, XA_INTEGER, 8, PropModeReplace, &value, 1); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) return FALSE; return TRUE; } static const char * custom_command_to_string (CustomCommand command) { switch (command) { case COMMAND_DEVICE_ADDED: return "added"; case COMMAND_DEVICE_REMOVED: return "removed"; case COMMAND_DEVICE_PRESENT: return "present"; default: g_assert_not_reached (); } } /* Run a custom command on device presence events. Parameters passed into * the custom command are: * command -t [added|removed|present] -i * Type 'added' and 'removed' signal 'device added' and 'device removed', * respectively. Type 'present' signals 'device present at * cinnamon-settings-daemon init'. * * The script is expected to run synchronously, and an exit value * of "1" means that no other settings will be applied to this * particular device. * * More options may be added in the future. * * This function returns TRUE if we should not apply any more settings * to the device. */ gboolean run_custom_command (GdkDevice *device, CustomCommand command) { GSettings *settings; char *cmd; char *argv[7]; int exit_status; gboolean rc; int id; settings = g_settings_new (INPUT_DEVICES_SCHEMA); cmd = g_settings_get_string (settings, KEY_HOTPLUG_COMMAND); g_object_unref (settings); if (!cmd || cmd[0] == '\0') { g_free (cmd); return FALSE; } /* Easter egg! */ g_object_get (device, "device-id", &id, NULL); argv[0] = cmd; argv[1] = (char *)"-t"; argv[2] = (char *) custom_command_to_string (command); argv[3] = (char *)"-i"; argv[4] = g_strdup_printf ("%d", id); argv[5] = g_strdup_printf ("%s", gdk_device_get_name (device)); argv[6] = NULL; rc = g_spawn_sync (g_get_home_dir (), argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &exit_status, NULL); if (rc == FALSE) g_warning ("Couldn't execute command '%s', verify that this is a valid command.", cmd); g_free (argv[0]); g_free (argv[4]); g_free (argv[5]); return (exit_status == 0); } GList * get_disabled_devices (GdkDeviceManager *manager) { XDeviceInfo *device_info; gint n_devices; gint i; GList *ret; ret = NULL; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return ret; for (i = 0; i < n_devices; i++) { GdkDevice *device; /* Ignore core devices */ if (device_info[i].use == IsXKeyboard || device_info[i].use == IsXPointer) continue; /* Check whether the device is actually available */ device = gdk_x11_device_manager_lookup (manager, device_info[i].id); if (device != NULL) continue; ret = g_list_prepend (ret, GINT_TO_POINTER (device_info[i].id)); } XFreeDeviceList (device_info); return ret; } void xdevice_close (XDevice *xdevice) { gdk_x11_display_error_trap_push (gdk_display_get_default ()); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default ()); } cinnamon-settings-daemon-4.4.0/plugins/common/csd-input-helper.h000066400000000000000000000063411356401377300247420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera * * 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 __CSD_INPUT_HELPER_H #define __CSD_INPUT_HELPER_H G_BEGIN_DECLS #include #include #include #define WACOM_SERIAL_IDS_PROP "Wacom Serial IDs" typedef enum { COMMAND_DEVICE_ADDED, COMMAND_DEVICE_REMOVED, COMMAND_DEVICE_PRESENT } CustomCommand; /* Generic property setting code. Fill up the struct property with the property * data and pass it into device_set_property together with the device to be * changed. Note: doesn't cater for non-zero offsets yet, but we don't have * any settings that require that. */ typedef struct { const char *name; /* property name */ gint nitems; /* number of items in data */ gint format; /* CARD8 or CARD32 sized-items */ gint type; /* Atom representing data type */ union { const gchar *c; /* 8 bit data */ const gint *i; /* 32 bit data */ } data; } PropertyHelper; gboolean supports_xinput_devices (void); gboolean supports_xinput2_devices (int *opcode); gboolean supports_xtest (void); gboolean set_device_enabled (int device_id, gboolean enabled); gboolean device_is_touchpad (XDevice *xdevice); gboolean device_info_is_touchpad (XDeviceInfo *device_info); gboolean device_info_is_touchscreen (XDeviceInfo *device_info); gboolean device_info_is_tablet (XDeviceInfo *device_info); gboolean device_info_is_mouse (XDeviceInfo *device_info); gboolean touchpad_is_present (void); gboolean touchscreen_is_present (void); gboolean mouse_is_present (void); gboolean device_set_property (XDevice *xdevice, const char *device_name, PropertyHelper *property); gboolean run_custom_command (GdkDevice *device, CustomCommand command); GList * get_disabled_devices (GdkDeviceManager *manager); char * xdevice_get_device_node (int deviceid); int xdevice_get_last_tool_id (int deviceid); void xdevice_close (XDevice *xdevice); G_END_DECLS #endif /* __CSD_INPUT_HELPER_H */ cinnamon-settings-daemon-4.4.0/plugins/common/csd-keygrab.c000066400000000000000000000326471356401377300237550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2001-2003 Bastien Nocera * Copyright (C) 2006-2007 William Jon McCann * Copyright (C) 2008 Jens Granseuer * * 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 #include #include #include #include #include #include #include #include "csd-keygrab.h" /* these are the mods whose combinations are ignored by the keygrabbing code */ static GdkModifierType csd_ignored_mods = 0; /* these are the ones we actually use for global keys, we always only check * for these set */ static GdkModifierType csd_used_mods = 0; /* Taken from a comment in XF86keysym.h */ #define XF86KEYS_RANGE_MIN 0x10080001 #define XF86KEYS_RANGE_MAX 0x1008FFFF #define FKEYS_RANGE_MIN GDK_KEY_F1 #define FKEYS_RANGE_MAX GDK_KEY_R15 #define IN_RANGE(x, min, max) (x >= min && x <= max) static void setup_modifiers (void) { if (csd_used_mods == 0 || csd_ignored_mods == 0) { GdkModifierType dynmods; /* default modifiers */ csd_ignored_mods = \ 0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | GDK_HYPER_MASK; csd_used_mods = \ GDK_SHIFT_MASK | GDK_CONTROL_MASK |\ GDK_MOD1_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK |\ GDK_MOD5_MASK | GDK_SUPER_MASK | GDK_META_MASK; /* NumLock can be assigned to varying keys so we need to * resolve and ignore it specially */ dynmods = XkbKeysymToModifiers (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_KEY_Num_Lock); csd_ignored_mods |= dynmods; csd_used_mods &= ~dynmods; } } static void grab_key_real (guint keycode, GdkWindow *root, gboolean grab, gboolean synchronous, XIGrabModifiers *mods, int num_mods) { XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8]; memset (mask, 0, sizeof (mask)); XISetMask (mask, XI_KeyPress); XISetMask (mask, XI_KeyRelease); evmask.deviceid = XIAllMasterDevices; evmask.mask_len = sizeof (mask); evmask.mask = mask; if (grab) { XIGrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XIAllMasterDevices, keycode, GDK_WINDOW_XID (root), GrabModeAsync, synchronous ? GrabModeSync : GrabModeAsync, False, &evmask, num_mods, mods); } else { XIUngrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XIAllMasterDevices, keycode, GDK_WINDOW_XID (root), num_mods, mods); } } /* Grab the key. In order to ignore CSD_IGNORED_MODS we need to grab * all combinations of the ignored modifiers and those actually used * for the binding (if any). * * inspired by all_combinations from gnome-panel/gnome-panel/global-keys.c * * This may generate X errors. The correct way to use this is like: * * gdk_x11_display_error_trap_push (gdk_display_get_default ()); * * grab_key_unsafe (key, grab, screens); * * gdk_flush (); * if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) * g_warning ("Grab failed, another application may already have access to key '%u'", * key->keycode); * * This is not done in the function itself, to allow doing multiple grab_key * operations with one flush only. */ #define N_BITS 32 static void grab_key_internal (Key *key, gboolean grab, CsdKeygrabFlags flags, GSList *screens) { int indexes[N_BITS]; /* indexes of bits we need to flip */ int i; int bit; int bits_set_cnt; int uppervalue; guint mask, modifiers; GArray *all_mods; GSList *l; setup_modifiers (); mask = csd_ignored_mods & ~key->state & GDK_MODIFIER_MASK; /* XGrabKey requires real modifiers, not virtual ones */ modifiers = key->state; gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &modifiers); modifiers &= ~(GDK_META_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK); /* If key doesn't have a usable modifier, we don't want * to grab it, since the user might lose a useful key. * * The exception is the XFree86 keys and the Function keys * (which are useful to grab without a modifier). */ if (!(flags & CSD_KEYGRAB_ALLOW_UNMODIFIED) && (modifiers & csd_used_mods) == 0 && !IN_RANGE(key->keysym, XF86KEYS_RANGE_MIN, XF86KEYS_RANGE_MAX) && !IN_RANGE(key->keysym, FKEYS_RANGE_MIN, FKEYS_RANGE_MAX) && key->keysym != GDK_KEY_Pause && key->keysym != GDK_KEY_Print && key->keysym != GDK_KEY_Scroll_Lock && key->keysym != GDK_KEY_Break && key->keysym != GDK_KEY_Menu) { GString *keycodes; keycodes = g_string_new (""); if (key->keycodes != NULL) { guint *c; for (c = key->keycodes; *c; ++c) { g_string_printf (keycodes, " %u", *c); } } g_warning ("Key 0x%x (keycodes: %s) with state 0x%x (resolved to 0x%x) " " has no usable modifiers (usable modifiers are 0x%x)", key->keysym, keycodes->str, key->state, modifiers, csd_used_mods); g_string_free (keycodes, TRUE); return; } bit = 0; /* store the indexes of all set bits in mask in the array */ for (i = 0; mask; ++i, mask >>= 1) { if (mask & 0x1) { indexes[bit++] = i; } } bits_set_cnt = bit; all_mods = g_array_new (FALSE, TRUE, sizeof(XIGrabModifiers)); uppervalue = 1 << bits_set_cnt; /* store all possible modifier combinations for our mask into all_mods */ for (i = 0; i < uppervalue; ++i) { int j; int result = 0; XIGrabModifiers *mod; /* map bits in the counter to those in the mask */ for (j = 0; j < bits_set_cnt; ++j) { if (i & (1 << j)) { result |= (1 << indexes[j]); } } /* Grow the array by one, to fit our new XIGrabModifiers item */ g_array_set_size (all_mods, all_mods->len + 1); mod = &g_array_index (all_mods, XIGrabModifiers, all_mods->len - 1); mod->modifiers = result | modifiers; } /* Capture the actual keycodes with the modifier array */ for (l = screens; l; l = l->next) { GdkScreen *screen = l->data; guint *code; for (code = key->keycodes; *code; ++code) { grab_key_real (*code, gdk_screen_get_root_window (screen), grab, flags & CSD_KEYGRAB_SYNCHRONOUS, (XIGrabModifiers *) all_mods->data, all_mods->len); } } g_array_free (all_mods, TRUE); } void grab_key_unsafe (Key *key, CsdKeygrabFlags flags, GSList *screens) { grab_key_internal (key, TRUE, flags, screens); } void ungrab_key_unsafe (Key *key, GSList *screens) { grab_key_internal (key, FALSE, 0, screens); } static gboolean have_xkb (Display *dpy) { static int have_xkb = -1; if (have_xkb == -1) { int opcode, error_base, major, minor, xkb_event_base; have_xkb = XkbQueryExtension (dpy, &opcode, &xkb_event_base, &error_base, &major, &minor) && XkbUseExtension (dpy, &major, &minor); } return have_xkb; } gboolean key_uses_keycode (const Key *key, guint keycode) { if (key->keycodes != NULL) { guint *c; for (c = key->keycodes; *c; ++c) { if (*c == keycode) return TRUE; } } return FALSE; } /* Adapted from _gdk_x11_device_xi2_translate_state() * in gtk+/gdk/x11/gdkdevice-xi2.c */ static guint device_xi2_translate_state (XIModifierState *mods_state, XIGroupState *group_state) { guint state; gint group; state = (guint) mods_state->base | mods_state->latched | mods_state->locked; group = group_state->base | group_state->latched | group_state->locked; /* FIXME: do we need the XKB complications for this ? */ group = CLAMP(group, 0, 3); state |= group << 13; return state; } gboolean match_xi2_key (Key *key, XIDeviceEvent *event) { guint keyval; GdkModifierType consumed; gint group; guint keycode, state; if (key == NULL) return FALSE; setup_modifiers (); state = device_xi2_translate_state (&event->mods, &event->group); if (have_xkb (event->display)) group = XkbGroupForCoreState (state); else group = (state & GDK_KEY_Mode_switch) ? 1 : 0; keycode = event->detail; /* Check if we find a keysym that matches our current state */ if (gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), keycode, state, group, &keyval, NULL, NULL, &consumed)) { guint lower, upper; guint mask; /* HACK: we don't want to use SysRq as a keybinding, so we avoid * its translation from Alt+Print. */ if (keyval == GDK_KEY_Sys_Req && (state & GDK_MOD1_MASK) != 0) { consumed = 0; keyval = GDK_KEY_Print; } /* The Key structure contains virtual modifiers, whereas * the XEvent will be using the real modifier, so translate those */ mask = key->state; gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &mask); mask &= ~(GDK_META_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK); gdk_keyval_convert_case (keyval, &lower, &upper); /* If we are checking against the lower version of the * keysym, we might need the Shift state for matching, * so remove it from the consumed modifiers */ if (lower == key->keysym) consumed &= ~GDK_SHIFT_MASK; return ((lower == key->keysym || upper == key->keysym) && (state & ~consumed & csd_used_mods) == mask); } /* The key we passed doesn't have a keysym, so try with just the keycode */ return (key != NULL && key->state == (state & csd_used_mods) && key_uses_keycode (key, keycode)); } Key * parse_key (const char *str) { Key *key; if (str == NULL || *str == '\0' || g_str_equal (str, "disabled")) { return NULL; } key = g_new0 (Key, 1); gtk_accelerator_parse_with_keycode (str, &key->keysym, &key->keycodes, &key->state); if (key->keysym == 0 && key->keycodes == NULL && key->state == 0) { g_free (key); return NULL; } return key; } void free_key (Key *key) { if (key == NULL) return; g_free (key->keycodes); g_free (key); } static void grab_button_real (int deviceid, gboolean grab, GdkWindow *root) { XIGrabModifiers mods; mods.modifiers = XIAnyModifier; if (grab) { XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8]; memset (mask, 0, sizeof (mask)); XISetMask (mask, XI_ButtonRelease); XISetMask (mask, XI_ButtonPress); evmask.deviceid = deviceid; evmask.mask_len = sizeof (mask); evmask.mask = mask; XIGrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, XIAnyButton, GDK_WINDOW_XID (root), None, GrabModeAsync, GrabModeAsync, False, &evmask, 1, &mods); } else { XIUngrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, XIAnyButton, GDK_WINDOW_XID (root), 1, &mods); } } void grab_button (int deviceid, gboolean grab, GSList *screens) { GSList *l; for (l = screens; l; l = l->next) { GdkScreen *screen = l->data; grab_button_real (deviceid, grab, gdk_screen_get_root_window (screen)); } } cinnamon-settings-daemon-4.4.0/plugins/common/csd-keygrab.h000066400000000000000000000037341356401377300237550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Jens Granseuer * * 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 __CSD_COMMON_KEYGRAB_H #define __CSD_COMMON_KEYGRAB_H G_BEGIN_DECLS #include #include #include typedef struct { guint keysym; guint state; guint *keycodes; } Key; typedef enum { CSD_KEYGRAB_NORMAL = 0, CSD_KEYGRAB_ALLOW_UNMODIFIED = 1 << 0, CSD_KEYGRAB_SYNCHRONOUS = 1 << 1 } CsdKeygrabFlags; void grab_key_unsafe (Key *key, CsdKeygrabFlags flags, GSList *screens); void ungrab_key_unsafe (Key *key, GSList *screens); gboolean match_xi2_key (Key *key, XIDeviceEvent *event); gboolean key_uses_keycode (const Key *key, guint keycode); Key * parse_key (const char *str); void free_key (Key *key); void grab_button (int deviceid, gboolean grab, GSList *screens); G_END_DECLS #endif /* __CSD_COMMON_KEYGRAB_H */ cinnamon-settings-daemon-4.4.0/plugins/common/csd-power-helper.c000066400000000000000000000265151356401377300247370ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * 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 #include "config.h" #include "csd-power-helper.h" #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define CONSOLEKIT_DBUS_NAME "org.freedesktop.ConsoleKit" #define CONSOLEKIT_DBUS_PATH_MANAGER "/org/freedesktop/ConsoleKit/Manager" #define CONSOLEKIT_DBUS_INTERFACE_MANAGER "org.freedesktop.ConsoleKit.Manager" #ifdef HAVE_LOGIND static gboolean use_logind (void) { static gboolean should_use_logind = FALSE; static gsize once_init_value = 0; if (g_once_init_enter (&once_init_value)) { should_use_logind = access("/run/systemd/system/", F_OK) == 0; // sd_booted () g_once_init_leave (&once_init_value, 1); } return should_use_logind; } #else /* HAVE_LOGIND */ static gboolean use_logind (void) { return FALSE; } #endif /* HAVE_LOGIND */ static void logind_stop (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "PowerOff", g_variant_new ("(b)", FALSE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void logind_suspend (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "Suspend", g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void logind_hybrid_suspend (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "HybridSleep", g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static gboolean can_hybrid_sleep (void) { GDBusConnection *bus; GVariant *res; gchar *rv; gboolean can_hybrid; GError *error = NULL; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); res = g_dbus_connection_call_sync (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "CanHybridSleep", NULL, G_VARIANT_TYPE_TUPLE, 0, G_MAXINT, NULL, &error); g_object_unref (bus); if (error) { g_warning ("Calling CanHybridSleep failed: %s", error->message); g_clear_error (&error); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_hybrid = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; if (!can_hybrid) { g_warning ("logind does not support hybrid sleep"); } g_free (rv); return can_hybrid; } static void logind_hibernate (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "Hibernate", g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void consolekit_stop_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("couldn't stop using ConsoleKit: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void consolekit_stop (void) { GError *error = NULL; GDBusProxy *proxy; /* power down the machine in a safe way */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_stop_cb, NULL); g_object_unref (proxy); } static void consolekit_sleep_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("couldn't sleep using ConsoleKit: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void consolekit_suspend (void) { GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Suspend", g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } static void consolekit_hibernate (void) { GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Hibernate", g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } static void consolekit_hybrid_suspend (void) { GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "HybridSleep", g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } void csd_power_suspend (gboolean try_hybrid) { if (use_logind ()) { if (try_hybrid && can_hybrid_sleep ()) { logind_hybrid_suspend (); } else { logind_suspend (); } } else { if (try_hybrid && can_hybrid_sleep ()) { consolekit_hybrid_suspend (); } else { consolekit_suspend (); } } } void csd_power_poweroff (void) { if (use_logind ()) { logind_stop (); } else { consolekit_stop (); } } void csd_power_hibernate (void) { if (use_logind ()) { logind_hibernate (); } else { consolekit_hibernate (); } } cinnamon-settings-daemon-4.4.0/plugins/common/csd-power-helper.h000066400000000000000000000021331356401377300247320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * 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 __CSD_POWER_HELPER_H #define __CSD_POWER_HELPER_H #include G_BEGIN_DECLS void csd_power_suspend (gboolean try_hybrid); void csd_power_hibernate (void); void csd_power_poweroff (void); G_END_DECLS #endif /* __CSD_POWER_HELPER_H */ cinnamon-settings-daemon-4.4.0/plugins/common/daemon-skeleton.h000066400000000000000000000163451356401377300246510ustar00rootroot00000000000000/** * Create a test app for your plugin quickly. * * #define NEW csd_media_keys_manager_new * #define START csd_media_keys_manager_start * #define MANAGER CsdMediaKeysManager * #include "csd-media-keys-manager.h" * * #include "daemon-skeleton.h" */ #include "config.h" #include #include #include #include #ifndef PLUGIN_NAME #error Include PLUGIN_CFLAGS in the daemon s CFLAGS #endif /* !PLUGIN_NAME */ #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_CLIENT_PRIVATE_NAME "org.gnome.SessionManager.ClientPrivate" static MANAGER *manager = NULL; static int timeout = -1; static gboolean verbose = FALSE; static GOptionEntry entries[] = { { "exit-time", 0, 0, G_OPTION_ARG_INT, &timeout, "Exit after n seconds time", NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose", NULL }, {NULL} }; static void respond_to_end_session (GDBusProxy *proxy) { /* we must answer with "EndSessionResponse" */ g_dbus_proxy_call (proxy, "EndSessionResponse", g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } static void client_proxy_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { if (g_strcmp0 (signal_name, "QueryEndSession") == 0) { g_debug ("Got QueryEndSession signal"); respond_to_end_session (proxy); } else if (g_strcmp0 (signal_name, "EndSession") == 0) { g_debug ("Got EndSession signal"); respond_to_end_session (proxy); } else if (g_strcmp0 (signal_name, "Stop") == 0) { g_debug ("Got Stop signal"); /* Ideally, we would call gtk_main_quit (); here. Instead, do nothing. cinnamon-session-manager doesn't wait in this STOP PHASE. so we're not delaying the logout/shutdown sequence. Also, if another process is lagging and delaying previous phases, we don't want to lose CSD in the background. We want CSD plugins to run until the very very end of the session. */ } } static void on_client_registered (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *variant; GDBusProxy *client_proxy; GError *error = NULL; gchar *object_path = NULL; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (!variant) { if (error != NULL) { g_warning ("Unable to register client: %s", error->message); g_error_free (error); } return; } g_variant_get (variant, "(o)", &object_path); g_debug ("Registered client at path %s", object_path); client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, 0, NULL, GNOME_SESSION_DBUS_NAME, object_path, GNOME_SESSION_CLIENT_PRIVATE_NAME, NULL, &error); if (!client_proxy) { if (error != NULL) { g_warning ("Unable to get the session client proxy: %s", error->message); g_error_free (error); } return; } g_signal_connect (client_proxy, "g-signal", G_CALLBACK (client_proxy_signal_cb), NULL); g_free (object_path); g_variant_unref (variant); } static void register_with_cinnamon_session (void) { const char *startup_id; GError *error = NULL; GDBusProxy *proxy; GDBusConnection *bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); if (!bus) { g_debug ("Could not connect to the dbus session bus"); return; } proxy = g_dbus_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_NONE, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_NAME, NULL, &error); g_object_unref (bus); if (proxy == NULL) { if (error != NULL) { g_debug ("Could not connect to the Session manager: %s", error->message); g_error_free (error); } return; } startup_id = g_getenv ("DESKTOP_AUTOSTART_ID"); g_dbus_proxy_call (proxy, "RegisterClient", g_variant_new ("(ss)", PLUGIN_NAME, startup_id ? startup_id : ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback) on_client_registered, NULL); } int main (int argc, char **argv) { GError *error; gboolean started; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* Work around https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ g_type_ensure (G_TYPE_DBUS_CONNECTION); g_type_ensure (G_TYPE_DBUS_PROXY); gdk_set_allowed_backends ("x11"); notify_init ("cinnamon-settings-daemon"); if (FORCE_GDK_SCALE) { g_setenv ("GDK_SCALE", "1", TRUE); } error = NULL; if (! gtk_init_with_args (&argc, &argv, PLUGIN_NAME, entries, NULL, &error)) { if (error != NULL) { fprintf (stderr, "%s\n", error->message); g_error_free (error); } exit (1); } if (FORCE_GDK_SCALE) { g_unsetenv ("GDK_SCALE"); } if (verbose) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (timeout > 0) { guint id; id = g_timeout_add_seconds (timeout, (GSourceFunc) gtk_main_quit, NULL); g_source_set_name_by_id (id, "[cinnamon-settings-daemon] gtk_main_quit"); } manager = NEW (); error = NULL; if (REGISTER_BEFORE_STARTING) { register_with_cinnamon_session (); started = START (manager, &error); } else { started = START (manager, &error); register_with_cinnamon_session (); } if (!started) { if (error != NULL) { fprintf (stderr, "[cinnamon-settings-daemon-%s] Failed to start: %s\n", PLUGIN_NAME, error->message); g_error_free (error); } exit (1); } gtk_main (); STOP (manager); g_object_unref (manager); return 0; } cinnamon-settings-daemon-4.4.0/plugins/common/input-device-example.sh000066400000000000000000000030141356401377300257610ustar00rootroot00000000000000#!/bin/sh # # This script is an example hotplug script for use with the various # input devices plugins. # # The script is called with the arguments: # -t [added|present|removed] # added ... device was just plugged in # present.. device was present at cinnamon-settings-daemon startup # removed.. device was just removed # -i # device ID being the XInput device ID # The name of the device # # The script should return 0 if the device is to be # ignored from future configuration. # # Set the script to be used with: # gsettings set org.cinnamon.settings-daemon.peripherals.input-devices hotplug-command /path/to/script/input-devices.sh # args=`getopt "t:i:" $*` set -- $args while [ $# -gt 0 ] do case $1 in -t) shift; type="$1" ;; -i) shift; id="$1" ;; --) shift; device="$@" break; ;; *) echo "Unknown option $1"; exit 1 ;; esac shift done retval=0 case $type in added) echo "Device '$device' (ID=$id) was added" ;; present) echo "Device '$device' (ID=$id) was already present at startup" ;; removed) echo "Device '$device' (ID=$id) was removed" ;; *) echo "Unknown operation" retval=1 ;; esac # All further processing will be disabled if $retval == 0 exit $retval cinnamon-settings-daemon-4.4.0/plugins/common/test-input-helper.c000066400000000000000000000070701356401377300251430ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Bastien Nocera * * 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 #include #include #include #include #include "csd-input-helper.h" static void print_disabled_devices (void) { GList *devices, *l; GdkDeviceManager *manager; manager = gdk_display_get_device_manager (gdk_display_get_default ()); devices = get_disabled_devices (manager); g_print ("Disabled devices:\t\t\t"); if (devices == NULL) { g_print ("no\n"); return; } for (l = devices; l != NULL; l = l->next) { g_print ("%d ", GPOINTER_TO_INT (l->data)); } g_list_free (devices); g_print ("\n"); } int main (int argc, char **argv) { gboolean supports_xinput; gboolean has_touchpad, has_touchscreen; XDeviceInfo *device_info; gint n_devices, opcode, i; gtk_init (&argc, &argv); supports_xinput = supports_xinput_devices (); if (supports_xinput) { g_print ("Supports XInput:\t\t\tyes\n"); } else { g_print ("Supports XInput:\t\t\tno\n"); return 0; } supports_xinput = supports_xinput2_devices (&opcode); if (supports_xinput) { g_print ("Supports XInput2:\t\t\tyes (opcode: %d)\n", opcode); } else { g_print ("Supports XInput2:\t\t\tno\n"); return 0; } has_touchpad = touchpad_is_present (); g_print ("Has touchpad:\t\t\t\t%s\n", has_touchpad ? "yes" : "no"); has_touchscreen = touchscreen_is_present (); g_print ("Has touchscreen:\t\t\t%s\n", has_touchscreen ? "yes" : "no"); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) { g_warning ("Has no input devices"); return 1; } print_disabled_devices (); for (i = 0; i < n_devices; i++) { XDevice *device; if (device_info_is_touchscreen (&device_info[i])) { g_print ("Device %d is touchscreen:\t\t%s\n", (int) device_info[i].id, "yes"); continue; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) continue; if (device_is_touchpad (device)) g_print ("Device %d is touchpad:\t\t%s\n", (int) device_info[i].id, "yes"); else { int tool_id; tool_id = xdevice_get_last_tool_id (device_info[i].id); if (tool_id >= 0x0) g_print ("Device %d is touchpad/touchscreen:\t%s (tool ID: 0x%x)\n", (int) device_info[i].id, "no", tool_id); else g_print ("Device %d is touchpad/touchscreen:\t%s\n", (int) device_info[i].id, "no"); } xdevice_close (device); } XFreeDeviceList (device_info); return 0; } cinnamon-settings-daemon-4.4.0/plugins/cursor/000077500000000000000000000000001356401377300214275ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/cursor/Makefile.am000066400000000000000000000020101356401377300234540ustar00rootroot00000000000000plugin_name = cursor AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-cursor csd_cursor_SOURCES = \ main.c \ csd-cursor-manager.c \ csd-cursor-manager.h csd_cursor_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_cursor_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(CURSOR_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_cursor_LDADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(CURSOR_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-cursor.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-cursor.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/cursor/cinnamon-settings-daemon-cursor.desktop.in000066400000000000000000000003511356401377300316420ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - cursor Exec=@libexecdir@/csd-cursor OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/cursor/csd-cursor-manager.c000066400000000000000000000301471356401377300252740ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-cursor-manager.h" #include "csd-input-helper.h" #define XFIXES_CURSOR_HIDING_MAJOR 4 #define CSD_CURSOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerPrivate)) struct CsdCursorManagerPrivate { guint start_idle_id; guint added_id; guint removed_id; gboolean cursor_shown; }; enum { PROP_0, }; static void csd_cursor_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdCursorManager, csd_cursor_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean device_is_xtest (XDevice *xdevice) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XTEST Device", False); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); XFree (data); return TRUE; } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return FALSE; } static void set_cursor_visibility (CsdCursorManager *manager, gboolean visible) { Display *xdisplay; GdkDisplay *display; GdkScreen *screen; g_debug ("Attempting to %s the cursor", visible ? "show" : "hide"); display = gdk_display_get_default (); if (display) { xdisplay = GDK_DISPLAY_XDISPLAY (display); gdk_x11_display_error_trap_push (gdk_display_get_default ()); screen = gdk_display_get_screen (display, 0); if (visible) XFixesShowCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen))); else XFixesHideCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen))); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("An error occurred trying to %s the cursor", visible ? "show" : "hide"); } } manager->priv->cursor_shown = visible; } static gboolean device_info_is_ps2_mouse (XDeviceInfo *info) { return (g_strcmp0 (info->name, "ImPS/2 Generic Wheel Mouse") == 0); } static void update_cursor_for_current (CsdCursorManager *manager) { XDeviceInfo *device_info; guint num_mice; int n_devices; guint i; /* List all the pointer devices * ignore the touchscreens * ignore the XTest devices * see if there's anything left */ device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return; num_mice = 0; for (i = 0; i < n_devices; i++) { XDevice *device; if (device_info[i].use != IsXExtensionPointer) continue; if (device_info_is_touchscreen (&device_info[i])) continue; if (device_info_is_ps2_mouse (&device_info[i])) continue; gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) continue; if (device_is_xtest (device)) { xdevice_close (device); continue; } g_debug ("Counting '%s' as mouse", device_info[i].name); num_mice++; } XFreeDeviceList (device_info); g_debug ("Found %d devices that aren't touchscreens or fake devices", num_mice); if (num_mice > 0) { g_debug ("Mice are present"); if (manager->priv->cursor_shown == FALSE) { set_cursor_visibility (manager, TRUE); } } else { g_debug ("No mice present"); if (manager->priv->cursor_shown != FALSE) { set_cursor_visibility (manager, FALSE); } } } static void devices_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdCursorManager *manager) { update_cursor_for_current (manager); } static void devices_removed_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdCursorManager *manager) { /* If devices are removed, then it's unlikely * a mouse appeared */ if (manager->priv->cursor_shown == FALSE) return; update_cursor_for_current (manager); } static gboolean supports_xfixes (void) { gint op_code, event, error; return XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XFIXES", &op_code, &event, &error); } static gboolean supports_cursor_xfixes (void) { int major = XFIXES_CURSOR_HIDING_MAJOR; int minor = 0; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (!supports_xfixes ()) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return FALSE; } if (!XFixesQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor)) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return FALSE; } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); if (major >= XFIXES_CURSOR_HIDING_MAJOR) return TRUE; return FALSE; } static gboolean csd_cursor_manager_idle_cb (CsdCursorManager *manager) { GdkDeviceManager *device_manager; cinnamon_settings_profile_start (NULL); if (supports_cursor_xfixes () == FALSE) { g_debug ("XFixes cursor extension not available, will not hide the cursor"); return FALSE; } if (supports_xinput_devices () == FALSE) { g_debug ("XInput support not available, will not hide the cursor"); return FALSE; } /* We assume that the touchscreen is builtin and * won't be appearing in the middle of the session... */ if (touchscreen_is_present () == FALSE) { g_debug ("Did not find a touchscreen, will not hide the cursor"); cinnamon_settings_profile_end (NULL); return FALSE; } update_cursor_for_current (manager); device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); manager->priv->added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (devices_added_cb), manager); manager->priv->removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed", G_CALLBACK (devices_removed_cb), manager); cinnamon_settings_profile_end (NULL); return FALSE; } gboolean csd_cursor_manager_start (CsdCursorManager *manager, GError **error) { g_debug ("Starting cursor manager"); cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_cursor_manager_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_cursor_manager_stop (CsdCursorManager *manager) { GdkDeviceManager *device_manager; g_debug ("Stopping cursor manager"); device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); if (manager->priv->added_id > 0) { g_signal_handler_disconnect (G_OBJECT (device_manager), manager->priv->added_id); manager->priv->added_id = 0; } if (manager->priv->removed_id > 0) { g_signal_handler_disconnect (G_OBJECT (device_manager), manager->priv->removed_id); manager->priv->removed_id = 0; } if (manager->priv->cursor_shown == FALSE) { set_cursor_visibility (manager, TRUE); } } static GObject * csd_cursor_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdCursorManager *cursor_manager; cursor_manager = CSD_CURSOR_MANAGER (G_OBJECT_CLASS (csd_cursor_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (cursor_manager); } static void csd_cursor_manager_class_init (CsdCursorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_cursor_manager_constructor; object_class->finalize = csd_cursor_manager_finalize; g_type_class_add_private (klass, sizeof (CsdCursorManagerPrivate)); } static void csd_cursor_manager_init (CsdCursorManager *manager) { manager->priv = CSD_CURSOR_MANAGER_GET_PRIVATE (manager); manager->priv->cursor_shown = TRUE; } static void csd_cursor_manager_finalize (GObject *object) { CsdCursorManager *cursor_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CURSOR_MANAGER (object)); cursor_manager = CSD_CURSOR_MANAGER (object); g_return_if_fail (cursor_manager->priv != NULL); G_OBJECT_CLASS (csd_cursor_manager_parent_class)->finalize (object); } CsdCursorManager * csd_cursor_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_CURSOR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_CURSOR_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/cursor/csd-cursor-manager.h000066400000000000000000000044311356401377300252760ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_CURSOR_MANAGER_H #define __CSD_CURSOR_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_CURSOR_MANAGER (csd_cursor_manager_get_type ()) #define CSD_CURSOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManager)) #define CSD_CURSOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerClass)) #define CSD_IS_CURSOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CURSOR_MANAGER)) #define CSD_IS_CURSOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CURSOR_MANAGER)) #define CSD_CURSOR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerClass)) typedef struct CsdCursorManagerPrivate CsdCursorManagerPrivate; typedef struct { GObject parent; CsdCursorManagerPrivate *priv; } CsdCursorManager; typedef struct { GObjectClass parent_class; } CsdCursorManagerClass; GType csd_cursor_manager_get_type (void); CsdCursorManager * csd_cursor_manager_new (void); gboolean csd_cursor_manager_start (CsdCursorManager *manager, GError **error); void csd_cursor_manager_stop (CsdCursorManager *manager); G_END_DECLS #endif /* __CSD_CURSOR_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/cursor/main.c000066400000000000000000000010121356401377300225110ustar00rootroot00000000000000#define NEW csd_cursor_manager_new #define START csd_cursor_manager_start #define STOP csd_cursor_manager_stop #define MANAGER CsdCursorManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-cursor-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/datetime/000077500000000000000000000000001356401377300217065ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/datetime/Makefile.am000066400000000000000000000041451356401377300237460ustar00rootroot00000000000000plugin_name = datetime dbus_servicesdir = $(datadir)/dbus-1/system-services dbus_confdir = $(sysconfdir)/dbus-1/system.d polkitdir = $(datadir)/polkit-1/actions dbus_services_in_files = org.cinnamon.SettingsDaemon.DateTimeMechanism.service.in polkit_in_files = org.cinnamon.settingsdaemon.datetimemechanism.policy.in csd-datetime-mechanism-glue.h: $(srcdir)/csd-datetime-mechanism.xml $(AM_V_GEN) dbus-binding-tool \ --prefix=csd_datetime_mechanism --mode=glib-server \ --output=csd-datetime-mechanism-glue.h \ $(srcdir)/csd-datetime-mechanism.xml if HAVE_POLKIT libexec_PROGRAMS = csd-datetime-mechanism noinst_PROGRAMS = test-system-timezone endif csd_datetime_mechanism_SOURCES = \ csd-datetime-mechanism.c \ csd-datetime-mechanism.h \ csd-datetime-mechanism-fedora.c \ csd-datetime-mechanism-fedora.h \ csd-datetime-mechanism-debian.c \ csd-datetime-mechanism-debian.h \ csd-datetime-mechanism-suse.c \ csd-datetime-mechanism-suse.h \ csd-datetime-mechanism-main.c \ system-timezone.c \ system-timezone.h if HAVE_POLKIT BUILT_SOURCES = csd-datetime-mechanism-glue.h endif AM_CFLAGS = $(WARN_CFLAGS) $(PLUGIN_CFLAGS) $(SETTINGS_PLUGIN_CFLAGS) $(POLKIT_CFLAGS) csd_datetime_mechanism_LDADD = $(POLKIT_LIBS) $(SETTINGS_PLUGIN_LIBS) test_system_timezone_SOURCES = test-system-timezone.c system-timezone.c system-timezone.h test_system_timezone_LDADD = $(POLKIT_LIBS) $(SETTINGS_PLUGIN_LIBS) if HAVE_POLKIT dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) $(dbus_services_DATA): $(dbus_services_in_files) $(AM_V_GEN)sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ dbus_conf_DATA = org.cinnamon.SettingsDaemon.DateTimeMechanism.conf @INTLTOOL_POLICY_RULE@ polkit_DATA = $(polkit_in_files:.policy.in=.policy) else dbus_services_DATA = dbus_conf_DATA = polkit_DATA = endif EXTRA_DIST = \ $(dbus_services_in_files) \ org.cinnamon.SettingsDaemon.DateTimeMechanism.conf \ $(polkit_in_files) \ csd-datetime-mechanism.xml CLEANFILES = \ org.cinnamon.SettingsDaemon.DateTimeMechanism.service \ org.cinnamon.settingsdaemon.datetimemechanism.policy \ $(BUILT_SOURCES) cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-debian.c000066400000000000000000000163171356401377300276070ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * 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. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "csd-datetime-mechanism-debian.h" #include "csd-datetime-mechanism.h" static void _get_using_ntpdate (gboolean *can_use, gboolean *is_using, GError ** error) { if (!g_file_test ("/usr/sbin/ntpdate-debian", G_FILE_TEST_EXISTS)) return; *can_use = TRUE; if (g_file_test ("/etc/network/if-up.d/ntpdate", G_FILE_TEST_EXISTS)) *is_using = TRUE; } static void _get_using_ntpd (gboolean *can_use, gboolean *is_using, GError ** error) { int exit_status; GError *tmp_error = NULL; if (!g_file_test ("/usr/sbin/ntpd", G_FILE_TEST_EXISTS)) return; *can_use = TRUE; if (!g_spawn_command_line_sync ("/usr/sbin/service ntp status", NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /usr/sbin/service: %s", tmp_error->message); } g_error_free (tmp_error); return; } if (exit_status == 0) *is_using = TRUE; } gboolean _get_using_ntp_debian (DBusGMethodInvocation *context) { gboolean can_use_ntp = FALSE; gboolean is_using_ntp = FALSE; GError *error = NULL; /* In Debian, ntpdate is used whenever the network comes up. So if either ntpdate or ntpd is installed and available, can_use is true. If either is active, is_using is true. */ _get_using_ntpdate (&can_use_ntp, &is_using_ntp, &error); _get_using_ntpd (&can_use_ntp, &is_using_ntp, &error); if (error == NULL) { dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } else { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } static void _set_using_ntpdate (gboolean using_ntp, GError **error) { const gchar *cmd = NULL; GError *tmp_error = NULL; /* Debian uses an if-up.d script to sync network time when an interface comes up. This is a separate mechanism from ntpd altogether. */ #define NTPDATE_ENABLED "/etc/network/if-up.d/ntpdate" #define NTPDATE_DISABLED "/etc/network/if-up.d/ntpdate.disabled" if (using_ntp && g_file_test (NTPDATE_DISABLED, G_FILE_TEST_EXISTS)) cmd = "/bin/mv -f "NTPDATE_DISABLED" "NTPDATE_ENABLED; else if (!using_ntp && g_file_test (NTPDATE_ENABLED, G_FILE_TEST_EXISTS)) cmd = "/bin/mv -f "NTPDATE_ENABLED" "NTPDATE_DISABLED; else return; if (!g_spawn_command_line_sync (cmd, NULL, NULL, NULL, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /bin/mv: %s", tmp_error->message); } g_error_free (tmp_error); return; } /* Kick start ntpdate to sync time immediately */ if (using_ntp && !g_spawn_command_line_sync ("/etc/network/if-up.d/ntpdate", NULL, NULL, NULL, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /etc/network/if-up.d/ntpdate: %s", tmp_error->message); } g_error_free (tmp_error); return; } } static void _set_using_ntpd (gboolean using_ntp, GError **error) { GError *tmp_error = NULL; int exit_status; char *cmd; if (!g_file_test ("/usr/sbin/ntpd", G_FILE_TEST_EXISTS)) return; cmd = g_strconcat ("/usr/sbin/update-rc.d ntp ", using_ntp ? "enable" : "disable", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, tmp_error->message); } g_error_free (tmp_error); g_free (cmd); return; } g_free (cmd); cmd = g_strconcat ("/usr/sbin/service ntp ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, tmp_error->message); } g_error_free (tmp_error); g_free (cmd); return; } g_free (cmd); } gboolean _set_using_ntp_debian (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error = NULL; /* In Debian, ntpdate and ntpd may be installed separately, so don't assume both are valid. */ _set_using_ntpdate (using_ntp, &error); _set_using_ntpd (using_ntp, &error); if (error == NULL) { dbus_g_method_return (context); return TRUE; } else { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-debian.h000066400000000000000000000022171356401377300276060ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * 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 #include gboolean _get_using_ntp_debian (DBusGMethodInvocation *context); gboolean _set_using_ntp_debian (DBusGMethodInvocation *context, gboolean using_ntp); cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-fedora.c000066400000000000000000000171131356401377300276200ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * 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. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "csd-datetime-mechanism-fedora.h" #include "csd-datetime-mechanism.h" /* Return the name of the installed NTP client, prefer chrony if both chrony * and ntp are installed */ static const char * get_ntp_client () { if (g_file_test ("/etc/chrony.conf", G_FILE_TEST_EXISTS)) return "chronyd"; else if (g_file_test ("/etc/ntp.conf", G_FILE_TEST_EXISTS)) return "ntpd"; return NULL; } gboolean _get_using_ntp_fedora (DBusGMethodInvocation *context) { int exit_status; GError *error = NULL; gboolean can_use_ntp; gboolean is_using_ntp; const char *ntp_client; char *cmd; ntp_client = get_ntp_client (); if (ntp_client) { can_use_ntp = TRUE; cmd = g_strconcat ("/sbin/service ", ntp_client, " status", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/service: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); if (exit_status == 0) is_using_ntp = TRUE; else is_using_ntp = FALSE; } else { can_use_ntp = FALSE; is_using_ntp = FALSE; } dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } gboolean _set_using_ntp_fedora (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error; int exit_status; const char *ntp_client; char *cmd; error = NULL; ntp_client = get_ntp_client (); /* We omit --level 2345 so that systemd doesn't try to use the * SysV init scripts */ cmd = g_strconcat ("/sbin/chkconfig ", ntp_client, " ", using_ntp ? "on" : "off", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); cmd = g_strconcat ("/sbin/service ", ntp_client, " ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); dbus_g_method_return (context); return TRUE; } gboolean _update_etc_sysconfig_clock_fedora (DBusGMethodInvocation *context, const char *key, const char *value) { char **lines; int n; gboolean replaced; char *data; gsize len; GError *error; /* On Red Hat / Fedora, the /etc/sysconfig/clock file needs to be kept in sync */ if (!g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", "No such file"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } error = NULL; if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } replaced = FALSE; lines = g_strsplit (data, "\n", 0); g_free (data); for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key)) { g_free (lines[n]); lines[n] = g_strdup_printf ("%s%s", key, value); replaced = TRUE; } } if (replaced) { GString *str; str = g_string_new (NULL); for (n = 0; lines[n] != NULL; n++) { g_string_append (str, lines[n]); if (lines[n + 1] != NULL) g_string_append_c (str, '\n'); } data = g_string_free (str, FALSE); len = strlen (data); if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error updating /etc/sysconfig/clock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (data); return FALSE; } g_free (data); } g_strfreev (lines); return TRUE; } cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-fedora.h000066400000000000000000000025721356401377300276300ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * 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 #include gboolean _get_using_ntp_fedora (DBusGMethodInvocation *context); gboolean _set_using_ntp_fedora (DBusGMethodInvocation *context, gboolean using_ntp); gboolean _update_etc_sysconfig_clock_fedora (DBusGMethodInvocation *context, const char *key, const char *value); cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-main.c000066400000000000000000000107431356401377300273060ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * 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. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "csd-datetime-mechanism.h" static DBusGProxy * get_bus_proxy (DBusGConnection *connection) { DBusGProxy *bus_proxy; bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); return bus_proxy; } #define BUS_NAME "org.cinnamon.SettingsDaemon.DateTimeMechanism" static gboolean acquire_name_on_proxy (DBusGProxy *bus_proxy) { GError *error; guint result; gboolean res; gboolean ret; ret = FALSE; if (bus_proxy == NULL) { goto out; } error = NULL; res = dbus_g_proxy_call (bus_proxy, "RequestName", &error, G_TYPE_STRING, BUS_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID); if (! res) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", BUS_NAME); } goto out; } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", BUS_NAME); } goto out; } ret = TRUE; out: return ret; } static DBusGConnection * get_system_bus (void) { GError *error; DBusGConnection *bus; error = NULL; bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (bus == NULL) { g_warning ("Couldn't connect to system bus: %s", error->message); g_error_free (error); } return bus; } int main (int argc, char **argv) { GMainLoop *loop; CsdDatetimeMechanism *mechanism; DBusGProxy *bus_proxy; DBusGConnection *connection; int ret; ret = 1; dbus_g_thread_init (); connection = get_system_bus (); if (connection == NULL) { goto out; } bus_proxy = get_bus_proxy (connection); if (bus_proxy == NULL) { g_warning ("Could not construct bus_proxy object; bailing out"); goto out; } if (!acquire_name_on_proxy (bus_proxy) ) { g_warning ("Could not acquire name; bailing out"); goto out; } mechanism = csd_datetime_mechanism_new (); if (mechanism == NULL) { goto out; } loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); g_object_unref (mechanism); g_main_loop_unref (loop); ret = 0; out: return ret; } cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-suse.c000066400000000000000000000157471356401377300273520ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * Copyright (C) 2011 Vincent Untz * * 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. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "csd-datetime-mechanism-suse.h" #include "csd-datetime-mechanism.h" gboolean _get_using_ntp_suse (DBusGMethodInvocation *context) { int exit_status; GError *error = NULL; gboolean can_use_ntp; gboolean is_using_ntp; if (g_file_test ("/etc/ntp.conf", G_FILE_TEST_EXISTS)) { can_use_ntp = TRUE; if (!g_spawn_command_line_sync ("/sbin/service ntp status", NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/service: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } if (exit_status == 0) is_using_ntp = TRUE; else is_using_ntp = FALSE; } else { can_use_ntp = FALSE; is_using_ntp = FALSE; } dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } gboolean _set_using_ntp_suse (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error; int exit_status; char *cmd; error = NULL; /* We omit --level 2345 so that systemd doesn't try to use the * SysV init scripts */ cmd = g_strconcat ("/sbin/chkconfig ntp ", using_ntp ? "on" : "off", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); cmd = g_strconcat ("/sbin/service ntp ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); dbus_g_method_return (context); return TRUE; } gboolean _update_etc_sysconfig_clock_suse (DBusGMethodInvocation *context, const char *key, const char *value) { char **lines; int n; gboolean replaced; char *data; gsize len; GError *error; /* On SUSE variants, the /etc/sysconfig/clock file needs to be kept in sync */ if (!g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", "No such file"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } error = NULL; if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } replaced = FALSE; lines = g_strsplit (data, "\n", 0); g_free (data); for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key)) { g_free (lines[n]); lines[n] = g_strdup_printf ("%s%s", key, value); replaced = TRUE; } } if (replaced) { GString *str; str = g_string_new (NULL); for (n = 0; lines[n] != NULL; n++) { g_string_append (str, lines[n]); if (lines[n + 1] != NULL) g_string_append_c (str, '\n'); } data = g_string_free (str, FALSE); len = strlen (data); if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error updating /etc/sysconfig/clock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (data); return FALSE; } g_free (data); } g_strfreev (lines); return TRUE; } cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism-suse.h000066400000000000000000000026471356401377300273520ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * Copyright (C) 2011 Vincent Untz * * 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 #include gboolean _get_using_ntp_suse (DBusGMethodInvocation *context); gboolean _set_using_ntp_suse (DBusGMethodInvocation *context, gboolean using_ntp); gboolean _update_etc_sysconfig_clock_suse (DBusGMethodInvocation *context, const char *key, const char *value); cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism.c000066400000000000000000000644561356401377300263760ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * 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. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "system-timezone.h" #include "csd-datetime-mechanism.h" #include "csd-datetime-mechanism-glue.h" /* NTP helper functions for various distributions */ #include "csd-datetime-mechanism-fedora.h" #include "csd-datetime-mechanism-debian.h" #include "csd-datetime-mechanism-suse.h" static gboolean do_exit (gpointer user_data) { g_debug ("Exiting due to inactivity"); exit (1); return FALSE; } static void reset_killtimer (void) { static guint timer_id = 0; if (timer_id > 0) { g_source_remove (timer_id); timer_id = 0; } g_debug ("Setting killtimer to 30 seconds..."); timer_id = g_timeout_add_seconds (30, do_exit, NULL); } struct CsdDatetimeMechanismPrivate { DBusGConnection *system_bus_connection; DBusGProxy *system_bus_proxy; PolkitAuthority *auth; }; static void csd_datetime_mechanism_finalize (GObject *object); G_DEFINE_TYPE (CsdDatetimeMechanism, csd_datetime_mechanism, G_TYPE_OBJECT) #define CSD_DATETIME_MECHANISM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismPrivate)) GQuark csd_datetime_mechanism_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csd_datetime_mechanism_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csd_datetime_mechanism_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "NotPrivileged"), ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "InvalidTimezoneFile"), { 0, 0, 0 } }; g_assert (CSD_DATETIME_MECHANISM_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsdDatetimeMechanismError", values); } return etype; } static GObject * csd_datetime_mechanism_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdDatetimeMechanism *mechanism; mechanism = CSD_DATETIME_MECHANISM (G_OBJECT_CLASS (csd_datetime_mechanism_parent_class)->constructor ( type, n_construct_properties, construct_properties)); return G_OBJECT (mechanism); } static void csd_datetime_mechanism_class_init (CsdDatetimeMechanismClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_datetime_mechanism_constructor; object_class->finalize = csd_datetime_mechanism_finalize; g_type_class_add_private (klass, sizeof (CsdDatetimeMechanismPrivate)); dbus_g_object_type_install_info (CSD_DATETIME_TYPE_MECHANISM, &dbus_glib_csd_datetime_mechanism_object_info); dbus_g_error_domain_register (CSD_DATETIME_MECHANISM_ERROR, NULL, CSD_DATETIME_MECHANISM_TYPE_ERROR); } static void csd_datetime_mechanism_init (CsdDatetimeMechanism *mechanism) { mechanism->priv = CSD_DATETIME_MECHANISM_GET_PRIVATE (mechanism); } static void csd_datetime_mechanism_finalize (GObject *object) { CsdDatetimeMechanism *mechanism; g_return_if_fail (object != NULL); g_return_if_fail (CSD_DATETIME_IS_MECHANISM (object)); mechanism = CSD_DATETIME_MECHANISM (object); g_return_if_fail (mechanism->priv != NULL); g_object_unref (mechanism->priv->system_bus_proxy); G_OBJECT_CLASS (csd_datetime_mechanism_parent_class)->finalize (object); } static gboolean register_mechanism (CsdDatetimeMechanism *mechanism) { GError *error = NULL; mechanism->priv->auth = polkit_authority_get_sync (NULL, &error); if (mechanism->priv->auth == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } goto error; } mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (mechanism->priv->system_bus_connection == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } goto error; } dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", G_OBJECT (mechanism)); mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); reset_killtimer (); return TRUE; error: return FALSE; } CsdDatetimeMechanism * csd_datetime_mechanism_new (void) { GObject *object; gboolean res; object = g_object_new (CSD_DATETIME_TYPE_MECHANISM, NULL); res = register_mechanism (CSD_DATETIME_MECHANISM (object)); if (! res) { g_object_unref (object); return NULL; } return CSD_DATETIME_MECHANISM (object); } static gboolean _check_polkit_for_action (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { const char *action = "org.cinnamon.settingsdaemon.datetimemechanism.configure"; const char *sender; GError *error; PolkitSubject *subject; PolkitAuthorizationResult *result; error = NULL; /* Check that caller is privileged */ sender = dbus_g_method_get_sender (context); subject = polkit_system_bus_name_new (sender); result = polkit_authority_check_authorization_sync (mechanism->priv->auth, subject, action, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, &error); g_object_unref (subject); if (error) { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!polkit_authorization_result_get_is_authorized (result)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "Not Authorized for action %s", action); dbus_g_method_return_error (context, error); g_error_free (error); g_object_unref (result); return FALSE; } g_object_unref (result); return TRUE; } static gboolean _sync_hwclock (DBusGMethodInvocation *context) { GError *error; error = NULL; if (g_file_test ("/sbin/hwclock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) { int exit_status; if (!g_spawn_command_line_sync ("/sbin/hwclock --systohc", NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/hwclock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/sbin/hwclock returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } return TRUE; } static gboolean _set_time (CsdDatetimeMechanism *mechanism, const struct timeval *tv, DBusGMethodInvocation *context) { GError *error; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (settimeofday (tv, NULL) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error calling settimeofday({%lld,%lld}): %s", (gint64) tv->tv_sec, (gint64) tv->tv_usec, strerror (errno)); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!_sync_hwclock (context)) return FALSE; dbus_g_method_return (context); return TRUE; } static gboolean _set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context) { GDateTime *time; char *date_str, *time_str; char *date_cmd; int exit_status; GError *error; if (!_check_polkit_for_action (mechanism, context)) return FALSE; date_str = g_strdup_printf ("%02d/%02d/%d", month, day, year); error = NULL; time = g_date_time_new_now_local (); time_str = g_date_time_format (time, "%R:%S"); g_date_time_unref (time); date_cmd = g_strdup_printf ("/bin/date -s \"%s %s\" +\"%%D %%R:%%S\"", date_str, time_str); g_free (date_str); g_free (time_str); if (!g_spawn_command_line_sync (date_cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /bin/date: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (date_cmd); return FALSE; } g_free (date_cmd); if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/bin/date returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!_sync_hwclock (context)) return FALSE; return TRUE; } /* exported methods */ gboolean csd_datetime_mechanism_set_time (CsdDatetimeMechanism *mechanism, gint64 seconds_since_epoch, DBusGMethodInvocation *context) { struct timeval tv; reset_killtimer (); g_debug ("SetTime(%" G_GINT64_FORMAT ") called", seconds_since_epoch); tv.tv_sec = (time_t) seconds_since_epoch; tv.tv_usec = 0; return _set_time (mechanism, &tv, context); } gboolean csd_datetime_mechanism_set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context) { reset_killtimer (); g_debug ("SetDate(%d, %d, %d) called", day, month, year); return _set_date (mechanism, day, month, year, context); } gboolean csd_datetime_mechanism_adjust_time (CsdDatetimeMechanism *mechanism, gint64 seconds_to_add, DBusGMethodInvocation *context) { struct timeval tv; reset_killtimer (); g_debug ("AdjustTime(%" G_GINT64_FORMAT " ) called", seconds_to_add); if (gettimeofday (&tv, NULL) != 0) { GError *error; error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error calling gettimeofday(): %s", strerror (errno)); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } tv.tv_sec += (time_t) seconds_to_add; return _set_time (mechanism, &tv, context); } static gboolean csd_datetime_check_tz_name (const char *tz, GError **error) { GFile *file; char *tz_path, *actual_path; gboolean retval; retval = TRUE; tz_path = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL); /* Get the actual resolved path */ file = g_file_new_for_path (tz_path); actual_path = g_file_get_path (file); g_object_unref (file); /* The tz name passed had relative paths in it */ if (g_strcmp0 (tz_path, actual_path) != 0) { g_set_error (error, CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "Timezone file '%s' was invalid.", tz); retval = FALSE; } g_free (tz_path); g_free (actual_path); return retval; } gboolean csd_datetime_mechanism_set_timezone (CsdDatetimeMechanism *mechanism, const char *tz, DBusGMethodInvocation *context) { GError *error; reset_killtimer (); g_debug ("SetTimezone('%s') called", tz); if (!_check_polkit_for_action (mechanism, context)) return FALSE; error = NULL; if (!csd_datetime_check_tz_name (tz, &error)) return FALSE; if (!system_timezone_set (tz, &error)) { GError *error2; int code; if (error->code == SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE) code = CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE; else code = CSD_DATETIME_MECHANISM_ERROR_GENERAL; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, code, "%s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } dbus_g_method_return (context); return TRUE; } gboolean csd_datetime_mechanism_get_timezone (CsdDatetimeMechanism *mechism, DBusGMethodInvocation *context) { gchar *timezone; reset_killtimer (); timezone = system_timezone_find (); dbus_g_method_return (context, timezone); return TRUE; } gboolean csd_datetime_mechanism_get_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { char **lines; char *data; gsize len; GError *error; gboolean is_utc; error = NULL; if (!g_file_get_contents ("/etc/adjtime", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/adjtime file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } lines = g_strsplit (data, "\n", 0); g_free (data); if (g_strv_length (lines) < 3) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Cannot parse /etc/adjtime"); dbus_g_method_return_error (context, error); g_error_free (error); g_strfreev (lines); return FALSE; } if (strcmp (lines[2], "UTC") == 0) { is_utc = TRUE; } else if (strcmp (lines[2], "LOCAL") == 0) { is_utc = FALSE; } else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Expected UTC or LOCAL at line 3 of /etc/adjtime; found '%s'", lines[2]); dbus_g_method_return_error (context, error); g_error_free (error); g_strfreev (lines); return FALSE; } g_strfreev (lines); dbus_g_method_return (context, is_utc); return TRUE; } gboolean csd_datetime_mechanism_set_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, gboolean using_utc, DBusGMethodInvocation *context) { GError *error; error = NULL; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (g_file_test ("/sbin/hwclock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) { int exit_status; char *cmd; cmd = g_strdup_printf ("/sbin/hwclock %s --systohc", using_utc ? "--utc" : "--localtime"); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/hwclock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/sbin/hwclock returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) { /* Fedora */ if (!_update_etc_sysconfig_clock_fedora (context, "UTC=", using_utc ? "true" : "false")) return FALSE; } else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) { /* SUSE variant */ if (!_update_etc_sysconfig_clock_suse (context, "HWCLOCK=", using_utc ? "-u" : "--localtime")) return FALSE; } } dbus_g_method_return (context); return TRUE; } gboolean csd_datetime_mechanism_get_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { GError *error = NULL; gboolean ret; if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) /* Fedora */ ret = _get_using_ntp_fedora (context); else if (g_file_test ("/usr/sbin/update-rc.d", G_FILE_TEST_EXISTS)) /* Debian */ ret = _get_using_ntp_debian (context); else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) /* SUSE variant */ ret = _get_using_ntp_suse (context); else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error enabling NTP: OS variant not supported"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } return ret; } gboolean csd_datetime_mechanism_set_using_ntp (CsdDatetimeMechanism *mechanism, gboolean using_ntp, DBusGMethodInvocation *context) { GError *error; gboolean ret; error = NULL; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) /* Fedora */ ret = _set_using_ntp_fedora (context, using_ntp); else if (g_file_test ("/usr/sbin/update-rc.d", G_FILE_TEST_EXISTS)) /* Debian */ ret = _set_using_ntp_debian (context, using_ntp); else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) /* SUSE variant */ ret = _set_using_ntp_suse (context, using_ntp); else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error enabling NTP: OS variant not supported"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } return ret; } static void check_can_do (CsdDatetimeMechanism *mechanism, const char *action, DBusGMethodInvocation *context) { const char *sender; PolkitSubject *subject; PolkitAuthorizationResult *result; GError *error; /* Check that caller is privileged */ sender = dbus_g_method_get_sender (context); subject = polkit_system_bus_name_new (sender); error = NULL; result = polkit_authority_check_authorization_sync (mechanism->priv->auth, subject, action, NULL, 0, NULL, &error); g_object_unref (subject); if (error) { dbus_g_method_return_error (context, error); g_error_free (error); return; } if (polkit_authorization_result_get_is_authorized (result)) { dbus_g_method_return (context, 2); } else if (polkit_authorization_result_get_is_challenge (result)) { dbus_g_method_return (context, 1); } else { dbus_g_method_return (context, 0); } g_object_unref (result); } gboolean csd_datetime_mechanism_can_set_time (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } gboolean csd_datetime_mechanism_can_set_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } gboolean csd_datetime_mechanism_can_set_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism.h000066400000000000000000000132131356401377300263640ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * 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 CSD_DATETIME_MECHANISM_H #define CSD_DATETIME_MECHANISM_H #include #include G_BEGIN_DECLS #define CSD_DATETIME_TYPE_MECHANISM (csd_datetime_mechanism_get_type ()) #define CSD_DATETIME_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanism)) #define CSD_DATETIME_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismClass)) #define CSD_DATETIME_IS_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_DATETIME_TYPE_MECHANISM)) #define CSD_DATETIME_IS_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_DATETIME_TYPE_MECHANISM)) #define CSD_DATETIME_MECHANISM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismClass)) typedef struct CsdDatetimeMechanismPrivate CsdDatetimeMechanismPrivate; typedef struct { GObject parent; CsdDatetimeMechanismPrivate *priv; } CsdDatetimeMechanism; typedef struct { GObjectClass parent_class; } CsdDatetimeMechanismClass; typedef enum { CSD_DATETIME_MECHANISM_ERROR_GENERAL, CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, CSD_DATETIME_MECHANISM_NUM_ERRORS } CsdDatetimeMechanismError; #define CSD_DATETIME_MECHANISM_ERROR csd_datetime_mechanism_error_quark () GType csd_datetime_mechanism_error_get_type (void); #define CSD_DATETIME_MECHANISM_TYPE_ERROR (csd_datetime_mechanism_error_get_type ()) GQuark csd_datetime_mechanism_error_quark (void); GType csd_datetime_mechanism_get_type (void); CsdDatetimeMechanism *csd_datetime_mechanism_new (void); /* exported methods */ gboolean csd_datetime_mechanism_get_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_timezone (CsdDatetimeMechanism *mechanism, const char *zone_file, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_time (CsdDatetimeMechanism *mechanism, gint64 seconds_since_epoch, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_time (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_adjust_time (CsdDatetimeMechanism *mechanism, gint64 seconds_to_add, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_get_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, gboolean using_utc, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_get_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_using_ntp (CsdDatetimeMechanism *mechanism, gboolean using_ntp, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); G_END_DECLS #endif /* CSD_DATETIME_MECHANISM_H */ cinnamon-settings-daemon-4.4.0/plugins/datetime/csd-datetime-mechanism.xml000066400000000000000000000123651356401377300267440ustar00rootroot00000000000000 Whether the caller can set the timezone The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot set the timezone 1 the caller will be challenged before being able to set the timezone 2 the caller is authorized to set the timezone Whether the caller can set the time The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot set the time 1 the caller will be challenged before being able to set the time 2 the caller is authorized to set the time Whether the caller can set the "use NTP" setting The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot change the "use NTP" setting 1 the caller will be challenged before being able to change "use NTP" setting 2 the caller is authorized to change the "use NTP" setting cinnamon-settings-daemon-4.4.0/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.conf000066400000000000000000000011711356401377300334100ustar00rootroot00000000000000 org.cinnamon.SettingsDaemon.DateTimeMechanism.service.in000066400000000000000000000001661356401377300344540ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/datetime[D-BUS Service] Name=org.cinnamon.SettingsDaemon.DateTimeMechanism Exec=@LIBEXECDIR@/csd-datetime-mechanism User=root org.cinnamon.settingsdaemon.datetimemechanism.policy.in000066400000000000000000000013701356401377300345510ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/datetime Cinnamon http://cinnamon.linuxmint.com/ gnome-panel-clock <_description>Change system time and date settings <_message>To change time or date settings, you need to authenticate. no no auth_admin_keep cinnamon-settings-daemon-4.4.0/plugins/datetime/system-timezone.c000066400000000000000000000714171356401377300252400ustar00rootroot00000000000000/* System timezone handling * * Copyright (C) 2008 Novell, Inc. * * Authors: Vincent Untz * * 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. * * Some code is based on previous code in clock-location.c and on code from * tz.c (shipped with version <= 2.22.0). Those files were under the same * license, with those authors and copyrights: * * clock-location.c: * ================ * No header, but most of the work was done (AFAIK) by * Federico Mena Quintero * Matthias Clasen * * tz.c: * ==== * Copyright (C) 2000-2001 Ximian, Inc. * Copyright (C) 2004 Sun Microsystems, Inc. * * Authors: Hans Petter Jansson * additional functions by Erwann Chenede * reworked by Vincent Untz * * Largely based on Michael Fulbright's work on Anaconda. */ /* FIXME: it'd be nice to filter out the timezones that we might get when * parsing config files that are not in zone.tab. Note that it's also wrong * in some cases: eg, in tzdata2008b, Asia/Calcutta got renamed to * Asia/Kolkata and the old name is not in zone.tab. */ #include #include #include #include #include #include "system-timezone.h" /* Files that we look at */ #define ETC_TIMEZONE "/etc/timezone" #define ETC_TIMEZONE_MAJ "/etc/TIMEZONE" #define ETC_RC_CONF "/etc/rc.conf" #define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock" #define ETC_CONF_D_CLOCK "/etc/conf.d/clock" #define ETC_LOCALTIME "/etc/localtime" /* The first 4 characters in a timezone file, from tzfile.h */ #define TZ_MAGIC "TZif" static GObject *systz_singleton = NULL; G_DEFINE_TYPE (SystemTimezone, system_timezone, G_TYPE_OBJECT) typedef struct { char *tz; char *env_tz; } SystemTimezonePrivate; static GObject *system_timezone_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties); static void system_timezone_finalize (GObject *obj); #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezonePrivate)) SystemTimezone * system_timezone_new (void) { return g_object_new (SYSTEM_TIMEZONE_TYPE, NULL); } const char * system_timezone_get (SystemTimezone *systz) { SystemTimezonePrivate *priv; g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); priv = PRIVATE (systz); return priv->tz; } const char * system_timezone_get_env (SystemTimezone *systz) { SystemTimezonePrivate *priv; g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); priv = PRIVATE (systz); return priv->env_tz; } static void system_timezone_class_init (SystemTimezoneClass *class) { GObjectClass *g_obj_class = G_OBJECT_CLASS (class); g_obj_class->constructor = system_timezone_constructor; g_obj_class->finalize = system_timezone_finalize; g_type_class_add_private (class, sizeof (SystemTimezonePrivate)); } static void system_timezone_init (SystemTimezone *systz) { SystemTimezonePrivate *priv = PRIVATE (systz); priv->tz = NULL; priv->env_tz = NULL; } static GObject * system_timezone_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *obj; SystemTimezonePrivate *priv; /* This is a singleton, we don't need to have it per-applet */ if (systz_singleton) return g_object_ref (systz_singleton); obj = G_OBJECT_CLASS (system_timezone_parent_class)->constructor ( type, n_construct_properties, construct_properties); priv = PRIVATE (obj); priv->tz = system_timezone_find (); priv->env_tz = g_strdup (g_getenv ("TZ")); systz_singleton = obj; return systz_singleton; } static void system_timezone_finalize (GObject *obj) { SystemTimezonePrivate *priv = PRIVATE (obj); if (priv->tz) { g_free (priv->tz); priv->tz = NULL; } if (priv->env_tz) { g_free (priv->env_tz); priv->env_tz = NULL; } G_OBJECT_CLASS (system_timezone_parent_class)->finalize (obj); g_assert (obj == systz_singleton); systz_singleton = NULL; } /* * Code to deal with the system timezone on all distros. * There's no dependency on the SystemTimezone GObject here. * * Here's what we know: * * + /etc/localtime contains the binary data of the timezone. * It can be a symlink to the actual data file, a hard link to the data * file, or just a copy. So we can determine the timezone with this * (reading the symlink, comparing inodes, or comparing content). * * + However, most distributions also have the timezone setting * configured somewhere else. This might be better to read it from there. * * Debian/Ubuntu/Gentoo (new): content of /etc/timezone * Fedora/Mandriva: the ZONE key in /etc/sysconfig/clock * openSUSE: the TIMEZONE key in /etc/sysconfig/clock * Solaris/OpenSolaris: the TZ key in /etc/TIMEZONE * Arch Linux: the TIMEZONE key in /etc/rc.conf * Gentoo (old): the ZONE key in /etc/conf.d/clock * * FIXME: reading the system-tools-backends, it seems there's this too: * Solaris: the TZ key in /etc/default/init * /etc/TIMEZONE seems to be a link to /etc/default/init * * First, some functions to handle those system config files. * */ /* This works for Debian and derivatives (including Ubuntu), and new Gentoo */ static char * system_timezone_read_etc_timezone (void) { FILE *etc_timezone; GString *reading; int c; etc_timezone = g_fopen (ETC_TIMEZONE, "r"); if (!etc_timezone) return NULL; reading = g_string_new (""); c = fgetc (etc_timezone); /* only get the first line, we'll validate the value later */ while (c != EOF && !g_ascii_isspace (c)) { reading = g_string_append_c (reading, c); c = fgetc (etc_timezone); } fclose (etc_timezone); if (reading->str && reading->str[0] != '\0') return g_string_free (reading, FALSE); else g_string_free (reading, TRUE); return NULL; } static gboolean system_timezone_write_etc_timezone (const char *tz, GError **error) { char *content; GError *our_error; gboolean retval; if (!g_file_test (ETC_TIMEZONE, G_FILE_TEST_IS_REGULAR)) return TRUE; content = g_strdup_printf ("%s\n", tz); our_error = NULL; retval = g_file_set_contents (ETC_TIMEZONE, content, -1, &our_error); g_free (content); if (!retval) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, ETC_TIMEZONE" cannot be overwritten: %s", our_error->message); g_error_free (our_error); } return retval; } /* Read a file that looks like a key-file (but there's no need for groups) * and get the last value for a specific key */ static char * system_timezone_read_key_file (const char *filename, const char *key) { GIOChannel *channel; char *key_eq; char *line; char *retval; if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return NULL; channel = g_io_channel_new_file (filename, "r", NULL); if (!channel) return NULL; key_eq = g_strdup_printf ("%s=", key); retval = NULL; while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) { if (g_str_has_prefix (line, key_eq)) { char *value; int len; value = line + strlen (key_eq); g_strstrip (value); len = strlen (value); if (value[0] == '\"') { if (value[len - 1] == '\"') { if (retval) g_free (retval); retval = g_strndup (value + 1, len - 2); } } else { if (retval) g_free (retval); retval = g_strdup (line + strlen (key_eq)); } g_strstrip (retval); } g_free (line); } g_free (key_eq); g_io_channel_unref (channel); return retval; } static gboolean system_timezone_write_key_file (const char *filename, const char *key, const char *value, GError **error) { GError *our_error; char *content; gsize len; char *key_eq; char **lines; gboolean replaced; gboolean retval; int n; if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return TRUE; our_error = NULL; if (!g_file_get_contents (filename, &content, &len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "%s cannot be read: %s", filename, our_error->message); g_error_free (our_error); return FALSE; } lines = g_strsplit (content, "\n", 0); g_free (content); key_eq = g_strdup_printf ("%s=", key); replaced = FALSE; for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key_eq)) { char *old_value; gboolean use_quotes; old_value = lines[n] + strlen (key_eq); g_strstrip (old_value); use_quotes = old_value[0] == '\"'; g_free (lines[n]); if (use_quotes) lines[n] = g_strdup_printf ("%s\"%s\"", key_eq, value); else lines[n] = g_strdup_printf ("%s%s", key_eq, value); replaced = TRUE; } } g_free (key_eq); if (!replaced) { g_strfreev (lines); return TRUE; } content = g_strjoinv ("\n", lines); g_strfreev (lines); retval = g_file_set_contents (filename, content, -1, &our_error); g_free (content); if (!retval) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "%s cannot be overwritten: %s", filename, our_error->message); g_error_free (our_error); } return retval; } /* This works for Solaris/OpenSolaris */ static char * system_timezone_read_etc_TIMEZONE (void) { return system_timezone_read_key_file (ETC_TIMEZONE_MAJ, "TZ"); } static gboolean system_timezone_write_etc_TIMEZONE (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_TIMEZONE_MAJ, "TZ", tz, error); } /* This works for Fedora and Mandriva */ static char * system_timezone_read_etc_sysconfig_clock (void) { return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, "ZONE"); } static gboolean system_timezone_write_etc_sysconfig_clock (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, "ZONE", tz, error); } /* This works for openSUSE */ static char * system_timezone_read_etc_sysconfig_clock_alt (void) { return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, "TIMEZONE"); } static gboolean system_timezone_write_etc_sysconfig_clock_alt (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, "TIMEZONE", tz, error); } /* This works for old Gentoo */ static char * system_timezone_read_etc_conf_d_clock (void) { return system_timezone_read_key_file (ETC_CONF_D_CLOCK, "TIMEZONE"); } static gboolean system_timezone_write_etc_conf_d_clock (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_CONF_D_CLOCK, "TIMEZONE", tz, error); } /* This works for Arch Linux */ static char * system_timezone_read_etc_rc_conf (void) { return system_timezone_read_key_file (ETC_RC_CONF, "TIMEZONE"); } static gboolean system_timezone_write_etc_rc_conf (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_RC_CONF, "TIMEZONE", tz, error); } /* * * First, getting the timezone. * */ static char * system_timezone_strip_path_if_valid (const char *filename) { int skip; if (!filename || !g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/")) return NULL; /* Timezone data files also live under posix/ and right/ for some * reason. * FIXME: make sure accepting those files is valid. I think "posix" is * okay, not sure about "right" */ if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/posix/")) skip = strlen (SYSTEM_ZONEINFODIR"/posix/"); else if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/right/")) skip = strlen (SYSTEM_ZONEINFODIR"/right/"); else skip = strlen (SYSTEM_ZONEINFODIR"/"); return g_strdup (filename + skip); } /* Read the soft symlink from /etc/localtime */ static char * system_timezone_read_etc_localtime_softlink (void) { char *file; char *tz; if (!g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) return NULL; file = g_file_read_link (ETC_LOCALTIME, NULL); tz = system_timezone_strip_path_if_valid (file); g_free (file); return tz; } typedef gboolean (*CompareFiles) (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename); static char * recursive_compare (struct stat *localtime_stat, const char *localtime_content, gsize localtime_content_len, char *file, CompareFiles compare_func) { struct stat file_stat; if (g_stat (file, &file_stat) != 0) return NULL; if (S_ISREG (file_stat.st_mode)) { if (compare_func (localtime_stat, &file_stat, localtime_content, localtime_content_len, file)) return system_timezone_strip_path_if_valid (file); else return NULL; } else if (S_ISDIR (file_stat.st_mode)) { GDir *dir = NULL; char *ret = NULL; const char *subfile = NULL; char *subpath = NULL; dir = g_dir_open (file, 0, NULL); if (dir == NULL) return NULL; while ((subfile = g_dir_read_name (dir)) != NULL) { subpath = g_build_filename (file, subfile, NULL); ret = recursive_compare (localtime_stat, localtime_content, localtime_content_len, subpath, compare_func); g_free (subpath); if (ret != NULL) break; } g_dir_close (dir); return ret; } return NULL; } static gboolean files_are_identical_inode (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename) { return (a_stat->st_ino == b_stat->st_ino); } /* Determine if /etc/localtime is a hard link to some file, by looking at * the inodes */ static char * system_timezone_read_etc_localtime_hardlink (void) { struct stat stat_localtime; if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) return NULL; if (!S_ISREG (stat_localtime.st_mode)) return NULL; return recursive_compare (&stat_localtime, NULL, 0, SYSTEM_ZONEINFODIR, files_are_identical_inode); } static gboolean files_are_identical_content (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename) { char *b_content = NULL; gsize b_content_len = -1; int cmp; if (a_stat->st_size != b_stat->st_size) return FALSE; if (!g_file_get_contents (b_filename, &b_content, &b_content_len, NULL)) return FALSE; if (a_content_len != b_content_len) { g_free (b_content); return FALSE; } cmp = memcmp (a_content, b_content, a_content_len); g_free (b_content); return (cmp == 0); } /* Determine if /etc/localtime is a copy of a timezone file */ static char * system_timezone_read_etc_localtime_content (void) { struct stat stat_localtime; char *localtime_content = NULL; gsize localtime_content_len = -1; char *retval; if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) return NULL; if (!S_ISREG (stat_localtime.st_mode)) return NULL; if (!g_file_get_contents (ETC_LOCALTIME, &localtime_content, &localtime_content_len, NULL)) return NULL; retval = recursive_compare (&stat_localtime, localtime_content, localtime_content_len, SYSTEM_ZONEINFODIR, files_are_identical_content); g_free (localtime_content); return retval; } typedef char * (*GetSystemTimezone) (void); /* The order of the functions here define the priority of the methods used * to find the timezone. First method has higher priority. */ static GetSystemTimezone get_system_timezone_methods[] = { /* cheap and "more correct" than data from a config file */ system_timezone_read_etc_localtime_softlink, /* reading various config files */ system_timezone_read_etc_timezone, system_timezone_read_etc_sysconfig_clock, system_timezone_read_etc_sysconfig_clock_alt, system_timezone_read_etc_TIMEZONE, system_timezone_read_etc_rc_conf, /* reading deprecated config files */ system_timezone_read_etc_conf_d_clock, /* reading /etc/timezone directly. Expensive since we have to stat * many files */ system_timezone_read_etc_localtime_hardlink, system_timezone_read_etc_localtime_content, NULL }; static gboolean system_timezone_is_valid (const char *tz) { const char *c; if (!tz) return FALSE; for (c = tz; *c != '\0'; c++) { if (!(g_ascii_isalnum (*c) || *c == '/' || *c == '-' || *c == '_')) return FALSE; } return TRUE; } char * system_timezone_find (void) { char *tz; int i; for (i = 0; get_system_timezone_methods[i] != NULL; i++) { tz = get_system_timezone_methods[i] (); if (system_timezone_is_valid (tz)) return tz; g_free (tz); } return g_strdup ("UTC"); } /* * * Now, setting the timezone. * */ static gboolean system_timezone_is_zone_file_valid (const char *zone_file, GError **error) { GError *our_error; GIOChannel *channel; char buffer[strlen (TZ_MAGIC)]; gsize read; /* First, check the zone_file is properly rooted */ if (!g_str_has_prefix (zone_file, SYSTEM_ZONEINFODIR"/")) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "Timezone file needs to be under "SYSTEM_ZONEINFODIR); return FALSE; } /* Second, check it's a regular file that exists */ if (!g_file_test (zone_file, G_FILE_TEST_IS_REGULAR)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "No such timezone file %s", zone_file); return FALSE; } /* Third, check that it's a tzfile (see tzfile(5)). The file has a 4 * bytes header which is TZ_MAGIC. * * TODO: is there glibc API for this? */ our_error = NULL; channel = g_io_channel_new_file (zone_file, "r", &our_error); if (!our_error) g_io_channel_read_chars (channel, buffer, strlen (TZ_MAGIC), &read, &our_error); if (channel) g_io_channel_unref (channel); if (our_error) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "Timezone file %s cannot be read: %s", zone_file, our_error->message); g_error_free (our_error); return FALSE; } if (read != strlen (TZ_MAGIC) || strncmp (buffer, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "%s is not a timezone file", zone_file); return FALSE; } return TRUE; } static gboolean system_timezone_set_etc_timezone (const char *zone_file, GError **error) { GError *our_error; char *content; gsize len; if (!system_timezone_is_zone_file_valid (zone_file, error)) return FALSE; /* If /etc/localtime is a symlink, write a symlink */ if (g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) { if (g_unlink (ETC_LOCALTIME) == 0 && symlink (zone_file, ETC_LOCALTIME) == 0) return TRUE; /* If we couldn't symlink the file, we'll just fallback on * copying it */ } /* Else copy the file to /etc/localtime. We explicitly avoid doing * hard links since they break with different partitions */ our_error = NULL; if (!g_file_get_contents (zone_file, &content, &len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "Timezone file %s cannot be read: %s", zone_file, our_error->message); g_error_free (our_error); return FALSE; } if (!g_file_set_contents (ETC_LOCALTIME, content, len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, ETC_LOCALTIME" cannot be overwritten: %s", our_error->message); g_error_free (our_error); g_free (content); return FALSE; } g_free (content); return TRUE; } typedef gboolean (*SetSystemTimezone) (const char *tz, GError **error); /* The order here does not matter too much: we'll try to change all files * that already have a timezone configured. It matters in case of error, * since the process will be stopped and the last methods won't be called. * So we use the same order as in get_system_timezone_methods */ static SetSystemTimezone set_system_timezone_methods[] = { /* writing various config files if they exist and have the * setting already present */ system_timezone_write_etc_timezone, system_timezone_write_etc_sysconfig_clock, system_timezone_write_etc_sysconfig_clock_alt, system_timezone_write_etc_TIMEZONE, system_timezone_write_etc_rc_conf, /* writing deprecated config files if they exist and have the * setting already present */ system_timezone_write_etc_conf_d_clock, NULL }; static gboolean system_timezone_update_config (const char *tz, GError **error) { int i; for (i = 0; set_system_timezone_methods[i] != NULL; i++) { if (!set_system_timezone_methods[i] (tz, error)) return FALSE; /* FIXME: maybe continue to change all config files if * possible? */ } return TRUE; } gboolean system_timezone_set (const char *tz, GError **error) { char *zone_file; gboolean retval; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); zone_file = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL); /* FIXME: is it right to return FALSE even when /etc/localtime was * changed but not the config files? */ retval = system_timezone_set_etc_timezone (zone_file, error) && system_timezone_update_config (tz, error); g_free (zone_file); return retval; } GQuark system_timezone_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("system-timezone-error"); } return ret; } cinnamon-settings-daemon-4.4.0/plugins/datetime/system-timezone.h000066400000000000000000000050451356401377300252370ustar00rootroot00000000000000/* System timezone handling * * Copyright (C) 2008 Novell, Inc. * * Authors: Vincent Untz * * 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 __SYSTEM_TIMEZONE_H__ #define __SYSTEM_TIMEZONE_H__ #include #include G_BEGIN_DECLS #ifdef HAVE_SOLARIS #define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab" #else #define SYSTEM_ZONEINFODIR "/usr/share/zoneinfo" #endif #define SYSTEM_TIMEZONE_TYPE (system_timezone_get_type ()) #define SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezone)) #define SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) #define IS_SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SYSTEM_TIMEZONE_TYPE)) #define IS_SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), SYSTEM_TIMEZONE_TYPE)) #define SYSTEM_TIMEZONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) typedef struct { GObject g_object; } SystemTimezone; typedef struct { GObjectClass g_object_class; } SystemTimezoneClass; GType system_timezone_get_type (void); SystemTimezone *system_timezone_new (void); const char *system_timezone_get (SystemTimezone *systz); const char *system_timezone_get_env (SystemTimezone *systz); /* Functions to set the timezone. They won't be used by the applet, but * by a program with more privileges */ #define SYSTEM_TIMEZONE_ERROR system_timezone_error_quark () GQuark system_timezone_error_quark (void); typedef enum { SYSTEM_TIMEZONE_ERROR_GENERAL, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, SYSTEM_TIMEZONE_NUM_ERRORS } SystemTimezoneError; char *system_timezone_find (void); gboolean system_timezone_set (const char *tz, GError **error); G_END_DECLS #endif /* __SYSTEM_TIMEZONE_H__ */ cinnamon-settings-daemon-4.4.0/plugins/datetime/test-system-timezone.c000066400000000000000000000044531356401377300262110ustar00rootroot00000000000000/* Test for system timezone handling * * Copyright (C) 2008-2010 Novell, Inc. * * Authors: Vincent Untz * * 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 #include "system-timezone.h" static void timezone_print (void) { SystemTimezone *systz; systz = system_timezone_new (); g_print ("Current timezone: %s\n", system_timezone_get (systz)); g_object_unref (systz); } static int timezone_set (const char *new_tz) { GError *error; error = NULL; if (!system_timezone_set (new_tz, &error)) { g_printerr ("%s\n", error->message); g_error_free (error); return 1; } return 0; } int main (int argc, char **argv) { int retval; gboolean get = FALSE; char *tz_set = NULL; GError *error; GOptionContext *context; GOptionEntry options[] = { { "get", 'g', 0, G_OPTION_ARG_NONE, &get, "Get the current timezone", NULL }, { "set", 's', 0, G_OPTION_ARG_STRING, &tz_set, "Set the timezone to TIMEZONE", "TIMEZONE" }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; retval = 0; context = g_option_context_new (""); g_option_context_add_main_entries (context, options, NULL); error = NULL; if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); g_error_free (error); g_option_context_free (context); return 1; } g_option_context_free (context); if (get || (!tz_set)) timezone_print (); else if (tz_set) retval = timezone_set (tz_set); else g_assert_not_reached (); return retval; } cinnamon-settings-daemon-4.4.0/plugins/dummy/000077500000000000000000000000001356401377300212455ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/dummy/Makefile.am000066400000000000000000000010031356401377300232730ustar00rootroot00000000000000plugin_name = dummy AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-dummy csd_dummy_SOURCES = \ main.c \ csd-dummy-manager.c \ csd-dummy-manager.h csd_dummy_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_dummy_CPPFLAGS = \ -I$(top_srcdir)/plugins/common \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_dummy_LDADD = $(SETTINGS_PLUGIN_LIBS) $(top_builddir)/cinnamon-settings-daemon/libcsd.la cinnamon-settings-daemon-4.4.0/plugins/dummy/csd-dummy-manager.c000066400000000000000000000117651356401377300247350ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-dummy-manager.h" #define CSD_DUMMY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerPrivate)) struct CsdDummyManagerPrivate { gboolean padding; }; enum { PROP_0, }; static void csd_dummy_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdDummyManager, csd_dummy_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; gboolean csd_dummy_manager_start (CsdDummyManager *manager, GError **error) { g_debug ("Starting dummy manager"); cinnamon_settings_profile_start (NULL); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_dummy_manager_stop (CsdDummyManager *manager) { g_debug ("Stopping dummy manager"); } static void csd_dummy_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_dummy_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * csd_dummy_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdDummyManager *dummy_manager; dummy_manager = CSD_DUMMY_MANAGER (G_OBJECT_CLASS (csd_dummy_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (dummy_manager); } static void csd_dummy_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_dummy_manager_parent_class)->dispose (object); } static void csd_dummy_manager_class_init (CsdDummyManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csd_dummy_manager_get_property; object_class->set_property = csd_dummy_manager_set_property; object_class->constructor = csd_dummy_manager_constructor; object_class->dispose = csd_dummy_manager_dispose; object_class->finalize = csd_dummy_manager_finalize; g_type_class_add_private (klass, sizeof (CsdDummyManagerPrivate)); } static void csd_dummy_manager_init (CsdDummyManager *manager) { manager->priv = CSD_DUMMY_MANAGER_GET_PRIVATE (manager); } static void csd_dummy_manager_finalize (GObject *object) { CsdDummyManager *dummy_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_DUMMY_MANAGER (object)); dummy_manager = CSD_DUMMY_MANAGER (object); g_return_if_fail (dummy_manager->priv != NULL); G_OBJECT_CLASS (csd_dummy_manager_parent_class)->finalize (object); } CsdDummyManager * csd_dummy_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_DUMMY_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_DUMMY_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/dummy/csd-dummy-manager.h000066400000000000000000000043731356401377300247370ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_DUMMY_MANAGER_H #define __CSD_DUMMY_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_DUMMY_MANAGER (csd_dummy_manager_get_type ()) #define CSD_DUMMY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManager)) #define CSD_DUMMY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerClass)) #define CSD_IS_DUMMY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_DUMMY_MANAGER)) #define CSD_IS_DUMMY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_DUMMY_MANAGER)) #define CSD_DUMMY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerClass)) typedef struct CsdDummyManagerPrivate CsdDummyManagerPrivate; typedef struct { GObject parent; CsdDummyManagerPrivate *priv; } CsdDummyManager; typedef struct { GObjectClass parent_class; } CsdDummyManagerClass; GType csd_dummy_manager_get_type (void); CsdDummyManager * csd_dummy_manager_new (void); gboolean csd_dummy_manager_start (CsdDummyManager *manager, GError **error); void csd_dummy_manager_stop (CsdDummyManager *manager); G_END_DECLS #endif /* __CSD_DUMMY_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/dummy/main.c000066400000000000000000000010051356401377300223310ustar00rootroot00000000000000#define NEW csd_dummy_manager_new #define START csd_dummy_manager_start #define STOP csd_dummy_manager_stop #define MANAGER CsdDummyManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-dummy-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/housekeeping/000077500000000000000000000000001356401377300226005ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/housekeeping/Makefile.am000066400000000000000000000035461356401377300246440ustar00rootroot00000000000000plugin_name = housekeeping COMMON_FILES = \ csd-disk-space.c \ csd-disk-space.h \ csd-ldsm-dialog.c \ csd-ldsm-dialog.h \ csd-disk-space-helper.h \ csd-disk-space-helper.c noinst_PROGRAMS = csd-disk-space-test csd-empty-trash-test AM_CFLAGS = $(WARN_CFLAGS) csd_disk_space_test_SOURCES = \ csd-disk-space-test.c \ $(COMMON_FILES) csd_disk_space_test_LDADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS) csd_disk_space_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) csd_empty_trash_test_SOURCES = \ csd-empty-trash-test.c \ $(COMMON_FILES) csd_empty_trash_test_LDADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS) csd_empty_trash_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) libexec_PROGRAMS = csd-housekeeping csd_housekeeping_SOURCES = \ main.c \ $(COMMON_FILES) \ csd-housekeeping-manager.c \ csd-housekeeping-manager.h csd_housekeeping_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) csd_housekeeping_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_housekeeping_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(GIOUNIX_LIBS) \ $(LIBNOTIFY_LIBS) \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-housekeeping.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-housekeeping.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/housekeeping/cinnamon-settings-daemon-housekeeping.desktop.in000066400000000000000000000003651356401377300341710ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - housekeeping Exec=@libexecdir@/csd-housekeeping OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-disk-space-helper.c000066400000000000000000000066751356401377300270310ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * Copyright (c) 2012, Red Hat, Inc. * * Authors: Vincent Untz * Bastien Nocera * * 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 #include #include "csd-disk-space-helper.h" gboolean csd_should_ignore_unix_mount (GUnixMountEntry *mount) { const char *fs, *device; guint i; /* This is borrowed from GLib and used as a way to determine * which mounts we should ignore by default. GLib doesn't * expose this in a way that allows it to be used for this * purpose */ /* We also ignore network filesystems */ const gchar *ignore_fs[] = { "adfs", "afs", "auto", "autofs", "autofs4", "cifs", "cxfs", "devfs", "devpts", "ecryptfs", "fdescfs", "gfs", "gfs2", "kernfs", "linprocfs", "linsysfs", "lustre", "lustre_lite", "ncpfs", "nfs", "nfs4", "nfsd", "ocfs2", "proc", "procfs", "ptyfs", "rpc_pipefs", "selinuxfs", "smbfs", "sysfs", "tmpfs", "usbfs", "zfs", NULL }; const gchar *ignore_devices[] = { "none", "sunrpc", "devpts", "nfsd", "/dev/loop", "/dev/vn", NULL }; fs = g_unix_mount_get_fs_type (mount); device = g_unix_mount_get_device_path (mount); for (i = 0; ignore_fs[i] != NULL; i++) if (g_str_equal (ignore_fs[i], fs)) return TRUE; for (i = 0; ignore_devices[i] != NULL; i++) if (g_str_equal (ignore_devices[i], device)) return TRUE; return FALSE; } gboolean csd_is_removable_mount (GUnixMountEntry *mount) { const char *mount_path; char *path; mount_path = g_unix_mount_get_mount_path (mount); if (mount_path == NULL) return FALSE; path = g_strdup_printf ("/run/media/%s", g_get_user_name ()); if (g_str_has_prefix (mount_path, path)) { g_free (path); return TRUE; } g_free (path); return FALSE; } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-disk-space-helper.h000066400000000000000000000024261356401377300270240ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * Copyright (c) 2012, Red Hat, Inc. * * Authors: Vincent Untz * Bastien Nocera * * 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 __CSD_DISK_SPACE_HELPER_H #define __CSD_DISK_SPACE_HELPER_H #include #include G_BEGIN_DECLS gboolean csd_should_ignore_unix_mount (GUnixMountEntry *mount); gboolean csd_is_removable_mount (GUnixMountEntry *mount); G_END_DECLS #endif /* __CSD_DISK_SPACE_HELPER_H */ cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-disk-space-test.c000066400000000000000000000025161356401377300265170ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * * Authors: Vincent Untz * * 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 #include #include "csd-disk-space.h" int main (int argc, char **argv) { GMainLoop *loop; gtk_init (&argc, &argv); notify_init ("csd-disk-space-test"); loop = g_main_loop_new (NULL, FALSE); csd_ldsm_setup (TRUE); g_main_loop_run (loop); csd_ldsm_clean (); g_main_loop_unref (loop); return 0; } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-disk-space.c000066400000000000000000000704141356401377300255440ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * * Authors: Vincent Untz * * 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 #include #include #include #include #include #include #include #include #include #include "csd-disk-space.h" #include "csd-ldsm-dialog.h" #include "csd-disk-space-helper.h" #define GIGABYTE 1024 * 1024 * 1024 #define CHECK_EVERY_X_SECONDS 60 #define DISK_SPACE_ANALYZER "baobab" #define SETTINGS_HOUSEKEEPING_DIR "org.cinnamon.settings-daemon.plugins.housekeeping" #define SETTINGS_FREE_PC_NOTIFY_KEY "free-percent-notify" #define SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY "free-percent-notify-again" #define SETTINGS_FREE_SIZE_NO_NOTIFY "free-size-gb-no-notify" #define SETTINGS_MIN_NOTIFY_PERIOD "min-notify-period" #define SETTINGS_IGNORE_PATHS "ignore-paths" typedef struct { GUnixMountEntry *mount; struct statvfs buf; time_t notify_time; } LdsmMountInfo; static GHashTable *ldsm_notified_hash = NULL; static unsigned int ldsm_timeout_id = 0; static GUnixMountMonitor *ldsm_monitor = NULL; static double free_percent_notify = 0.05; static double free_percent_notify_again = 0.01; static unsigned int free_size_gb_no_notify = 2; static unsigned int min_notify_period = 10; static GSList *ignore_paths = NULL; static GSettings *settings = NULL; static CsdLdsmDialog *dialog = NULL; static NotifyNotification *notification = NULL; static guint64 *time_read; static gchar* ldsm_get_fs_id_for_path (const gchar *path) { GFile *file; GFileInfo *fileinfo; gchar *attr_id_fs; file = g_file_new_for_path (path); fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (fileinfo) { attr_id_fs = g_strdup (g_file_info_get_attribute_string (fileinfo, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); g_object_unref (fileinfo); } else { attr_id_fs = NULL; } g_object_unref (file); return attr_id_fs; } static gboolean ldsm_mount_has_trash (LdsmMountInfo *mount) { const gchar *user_data_dir; gchar *user_data_attr_id_fs; gchar *path_attr_id_fs; gboolean mount_uses_user_trash = FALSE; gchar *trash_files_dir; gboolean has_trash = FALSE; GDir *dir; const gchar *path; user_data_dir = g_get_user_data_dir (); user_data_attr_id_fs = ldsm_get_fs_id_for_path (user_data_dir); path = g_unix_mount_get_mount_path (mount->mount); path_attr_id_fs = ldsm_get_fs_id_for_path (path); if (g_strcmp0 (user_data_attr_id_fs, path_attr_id_fs) == 0) { /* The volume that is low on space is on the same volume as our home * directory. This means the trash is at $XDG_DATA_HOME/Trash, * not at the root of the volume which is full. */ mount_uses_user_trash = TRUE; } g_free (user_data_attr_id_fs); g_free (path_attr_id_fs); /* I can't think of a better way to find out if a volume has any trash. Any suggestions? */ if (mount_uses_user_trash) { trash_files_dir = g_build_filename (g_get_user_data_dir (), "Trash", "files", NULL); } else { gchar *uid; uid = g_strdup_printf ("%d", getuid ()); trash_files_dir = g_build_filename (path, ".Trash", uid, "files", NULL); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { gchar *trash_dir; g_free (trash_files_dir); trash_dir = g_strdup_printf (".Trash-%s", uid); trash_files_dir = g_build_filename (path, trash_dir, "files", NULL); g_free (trash_dir); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { g_free (trash_files_dir); g_free (uid); return has_trash; } } g_free (uid); } dir = g_dir_open (trash_files_dir, 0, NULL); if (dir) { if (g_dir_read_name (dir)) has_trash = TRUE; g_dir_close (dir); } g_free (trash_files_dir); return has_trash; } static void ldsm_analyze_path (const gchar *path) { const gchar *argv[] = { DISK_SPACE_ANALYZER, path, NULL }; g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); } static gboolean server_has_actions (void) { gboolean has; GList *caps; GList *l; caps = notify_get_server_caps (); if (caps == NULL) { fprintf (stderr, "Failed to receive server caps.\n"); return FALSE; } l = g_list_find_custom (caps, "actions", (GCompareFunc)strcmp); has = l != NULL; g_list_foreach (caps, (GFunc) g_free, NULL); g_list_free (caps); return has; } static void ignore_callback (NotifyNotification *n, const char *action) { g_assert (action != NULL); g_assert (strcmp (action, "ignore") == 0); /* Do nothing */ notify_notification_close (n, NULL); } static void examine_callback (NotifyNotification *n, const char *action, const char *path) { g_assert (action != NULL); g_assert (strcmp (action, "examine") == 0); ldsm_analyze_path (path); notify_notification_close (n, NULL); } static void nemo_empty_trash_cb (GObject *object, GAsyncResult *res, gpointer _unused) { GDBusProxy *proxy = G_DBUS_PROXY (object); GError *error = NULL; g_dbus_proxy_call_finish (proxy, res, &error); if (error != NULL) { g_warning ("Unable to call EmptyTrash() on the Nemo DBus interface: %s", error->message); g_error_free (error); } /* clean up the proxy object */ g_object_unref (proxy); } static void nemo_proxy_ready_cb (GObject *object, GAsyncResult *res, gpointer _unused) { GDBusProxy *proxy = NULL; GError *error = NULL; proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (proxy == NULL) { g_warning ("Unable to create a proxy object for the Nemo DBus interface: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "EmptyTrash", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, nemo_empty_trash_cb, NULL); } void csd_ldsm_show_empty_trash (void) { /* prepare the Nemo proxy object */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.Nemo", "/org/Nemo", "org.Nemo.FileOperations", NULL, nemo_proxy_ready_cb, NULL); } static void empty_trash_callback (NotifyNotification *n, const char *action) { g_assert (action != NULL); g_assert (strcmp (action, "empty-trash") == 0); csd_ldsm_show_empty_trash (); notify_notification_close (n, NULL); } static void on_notification_closed (NotifyNotification *n) { g_object_unref (notification); notification = NULL; } static gboolean ldsm_notify_for_mount (LdsmMountInfo *mount, gboolean multiple_volumes, gboolean other_usable_volumes) { gchar *name, *program; gint64 free_space; gint response; gboolean has_trash; gboolean has_disk_analyzer; gboolean retval = TRUE; gchar *path; /* Don't show a notice if one is already displayed */ if (dialog != NULL || notification != NULL) return retval; name = g_unix_mount_guess_name (mount->mount); free_space = (gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail; has_trash = ldsm_mount_has_trash (mount); path = g_strdup (g_unix_mount_get_mount_path (mount->mount)); program = g_find_program_in_path (DISK_SPACE_ANALYZER); has_disk_analyzer = (program != NULL); g_free (program); if (server_has_actions ()) { char *free_space_str; char *summary; char *body; free_space_str = g_format_size (free_space); if (multiple_volumes) { summary = g_strdup_printf (_("Low Disk Space on \"%s\""), name); if (has_trash) { body = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining. You may free up some space by emptying the trash."), name, free_space_str); } else { body = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining."), name, free_space_str); } } else { summary = g_strdup (_("Low Disk Space")); if (has_trash) { body = g_strdup_printf (_("This computer has only %s disk space remaining. You may free up some space by emptying the trash."), free_space_str); } else { body = g_strdup_printf (_("This computer has only %s disk space remaining."), free_space_str); } } g_free (free_space_str); notification = notify_notification_new (summary, body, "drive-harddisk-symbolic"); g_free (summary); g_free (body); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); notify_notification_set_app_name (notification, _("Disk space")); notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_DEFAULT); if (has_disk_analyzer) { notify_notification_add_action (notification, "examine", _("Examine"), (NotifyActionCallback) examine_callback, g_strdup (path), g_free); } if (has_trash) { notify_notification_add_action (notification, "empty-trash", _("Empty Trash"), (NotifyActionCallback) empty_trash_callback, NULL, NULL); } notify_notification_add_action (notification, "ignore", _("Ignore"), (NotifyActionCallback) ignore_callback, NULL, NULL); notify_notification_set_category (notification, "device"); if (!notify_notification_show (notification, NULL)) { g_warning ("failed to send disk space notification\n"); } } else { dialog = csd_ldsm_dialog_new (other_usable_volumes, multiple_volumes, has_disk_analyzer, has_trash, free_space, name, path); g_object_ref (G_OBJECT (dialog)); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); dialog = NULL; switch (response) { case GTK_RESPONSE_CANCEL: retval = FALSE; break; case CSD_LDSM_DIALOG_RESPONSE_ANALYZE: retval = FALSE; ldsm_analyze_path (path); break; case CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH: retval = TRUE; csd_ldsm_show_empty_trash (); break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: retval = TRUE; break; default: g_assert_not_reached (); } } g_free (name); g_free (path); return retval; } static gboolean ldsm_mount_has_space (LdsmMountInfo *mount) { gdouble free_space; free_space = (double) mount->buf.f_bavail / (double) mount->buf.f_blocks; /* enough free space, nothing to do */ if (free_space > free_percent_notify) return TRUE; if (((gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail) > ((gint64) free_size_gb_no_notify * GIGABYTE)) return TRUE; /* If we got here, then this volume is low on space */ return FALSE; } static gboolean ldsm_mount_is_virtual (LdsmMountInfo *mount) { if (mount->buf.f_blocks == 0) { /* Filesystems with zero blocks are virtual */ return TRUE; } return FALSE; } static gint ldsm_ignore_path_compare (gconstpointer a, gconstpointer b) { return g_strcmp0 ((const gchar *)a, (const gchar *)b); } static gboolean ldsm_mount_is_user_ignore (const gchar *path) { if (g_slist_find_custom (ignore_paths, path, (GCompareFunc) ldsm_ignore_path_compare) != NULL) return TRUE; else return FALSE; } static void ldsm_free_mount_info (gpointer data) { LdsmMountInfo *mount = data; g_return_if_fail (mount != NULL); g_unix_mount_free (mount->mount); g_free (mount); } static void ldsm_maybe_warn_mounts (GList *mounts, gboolean multiple_volumes, gboolean other_usable_volumes) { GList *l; gboolean done = FALSE; for (l = mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = l->data; LdsmMountInfo *previous_mount_info; gdouble free_space; gdouble previous_free_space; time_t curr_time; const gchar *path; gboolean show_notify; if (done) { /* Don't show any more dialogs if the user took action with the last one. The user action * might free up space on multiple volumes, making the next dialog redundant. */ ldsm_free_mount_info (mount_info); continue; } path = g_unix_mount_get_mount_path (mount_info->mount); previous_mount_info = g_hash_table_lookup (ldsm_notified_hash, path); if (previous_mount_info != NULL) previous_free_space = (gdouble) previous_mount_info->buf.f_bavail / (gdouble) previous_mount_info->buf.f_blocks; free_space = (gdouble) mount_info->buf.f_bavail / (gdouble) mount_info->buf.f_blocks; if (previous_mount_info == NULL) { /* We haven't notified for this mount yet */ show_notify = TRUE; mount_info->notify_time = time (NULL); g_hash_table_replace (ldsm_notified_hash, g_strdup (path), mount_info); } else if ((previous_free_space - free_space) > free_percent_notify_again) { /* We've notified for this mount before and free space has decreased sufficiently since last time to notify again */ curr_time = time (NULL); if (difftime (curr_time, previous_mount_info->notify_time) > (gdouble)(min_notify_period * 60)) { show_notify = TRUE; mount_info->notify_time = curr_time; } else { /* It's too soon to show the dialog again. However, we still replace the LdsmMountInfo * struct in the hash table, but give it the notfiy time from the previous dialog. * This will stop the notification from reappearing unnecessarily as soon as the timeout expires. */ show_notify = FALSE; mount_info->notify_time = previous_mount_info->notify_time; } g_hash_table_replace (ldsm_notified_hash, g_strdup (path), mount_info); } else { /* We've notified for this mount before, but the free space hasn't decreased sufficiently to notify again */ ldsm_free_mount_info (mount_info); show_notify = FALSE; } if (show_notify) { if (ldsm_notify_for_mount (mount_info, multiple_volumes, other_usable_volumes)) done = TRUE; } } } static gboolean ldsm_check_all_mounts (gpointer data) { GList *mounts; GList *l; GList *check_mounts = NULL; GList *full_mounts = NULL; guint number_of_mounts; guint number_of_full_mounts; gboolean multiple_volumes = FALSE; gboolean other_usable_volumes = FALSE; /* We iterate through the static mounts in /etc/fstab first, seeing if * they're mounted by checking if the GUnixMountPoint has a corresponding GUnixMountEntry. * Iterating through the static mounts means we automatically ignore dynamically mounted media. */ mounts = g_unix_mount_points_get (time_read); for (l = mounts; l != NULL; l = l->next) { GUnixMountPoint *mount_point = l->data; GUnixMountEntry *mount; LdsmMountInfo *mount_info; const gchar *path; path = g_unix_mount_point_get_mount_path (mount_point); mount = g_unix_mount_at (path, time_read); g_unix_mount_point_free (mount_point); if (mount == NULL) { /* The GUnixMountPoint is not mounted */ continue; } mount_info = g_new0 (LdsmMountInfo, 1); mount_info->mount = mount; path = g_unix_mount_get_mount_path (mount); if (g_unix_mount_is_readonly (mount)) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_is_user_ignore (path)) { ldsm_free_mount_info (mount_info); continue; } if (csd_should_ignore_unix_mount (mount)) { ldsm_free_mount_info (mount_info); continue; } if (statvfs (path, &mount_info->buf) != 0) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_is_virtual (mount_info)) { ldsm_free_mount_info (mount_info); continue; } check_mounts = g_list_prepend (check_mounts, mount_info); } g_list_free (mounts); number_of_mounts = g_list_length (check_mounts); if (number_of_mounts > 1) multiple_volumes = TRUE; for (l = check_mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = l->data; if (!ldsm_mount_has_space (mount_info)) { full_mounts = g_list_prepend (full_mounts, mount_info); } else { g_hash_table_remove (ldsm_notified_hash, g_unix_mount_get_mount_path (mount_info->mount)); ldsm_free_mount_info (mount_info); } } number_of_full_mounts = g_list_length (full_mounts); if (number_of_mounts > number_of_full_mounts) other_usable_volumes = TRUE; ldsm_maybe_warn_mounts (full_mounts, multiple_volumes, other_usable_volumes); g_list_free (check_mounts); g_list_free (full_mounts); return TRUE; } static gboolean ldsm_is_hash_item_not_in_mounts (gpointer key, gpointer value, gpointer user_data) { GList *l; for (l = (GList *) user_data; l != NULL; l = l->next) { GUnixMountEntry *mount = l->data; const char *path; path = g_unix_mount_get_mount_path (mount); if (strcmp (path, key) == 0) return FALSE; } return TRUE; } static void ldsm_mounts_changed (GObject *monitor, gpointer data) { GList *mounts; /* remove the saved data for mounts that got removed */ mounts = g_unix_mounts_get (time_read); g_hash_table_foreach_remove (ldsm_notified_hash, ldsm_is_hash_item_not_in_mounts, mounts); g_list_free_full (mounts, (GDestroyNotify) g_unix_mount_free); /* check the status now, for the new mounts */ ldsm_check_all_mounts (NULL); /* and reset the timeout */ if (ldsm_timeout_id) { g_source_remove (ldsm_timeout_id); ldsm_timeout_id = 0; } ldsm_timeout_id = g_timeout_add_seconds (CHECK_EVERY_X_SECONDS, ldsm_check_all_mounts, NULL); } static gboolean ldsm_is_hash_item_in_ignore_paths (gpointer key, gpointer value, gpointer user_data) { return ldsm_mount_is_user_ignore (key); } static void csd_ldsm_get_config (void) { gchar **settings_list; free_percent_notify = g_settings_get_double (settings, SETTINGS_FREE_PC_NOTIFY_KEY); if (free_percent_notify >= 1 || free_percent_notify < 0) { g_warning ("Invalid configuration of free_percent_notify: %f\n" \ "Using sensible default", free_percent_notify); free_percent_notify = 0.05; } free_percent_notify_again = g_settings_get_double (settings, SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY); if (free_percent_notify_again >= 1 || free_percent_notify_again < 0) { g_warning ("Invalid configuration of free_percent_notify_again: %f\n" \ "Using sensible default\n", free_percent_notify_again); free_percent_notify_again = 0.01; } free_size_gb_no_notify = g_settings_get_int (settings, SETTINGS_FREE_SIZE_NO_NOTIFY); min_notify_period = g_settings_get_int (settings, SETTINGS_MIN_NOTIFY_PERIOD); if (ignore_paths != NULL) { g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_clear_pointer (&ignore_paths, g_slist_free); } settings_list = g_settings_get_strv (settings, SETTINGS_IGNORE_PATHS); if (settings_list != NULL) { guint i; for (i = 0; settings_list[i] != NULL; i++) ignore_paths = g_slist_prepend (ignore_paths, g_strdup (settings_list[i])); /* Make sure we don't leave stale entries in ldsm_notified_hash */ g_hash_table_foreach_remove (ldsm_notified_hash, ldsm_is_hash_item_in_ignore_paths, NULL); g_strfreev (settings_list); } } static void csd_ldsm_update_config (GSettings *settings, const gchar *key, gpointer user_data) { csd_ldsm_get_config (); } void csd_ldsm_setup (gboolean check_now) { if (ldsm_notified_hash || ldsm_timeout_id || ldsm_monitor) { g_warning ("Low disk space monitor already initialized."); return; } ldsm_notified_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ldsm_free_mount_info); settings = g_settings_new (SETTINGS_HOUSEKEEPING_DIR); csd_ldsm_get_config (); g_signal_connect (G_OBJECT (settings), "changed", G_CALLBACK (csd_ldsm_update_config), NULL); ldsm_monitor = g_unix_mount_monitor_get (); g_signal_connect (ldsm_monitor, "mounts-changed", G_CALLBACK (ldsm_mounts_changed), NULL); if (check_now) ldsm_check_all_mounts (NULL); ldsm_timeout_id = g_timeout_add_seconds (CHECK_EVERY_X_SECONDS, ldsm_check_all_mounts, NULL); } void csd_ldsm_clean (void) { if (ldsm_timeout_id) { g_source_remove (ldsm_timeout_id); ldsm_timeout_id = 0; } g_clear_pointer (&ldsm_notified_hash, g_hash_table_destroy); g_clear_object (&ldsm_monitor); g_clear_object (&settings); g_clear_object (&dialog); if (notification != NULL) notify_notification_close (notification, NULL); g_slist_free_full (ignore_paths, g_free); ignore_paths = NULL; } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-disk-space.h000066400000000000000000000022321356401377300255420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * * Authors: Vincent Untz * * 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 __CSD_DISK_SPACE_H #define __CSD_DISK_SPACE_H #include G_BEGIN_DECLS void csd_ldsm_setup (gboolean check_now); void csd_ldsm_clean (void); /* for the test */ void csd_ldsm_show_empty_trash (void); G_END_DECLS #endif /* __CSD_DISK_SPACE_H */ cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-empty-trash-test.c000066400000000000000000000023631356401377300267510ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2011, Red Hat, Inc. * * Authors: Cosimo Cecchi * * 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 #include "csd-disk-space.h" int main (int argc, char **argv) { GMainLoop *loop; gtk_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); csd_ldsm_show_empty_trash (); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-housekeeping-manager.c000066400000000000000000000260511356401377300276150ustar00rootroot00000000000000/* * Copyright (C) 2008 Michael J. Chudobiak * * 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 #include #include #include "cinnamon-settings-profile.h" #include "csd-housekeeping-manager.h" #include "csd-disk-space.h" /* General */ #define INTERVAL_ONCE_A_DAY 24*60*60 #define INTERVAL_TWO_MINUTES 2*60 /* Thumbnail cleaner */ #define THUMB_PREFIX "org.cinnamon.desktop.thumbnail-cache" #define THUMB_AGE_KEY "maximum-age" #define THUMB_SIZE_KEY "maximum-size" struct CsdHousekeepingManagerPrivate { GSettings *settings; guint long_term_cb; guint short_term_cb; }; #define CSD_HOUSEKEEPING_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerPrivate)) G_DEFINE_TYPE (CsdHousekeepingManager, csd_housekeeping_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; typedef struct { glong now; glong max_age; goffset total_size; goffset max_size; } PurgeData; typedef struct { time_t mtime; char *path; glong size; } ThumbData; static void thumb_data_free (gpointer data) { ThumbData *info = data; if (info) { g_free (info->path); g_free (info); } } static GList * read_dir_for_purge (const char *path, GList *files) { GFile *read_path; GFileEnumerator *enum_dir; read_path = g_file_new_for_path (path); enum_dir = g_file_enumerate_children (read_path, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_TIME_MODIFIED "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (enum_dir != NULL) { GFileInfo *info; while ((info = g_file_enumerator_next_file (enum_dir, NULL, NULL)) != NULL) { const char *name; name = g_file_info_get_name (info); if (strlen (name) == 36 && strcmp (name + 32, ".png") == 0) { ThumbData *td; GFile *entry; char *entry_path; GTimeVal mod_time; entry = g_file_get_child (read_path, name); entry_path = g_file_get_path (entry); g_object_unref (entry); g_file_info_get_modification_time (info, &mod_time); td = g_new0 (ThumbData, 1); td->path = entry_path; td->mtime = mod_time.tv_sec; td->size = g_file_info_get_size (info); files = g_list_prepend (files, td); } g_object_unref (info); } g_object_unref (enum_dir); } g_object_unref (read_path); return files; } static void purge_old_thumbnails (ThumbData *info, PurgeData *purge_data) { if ((purge_data->now - info->mtime) > purge_data->max_age) { g_unlink (info->path); info->size = 0; } else { purge_data->total_size += info->size; } } static int sort_file_mtime (ThumbData *file1, ThumbData *file2) { return file1->mtime - file2->mtime; } static char ** get_thumbnail_dirs (void) { GPtrArray *array; char *path; array = g_ptr_array_new (); /* check new XDG cache */ path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "normal", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "large", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "fail", "gnome-thumbnail-factory", NULL); g_ptr_array_add (array, path); /* cleanup obsolete locations too */ path = g_build_filename (g_get_home_dir (), ".thumbnails", "normal", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_home_dir (), ".thumbnails", "large", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_home_dir (), ".thumbnails", "fail", "gnome-thumbnail-factory", NULL); g_ptr_array_add (array, path); g_ptr_array_add (array, NULL); return (char **) g_ptr_array_free (array, FALSE); } static void purge_thumbnail_cache (CsdHousekeepingManager *manager) { char **paths; GList *files; PurgeData purge_data; GTimeVal current_time; guint i; g_debug ("housekeeping: checking thumbnail cache size and freshness"); paths = get_thumbnail_dirs (); files = NULL; for (i = 0; paths[i] != NULL; i++) files = read_dir_for_purge (paths[i], files); g_strfreev (paths); g_get_current_time (¤t_time); purge_data.now = current_time.tv_sec; purge_data.max_age = g_settings_get_int (manager->priv->settings, THUMB_AGE_KEY) * 24 * 60 * 60; purge_data.max_size = g_settings_get_int (manager->priv->settings, THUMB_SIZE_KEY) * 1024 * 1024; purge_data.total_size = 0; if (purge_data.max_age >= 0) g_list_foreach (files, (GFunc) purge_old_thumbnails, &purge_data); if ((purge_data.total_size > purge_data.max_size) && (purge_data.max_size >= 0)) { GList *scan; files = g_list_sort (files, (GCompareFunc) sort_file_mtime); for (scan = files; scan && (purge_data.total_size > purge_data.max_size); scan = scan->next) { ThumbData *info = scan->data; g_unlink (info->path); purge_data.total_size -= info->size; } } g_list_foreach (files, (GFunc) thumb_data_free, NULL); g_list_free (files); } static gboolean do_cleanup (CsdHousekeepingManager *manager) { purge_thumbnail_cache (manager); return TRUE; } static gboolean do_cleanup_once (CsdHousekeepingManager *manager) { do_cleanup (manager); manager->priv->short_term_cb = 0; return FALSE; } static void do_cleanup_soon (CsdHousekeepingManager *manager) { if (manager->priv->short_term_cb == 0) { g_debug ("housekeeping: will tidy up in 2 minutes"); manager->priv->short_term_cb = g_timeout_add_seconds (INTERVAL_TWO_MINUTES, (GSourceFunc) do_cleanup_once, manager); } } static void settings_changed_callback (GSettings *settings, const char *key, CsdHousekeepingManager *manager) { do_cleanup_soon (manager); } gboolean csd_housekeeping_manager_start (CsdHousekeepingManager *manager, GError **error) { g_debug ("Starting housekeeping manager"); cinnamon_settings_profile_start (NULL); csd_ldsm_setup (FALSE); manager->priv->settings = g_settings_new (THUMB_PREFIX); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (settings_changed_callback), manager); /* Clean once, a few minutes after start-up */ do_cleanup_soon (manager); /* Clean periodically, on a daily basis. */ manager->priv->long_term_cb = g_timeout_add_seconds (INTERVAL_ONCE_A_DAY, (GSourceFunc) do_cleanup, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_housekeeping_manager_stop (CsdHousekeepingManager *manager) { CsdHousekeepingManagerPrivate *p = manager->priv; g_debug ("Stopping housekeeping manager"); if (p->short_term_cb) { g_source_remove (p->short_term_cb); p->short_term_cb = 0; } if (p->long_term_cb) { g_source_remove (p->long_term_cb); p->long_term_cb = 0; /* Do a clean-up on shutdown if and only if the size or age limits have been set to paranoid levels (zero) */ if ((g_settings_get_int (p->settings, THUMB_AGE_KEY) == 0) || (g_settings_get_int (p->settings, THUMB_SIZE_KEY) == 0)) { do_cleanup (manager); } g_clear_object (&p->settings); } csd_ldsm_clean (); } static void csd_housekeeping_manager_class_init (CsdHousekeepingManagerClass *klass) { g_type_class_add_private (klass, sizeof (CsdHousekeepingManagerPrivate)); } static void csd_housekeeping_manager_init (CsdHousekeepingManager *manager) { manager->priv = CSD_HOUSEKEEPING_MANAGER_GET_PRIVATE (manager); } CsdHousekeepingManager * csd_housekeeping_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_HOUSEKEEPING_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_HOUSEKEEPING_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-housekeeping-manager.h000066400000000000000000000047101356401377300276200ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Michael J. Chudobiak * * 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 __CSD_HOUSEKEEPING_MANAGER_H #define __CSD_HOUSEKEEPING_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_HOUSEKEEPING_MANAGER (csd_housekeeping_manager_get_type ()) #define CSD_HOUSEKEEPING_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManager)) #define CSD_HOUSEKEEPING_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerClass)) #define CSD_IS_HOUSEKEEPING_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_HOUSEKEEPING_MANAGER)) #define CSD_IS_HOUSEKEEPING_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_HOUSEKEEPING_MANAGER)) #define CSD_HOUSEKEEPING_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerClass)) typedef struct CsdHousekeepingManagerPrivate CsdHousekeepingManagerPrivate; typedef struct { GObject parent; CsdHousekeepingManagerPrivate *priv; } CsdHousekeepingManager; typedef struct { GObjectClass parent_class; } CsdHousekeepingManagerClass; GType csd_housekeeping_manager_get_type (void); CsdHousekeepingManager * csd_housekeeping_manager_new (void); gboolean csd_housekeeping_manager_start (CsdHousekeepingManager *manager, GError **error); void csd_housekeeping_manager_stop (CsdHousekeepingManager *manager); G_END_DECLS #endif /* __CSD_HOUSEKEEPING_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-ldsm-dialog.c000066400000000000000000000472621356401377300257220ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * csd-ldsm-dialog.c * Copyright (C) Chris Coulson 2009 * * 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 #include #include "csd-ldsm-dialog.h" #define SETTINGS_HOUSEKEEPING_DIR "org.cinnamon.settings-daemon.plugins.housekeeping" enum { PROP_0, PROP_OTHER_USABLE_PARTITIONS, PROP_OTHER_PARTITIONS, PROP_HAS_TRASH, PROP_SPACE_REMAINING, PROP_PARTITION_NAME, PROP_MOUNT_PATH }; struct CsdLdsmDialogPrivate { GtkWidget *primary_label; GtkWidget *secondary_label; GtkWidget *ignore_check_button; gboolean other_usable_partitions; gboolean other_partitions; gboolean has_trash; gint64 space_remaining; gchar *partition_name; gchar *mount_path; }; #define CSD_LDSM_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogPrivate)) G_DEFINE_TYPE (CsdLdsmDialog, csd_ldsm_dialog, GTK_TYPE_DIALOG); static const gchar* csd_ldsm_dialog_get_checkbutton_text (CsdLdsmDialog *dialog) { g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); if (dialog->priv->other_partitions) return _("Don't show any warnings again for this file system"); else return _("Don't show any warnings again"); } static gchar* csd_ldsm_dialog_get_primary_text (CsdLdsmDialog *dialog) { gchar *primary_text, *free_space; g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); free_space = g_format_size (dialog->priv->space_remaining); if (dialog->priv->other_partitions) { primary_text = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining."), dialog->priv->partition_name, free_space); } else { primary_text = g_strdup_printf (_("This computer has only %s disk space remaining."), free_space); } g_free (free_space); return primary_text; } static const gchar* csd_ldsm_dialog_get_secondary_text (CsdLdsmDialog *dialog) { g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); if (dialog->priv->other_usable_partitions) { if (dialog->priv->has_trash) { return _("You can free up disk space by emptying the Trash, removing " \ "unused programs or files, or moving files to another disk or partition."); } else { return _("You can free up disk space by removing unused programs or files, " \ "or by moving files to another disk or partition."); } } else { if (dialog->priv->has_trash) { return _("You can free up disk space by emptying the Trash, removing unused " \ "programs or files, or moving files to an external disk."); } else { return _("You can free up disk space by removing unused programs or files, " \ "or by moving files to an external disk."); } } } static gint ignore_path_compare (gconstpointer a, gconstpointer b) { return g_strcmp0 ((const gchar *)a, (const gchar *)b); } static gboolean update_ignore_paths (GSList **ignore_paths, const gchar *mount_path, gboolean ignore) { GSList *found; gchar *path_to_remove; found = g_slist_find_custom (*ignore_paths, mount_path, (GCompareFunc) ignore_path_compare); if (ignore && (found == NULL)) { *ignore_paths = g_slist_prepend (*ignore_paths, g_strdup (mount_path)); return TRUE; } if (!ignore && (found != NULL)) { path_to_remove = found->data; *ignore_paths = g_slist_remove (*ignore_paths, path_to_remove); g_free (path_to_remove); return TRUE; } return FALSE; } static void ignore_check_button_toggled_cb (GtkToggleButton *button, gpointer user_data) { CsdLdsmDialog *dialog = (CsdLdsmDialog *)user_data; GSettings *settings; gchar **settings_list; gboolean ignore, updated; gint i; GSList *ignore_paths = NULL; settings = g_settings_new (SETTINGS_HOUSEKEEPING_DIR); settings_list = g_settings_get_strv (settings, "ignore-paths"); for (i = 0; i < G_N_ELEMENTS (settings_list); i++) { if (settings_list[i] != NULL) ignore_paths = g_slist_append (ignore_paths, g_strdup (settings_list[i])); } ignore = gtk_toggle_button_get_active (button); updated = update_ignore_paths (&ignore_paths, dialog->priv->mount_path, ignore); g_strfreev (settings_list); if (updated) { GSList *l; GPtrArray *array = g_ptr_array_new (); for (l = ignore_paths; l != NULL; l = l->next) g_ptr_array_add (array, l->data); g_ptr_array_add (array, NULL); if (!g_settings_set_strv (settings, "ignore-paths", (const gchar **) array->pdata)) { g_warning ("Cannot change ignore preference - failed to commit changes"); } g_ptr_array_free (array, FALSE); } g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); g_object_unref (settings); } static void csd_ldsm_dialog_init (CsdLdsmDialog *dialog) { GtkWidget *main_vbox, *text_vbox, *hbox; GtkWidget *image; dialog->priv = CSD_LDSM_DIALOG_GET_PRIVATE (dialog); main_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); /* Set up all the window stuff here */ gtk_window_set_title (GTK_WINDOW (dialog), _("Low Disk Space")); gtk_window_set_icon_name (GTK_WINDOW (dialog), "dialog-warning"); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE); gtk_window_set_focus_on_map (GTK_WINDOW (dialog), FALSE); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); /* Create the image */ image = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_DIALOG); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); /* Create the labels */ dialog->priv->primary_label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (dialog->priv->primary_label), TRUE); gtk_label_set_single_line_mode (GTK_LABEL (dialog->priv->primary_label), FALSE); gtk_misc_set_alignment (GTK_MISC (dialog->priv->primary_label), 0.0, 0.0); dialog->priv->secondary_label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (dialog->priv->secondary_label), TRUE); gtk_label_set_single_line_mode (GTK_LABEL (dialog->priv->secondary_label), FALSE); gtk_misc_set_alignment (GTK_MISC (dialog->priv->secondary_label), 0.0, 0.0); /* Create the check button to ignore future warnings */ dialog->priv->ignore_check_button = gtk_check_button_new (); /* The button should be inactive if the dialog was just called. * I suppose it could be possible for the user to manually edit the GSettings key between * the mount being checked and the dialog appearing, but I don't think it matters * too much */ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->ignore_check_button), FALSE); g_signal_connect (dialog->priv->ignore_check_button, "toggled", G_CALLBACK (ignore_check_button_toggled_cb), dialog); /* Now set up the dialog's GtkBox's' */ gtk_box_set_spacing (GTK_BOX (main_vbox), 14); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); text_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->primary_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->secondary_label, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->ignore_check_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), text_vbox, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); /* Set up the action area */ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), 6); gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), 5); gtk_widget_show_all (hbox); } static void csd_ldsm_dialog_finalize (GObject *object) { CsdLdsmDialog *self; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); if (self->priv->partition_name) g_free (self->priv->partition_name); if (self->priv->mount_path) g_free (self->priv->mount_path); G_OBJECT_CLASS (csd_ldsm_dialog_parent_class)->finalize (object); } static void csd_ldsm_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdLdsmDialog *self; g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); switch (prop_id) { case PROP_OTHER_USABLE_PARTITIONS: self->priv->other_usable_partitions = g_value_get_boolean (value); break; case PROP_OTHER_PARTITIONS: self->priv->other_partitions = g_value_get_boolean (value); break; case PROP_HAS_TRASH: self->priv->has_trash = g_value_get_boolean (value); break; case PROP_SPACE_REMAINING: self->priv->space_remaining = g_value_get_int64 (value); break; case PROP_PARTITION_NAME: self->priv->partition_name = g_value_dup_string (value); break; case PROP_MOUNT_PATH: self->priv->mount_path = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_ldsm_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdLdsmDialog *self; g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); switch (prop_id) { case PROP_OTHER_USABLE_PARTITIONS: g_value_set_boolean (value, self->priv->other_usable_partitions); break; case PROP_OTHER_PARTITIONS: g_value_set_boolean (value, self->priv->other_partitions); break; case PROP_HAS_TRASH: g_value_set_boolean (value, self->priv->has_trash); break; case PROP_SPACE_REMAINING: g_value_set_int64 (value, self->priv->space_remaining); break; case PROP_PARTITION_NAME: g_value_set_string (value, self->priv->partition_name); break; case PROP_MOUNT_PATH: g_value_set_string (value, self->priv->mount_path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_ldsm_dialog_class_init (CsdLdsmDialogClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_ldsm_dialog_finalize; object_class->set_property = csd_ldsm_dialog_set_property; object_class->get_property = csd_ldsm_dialog_get_property; g_object_class_install_property (object_class, PROP_OTHER_USABLE_PARTITIONS, g_param_spec_boolean ("other-usable-partitions", "other-usable-partitions", "Set to TRUE if there are other usable partitions on the system", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_OTHER_PARTITIONS, g_param_spec_boolean ("other-partitions", "other-partitions", "Set to TRUE if there are other partitions on the system", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_HAS_TRASH, g_param_spec_boolean ("has-trash", "has-trash", "Set to TRUE if the partition has files in it's trash folder that can be deleted", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_SPACE_REMAINING, g_param_spec_int64 ("space-remaining", "space-remaining", "Specify how much space is remaining in bytes", G_MININT64, G_MAXINT64, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_PARTITION_NAME, g_param_spec_string ("partition-name", "partition-name", "Specify the name of the partition", "Unknown", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_MOUNT_PATH, g_param_spec_string ("mount-path", "mount-path", "Specify the mount path for the partition", "Unknown", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (CsdLdsmDialogPrivate)); } CsdLdsmDialog* csd_ldsm_dialog_new (gboolean other_usable_partitions, gboolean other_partitions, gboolean display_baobab, gboolean display_empty_trash, gint64 space_remaining, const gchar *partition_name, const gchar *mount_path) { CsdLdsmDialog *dialog; GtkWidget *button_empty_trash, *button_ignore, *button_analyze; GtkWidget *empty_trash_image, *analyze_image, *ignore_image; gchar *primary_text, *primary_text_markup; const gchar *secondary_text, *checkbutton_text; dialog = CSD_LDSM_DIALOG (g_object_new (CSD_TYPE_LDSM_DIALOG, "other-usable-partitions", other_usable_partitions, "other-partitions", other_partitions, "has-trash", display_empty_trash, "space-remaining", space_remaining, "partition-name", partition_name, "mount-path", mount_path, NULL)); /* Add some buttons */ if (dialog->priv->has_trash) { button_empty_trash = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Empty Trash"), CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH); empty_trash_image = gtk_image_new_from_icon_name ("edit-clear", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_empty_trash), empty_trash_image); } if (display_baobab) { button_analyze = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Examine..."), CSD_LDSM_DIALOG_RESPONSE_ANALYZE); analyze_image = gtk_image_new_from_icon_name ("baobab", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_analyze), analyze_image); } button_ignore = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Ignore"), GTK_RESPONSE_CANCEL); ignore_image = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_ignore), ignore_image); gtk_widget_grab_default (button_ignore); /* Set the label text */ primary_text = csd_ldsm_dialog_get_primary_text (dialog); primary_text_markup = g_markup_printf_escaped ("%s", primary_text); gtk_label_set_markup (GTK_LABEL (dialog->priv->primary_label), primary_text_markup); secondary_text = csd_ldsm_dialog_get_secondary_text (dialog); gtk_label_set_text (GTK_LABEL (dialog->priv->secondary_label), secondary_text); checkbutton_text = csd_ldsm_dialog_get_checkbutton_text (dialog); gtk_button_set_label (GTK_BUTTON (dialog->priv->ignore_check_button), checkbutton_text); g_free (primary_text); g_free (primary_text_markup); return dialog; } cinnamon-settings-daemon-4.4.0/plugins/housekeeping/csd-ldsm-dialog.h000066400000000000000000000051021356401377300257120ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * csd-ldsm-dialog.c * Copyright (C) Chris Coulson 2009 * * 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 _CSD_LDSM_DIALOG_H_ #define _CSD_LDSM_DIALOG_H_ #include #include G_BEGIN_DECLS #define CSD_TYPE_LDSM_DIALOG (csd_ldsm_dialog_get_type ()) #define CSD_LDSM_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialog)) #define CSD_LDSM_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogClass)) #define CSD_IS_LDSM_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_LDSM_DIALOG)) #define CSD_IS_LDSM_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_LDSM_DIALOG)) #define CSD_LDSM_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogClass)) enum { CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH = -20, CSD_LDSM_DIALOG_RESPONSE_ANALYZE = -21 }; typedef struct CsdLdsmDialogPrivate CsdLdsmDialogPrivate; typedef struct _CsdLdsmDialogClass CsdLdsmDialogClass; typedef struct _CsdLdsmDialog CsdLdsmDialog; struct _CsdLdsmDialogClass { GtkDialogClass parent_class; }; struct _CsdLdsmDialog { GtkDialog parent_instance; CsdLdsmDialogPrivate *priv; }; GType csd_ldsm_dialog_get_type (void) G_GNUC_CONST; CsdLdsmDialog * csd_ldsm_dialog_new (gboolean other_usable_partitions, gboolean other_partitions, gboolean display_baobab, gboolean display_empty_trash, gint64 space_remaining, const gchar *partition_name, const gchar *mount_path); G_END_DECLS #endif /* _CSD_LDSM_DIALOG_H_ */ cinnamon-settings-daemon-4.4.0/plugins/housekeeping/main.c000066400000000000000000000010501356401377300236640ustar00rootroot00000000000000#define NEW csd_housekeeping_manager_new #define START csd_housekeeping_manager_start #define STOP csd_housekeeping_manager_stop #define MANAGER CsdHousekeepingManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-housekeeping-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/keyboard/000077500000000000000000000000001356401377300217125ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/keyboard/Makefile.am000066400000000000000000000031261356401377300237500ustar00rootroot00000000000000NULL = plugin_name = keyboard themedir = $(pkgdatadir)/icons/hicolor size = 64x64 context = devices iconsdir = $(themedir)/$(size)/$(context) icons_DATA = \ kbd-capslock-off.png kbd-numlock-off.png kbd-scrolllock-off.png \ kbd-capslock-on.png kbd-numlock-on.png kbd-scrolllock-on.png AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-keyboard csd_keyboard_SOURCES = \ main.c \ csd-keyboard-manager.h \ csd-keyboard-manager.c \ csd-keyboard-xkb.h \ csd-keyboard-xkb.c \ delayed-dialog.h \ delayed-dialog.c \ gkbd-configuration.c \ gkbd-configuration.h \ $(NULL) csd_keyboard_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/data \ -I$(top_srcdir)/plugins/common \ -DDATADIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_keyboard_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(APPINDICATOR_CFLAGS) \ $(KEYBOARD_CFLAGS) \ $(AM_CFLAGS) csd_keyboard_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(XF86MISC_LIBS) \ $(KEYBOARD_LIBS) \ $(APPINDICATOR_LIBS) \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la $(NULL) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-keyboard.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-keyboard.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(icons_DATA) \ $(desktop_in_files) \ $(ui_DATA) \ $(NULL) CLEANFILES = \ $(desktop_DATA) \ $(NULL) DISTCLEANFILES = \ $(desktop_DATA) \ $(NULL) cinnamon-settings-daemon-4.4.0/plugins/keyboard/cinnamon-settings-daemon-keyboard.desktop.in000066400000000000000000000003551356401377300324140ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - keyboard Exec=@libexecdir@/csd-keyboard OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/keyboard/csd-input-sources-switcher.c000066400000000000000000000376251356401377300273100ustar00rootroot00000000000000/* * Copyright (C) 2012 Red Hat, Inc. * * Written by: Rui Matos * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include "csd-enums.h" #include "csd-keygrab.h" #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.cinnamon.desktop.input-sources" #define KEY_CURRENT_INPUT_SOURCE "current" #define KEY_INPUT_SOURCES "sources" #define CSD_KEYBOARD_DIR "org.cinnamon.settings-daemon.peripherals.keyboard" #define KEY_SWITCHER "input-sources-switcher" static GSettings *input_sources_settings; static Key *the_keys = NULL; static guint n_keys = 0; static guint master_keyboard_id = 0; static gboolean includes_caps = FALSE; static void do_switch (void) { GVariant *sources; gint i, n; /* FIXME: this is racy with the g-s-d media-keys plugin. Instead we should have a DBus API on g-s-d and poke it from here.*/ sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); n = g_variant_n_children (sources); if (n < 2) goto out; i = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE) + 1; if (i >= n) i = 0; g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, i); out: g_variant_unref (sources); } static void init_keys (void) { GSettings *settings; settings = g_settings_new (CSD_KEYBOARD_DIR); switch (g_settings_get_enum (settings, KEY_SWITCHER)) { case CSD_INPUT_SOURCES_SWITCHER_SHIFT_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_R: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_R; the_keys[0].state = 0; the_keys[1].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[1].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_R: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_R; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_L: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_L; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_R: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_R; the_keys[1].state = GDK_SHIFT_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_MOD5_MASK; the_keys[3].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[3].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_L: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_R; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_L_SHIFT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_SHIFT_MASK; the_keys[1].keysym = GDK_KEY_Shift_R; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_L_ALT_R: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_R; the_keys[1].state = GDK_MOD1_MASK; the_keys[2].keysym = GDK_KEY_Alt_L; the_keys[2].state = GDK_MOD5_MASK; the_keys[3].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[3].state = GDK_MOD1_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_L_CTRL_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_R; the_keys[1].state = GDK_CONTROL_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT: n_keys = 7; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Shift_L; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_MOD1_MASK; the_keys[3].keysym = GDK_KEY_Shift_R; the_keys[3].state = GDK_MOD5_MASK; the_keys[4].keysym = GDK_KEY_Alt_L; the_keys[4].state = GDK_SHIFT_MASK; the_keys[5].keysym = GDK_KEY_Alt_R; the_keys[5].state = GDK_SHIFT_MASK; the_keys[6].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[6].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Shift_R; the_keys[1].state = GDK_CONTROL_MASK; the_keys[2].keysym = GDK_KEY_Control_L; the_keys[2].state = GDK_SHIFT_MASK; the_keys[3].keysym = GDK_KEY_Control_R; the_keys[3].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_CTRL: n_keys = 7; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Control_R; the_keys[2].state = GDK_MOD1_MASK; the_keys[3].keysym = GDK_KEY_Control_R; the_keys[3].state = GDK_MOD5_MASK; the_keys[4].keysym = GDK_KEY_Alt_L; the_keys[4].state = GDK_CONTROL_MASK; the_keys[5].keysym = GDK_KEY_Alt_R; the_keys[5].state = GDK_CONTROL_MASK; the_keys[6].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[6].state = GDK_CONTROL_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CAPS: includes_caps = TRUE; n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_CAPS: includes_caps = TRUE; n_keys = 3; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_SHIFT_MASK; the_keys[1].keysym = GDK_KEY_Shift_L; the_keys[1].state = GDK_LOCK_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_LOCK_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_CAPS: includes_caps = TRUE; n_keys = 5; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Caps_Lock; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Alt_L; the_keys[2].state = GDK_LOCK_MASK; the_keys[3].keysym = GDK_KEY_Alt_R; the_keys[3].state = GDK_LOCK_MASK; the_keys[4].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[4].state = GDK_LOCK_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_CAPS: includes_caps = TRUE; n_keys = 3; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_LOCK_MASK; the_keys[2].keysym = GDK_KEY_Control_R; the_keys[2].state = GDK_LOCK_MASK; break; } g_object_unref (settings); } static void free_keys (void) { gint i; for (i = 0; i < n_keys; ++i) g_free (the_keys[i].keycodes); g_free (the_keys); } static gboolean match_caps_locked (const Key *key, XIDeviceEvent *xev) { if (key->state & xev->mods.effective && key->keysym == XkbKeycodeToKeysym (xev->display, xev->detail, 0, 0)) return TRUE; return FALSE; } static gboolean match_modifier (const Key *key, XIEvent *xiev) { Key meta; /* When the grab is established with Caps Lock as the modifier (i.e. key->state == GDK_LOCK_MASK) we can't use match_xi2_key() as this modifier is black listed there, so we do the match ourselves. */ if (key->state == GDK_LOCK_MASK) return match_caps_locked (key, (XIDeviceEvent *) xiev); meta = *key; switch (key->keysym) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_SHIFT_MASK; break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_CONTROL_MASK; break; case GDK_KEY_ISO_Level3_Shift: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_MOD5_MASK; break; case GDK_KEY_Alt_L: case GDK_KEY_Alt_R: if (key->state == GDK_SHIFT_MASK) meta.keysym = key->keysym == GDK_KEY_Alt_L ? GDK_KEY_Meta_L : GDK_KEY_Meta_R; if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_MOD1_MASK; break; } return match_xi2_key (&meta, (XIDeviceEvent *) xiev); } static gboolean matches_key (XIEvent *xiev) { gint i; for (i = 0; i < n_keys; ++i) if (match_modifier (&the_keys[i], xiev)) return TRUE; return FALSE; } /* Owen magic, ported to XI2 */ static GdkFilterReturn filter (XEvent *xevent, GdkEvent *event, gpointer data) { XIEvent *xiev; XIDeviceEvent *xev; XIGrabModifiers mods; XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8] = { 0 }; if (xevent->type != GenericEvent) return GDK_FILTER_CONTINUE; xiev = (XIEvent *) xevent->xcookie.data; if (xiev->evtype != XI_ButtonPress && xiev->evtype != XI_KeyPress && xiev->evtype != XI_KeyRelease) return GDK_FILTER_CONTINUE; xev = (XIDeviceEvent *) xiev; mods.modifiers = XIAnyModifier; XISetMask (mask, XI_ButtonPress); evmask.deviceid = XIAllMasterDevices; evmask.mask_len = sizeof (mask); evmask.mask = mask; if (xiev->evtype != XI_ButtonPress && matches_key (xiev)) { if (xiev->evtype == XI_KeyPress) { if (includes_caps) { do_switch (); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XkbLockModifiers (xev->display, XkbUseCoreKbd, LockMask, 0); } else { XIAllowEvents (xev->display, xev->deviceid, XISyncDevice, xev->time); XIGrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, None, GrabModeSync, GrabModeSync, False, &evmask, 1, &mods); } } else { do_switch (); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XIUngrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, 1, &mods); } } else { XIAllowEvents (xev->display, xev->deviceid, XIReplayDevice, xev->time); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XIUngrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, 1, &mods); } return GDK_FILTER_CONTINUE; } static void grab_key (Key *key, GdkDisplay *display, GSList *screens) { GdkKeymapKey *keys; gboolean has_entries; GArray *keycodes; gint n, i; has_entries = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), key->keysym, &keys, &n); if (!has_entries) return; keycodes = g_array_sized_new (TRUE, TRUE, sizeof (guint), n); for (i = 0; i < n; ++i) g_array_append_val (keycodes, keys[i].keycode); key->keycodes = (guint *) g_array_free (keycodes, FALSE); gdk_x11_display_error_trap_push (display); grab_key_unsafe (key, CSD_KEYGRAB_ALLOW_UNMODIFIED | CSD_KEYGRAB_SYNCHRONOUS, screens); gdk_x11_display_error_trap_pop_ignored (display); g_free (keys); } static guint get_master_keyboard_id (GdkDisplay *display) { XIDeviceInfo *info; guint id; int i, n; id = 0; info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display), XIAllMasterDevices, &n); for (i = 0; i < n; ++i) if (info[i].use == XIMasterKeyboard && info[i].enabled) { id = info[i].deviceid; break; } XIFreeDeviceInfo (info); return id; } static void set_input_sources_switcher (void) { GdkDisplay *display; gint n_screens; GSList *screens, *l; gint i; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); screens = NULL; for (i = 0; i < n_screens; ++i) screens = g_slist_prepend (screens, gdk_display_get_screen (display, i)); for (i = 0; i < n_keys; ++i) grab_key (&the_keys[i], display, screens); for (l = screens; l; l = l->next) { GdkScreen *screen; screen = (GdkScreen *) l->data; gdk_window_add_filter (gdk_screen_get_root_window (screen), (GdkFilterFunc) filter, screen); } g_slist_free (screens); master_keyboard_id = get_master_keyboard_id (display); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); init_keys (); if (n_keys == 0) { g_warning ("No shortcut defined, exiting"); return -1; } input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); set_input_sources_switcher (); gtk_main (); g_object_unref (input_sources_settings); free_keys (); return 0; } cinnamon-settings-daemon-4.4.0/plugins/keyboard/csd-keyboard-manager.c000066400000000000000000000314471356401377300260460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 William Jon McCann * Written by Sergey V. Oudaltsov * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-keyboard-manager.h" #include "csd-enums.h" #include "csd-keyboard-xkb.h" #define CSD_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerPrivate)) #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 255 #endif #define CSD_KEYBOARD_DIR "org.cinnamon.settings-daemon.peripherals.keyboard" #define KEY_REPEAT "repeat" #define KEY_CLICK "click" #define KEY_INTERVAL "repeat-interval" #define KEY_DELAY "delay" #define KEY_CLICK_VOLUME "click-volume" #define KEY_NUMLOCK_STATE "numlock-state" #define KEY_BELL_VOLUME "bell-volume" #define KEY_BELL_PITCH "bell-pitch" #define KEY_BELL_DURATION "bell-duration" #define KEY_BELL_MODE "bell-mode" struct CsdKeyboardManagerPrivate { guint start_idle_id; GSettings *settings; gboolean have_xkb; gint xkb_event_base; CsdNumLockState old_state; }; static void csd_keyboard_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdKeyboardManager, csd_keyboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean xkb_set_keyboard_autorepeat_rate (guint delay, guint interval) { return XkbSetAutoRepeatRate (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, delay, interval); } static void numlock_xkb_init (CsdKeyboardManager *manager) { Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); gboolean have_xkb; int opcode, error_base, major, minor; have_xkb = XkbQueryExtension (dpy, &opcode, &manager->priv->xkb_event_base, &error_base, &major, &minor) && XkbUseExtension (dpy, &major, &minor); if (have_xkb) { XkbSelectEventDetails (dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbModifierLockMask, XkbModifierLockMask); } else { g_warning ("XKB extension not available"); } manager->priv->have_xkb = have_xkb; } static unsigned numlock_NumLock_modifier_mask (void) { Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); return XkbKeysymToModifiers (dpy, XK_Num_Lock); } static void numlock_set_xkb_state (CsdNumLockState new_state) { unsigned int num_mask; Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); if (new_state != CSD_NUM_LOCK_STATE_ON && new_state != CSD_NUM_LOCK_STATE_OFF) return; num_mask = numlock_NumLock_modifier_mask (); XkbLockModifiers (dpy, XkbUseCoreKbd, num_mask, new_state == CSD_NUM_LOCK_STATE_ON ? num_mask : 0); } static GdkFilterReturn numlock_xkb_callback (GdkXEvent *xev_, GdkEvent *gdkev_, gpointer user_data) { XEvent *xev = (XEvent *) xev_; XkbEvent *xkbev = (XkbEvent *) xev; CsdKeyboardManager *manager = (CsdKeyboardManager *) user_data; if (xev->type != manager->priv->xkb_event_base) return GDK_FILTER_CONTINUE; if (xkbev->any.xkb_type != XkbStateNotify) return GDK_FILTER_CONTINUE; if (xkbev->state.changed & XkbModifierLockMask) { unsigned num_mask = numlock_NumLock_modifier_mask (); unsigned locked_mods = xkbev->state.locked_mods; CsdNumLockState numlock_state; numlock_state = (num_mask & locked_mods) ? CSD_NUM_LOCK_STATE_ON : CSD_NUM_LOCK_STATE_OFF; if (numlock_state != manager->priv->old_state) { g_settings_set_enum (manager->priv->settings, KEY_NUMLOCK_STATE, numlock_state); manager->priv->old_state = numlock_state; } } return GDK_FILTER_CONTINUE; } static void numlock_install_xkb_callback (CsdKeyboardManager *manager) { if (!manager->priv->have_xkb) return; gdk_window_add_filter (NULL, numlock_xkb_callback, manager); } static guint _csd_settings_get_uint (GSettings *settings, const char *key) { guint value; g_settings_get (settings, key, "u", &value); return value; } static void apply_settings (GSettings *settings, const char *key, CsdKeyboardManager *manager) { XKeyboardControl kbdcontrol; gboolean repeat; gboolean click; guint interval; guint delay; int click_volume; int bell_volume; int bell_pitch; int bell_duration; CsdBellMode bell_mode; gboolean rnumlock; if (g_strcmp0 (key, KEY_NUMLOCK_STATE) == 0) return; repeat = g_settings_get_boolean (settings, KEY_REPEAT); click = g_settings_get_boolean (settings, KEY_CLICK); interval = _csd_settings_get_uint (settings, KEY_INTERVAL); delay = _csd_settings_get_uint (settings, KEY_DELAY); click_volume = g_settings_get_int (settings, KEY_CLICK_VOLUME); bell_pitch = g_settings_get_int (settings, KEY_BELL_PITCH); bell_duration = g_settings_get_int (settings, KEY_BELL_DURATION); bell_mode = g_settings_get_enum (settings, KEY_BELL_MODE); bell_volume = (bell_mode == CSD_BELL_MODE_ON) ? 50 : 0; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (repeat) { gboolean rate_set = FALSE; XAutoRepeatOn (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); /* Use XKB in preference */ rate_set = xkb_set_keyboard_autorepeat_rate (delay, interval); if (!rate_set) g_warning ("Neither XKeyboard not Xfree86's keyboard extensions are available,\n" "no way to support keyboard autorepeat rate settings"); } else { XAutoRepeatOff (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); } /* as percentage from 0..100 inclusive */ if (click_volume < 0) { click_volume = 0; } else if (click_volume > 100) { click_volume = 100; } kbdcontrol.key_click_percent = click ? click_volume : 0; kbdcontrol.bell_percent = bell_volume; kbdcontrol.bell_pitch = bell_pitch; kbdcontrol.bell_duration = bell_duration; XChangeKeyboardControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration, &kbdcontrol); if (g_strcmp0 (key, "remember-numlock-state") == 0 || key == NULL) { rnumlock = g_settings_get_boolean (settings, "remember-numlock-state"); manager->priv->old_state = g_settings_get_enum (manager->priv->settings, KEY_NUMLOCK_STATE); if (manager->priv->have_xkb && rnumlock) numlock_set_xkb_state (manager->priv->old_state); } XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } void csd_keyboard_manager_apply_settings (CsdKeyboardManager *manager) { apply_settings (manager->priv->settings, NULL, manager); } static gboolean start_keyboard_idle_cb (CsdKeyboardManager *manager) { cinnamon_settings_profile_start (NULL); g_debug ("Starting keyboard manager"); manager->priv->have_xkb = 0; manager->priv->settings = g_settings_new (CSD_KEYBOARD_DIR); /* Essential - xkb initialization should happen before */ csd_keyboard_xkb_init (manager); numlock_xkb_init (manager); /* apply current settings before we install the callback */ csd_keyboard_manager_apply_settings (manager); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (apply_settings), manager); numlock_install_xkb_callback (manager); cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_keyboard_manager_start (CsdKeyboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_keyboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_keyboard_manager_stop (CsdKeyboardManager *manager) { CsdKeyboardManagerPrivate *p = manager->priv; g_debug ("Stopping keyboard manager"); if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->have_xkb) { gdk_window_remove_filter (NULL, numlock_xkb_callback, manager); } csd_keyboard_xkb_shutdown (); } static GObject * csd_keyboard_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdKeyboardManager *keyboard_manager; keyboard_manager = CSD_KEYBOARD_MANAGER (G_OBJECT_CLASS (csd_keyboard_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (keyboard_manager); } static void csd_keyboard_manager_class_init (CsdKeyboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_keyboard_manager_constructor; object_class->finalize = csd_keyboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdKeyboardManagerPrivate)); } static void csd_keyboard_manager_init (CsdKeyboardManager *manager) { manager->priv = CSD_KEYBOARD_MANAGER_GET_PRIVATE (manager); } static void csd_keyboard_manager_finalize (GObject *object) { CsdKeyboardManager *keyboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_KEYBOARD_MANAGER (object)); keyboard_manager = CSD_KEYBOARD_MANAGER (object); g_return_if_fail (keyboard_manager->priv != NULL); if (keyboard_manager->priv->start_idle_id != 0) { g_source_remove (keyboard_manager->priv->start_idle_id); keyboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_keyboard_manager_parent_class)->finalize (object); } CsdKeyboardManager * csd_keyboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_KEYBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_KEYBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/keyboard/csd-keyboard-manager.h000066400000000000000000000046651356401377300260550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_KEYBOARD_MANAGER_H #define __CSD_KEYBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_KEYBOARD_MANAGER (csd_keyboard_manager_get_type ()) #define CSD_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManager)) #define CSD_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerClass)) #define CSD_IS_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_KEYBOARD_MANAGER)) #define CSD_IS_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_KEYBOARD_MANAGER)) #define CSD_KEYBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerClass)) typedef struct CsdKeyboardManagerPrivate CsdKeyboardManagerPrivate; typedef struct { GObject parent; CsdKeyboardManagerPrivate *priv; } CsdKeyboardManager; typedef struct { GObjectClass parent_class; } CsdKeyboardManagerClass; GType csd_keyboard_manager_get_type (void); CsdKeyboardManager * csd_keyboard_manager_new (void); gboolean csd_keyboard_manager_start (CsdKeyboardManager *manager, GError **error); void csd_keyboard_manager_stop (CsdKeyboardManager *manager); void csd_keyboard_manager_apply_settings (CsdKeyboardManager *manager); G_END_DECLS #endif /* __CSD_KEYBOARD_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/keyboard/csd-keyboard-xkb.c000066400000000000000000000345751356401377300252250ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2001 Udaltsoft * * Written by Sergey V. Oudaltsov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "csd-keyboard-xkb.h" #include "delayed-dialog.h" #include "cinnamon-settings-profile.h" #define SETTINGS_KEYBOARD_DIR "org.cinnamon.settings-daemon.plugins.keyboard" static CsdKeyboardManager *manager = NULL; static XklEngine *xkl_engine; static XklConfigRegistry *xkl_registry = NULL; static GkbdDesktopConfig current_config; static GkbdKeyboardConfig current_kbd_config; /* never terminated */ static GkbdKeyboardConfig initial_sys_kbd_config; static gboolean inited_ok = FALSE; static GSettings *settings_desktop = NULL; static GSettings *settings_keyboard = NULL; static PostActivationCallback pa_callback = NULL; static void *pa_callback_user_data = NULL; static GtkStatusIcon *icon = NULL; static GHashTable *preview_dialogs = NULL; static void activation_error (void) { char const *vendor; GtkWidget *dialog; vendor = ServerVendor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); /* VNC viewers will not work, do not barrage them with warnings */ if (NULL != vendor && NULL != strstr (vendor, "VNC")) return; dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _ ("Error activating XKB configuration.\n" "There can be various reasons for that.\n\n" "If you report this situation as a bug, include the results of\n" " %s\n" " %s\n" " %s\n" " %s"), "xprop -root | grep XKB", "gsettings get org.gnome.libgnomekbd.keyboard model", "gsettings get org.gnome.libgnomekbd.keyboard layouts", "gsettings get org.gnome.libgnomekbd.keyboard options"); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); csd_delayed_show_dialog (dialog); } static gboolean ensure_xkl_registry (void) { if (!xkl_registry) { xkl_registry = xkl_config_registry_get_instance (xkl_engine); /* load all materials, unconditionally! */ if (!xkl_config_registry_load (xkl_registry, TRUE)) { g_object_unref (xkl_registry); xkl_registry = NULL; return FALSE; } } return TRUE; } static void apply_desktop_settings (void) { if (!inited_ok) return; csd_keyboard_manager_apply_settings (manager); gkbd_desktop_config_load (¤t_config); /* again, probably it would be nice to compare things before activating them */ gkbd_desktop_config_activate (¤t_config); } static void popup_menu_launch_capplet () { GAppInfo *info; GdkAppLaunchContext *ctx; GError *error = NULL; info = g_app_info_create_from_commandline ("cinnamon-settings region", NULL, 0, &error); if (info != NULL) { ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); if (g_app_info_launch (info, NULL, G_APP_LAUNCH_CONTEXT (ctx), &error) == FALSE) { g_warning ("Could not execute keyboard properties capplet: [%s]\n", error->message); g_error_free (error); } g_object_unref (info); g_object_unref (ctx); } } static void show_layout_destroy (GtkWidget * dialog, gint group) { g_hash_table_remove (preview_dialogs, GINT_TO_POINTER (group)); } static void popup_menu_show_layout () { GtkWidget *dialog; XklEngine *engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); XklState *xkl_state = xkl_engine_get_current_state (engine); gchar **group_names = gkbd_status_get_group_names (); gpointer p = g_hash_table_lookup (preview_dialogs, GINT_TO_POINTER (xkl_state->group)); if (xkl_state->group < 0 || xkl_state->group >= g_strv_length (group_names)) { return; } if (p != NULL) { /* existing window */ gtk_window_present (GTK_WINDOW (p)); return; } if (!ensure_xkl_registry ()) return; dialog = gkbd_keyboard_drawing_dialog_new (); gkbd_keyboard_drawing_dialog_set_group (dialog, xkl_registry, xkl_state->group); g_signal_connect (dialog, "destroy", G_CALLBACK (show_layout_destroy), GINT_TO_POINTER (xkl_state->group)); g_hash_table_insert (preview_dialogs, GINT_TO_POINTER (xkl_state->group), dialog); gtk_widget_show_all (dialog); } static void popup_menu_set_group (gint group_number, gboolean only_menu) { XklEngine *engine = gkbd_status_get_xkl_engine (); XklState *st = xkl_engine_get_current_state(engine); Window cur; st->group = group_number; xkl_engine_allow_one_switch_to_secondary_group (engine); cur = xkl_engine_get_current_window (engine); if (cur != (Window) NULL) { xkl_debug (150, "Enforcing the state %d for window %lx\n", st->group, cur); xkl_engine_save_state (engine, xkl_engine_get_current_window (engine), st); /* XSetInputFocus( GDK_DISPLAY(), cur, RevertToNone, CurrentTime );*/ } else { xkl_debug (150, "??? Enforcing the state %d for unknown window\n", st->group); /* strange situation - bad things can happen */ } if (!only_menu) xkl_engine_lock_group (engine, st->group); } static void popup_menu_set_group_cb (GtkMenuItem * item, gpointer param) { gint group_number = GPOINTER_TO_INT (param); popup_menu_set_group(group_number, FALSE); } static GtkMenu * create_status_menu (void) { GtkMenu *popup_menu = GTK_MENU (gtk_menu_new ()); int i = 0; GtkMenu *groups_menu = GTK_MENU (gtk_menu_new ()); gchar **current_name = gkbd_status_get_group_names (); GtkWidget *item = gtk_menu_item_new_with_mnemonic (_("_Layouts")); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (groups_menu)); item = gtk_menu_item_new_with_mnemonic (_("Show _Keyboard Layout...")); gtk_widget_show (item); g_signal_connect (item, "activate", popup_menu_show_layout, NULL); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); /* translators note: * This is the name of the cinnamon-settings "region" panel */ item = gtk_menu_item_new_with_mnemonic (_("Region and Language Settings")); gtk_widget_show (item); g_signal_connect (item, "activate", popup_menu_launch_capplet, NULL); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); for (i = 0; current_name && *current_name; i++, current_name++) { gchar *image_file = gkbd_status_get_image_filename (i); if (image_file == NULL) { item = gtk_menu_item_new_with_label (*current_name); } else { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (image_file, 24, 24, NULL); GtkWidget *img = gtk_image_new_from_pixbuf (pixbuf); item = gtk_image_menu_item_new_with_label (*current_name); gtk_widget_show (img); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img); gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE); g_free (image_file); } gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (groups_menu), item); g_signal_connect (item, "activate", G_CALLBACK (popup_menu_set_group_cb), GINT_TO_POINTER (i)); } return popup_menu; } static void status_icon_popup_menu_cb (GtkStatusIcon * icon, guint button, guint time) { GtkMenu *popup_menu = create_status_menu (); gtk_menu_popup (popup_menu, NULL, NULL, gtk_status_icon_position_menu, (gpointer) icon, button, time); } static gboolean try_activating_xkb_config_if_new (GkbdKeyboardConfig * current_sys_kbd_config) { /* Activate - only if different! */ if (!gkbd_keyboard_config_equals (¤t_kbd_config, current_sys_kbd_config)) { if (gkbd_keyboard_config_activate (¤t_kbd_config)) { if (pa_callback != NULL) { (*pa_callback) (pa_callback_user_data); return TRUE; } } else { return FALSE; } } return TRUE; } static gboolean filter_xkb_config (void) { XklConfigItem *item; gchar *lname; gchar *vname; gchar **lv; gboolean any_change = FALSE; xkl_debug (100, "Filtering configuration against the registry\n"); if (!ensure_xkl_registry ()) return FALSE; lv = current_kbd_config.layouts_variants; item = xkl_config_item_new (); while (*lv) { xkl_debug (100, "Checking [%s]\n", *lv); if (gkbd_keyboard_config_split_items (*lv, &lname, &vname)) { gboolean should_be_dropped = FALSE; g_snprintf (item->name, sizeof (item->name), "%s", lname); if (!xkl_config_registry_find_layout (xkl_registry, item)) { xkl_debug (100, "Bad layout [%s]\n", lname); should_be_dropped = TRUE; } else if (vname) { g_snprintf (item->name, sizeof (item->name), "%s", vname); if (!xkl_config_registry_find_variant (xkl_registry, lname, item)) { xkl_debug (100, "Bad variant [%s(%s)]\n", lname, vname); should_be_dropped = TRUE; } } if (should_be_dropped) { gkbd_strv_behead (lv); any_change = TRUE; continue; } } lv++; } g_object_unref (item); return any_change; } static void apply_xkb_settings (void) { GkbdKeyboardConfig current_sys_kbd_config; if (!inited_ok) return; gkbd_keyboard_config_init (¤t_sys_kbd_config, xkl_engine); gkbd_keyboard_config_load (¤t_kbd_config, &initial_sys_kbd_config); gkbd_keyboard_config_load_from_x_current (¤t_sys_kbd_config, NULL); if (!try_activating_xkb_config_if_new (¤t_sys_kbd_config)) { if (filter_xkb_config ()) { if (!try_activating_xkb_config_if_new (¤t_sys_kbd_config)) { g_warning ("Could not activate the filtered XKB configuration"); activation_error (); } } else { g_warning ("Could not activate the XKB configuration"); activation_error (); } } else xkl_debug (100, "Actual KBD configuration was not changed: redundant notification\n"); gkbd_keyboard_config_term (¤t_sys_kbd_config); //show_hide_icon (); } static void csd_keyboard_xkb_analyze_sysconfig (void) { if (!inited_ok) return; gkbd_keyboard_config_init (&initial_sys_kbd_config, xkl_engine); gkbd_keyboard_config_load_from_x_initial (&initial_sys_kbd_config, NULL); } void csd_keyboard_xkb_set_post_activation_callback (PostActivationCallback fun, void *user_data) { pa_callback = fun; pa_callback_user_data = user_data; } static GdkFilterReturn csd_keyboard_xkb_evt_filter (GdkXEvent * xev, GdkEvent * event) { XEvent *xevent = (XEvent *) xev; xkl_engine_filter_events (xkl_engine, xevent); return GDK_FILTER_CONTINUE; } /* When new Keyboard is plugged in - reload the settings */ static void csd_keyboard_new_device (XklEngine * engine) { apply_desktop_settings (); apply_xkb_settings (); } void csd_keyboard_xkb_init (CsdKeyboardManager * kbd_manager) { Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); cinnamon_settings_profile_start (NULL); gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), DATADIR G_DIR_SEPARATOR_S "icons"); manager = kbd_manager; cinnamon_settings_profile_start ("xkl_engine_get_instance"); xkl_engine = xkl_engine_get_instance (display); cinnamon_settings_profile_end ("xkl_engine_get_instance"); if (xkl_engine) { inited_ok = TRUE; gkbd_desktop_config_init (¤t_config, xkl_engine); gkbd_keyboard_config_init (¤t_kbd_config, xkl_engine); xkl_engine_backup_names_prop (xkl_engine); csd_keyboard_xkb_analyze_sysconfig (); settings_desktop = g_settings_new (GKBD_DESKTOP_SCHEMA); settings_keyboard = g_settings_new (GKBD_KEYBOARD_SCHEMA); g_signal_connect (settings_desktop, "changed", (GCallback) apply_desktop_settings, NULL); g_signal_connect (settings_keyboard, "changed", (GCallback) apply_xkb_settings, NULL); gdk_window_add_filter (NULL, (GdkFilterFunc) csd_keyboard_xkb_evt_filter, NULL); if (xkl_engine_get_features (xkl_engine) & XKLF_DEVICE_DISCOVERY) g_signal_connect (xkl_engine, "X-new-device", G_CALLBACK (csd_keyboard_new_device), NULL); cinnamon_settings_profile_start ("xkl_engine_start_listen"); xkl_engine_start_listen (xkl_engine, XKLL_MANAGE_LAYOUTS | XKLL_MANAGE_WINDOW_STATES); cinnamon_settings_profile_end ("xkl_engine_start_listen"); cinnamon_settings_profile_start ("apply_desktop_settings"); apply_desktop_settings (); cinnamon_settings_profile_end ("apply_desktop_settings"); cinnamon_settings_profile_start ("apply_xkb_settings"); apply_xkb_settings (); cinnamon_settings_profile_end ("apply_xkb_settings"); } preview_dialogs = g_hash_table_new (g_direct_hash, g_direct_equal); cinnamon_settings_profile_end (NULL); } void csd_keyboard_xkb_shutdown (void) { if (!inited_ok) return; pa_callback = NULL; pa_callback_user_data = NULL; manager = NULL; if (preview_dialogs != NULL) g_hash_table_destroy (preview_dialogs); if (!inited_ok) return; xkl_engine_stop_listen (xkl_engine, XKLL_MANAGE_LAYOUTS | XKLL_MANAGE_WINDOW_STATES); gdk_window_remove_filter (NULL, (GdkFilterFunc) csd_keyboard_xkb_evt_filter, NULL); g_object_unref (settings_desktop); settings_desktop = NULL; g_object_unref (settings_keyboard); settings_keyboard = NULL; if (xkl_registry) { g_object_unref (xkl_registry); } g_object_unref (xkl_engine); xkl_engine = NULL; inited_ok = FALSE; } cinnamon-settings-daemon-4.4.0/plugins/keyboard/csd-keyboard-xkb.h000066400000000000000000000025411356401377300252160ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * cinnamon-settings-keyboard-xkb.h * * Copyright (C) 2001 Udaltsoft * * Written by Sergey V. Oudaltsov * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSD_KEYBOARD_XKB_H #define __CSD_KEYBOARD_XKB_H #include #include "csd-keyboard-manager.h" void csd_keyboard_xkb_init (CsdKeyboardManager *manager); void csd_keyboard_xkb_shutdown (void); typedef void (*PostActivationCallback) (void *userData); void csd_keyboard_xkb_set_post_activation_callback (PostActivationCallback fun, void *userData); #endif cinnamon-settings-daemon-4.4.0/plugins/keyboard/delayed-dialog.c000066400000000000000000000075541356401377300247350ustar00rootroot00000000000000/* * Copyright © 2006 Novell, 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include #include "delayed-dialog.h" static gboolean delayed_show_timeout (gpointer data); static GdkFilterReturn message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data); static GSList *dialogs = NULL; /** * csd_delayed_show_dialog: * @dialog: the dialog * * Shows the dialog as with gtk_widget_show(), unless a window manager * hasn't been started yet, in which case it will wait up to 5 seconds * for that to happen before showing the dialog. **/ void csd_delayed_show_dialog (GtkWidget *dialog) { GdkDisplay *display = gtk_widget_get_display (dialog); Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); GdkScreen *screen = gtk_widget_get_screen (dialog); char selection_name[10]; Atom selection_atom; /* We can't use gdk_selection_owner_get() for this, because * it's an unknown out-of-process window. */ snprintf (selection_name, sizeof (selection_name), "WM_S%d", gdk_screen_get_number (screen)); selection_atom = XInternAtom (xdisplay, selection_name, True); if (selection_atom && XGetSelectionOwner (xdisplay, selection_atom) != None) { gtk_widget_show (dialog); return; } dialogs = g_slist_prepend (dialogs, dialog); gdk_window_add_filter (NULL, message_filter, NULL); g_timeout_add (5000, delayed_show_timeout, NULL); } static gboolean delayed_show_timeout (gpointer data) { GSList *l; for (l = dialogs; l; l = l->next) gtk_widget_show (l->data); g_slist_free (dialogs); dialogs = NULL; /* FIXME: There's no gdk_display_remove_client_message_filter */ return FALSE; } static GdkFilterReturn message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XClientMessageEvent *evt; char *selection_name; int screen; GSList *l, *next; if (((XEvent *)xevent)->type != ClientMessage) return GDK_FILTER_CONTINUE; evt = (XClientMessageEvent *)xevent; if (evt->message_type != XInternAtom (evt->display, "MANAGER", FALSE)) return GDK_FILTER_CONTINUE; selection_name = XGetAtomName (evt->display, evt->data.l[1]); if (strncmp (selection_name, "WM_S", 4) != 0) { XFree (selection_name); return GDK_FILTER_CONTINUE; } screen = atoi (selection_name + 4); for (l = dialogs; l; l = next) { GtkWidget *dialog = l->data; next = l->next; if (gdk_screen_get_number (gtk_widget_get_screen (dialog)) == screen) { gtk_widget_show (dialog); dialogs = g_slist_remove (dialogs, dialog); } } if (!dialogs) { gdk_window_remove_filter (NULL, message_filter, NULL); } XFree (selection_name); return GDK_FILTER_CONTINUE; } cinnamon-settings-daemon-4.4.0/plugins/keyboard/delayed-dialog.h000066400000000000000000000016341356401377300247330ustar00rootroot00000000000000/* * Copyright © 2006 Novell, 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __DELAYED_DIALOG_H #define __DELAYED_DIALOG_H #include G_BEGIN_DECLS void csd_delayed_show_dialog (GtkWidget *dialog); G_END_DECLS #endif cinnamon-settings-daemon-4.4.0/plugins/keyboard/gkbd-configuration.c000066400000000000000000000234051356401377300256360ustar00rootroot00000000000000/* * Copyright (C) 2010 Canonical Ltd. * * Authors: Jan Arne Petersen * * Based on gkbd-status.c by Sergey V. Udaltsov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. */ #include #include #include #include #include #include #include "gkbd-configuration.h" struct _GkbdConfigurationPrivate { XklEngine *engine; XklConfigRegistry *registry; GkbdDesktopConfig cfg; GkbdIndicatorConfig ind_cfg; GkbdKeyboardConfig kbd_cfg; gchar **full_group_names; gchar **short_group_names; gulong state_changed_handler; gulong config_changed_handler; }; enum { SIGNAL_CHANGED, SIGNAL_GROUP_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0, }; #define GKBD_CONFIGURATION_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GKBD_TYPE_CONFIGURATION, GkbdConfigurationPrivate)) G_DEFINE_TYPE (GkbdConfiguration, gkbd_configuration, G_TYPE_OBJECT) /* Should be called once for all widgets */ static void gkbd_configuration_cfg_changed (GSettings *settings, const char *key, GkbdConfiguration * configuration) { GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "General configuration changed in GSettings - reiniting...\n"); gkbd_desktop_config_load (&priv->cfg); gkbd_desktop_config_activate (&priv->cfg); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); } /* Should be called once for all widgets */ static void gkbd_configuration_ind_cfg_changed (GSettings *settings, const char *key, GkbdConfiguration * configuration) { GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "Applet configuration changed in GSettings - reiniting...\n"); gkbd_indicator_config_load (&priv->ind_cfg); gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); gkbd_indicator_config_activate (&priv->ind_cfg); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); } static void gkbd_configuration_load_group_names (GkbdConfiguration * configuration, XklConfigRec * xklrec) { GkbdConfigurationPrivate *priv = configuration->priv; if (!gkbd_desktop_config_load_group_descriptions (&priv->cfg, priv->registry, (const char **) xklrec->layouts, (const char **) xklrec->variants, &priv->short_group_names, &priv->full_group_names)) { /* We just populate no short names (remain NULL) - * full names are going to be used anyway */ gint i, total_groups = xkl_engine_get_num_groups (priv->engine); xkl_debug (150, "group descriptions loaded: %d!\n", total_groups); priv->full_group_names = g_new0 (char *, total_groups + 1); if (xkl_engine_get_features (priv->engine) & XKLF_MULTIPLE_LAYOUTS_SUPPORTED) { for (i = 0; priv->kbd_cfg.layouts_variants[i]; i++) { priv->full_group_names[i] = g_strdup ((char *) priv->kbd_cfg.layouts_variants[i]); } } else { for (i = total_groups; --i >= 0;) { priv->full_group_names[i] = g_strdup_printf ("Group %d", i); } } } } /* Should be called once for all widgets */ static void gkbd_configuration_kbd_cfg_callback (XklEngine *engine, GkbdConfiguration *configuration) { GkbdConfigurationPrivate *priv = configuration->priv; XklConfigRec *xklrec = xkl_config_rec_new (); xkl_debug (100, "XKB configuration changed on X Server - reiniting...\n"); gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, xklrec); gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); g_strfreev (priv->full_group_names); priv->full_group_names = NULL; g_strfreev (priv->short_group_names); priv->short_group_names = NULL; gkbd_configuration_load_group_names (configuration, xklrec); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); g_object_unref (G_OBJECT (xklrec)); } /* Should be called once for all applets */ static void gkbd_configuration_state_callback (XklEngine * engine, XklEngineStateChange changeType, gint group, gboolean restore, GkbdConfiguration * configuration) { xkl_debug (150, "group is now %d, restore: %d\n", group, restore); if (changeType == GROUP_CHANGED) { g_signal_emit (configuration, signals[SIGNAL_GROUP_CHANGED], 0, group); } } static void gkbd_configuration_init (GkbdConfiguration *configuration) { GkbdConfigurationPrivate *priv; XklConfigRec *xklrec = xkl_config_rec_new (); priv = GKBD_CONFIGURATION_GET_PRIVATE (configuration); configuration->priv = priv; priv->engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); if (priv->engine == NULL) { xkl_debug (0, "Libxklavier initialization error"); return; } priv->state_changed_handler = g_signal_connect (priv->engine, "X-state-changed", G_CALLBACK (gkbd_configuration_state_callback), configuration); priv->config_changed_handler = g_signal_connect (priv->engine, "X-config-changed", G_CALLBACK (gkbd_configuration_kbd_cfg_callback), configuration); gkbd_desktop_config_init (&priv->cfg, priv->engine); gkbd_keyboard_config_init (&priv->kbd_cfg, priv->engine); gkbd_indicator_config_init (&priv->ind_cfg, priv->engine); gkbd_desktop_config_load (&priv->cfg); gkbd_desktop_config_activate (&priv->cfg); priv->registry = xkl_config_registry_get_instance (priv->engine); xkl_config_registry_load (priv->registry, priv->cfg.load_extra_items); gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, xklrec); gkbd_indicator_config_load (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); gkbd_indicator_config_activate (&priv->ind_cfg); gkbd_configuration_load_group_names (configuration, xklrec); g_object_unref (G_OBJECT (xklrec)); gkbd_desktop_config_start_listen (&priv->cfg, G_CALLBACK (gkbd_configuration_cfg_changed), configuration); gkbd_indicator_config_start_listen (&priv->ind_cfg, G_CALLBACK (gkbd_configuration_ind_cfg_changed), configuration); xkl_engine_start_listen (priv->engine, XKLL_TRACK_KEYBOARD_STATE); xkl_debug (100, "Initiating the widget startup process for %p\n", configuration); } static void gkbd_configuration_finalize (GObject * obj) { GkbdConfiguration *configuration = GKBD_CONFIGURATION (obj); GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "Starting the gnome-kbd-configuration widget shutdown process for %p\n", configuration); xkl_engine_stop_listen (priv->engine, XKLL_TRACK_KEYBOARD_STATE); gkbd_desktop_config_stop_listen (&priv->cfg); gkbd_indicator_config_stop_listen (&priv->ind_cfg); gkbd_indicator_config_term (&priv->ind_cfg); gkbd_keyboard_config_term (&priv->kbd_cfg); gkbd_desktop_config_term (&priv->cfg); if (g_signal_handler_is_connected (priv->engine, priv->state_changed_handler)) { g_signal_handler_disconnect (priv->engine, priv->state_changed_handler); priv->state_changed_handler = 0; } if (g_signal_handler_is_connected (priv->engine, priv->config_changed_handler)) { g_signal_handler_disconnect (priv->engine, priv->config_changed_handler); priv->config_changed_handler = 0; } g_object_unref (priv->registry); priv->registry = NULL; g_object_unref (priv->engine); priv->engine = NULL; G_OBJECT_CLASS (gkbd_configuration_parent_class)->finalize (obj); } static void gkbd_configuration_class_init (GkbdConfigurationClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /* Initing vtable */ object_class->finalize = gkbd_configuration_finalize; /* Signals */ signals[SIGNAL_CHANGED] = g_signal_new ("changed", GKBD_TYPE_CONFIGURATION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[SIGNAL_GROUP_CHANGED] = g_signal_new ("group-changed", GKBD_TYPE_CONFIGURATION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_type_class_add_private (klass, sizeof (GkbdConfigurationPrivate)); } GkbdConfiguration * gkbd_configuration_get (void) { static gpointer instance = NULL; if (!instance) { instance = g_object_new (GKBD_TYPE_CONFIGURATION, NULL); g_object_add_weak_pointer (instance, &instance); } else { g_object_ref (instance); } return instance; } XklEngine * gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration) { return configuration->priv->engine; } const char * const * gkbd_configuration_get_group_names (GkbdConfiguration *configuration) { return configuration->priv->full_group_names; } const char * const * gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration) { return configuration->priv->short_group_names; } cinnamon-settings-daemon-4.4.0/plugins/keyboard/gkbd-configuration.h000066400000000000000000000046451356401377300256500ustar00rootroot00000000000000/* * Copyright (C) 2010 Canonical Ltd. * * Authors: Jan Arne Petersen * * Based on gkbd-status.h by Sergey V. Udaltsov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. */ #ifndef __GKBD_CONFIGURATION_H__ #define __GKBD_CONFIGURATION_H__ #include #include G_BEGIN_DECLS typedef struct _GkbdConfiguration GkbdConfiguration; typedef struct _GkbdConfigurationPrivate GkbdConfigurationPrivate; typedef struct _GkbdConfigurationClass GkbdConfigurationClass; #define GKBD_TYPE_CONFIGURATION (gkbd_configuration_get_type ()) #define GKBD_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfiguration)) #define GKBD_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) #define GKBD_IS_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) #define GKBD_IS_CONFIGURATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) #define GKBD_CONFIGURATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) struct _GkbdConfiguration { GObject parent; GkbdConfigurationPrivate *priv; }; struct _GkbdConfigurationClass { GObjectClass parent_class; }; extern GType gkbd_configuration_get_type (void); extern GkbdConfiguration *gkbd_configuration_get (void); extern XklEngine *gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration); extern const char * const *gkbd_configuration_get_group_names (GkbdConfiguration *configuration); extern const char * const *gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration); G_END_DECLS #endif cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-capslock-off.png000066400000000000000000000031621356401377300255270ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsnNtEXtSoftwarewww.inkscape.org<IDATxME5|.DM#H(W<9p OzGA=iL< D$ Q? +]I0ay蚥fv&;dW .iْf>m(6d x vUD`p t- ǁ;%P@еpor\NIPPX*NKz?N~3 SC xhvC fފ,Gqh?o~`A9IY00@"ۀ]uO+g嬅]@[,6`w v"*Y5|%bK'5YY`Nrc} !ۜ@2ۇ&n`jrj}1Hڧs>;یa!IN ȹLݾp 5,|&z:M|P~|GS{dJ*5)Z,m0 (D_ᑬx qP>>)Q듂B{!n_D=Bөwd^ 8Tkq[al[b])8_I:KRC6zf`s% ,I9cΔ/1IrE@gf?g 6@c$7p0 ޛ"ic~ ج$gzewdIUdD?zXH6S[=Ƙ}9{ 6#r+qPn69U2֑-d(Iz(FP 9sՓpD'8'x$-l6 6 K|џ>N6 >u^!H4@G޵0WңL-cNCյ}! IY4)IE3+po*e,t*+9$̃9m5/d; }Ǟ,ǵ1r7&I ȗ3hwo3">H "I LkqK޳|r;w:v.f)f maO,d^4͹,1U4fmg JbvWVJlt``#?< ຣ30.ӎ=|ػ j{ܙB7t4vXKaM@a.]D@iJDc'Ocz5ֺer΀rOh@-],mZ\#_hWfd|i*ksK%)in ͝1:qAZCx+]zIzgJOBYjۦI1V ! W[PrO$%|/P@ٞsh$JҼ>NajjLjLIENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-capslock-on.png000066400000000000000000000027201356401377300253700ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYsnNtIME:=PIDATxKhE{#4YSZ|!u!nJk(iDtck] ҅(E4ޒB >jF%!M VHLdr{M3g93"#P 40q`0ӬGN`iR`!/_ԅ^+pH\ڜa$xZKr{IO%8۴3q|Bu \S0PQo1Rw 䁻y9+P,[`h@[`z 4+WD9 fC#۪p,/ tq vQ)|_z|xWÃ[%dZK`n5ckGJ(i2Ljʥ5n=hD͒<R^E綃d f ; @WsGآ 04Lv<&Sc)- `*ףɴ YL0,+0nIrd=Ydei!n1Y[@ 8qSmeN#Cn'dnP <2f. VY@1ǜ(T>W4h1`SfmZ῱yt ,w ~_F`tx둟eӽ2\9*8^ *!bs&00Č,uIh:ogMJ' ][bÚGVk r}Pw! ";*1iUIG U Io WQT7J0r\{,ֹ@( |ؙ$p\8y @ҍ/P@)}1qh#jvI^1 -q'HL r,62er_ 9Smj<"Id{L.K<^>%-{Tv!/Җ„:'N(KSB/M%6 l絹 3)\R&/ stTSO8`*K598C[{vT ql/SU_BcoN|H0IENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-numlock-off.png000066400000000000000000000033161356401377300254010ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsnNtEXtSoftwarewww.inkscape.org<KIDATx[VU6b7g}g{8笵ko}Y{*4GdI㍟$&I{scte6lnt\E VAg 8 Fx(*b36H^%|ץcBM%QN~%S`0 ]щD=]lBj[;̎c1g)>fVf‘CEщYpfa#0$`sU` F *$W3|mon0|)$>YlLր9$?[SɁ|7FzY'`/rRB:XcžR c*p0k&!#Jw1KVZ8Gɐ|ׇ#iNr&3W38x0]o~8(a:6z%{ -F|(>*A!~,/RISTg@-ToԙJs+]?J9uGzm]́L4[ p9O0K{XҨ޴$1fUԳ{alUm- Bވ8.c8$OݺM[@q~ PM|"r9I`uoJPS3b**YBEp}̓Խv48-wNh|AE7bIUm+Z SoVU 2ދHd$e܋VH:4Jz_~ 3DR)2{@5Hkkpm % HIw/sIpOJ]wyGa4Is$z)ԭSι'Z G ss0]+m+>1{4G; 'D*tZ mi+e;%؞E0Ob- l>^-@:Ou/c'>XIq~b0[ ` ?l 0Ep lbhV Ֆ୉!r/b]~Qkr.PX$ IKLhs/pJ߈J:;v_Aұ/Wse: lr<@_y`xH,]]$er)0`^Q(2>xKe], rDd&@hj7n~67O] R 1?k9 oaof|Yo>V3Ktrщ/\ >Ǹ؂] Z*T)K]cn+Tg?|wU&IENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-numlock-on.png000066400000000000000000000030671356401377300252460ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYsnNtIMEPLIDATxmhUu9 m±ޖl}^VNiїJCQ"(KA&RӈF\&Wr,Zlmm>ܳ|8?><׻<ߞso<"n%@(W:@\#qYlM`@!IɰO .PL]A}VN\b<&*p)e-f`Pƴqkc鄒4`^'R7ğ%^4R3v;1l1_/p%A=meX=)p^ZkɬFk M@K`D^e._n8CmhhDI50Íu%aE MPxV'Ц)tU\dpLPo&ǛN8ھEҌbԬaLˏEw+|Mj prb+$A`uD~,m P(0LhqDPKG.PHܩ p*d?(C!hNmw:4 L(\ P6Zi=8c .3*^ƍ H=+)Rj x0`Jϭ:@vJ&́;oI}Gs7O%U~xc m` cNXr $Fb5K8﷞`6ļAaGhU#<r0{qt.)up<r5km(4S&qrfwJi<U9޽ʻ[ϦXIyr KoxMl 0{~B;xxW"H.T\3&FGHT4oG*vGk'sʆbھpɽS< t,'.o%:EqDԑ/>`FQ%}poX BxpD"Vn+[ǀ ʇfn\k~Gp5F" 3\j WApd |Ϣ#ZBPQ#S%B<7%tSbv*yR7 <#P&*S)W]k:QZ[Ui紫4Q(HG:`KhLy~ (JkGcė [O-8C@mȄfREg<8E[c}zi`Լ@.h `)$ -BI-5X',WtB]PC~^\4՛i ksM;;k. =8z#͐'% L>df"`zsvJ'5j끀Jа}dE bhUw}GI8n. !IENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-scrolllock-off.png000066400000000000000000000026731356401377300261050ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsnNtEXtSoftwarewww.inkscape.org<8IDATxkUGǿ"F4"RЊJK6BnSM?@hiu!Db? آ.]"j(i\(qc]SlJtq癛s_˛y/ 9sΝ;wZ$O^IIssm pX`X_ۯq` <.{[t^}@Z]wIN ]֏ -蚐snFxR+0н߷+ewM Zz]ÛpBXʘ^J@GDϑ7qp8ߞnϙ@S(&`(h h {9Ƕ A(gTk_ *Qh CڼM6&ր8؇e@_{/ 3T2OڰDŽ*^&€{:|`xb40w{>gDIؓxCW=Yh 3<`/k EznßWXx4QZF6 jzmuw$?X*I˙]Js'#Ӓv4YTF'Ӵa?g"BdFAOK m{śͱx^"Kb|T42< @KAɦEv&S`fIӒJA#_J()tz+S|+ȜgAkSiL4Fnbd)a+sι#l\7&)hԀB=AQoz޾`CZ(cJ<ާlI:gkcp70i45v=m[cF $)7)=Gh~ wC(8I%(к~k{8g/ . +fxuȌT-K)5{P2qKe=AcK{-҈&2F4Q[<4Usab!=t9K2aA:)zmnI>Ifn[)VH9/m_lLWyROI%K%iv@?rIENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/kbd-scrolllock-on.png000066400000000000000000000024711356401377300257430ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYsnNtIME)zIDATxkTW?o#qDPl ĝBlڐvZB$[Хk.ϡJ"EQ$Cmi)͹3o2<<;sν{~G>( `Iiy_ x% ln |#p0B8#0+ }}y PX48)PhMG~[Nu6^J L NA{;-ЛCϚ0TR'^UnL`ZR!hk, \lX`4%80}\RiКdkg6D FpaNj:By@_"}'Fy =9,&NKc6Q>I T&]'"xxQо, E$jANe[IpO jOe8(`Uk3Z.ĔPsin-5F |Erԅ_0 %GK߳HJPa4æ)p" W]Dఁ2) }q4}%2Vtv#ֹer1[(#޹cJry&tޅ ew+3sB.MU6ziks'Z-䵹~m(r^|'\Yo<.pEjB\1i+:sW[)!VڊX:JT.+>OY>% -u"IENDB`cinnamon-settings-daemon-4.4.0/plugins/keyboard/main.c000066400000000000000000000010241356401377300227770ustar00rootroot00000000000000#define NEW csd_keyboard_manager_new #define START csd_keyboard_manager_start #define STOP csd_keyboard_manager_stop #define MANAGER CsdKeyboardManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-keyboard-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/media-keys/000077500000000000000000000000001356401377300221425ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/media-keys/Makefile.am000066400000000000000000000034721356401377300242040ustar00rootroot00000000000000icondir = $(datadir)/icons/hicolor context = actions plugin_name = media-keys NULL = SUBDIRS = AM_CFLAGS = $(WARN_CFLAGS) BUILT_SOURCES = \ csd-marshal.h \ csd-marshal.c \ $(NULL) csd-marshal.c: csd-marshal.list $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=csd_marshal $< --header --body --internal > $@ csd-marshal.h: csd-marshal.list $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=csd_marshal $< --header --internal > $@ libexec_PROGRAMS = csd-media-keys csd_media_keys_SOURCES = \ csd-media-keys-manager.c \ csd-media-keys-manager.h \ bus-watch-namespace.c \ bus-watch-namespace.h \ mpris-controller.c \ mpris-controller.h \ main.c \ $(BUILT_SOURCES) \ $(NULL) csd_media_keys_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_media_keys_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MEDIA_KEYS_CFLAGS) \ $(AM_CFLAGS) csd_media_keys_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(MEDIA_KEYS_LIBS) \ -lm desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-media-keys.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-media-keys.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ csd-marshal.list \ README.media-keys-API \ $(desktop_in_files) CLEANFILES = \ $(BUILT_SOURCES) \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/media-keys/README.media-keys-API000066400000000000000000000034711356401377300254650ustar00rootroot00000000000000This is very simple documentation to cinnamon-settings-daemon's D-Bus API for media players. cinnamon-settings-daemon will send key press events from multimedia keys to applications that register their interest in those events. This allows the play/pause button to control an audio player that's not focused for example. The D-Bus API is described in csd-media-keys-manager.c (look for introspection_xml), but a small explanation follows here. 1. Create yourself a proxy object for the remote interface: Object path: /org/gnome/SettingsDaemon/MediaKeys D-Bus name: org.gnome.SettingsDaemon.MediaKeys Interface name: org.gnome.SettingsDaemon.MediaKeys 2. Register your application with cinnamon-settings-daemon GrabMediaPlayerKeys ("my-application", 0) with the second argument being the current time (usually 0, or the time passed to you from an event, such as a mouse click) 3. Listen to the MediaPlayerKeyPressed() signal 4. When receiving a MediaPlayerKeyPressed() signal, check whether the first argument (application) matches the value you passed to GrabMediaPlayerKeys() and apply the action depending on the key (2nd argument) Possible values of key are: - Play - Pause - Stop - Previous - Next - Rewind - FastForward - Repeat - Shuffle 5. Every time your application is focused, you should call GrabMediaPlayerKeys() again, so that cinnamon-settings-daemon knows which one was last used. This allows switching between a movie player and a music player, for example, and have the buttons control the last used application. 6. When your application wants to stop using the functionality it can call ReleaseMediaPlayerKeys(). If your application does not call ReleaseMediaPlayerKeys() and releases its D-Bus connection then the application will be automatically removed from the list of applications held by cinnamon-settings-daemon. cinnamon-settings-daemon-4.4.0/plugins/media-keys/bus-watch-namespace.c000066400000000000000000000254501356401377300261430ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Lars Uebernickel */ #include "config.h" #include #include #include "bus-watch-namespace.h" typedef struct { guint id; gchar *name_space; GBusNameAppearedCallback appeared_handler; GBusNameVanishedCallback vanished_handler; gpointer user_data; GDestroyNotify user_data_destroy; GDBusConnection *connection; GCancellable *cancellable; GHashTable *names; guint subscription_id; } NamespaceWatcher; typedef struct { NamespaceWatcher *watcher; gchar *name; } GetNameOwnerData; static guint namespace_watcher_next_id; static GHashTable *namespace_watcher_watchers; static void namespace_watcher_stop (gpointer data) { NamespaceWatcher *watcher = data; g_cancellable_cancel (watcher->cancellable); g_object_unref (watcher->cancellable); if (watcher->subscription_id) g_dbus_connection_signal_unsubscribe (watcher->connection, watcher->subscription_id); if (watcher->vanished_handler) { GHashTableIter it; const gchar *name; g_hash_table_iter_init (&it, watcher->names); while (g_hash_table_iter_next (&it, (gpointer *) &name, NULL)) watcher->vanished_handler (watcher->connection, name, watcher->user_data); } if (watcher->user_data_destroy) watcher->user_data_destroy (watcher->user_data); if (watcher->connection) { g_signal_handlers_disconnect_by_func (watcher->connection, namespace_watcher_stop, watcher); g_object_unref (watcher->connection); } g_hash_table_unref (watcher->names); g_hash_table_remove (namespace_watcher_watchers, GUINT_TO_POINTER (watcher->id)); if (g_hash_table_size (namespace_watcher_watchers) == 0) g_clear_pointer (&namespace_watcher_watchers, g_hash_table_destroy); g_free (watcher); } static void namespace_watcher_name_appeared (NamespaceWatcher *watcher, const gchar *name, const gchar *owner) { /* There's a race between NameOwnerChanged signals arriving and the * ListNames/GetNameOwner sequence returning, so this function might * be called more than once for the same name. To ensure that * appeared_handler is only called once for each name, it is only * called when inserting the name into watcher->names (each name is * only inserted once there). */ if (g_hash_table_contains (watcher->names, name)) return; g_hash_table_add (watcher->names, g_strdup (name)); if (watcher->appeared_handler) watcher->appeared_handler (watcher->connection, name, owner, watcher->user_data); } static void namespace_watcher_name_vanished (NamespaceWatcher *watcher, const gchar *name) { if (g_hash_table_remove (watcher->names, name) && watcher->vanished_handler) watcher->vanished_handler (watcher->connection, name, watcher->user_data); } static gboolean dbus_name_has_namespace (const gchar *name, const gchar *name_space) { gint len_name; gint len_namespace; len_name = strlen (name); len_namespace = strlen (name_space); if (len_name < len_namespace) return FALSE; if (memcmp (name_space, name, len_namespace) != 0) return FALSE; return len_namespace == len_name || name[len_namespace] == '.'; } static void name_owner_changed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { NamespaceWatcher *watcher = user_data; const gchar *name; const gchar *old_owner; const gchar *new_owner; g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner); if (old_owner[0] != '\0') namespace_watcher_name_vanished (watcher, name); if (new_owner[0] != '\0') namespace_watcher_name_appeared (watcher, name, new_owner); } static void got_name_owner (GObject *object, GAsyncResult *result, gpointer user_data) { GetNameOwnerData *data = user_data; GError *error = NULL; GVariant *reply; const gchar *owner; reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); goto out; } if (reply == NULL) { if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) g_warning ("bus_watch_namespace: error calling org.freedesktop.DBus.GetNameOwner: %s", error->message); g_error_free (error); goto out; } g_variant_get (reply, "(&s)", &owner); namespace_watcher_name_appeared (data->watcher, data->name, owner); g_variant_unref (reply); out: g_free (data->name); g_slice_free (GetNameOwnerData, data); } static void names_listed (GObject *object, GAsyncResult *result, gpointer user_data) { NamespaceWatcher *watcher; GError *error = NULL; GVariant *reply; GVariantIter *iter; const gchar *name; reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } watcher = user_data; if (reply == NULL) { g_warning ("bus_watch_namespace: error calling org.freedesktop.DBus.ListNames: %s", error->message); g_error_free (error); return; } g_variant_get (reply, "(as)", &iter); while (g_variant_iter_next (iter, "&s", &name)) { if (dbus_name_has_namespace (name, watcher->name_space)) { GetNameOwnerData *data = g_slice_new (GetNameOwnerData); data->watcher = watcher; data->name = g_strdup (name); g_dbus_connection_call (watcher->connection, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner", g_variant_new ("(s)", name), G_VARIANT_TYPE ("(s)"), G_DBUS_CALL_FLAGS_NONE, -1, watcher->cancellable, got_name_owner, data); } } g_variant_iter_free (iter); g_variant_unref (reply); } static void connection_closed (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data) { NamespaceWatcher *watcher = user_data; namespace_watcher_stop (watcher); } static void got_bus (GObject *object, GAsyncResult *result, gpointer user_data) { GDBusConnection *connection; NamespaceWatcher *watcher; GError *error = NULL; connection = g_bus_get_finish (result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } watcher = user_data; if (connection == NULL) { namespace_watcher_stop (watcher); return; } watcher->connection = connection; g_signal_connect (watcher->connection, "closed", G_CALLBACK (connection_closed), watcher); #ifdef HAVE_NEW_GLIB // G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE is only available since Glib 2.38, LMDE uses 2.36 so we test the version of Glib here. watcher->subscription_id = g_dbus_connection_signal_subscribe (watcher->connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus", watcher->name_space, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, name_owner_changed, watcher, NULL); #endif /* HAVE_NEW_GLIB */ g_dbus_connection_call (watcher->connection, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames", NULL, G_VARIANT_TYPE ("(as)"), G_DBUS_CALL_FLAGS_NONE, -1, watcher->cancellable, names_listed, watcher); } guint bus_watch_namespace (GBusType bus_type, const gchar *name_space, GBusNameAppearedCallback appeared_handler, GBusNameVanishedCallback vanished_handler, gpointer user_data, GDestroyNotify user_data_destroy) { NamespaceWatcher *watcher; /* same rules for interfaces and well-known names */ g_return_val_if_fail (name_space != NULL && g_dbus_is_interface_name (name_space), 0); g_return_val_if_fail (appeared_handler || vanished_handler, 0); watcher = g_new0 (NamespaceWatcher, 1); watcher->id = namespace_watcher_next_id++; watcher->name_space = g_strdup (name_space); watcher->appeared_handler = appeared_handler; watcher->vanished_handler = vanished_handler; watcher->user_data = user_data; watcher->user_data_destroy = user_data_destroy; watcher->cancellable = g_cancellable_new ();; watcher->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (namespace_watcher_watchers == NULL) namespace_watcher_watchers = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (namespace_watcher_watchers, GUINT_TO_POINTER (watcher->id), watcher); g_bus_get (bus_type, watcher->cancellable, got_bus, watcher); return watcher->id; } void bus_unwatch_namespace (guint id) { /* namespace_watcher_stop() might have already removed the watcher * with @id in the case of a connection error. Thus, this function * doesn't warn when @id is absent from the hash table. */ if (namespace_watcher_watchers) { NamespaceWatcher *watcher; watcher = g_hash_table_lookup (namespace_watcher_watchers, GUINT_TO_POINTER (id)); if (watcher) { /* make sure vanished() is not called as a result of this function */ g_hash_table_remove_all (watcher->names); namespace_watcher_stop (watcher); } } } cinnamon-settings-daemon-4.4.0/plugins/media-keys/bus-watch-namespace.h000066400000000000000000000026121356401377300261430ustar00rootroot00000000000000/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Lars Uebernickel */ #ifndef __BUS_WATCH_NAMESPACE_H__ #define __BUS_WATCH_NAMESPACE_H__ #include guint bus_watch_namespace (GBusType bus_type, const gchar *name_space, GBusNameAppearedCallback appeared_handler, GBusNameVanishedCallback vanished_handler, gpointer user_data, GDestroyNotify user_data_destroy); void bus_unwatch_namespace (guint id); #endif cinnamon-settings-daemon-4.4.0/plugins/media-keys/cinnamon-settings-daemon-media-keys.desktop.in000066400000000000000000000003611356401377300330710ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - media-keys Exec=@libexecdir@/csd-media-keys OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/media-keys/csd-marshal.c000066400000000000000000000111411356401377300245020ustar00rootroot00000000000000 #ifndef __csd_marshal_MARSHAL_H__ #define __csd_marshal_MARSHAL_H__ #include G_BEGIN_DECLS #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_schar (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #define g_marshal_value_peek_variant(v) g_value_get_variant (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* VOID:STRING,STRING (csd-marshal.list:1) */ G_GNUC_INTERNAL void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2); GMarshalFunc_VOID__STRING_STRING callback; GCClosure *cc = (GCClosure*) closure; gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_string (param_values + 1), g_marshal_value_peek_string (param_values + 2), data2); } G_END_DECLS #endif /* __csd_marshal_MARSHAL_H__ */ cinnamon-settings-daemon-4.4.0/plugins/media-keys/csd-marshal.h000066400000000000000000000013001356401377300245030ustar00rootroot00000000000000 #ifndef __csd_marshal_MARSHAL_H__ #define __csd_marshal_MARSHAL_H__ #include G_BEGIN_DECLS /* VOID:STRING,STRING (csd-marshal.list:1) */ G_GNUC_INTERNAL void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); G_END_DECLS #endif /* __csd_marshal_MARSHAL_H__ */ cinnamon-settings-daemon-4.4.0/plugins/media-keys/csd-marshal.list000066400000000000000000000000231356401377300252300ustar00rootroot00000000000000VOID:STRING,STRING cinnamon-settings-daemon-4.4.0/plugins/media-keys/csd-media-keys-manager.c000066400000000000000000002426261356401377300265310ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2001-2003 Bastien Nocera * Copyright (C) 2006-2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GUDEV #include #endif #include "mpris-controller.h" #include "cinnamon-settings-profile.h" #include "csd-marshal.h" #include "csd-media-keys-manager.h" #include "csd-power-helper.h" #include "csd-input-helper.h" #include "csd-enums.h" #include #include #include #include /* For media keys, we need to keep using org.gnome because that's what apps are looking for */ #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" #define CSD_MEDIA_KEYS_DBUS_PATH "/org/gnome/SettingsDaemon/MediaKeys" #define CSD_MEDIA_KEYS_DBUS_NAME "org.gnome.SettingsDaemon.MediaKeys" #define CINNAMON_KEYBINDINGS_PATH "/org/cinnamon/SettingsDaemon/KeybindingHandler" #define CINNAMON_KEYBINDINGS_NAME "org.cinnamon.SettingsDaemon.KeybindingHandler" #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" #define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring" #define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon" #define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon" #define OSD_ALL_OUTPUTS -1 static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const gchar kb_introspection_xml[] = "" " " " " " " " " " " " " ""; #define SETTINGS_INTERFACE_DIR "org.cinnamon.desktop.interface" #define SETTINGS_POWER_DIR "org.cinnamon.settings-daemon.plugins.power" #define SETTINGS_XSETTINGS_DIR "org.cinnamon.settings-daemon.plugins.xsettings" #define SETTINGS_TOUCHPAD_DIR "org.cinnamon.settings-daemon.peripherals.touchpad" #define TOUCHPAD_ENABLED_KEY "touchpad-enabled" #define HIGH_CONTRAST "HighContrast" #define VOLUME_STEP 5 /* percents for one volume button press */ #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerPrivate)) typedef struct { char *application; char *name; guint32 time; guint watch_id; } MediaPlayer; struct CsdMediaKeysManagerPrivate { /* dbus owned names */ guint name_id; guint gnome_name_id; /* Volume bits */ GvcMixerControl *volume; GvcMixerStream *stream; GvcMixerStream *source_stream; /* Microphone */ ca_context *ca; #ifdef HAVE_GUDEV GHashTable *streams; /* key = X device ID, value = stream id */ GUdevClient *udev_client; #endif /* HAVE_GUDEV */ GtkWidget *dialog; /* HighContrast theme settings */ GSettings *interface_settings; char *icon_theme; char *gtk_theme; /* Power stuff */ GSettings *power_settings; GDBusProxy *upower_proxy; GDBusProxy *power_screen_proxy; GDBusProxy *power_keyboard_proxy; /* OSD stuff */ GDBusProxy *cinnamon_proxy; GCancellable *cinnamon_cancellable; /* logind stuff */ GDBusProxy *logind_proxy; gint inhibit_keys_fd; GSettings *desktop_session_settings; GSettings *cinnamon_session_settings; /* Multihead stuff */ GdkScreen *current_screen; GSList *screens; int opcode; GList *media_players; GDBusNodeInfo *introspection_data; GDBusNodeInfo *kb_introspection_data; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusProxy *xrandr_proxy; GCancellable *cancellable; guint start_idle_id; MprisController *mpris_controller; /* Ubuntu notifications */ NotifyNotification *volume_notification; NotifyNotification *brightness_notification; NotifyNotification *kb_backlight_notification; }; static void csd_media_keys_manager_finalize (GObject *object); static void register_manager (CsdMediaKeysManager *manager); static gboolean do_action (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp); G_DEFINE_TYPE (CsdMediaKeysManager, csd_media_keys_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define NOTIFY_CAP_PRIVATE_SYNCHRONOUS "x-canonical-private-synchronous" #define NOTIFY_CAP_PRIVATE_ICON_ONLY "x-canonical-private-icon-only" #define NOTIFY_HINT_TRUE "true" typedef struct { CsdMediaKeysManager *manager; CDesktopMediaKeyType type; guint old_percentage; } CsdBrightnessActionData; static void init_screens (CsdMediaKeysManager *manager) { GdkDisplay *display; int i; display = gdk_display_get_default (); for (i = 0; i < gdk_display_get_n_screens (display); i++) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); if (screen == NULL) { continue; } manager->priv->screens = g_slist_append (manager->priv->screens, screen); } manager->priv->current_screen = manager->priv->screens->data; } static char * get_term_command (CsdMediaKeysManager *manager) { char *cmd_term, *cmd_args;; char *cmd = NULL; GSettings *settings; settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal"); cmd_term = g_settings_get_string (settings, "exec"); if (cmd_term[0] == '\0') cmd_term = g_strdup ("gnome-terminal"); cmd_args = g_settings_get_string (settings, "exec-arg"); if (strcmp (cmd_term, "") != 0) { cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args); } else { cmd = g_strdup_printf ("%s -e", cmd_term); } g_free (cmd_args); g_free (cmd_term); g_object_unref (settings); return cmd; } static char ** get_keyring_env (CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant, *item; GVariantIter *iter; char **envp; variant = g_dbus_connection_call_sync (manager->priv->connection, GNOME_KEYRING_DBUS_NAME, GNOME_KEYRING_DBUS_PATH, GNOME_KEYRING_DBUS_INTERFACE, "GetEnvironment", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message); g_error_free (error); return NULL; } envp = g_get_environ (); g_variant_get (variant, "(a{ss})", &iter); while ((item = g_variant_iter_next_value (iter))) { char *key; char *value; g_variant_get (item, "{ss}", &key, &value); envp = g_environ_setenv (envp, key, value, TRUE); g_variant_unref (item); g_free (key); g_free (value); } g_variant_iter_free (iter); g_variant_unref (variant); return envp; } static void execute (CsdMediaKeysManager *manager, char *cmd, gboolean need_term) { gboolean retval; char **argv; int argc; char *exec; char *term = NULL; GError *error = NULL; retval = FALSE; if (need_term) term = get_term_command (manager); if (term) { exec = g_strdup_printf ("%s %s", term, cmd); g_free (term); } else { exec = g_strdup (cmd); } if (g_shell_parse_argv (exec, &argc, &argv, NULL)) { char **envp; envp = get_keyring_env (manager); retval = g_spawn_async (g_get_home_dir (), argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); g_strfreev (argv); g_strfreev (envp); } if (retval == FALSE && error != NULL) { g_warning ("Couldn't execute command: %s: %s", exec, error->message); g_error_free (error); } g_free (exec); } static void ensure_cancellable (GCancellable **cancellable) { if (*cancellable == NULL) { *cancellable = g_cancellable_new (); g_object_add_weak_pointer (G_OBJECT (*cancellable), (gpointer *)cancellable); } else { g_object_ref (*cancellable); } } static void cinnamon_proxy_complete (GObject *source, GAsyncResult *result, gpointer data) { CsdMediaKeysManager *manager = data; g_object_unref (manager->priv->cinnamon_cancellable); } static void show_osd (CsdMediaKeysManager *manager, const char *icon, int level, int monitor) { GVariantBuilder builder; if (manager->priv->connection == NULL || manager->priv->cinnamon_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle osd"); return; } g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT); if (icon) g_variant_builder_add (&builder, "{sv}", "icon", g_variant_new_string (icon)); if (level >= 0) g_variant_builder_add (&builder, "{sv}", "level", g_variant_new_int32 (level)); if (monitor >= 0) g_variant_builder_add (&builder, "{sv}", "monitor", g_variant_new_int32 (monitor)); g_variant_builder_close (&builder); ensure_cancellable (&manager->priv->cinnamon_cancellable); g_dbus_proxy_call (manager->priv->cinnamon_proxy, "ShowOSD", g_variant_builder_end (&builder), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, manager->priv->cinnamon_cancellable, cinnamon_proxy_complete, manager); } static const char * get_icon_name_for_volume (gboolean muted, int volume, gboolean is_mic) { static const char *icon_names[] = { "audio-volume-muted-symbolic", "audio-volume-low-symbolic", "audio-volume-medium-symbolic", "audio-volume-high-symbolic", "microphone-sensitivity-muted-symbolic", "microphone-sensitivity-low-symbolic", "microphone-sensitivity-medium-symbolic", "microphone-sensitivity-high-symbolic", NULL }; int n; if (muted) { n = 0; } else { n = 3 * volume / 100 + 1; if (n < 1) { n = 1; } else if (n > 3) { n = 3; } } if (is_mic) { n += 4; } return icon_names[n]; } static void launch_app (GAppInfo *app_info, gint64 timestamp) { GError *error = NULL; GdkAppLaunchContext *launch_context; /* setup the launch context so the startup notification is correct */ launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ()); gdk_app_launch_context_set_timestamp (launch_context, timestamp); if (!g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error)) { g_warning ("Could not launch '%s': %s", g_app_info_get_commandline (app_info), error->message); g_error_free (error); } g_object_unref (launch_context); } static void do_url_action (CsdMediaKeysManager *manager, const char *scheme, gint64 timestamp) { GAppInfo *app_info; app_info = g_app_info_get_default_for_uri_scheme (scheme); if (app_info != NULL) { launch_app (app_info, timestamp); g_object_unref (app_info); } else { g_warning ("Could not find default application for '%s' scheme", scheme); } } static void do_media_action (CsdMediaKeysManager *manager, gint64 timestamp) { GAppInfo *app_info; app_info = g_app_info_get_default_for_type ("audio/x-vorbis+ogg", FALSE); if (app_info != NULL) { launch_app (app_info, timestamp); g_object_unref (app_info); } else { g_warning ("Could not find default application for '%s' mime-type", "audio/x-vorbis+ogg"); } } static void do_terminal_action (CsdMediaKeysManager *manager) { GSettings *settings; char *term; settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal"); term = g_settings_get_string (settings, "exec"); if (term) execute (manager, term, FALSE); g_free (term); g_object_unref (settings); } static void do_calculator_action (CsdMediaKeysManager *manager) { GSettings *settings; char *calc; settings = g_settings_new ("org.cinnamon.desktop.default-applications.calculator"); calc = g_settings_get_string (settings, "exec"); if (calc) execute (manager, calc, FALSE); g_free (calc); g_object_unref (settings); } static void cinnamon_session_shutdown (CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant; /* Shouldn't happen, but you never know */ if (manager->priv->connection == NULL) { execute (manager, "cinnamon-session-quit --logout", FALSE); return; } variant = g_dbus_connection_call_sync (manager->priv->connection, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, "Shutdown", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_warning ("Failed to call Shutdown on session manager: %s", error->message); g_error_free (error); return; } g_variant_unref (variant); } static void do_logout_action (CsdMediaKeysManager *manager) { execute (manager, "cinnamon-session-quit --logout", FALSE); } static void do_eject_action_cb (GDrive *drive, GAsyncResult *res, CsdMediaKeysManager *manager) { g_drive_eject_with_operation_finish (drive, res, NULL); } #define NO_SCORE 0 #define SCORE_CAN_EJECT 50 #define SCORE_HAS_MEDIA 100 static void do_eject_action (CsdMediaKeysManager *manager) { GList *drives, *l; GDrive *fav_drive; guint score; GVolumeMonitor *volume_monitor; volume_monitor = g_volume_monitor_get (); /* Find the best drive to eject */ fav_drive = NULL; score = NO_SCORE; drives = g_volume_monitor_get_connected_drives (volume_monitor); for (l = drives; l != NULL; l = l->next) { GDrive *drive = l->data; if (g_drive_can_eject (drive) == FALSE) continue; if (g_drive_is_media_removable (drive) == FALSE) continue; if (score < SCORE_CAN_EJECT) { fav_drive = drive; score = SCORE_CAN_EJECT; } if (g_drive_has_media (drive) == FALSE) continue; if (score < SCORE_HAS_MEDIA) { fav_drive = drive; score = SCORE_HAS_MEDIA; break; } } /* Show the dialogue */ show_osd (manager, "media-eject-symbolic", -1, OSD_ALL_OUTPUTS); /* Clean up the drive selection and exit if no suitable * drives are found */ if (fav_drive != NULL) fav_drive = g_object_ref (fav_drive); g_list_foreach (drives, (GFunc) g_object_unref, NULL); if (fav_drive == NULL) return; /* Eject! */ g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE, NULL, NULL, (GAsyncReadyCallback) do_eject_action_cb, manager); g_object_unref (fav_drive); g_object_unref (volume_monitor); } static void do_home_key_action (CsdMediaKeysManager *manager, gint64 timestamp) { GFile *file; GError *error = NULL; char *uri; file = g_file_new_for_path (g_get_home_dir ()); uri = g_file_get_uri (file); g_object_unref (file); if (gtk_show_uri (NULL, uri, timestamp, &error) == FALSE) { g_warning ("Failed to launch '%s': %s", uri, error->message); g_error_free (error); } g_free (uri); } static void do_execute_desktop (CsdMediaKeysManager *manager, const char *desktop, gint64 timestamp) { GDesktopAppInfo *app_info; app_info = g_desktop_app_info_new (desktop); if (app_info != NULL) { launch_app (G_APP_INFO (app_info), timestamp); g_object_unref (app_info); } else { g_warning ("Could not find application '%s'", desktop); } } static void do_touchpad_osd_action (CsdMediaKeysManager *manager, gboolean state) { show_osd (manager, state ? "input-touchpad-symbolic" : "touchpad-disabled-symbolic", -1, OSD_ALL_OUTPUTS); } static void do_touchpad_action (CsdMediaKeysManager *manager) { GSettings *settings; gboolean state; if (touchpad_is_present () == FALSE) { do_touchpad_osd_action (manager, FALSE); return; } settings = g_settings_new (SETTINGS_TOUCHPAD_DIR); state = g_settings_get_boolean (settings, TOUCHPAD_ENABLED_KEY); do_touchpad_osd_action (manager, !state); g_settings_set_boolean (settings, TOUCHPAD_ENABLED_KEY, !state); g_object_unref (settings); } static void show_sound_osd (CsdMediaKeysManager *manager, GvcMixerStream *stream, gboolean is_mic, gint vol, gint max_vol, gboolean muted, gboolean sound_changed, gboolean quiet) { const char *icon; vol = CLAMP (vol, 0, max_vol); icon = get_icon_name_for_volume (muted, vol, is_mic); show_osd (manager, icon, vol, OSD_ALL_OUTPUTS); if (quiet == FALSE && sound_changed != FALSE && muted == FALSE) { GSettings *settings = g_settings_new ("org.cinnamon.desktop.sound"); gboolean enabled = g_settings_get_boolean (settings, "volume-sound-enabled"); char *sound = g_settings_get_string (settings, "volume-sound-file"); if (enabled) { ca_context_change_device (manager->priv->ca, gvc_mixer_stream_get_name (stream)); ca_context_play (manager->priv->ca, 1, CA_PROP_MEDIA_FILENAME, sound, NULL); } g_free(sound); g_object_unref (settings); } } #ifdef HAVE_GUDEV /* PulseAudio gives us /devices/... paths, when udev * expects /sys/devices/... paths. */ static GUdevDevice * get_udev_device_for_sysfs_path (CsdMediaKeysManager *manager, const char *sysfs_path) { char *path; GUdevDevice *dev; path = g_strdup_printf ("/sys%s", sysfs_path); dev = g_udev_client_query_by_sysfs_path (manager->priv->udev_client, path); g_free (path); return dev; } static GvcMixerStream * get_stream_for_device_id (CsdMediaKeysManager *manager, guint deviceid, gboolean is_source_stream) { char *devnode; gpointer id_ptr; GvcMixerStream *res; GUdevDevice *dev, *parent; GSList *streams, *l; id_ptr = g_hash_table_lookup (manager->priv->streams, GUINT_TO_POINTER (deviceid)); if (id_ptr != NULL) { if (GPOINTER_TO_UINT (id_ptr) == (guint) -1) return NULL; else return gvc_mixer_control_lookup_stream_id (manager->priv->volume, GPOINTER_TO_UINT (id_ptr)); } devnode = xdevice_get_device_node (deviceid); if (devnode == NULL) { g_debug ("Could not find device node for XInput device %d", deviceid); return NULL; } dev = g_udev_client_query_by_device_file (manager->priv->udev_client, devnode); if (dev == NULL) { g_debug ("Could not find udev device for device path '%s'", devnode); g_free (devnode); return NULL; } g_free (devnode); if (g_strcmp0 (g_udev_device_get_property (dev, "ID_BUS"), "usb") != 0) { g_debug ("Not handling XInput device %d, not USB", deviceid); g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER ((guint) -1)); g_object_unref (dev); return NULL; } parent = g_udev_device_get_parent_with_subsystem (dev, "usb", "usb_device"); if (parent == NULL) { g_warning ("No USB device parent for XInput device %d even though it's USB", deviceid); g_object_unref (dev); return NULL; } res = NULL; if (is_source_stream) { streams = gvc_mixer_control_get_sinks (manager->priv->volume); } else { streams = gvc_mixer_control_get_sources (manager->priv->volume); } for (l = streams; l; l = l->next) { GvcMixerStream *stream = l->data; const char *sysfs_path; GUdevDevice *stream_dev, *stream_parent; sysfs_path = gvc_mixer_stream_get_sysfs_path (stream); stream_dev = get_udev_device_for_sysfs_path (manager, sysfs_path); if (stream_dev == NULL) continue; stream_parent = g_udev_device_get_parent_with_subsystem (stream_dev, "usb", "usb_device"); g_object_unref (stream_dev); if (stream_parent == NULL) continue; if (g_strcmp0 (g_udev_device_get_sysfs_path (stream_parent), g_udev_device_get_sysfs_path (parent)) == 0) { res = stream; } g_object_unref (stream_parent); if (res != NULL) break; } if (res) g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER (gvc_mixer_stream_get_id (res))); else g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER ((guint) -1)); return res; } #endif /* HAVE_GUDEV */ static void do_sound_action (CsdMediaKeysManager *manager, guint deviceid, int type, gboolean quiet) { GvcMixerStream *stream; gboolean old_muted, new_muted; guint old_vol, new_vol, norm_vol_step, osd_vol, osd_max_vol; gboolean sound_changed; GSettings *settings; /* Find the stream that corresponds to the device, if any */ gboolean is_source_stream = type == C_DESKTOP_MEDIA_KEY_MIC_MUTE ? TRUE : FALSE; #ifdef HAVE_GUDEV stream = get_stream_for_device_id (manager, deviceid, is_source_stream); if (stream == NULL) #endif /* HAVE_GUDEV */ { if (is_source_stream) { stream = manager->priv->source_stream; } else { stream = manager->priv->stream; } } if (stream == NULL) return; norm_vol_step = PA_VOLUME_NORM * VOLUME_STEP / 100; settings = g_settings_new ("org.cinnamon.desktop.sound"); osd_max_vol = PA_VOLUME_NORM * g_settings_get_int (settings, "maximum-volume") / 100; g_object_unref (settings); /* FIXME: this is racy */ new_vol = old_vol = gvc_mixer_stream_get_volume (stream); new_muted = old_muted = gvc_mixer_stream_get_is_muted (stream); sound_changed = FALSE; switch (type) { case C_DESKTOP_MEDIA_KEY_MUTE: case C_DESKTOP_MEDIA_KEY_MIC_MUTE: new_muted = !old_muted; break; case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN: if (old_vol <= norm_vol_step) { new_vol = 0; new_muted = TRUE; } else { new_vol = old_vol - norm_vol_step; } break; case C_DESKTOP_MEDIA_KEY_VOLUME_UP: new_muted = FALSE; /* When coming out of mute only increase the volume if it was 0 */ if (!old_muted || old_vol == 0) new_vol = MIN (old_vol + norm_vol_step, osd_max_vol); break; } if (old_muted != new_muted) { gvc_mixer_stream_change_is_muted (stream, new_muted); sound_changed = TRUE; } if (old_vol != new_vol) { if (gvc_mixer_stream_set_volume (stream, new_vol) != FALSE) { gvc_mixer_stream_push_volume (stream); sound_changed = TRUE; } } if (type == C_DESKTOP_MEDIA_KEY_VOLUME_DOWN && old_vol == 0 && old_muted) osd_vol = -1; else if (type == C_DESKTOP_MEDIA_KEY_VOLUME_UP && old_vol == osd_max_vol && !old_muted) osd_vol = 101; else if (!new_muted) osd_vol = (int) (100 * (double) new_vol / osd_max_vol); else osd_vol = 0; show_sound_osd (manager, stream, is_source_stream, osd_vol, osd_max_vol, new_muted, sound_changed, quiet); } static void update_default_sink (CsdMediaKeysManager *manager) { GvcMixerStream *stream; stream = gvc_mixer_control_get_default_sink (manager->priv->volume); if (stream == manager->priv->stream) return; if (manager->priv->stream != NULL) { g_object_unref (manager->priv->stream); manager->priv->stream = NULL; } if (stream != NULL) { manager->priv->stream = g_object_ref (stream); } else { g_warning ("Unable to get default sink"); } } static void update_default_source (CsdMediaKeysManager *manager) { GvcMixerStream *stream; stream = gvc_mixer_control_get_default_source (manager->priv->volume); if (stream == manager->priv->source_stream) return; if (manager->priv->source_stream != NULL) { g_object_unref (manager->priv->source_stream); manager->priv->source_stream = NULL; } if (stream != NULL) { manager->priv->source_stream = g_object_ref (stream); } else { g_warning ("Unable to get default source"); } } static void on_control_state_changed (GvcMixerControl *control, GvcMixerControlState new_state, CsdMediaKeysManager *manager) { update_default_sink (manager); update_default_source (manager); } static void on_control_default_sink_changed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { update_default_sink (manager); } static void on_control_default_source_changed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { update_default_source (manager); } #ifdef HAVE_GUDEV static gboolean remove_stream (gpointer key, gpointer value, gpointer id) { if (GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (id)) return TRUE; return FALSE; } #endif /* HAVE_GUDEV */ static void on_control_stream_removed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { if (manager->priv->stream != NULL) { if (gvc_mixer_stream_get_id (manager->priv->stream) == id) { g_object_unref (manager->priv->stream); manager->priv->stream = NULL; } } if (manager->priv->source_stream != NULL) { if (gvc_mixer_stream_get_id (manager->priv->source_stream) == id) { g_object_unref (manager->priv->source_stream); manager->priv->source_stream = NULL; } } #ifdef HAVE_GUDEV g_hash_table_foreach_remove (manager->priv->streams, (GHRFunc) remove_stream, GUINT_TO_POINTER (id)); #endif } static void free_media_player (MediaPlayer *player) { if (player->watch_id > 0) { g_bus_unwatch_name (player->watch_id); player->watch_id = 0; } g_free (player->application); g_free (player->name); g_free (player); } static gint find_by_application (gconstpointer a, gconstpointer b) { return strcmp (((MediaPlayer *)a)->application, b); } static gint find_by_name (gconstpointer a, gconstpointer b) { return strcmp (((MediaPlayer *)a)->name, b); } static gint find_by_time (gconstpointer a, gconstpointer b) { return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time; } static void name_vanished_handler (GDBusConnection *connection, const gchar *name, CsdMediaKeysManager *manager) { GList *iter; iter = g_list_find_custom (manager->priv->media_players, name, find_by_name); if (iter != NULL) { MediaPlayer *player; player = iter->data; g_debug ("Deregistering vanished %s (name: %s)", player->application, player->name); free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } } /* * Register a new media player. Most applications will want to call * this with time = GDK_CURRENT_TIME. This way, the last registered * player will receive media events. In some cases, applications * may want to register with a lower priority (usually 1), to grab * events only nobody is interested. */ static void csd_media_keys_manager_grab_media_player_keys (CsdMediaKeysManager *manager, const char *application, const char *name, guint32 time) { GList *iter; MediaPlayer *media_player; guint watch_id; if (time == GDK_CURRENT_TIME) { GTimeVal tv; g_get_current_time (&tv); time = tv.tv_sec * 1000 + tv.tv_usec / 1000; } iter = g_list_find_custom (manager->priv->media_players, application, find_by_application); if (iter != NULL) { if (((MediaPlayer *)iter->data)->time < time) { MediaPlayer *player = iter->data; free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } else { return; } } watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, name, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, (GBusNameVanishedCallback) name_vanished_handler, manager, NULL); g_debug ("Registering %s at %u", application, time); media_player = g_new0 (MediaPlayer, 1); media_player->application = g_strdup (application); media_player->name = g_strdup (name); media_player->time = time; media_player->watch_id = watch_id; manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players, media_player, find_by_time); } static void csd_media_keys_manager_release_media_player_keys (CsdMediaKeysManager *manager, const char *application, const char *name) { GList *iter = NULL; g_return_if_fail (application != NULL || name != NULL); if (application != NULL) { iter = g_list_find_custom (manager->priv->media_players, application, find_by_application); } if (iter == NULL && name != NULL) { iter = g_list_find_custom (manager->priv->media_players, name, find_by_name); } if (iter != NULL) { MediaPlayer *player; player = iter->data; g_debug ("Deregistering %s (name: %s)", application, player->name); free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } } static gboolean csd_media_player_key_pressed (CsdMediaKeysManager *manager, const char *key) { const char *application; gboolean have_listeners; GError *error = NULL; MediaPlayer *player; g_return_val_if_fail (key != NULL, FALSE); g_debug ("Media key '%s' pressed", key); have_listeners = (manager->priv->media_players != NULL); if (!have_listeners) { if (!mpris_controller_key (manager->priv->mpris_controller, key)) { /* Popup a dialog with an (/) icon */ show_osd (manager, "action-unavailable-symbolic", -1, OSD_ALL_OUTPUTS); } return TRUE; } player = manager->priv->media_players->data; application = player->application; if (g_dbus_connection_emit_signal (manager->priv->connection, player->name, CSD_MEDIA_KEYS_DBUS_PATH, CSD_MEDIA_KEYS_DBUS_NAME, "MediaPlayerKeyPressed", g_variant_new ("(ss)", application ? application : "", key), &error) == FALSE) { g_debug ("Error emitting signal: %s", error->message); g_error_free (error); } return !have_listeners; } static void csd_media_keys_manager_handle_cinnamon_keybinding (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp) { do_action (manager, deviceid, type, timestamp); } static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { CsdMediaKeysManager *manager = (CsdMediaKeysManager *) user_data; g_debug ("Calling method '%s' for media-keys", method_name); if (g_strcmp0 (method_name, "ReleaseMediaPlayerKeys") == 0) { const char *app_name; g_variant_get (parameters, "(&s)", &app_name); csd_media_keys_manager_release_media_player_keys (manager, app_name, sender); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "GrabMediaPlayerKeys") == 0) { const char *app_name; guint32 time; g_variant_get (parameters, "(&su)", &app_name, &time); csd_media_keys_manager_grab_media_player_keys (manager, app_name, sender, time); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "HandleKeybinding") == 0) { CDesktopMediaKeyType action; g_variant_get (parameters, "(u)", &action); csd_media_keys_manager_handle_cinnamon_keybinding (manager, 0, action, CurrentTime); g_dbus_method_invocation_return_value (invocation, NULL); } } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, /* Get Property */ NULL, /* Set Property */ }; static gboolean do_multimedia_player_action (CsdMediaKeysManager *manager, const char *icon, const char *key) { return csd_media_player_key_pressed (manager, key); } static void on_xrandr_action_call_finished (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant; char *action; action = g_object_get_data (G_OBJECT (source_object), "csd-media-keys-manager-xrandr-action"); variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); g_object_unref (manager->priv->cancellable); manager->priv->cancellable = NULL; if (error != NULL) { g_warning ("Unable to call '%s': %s", action, error->message); g_error_free (error); } else { g_variant_unref (variant); } g_free (action); } static void do_xrandr_action (CsdMediaKeysManager *manager, const char *action, gint64 timestamp) { CsdMediaKeysManagerPrivate *priv = manager->priv; if (priv->connection == NULL || priv->xrandr_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle XRANDR keys"); return; } if (priv->cancellable != NULL) { g_debug ("xrandr action already in flight"); return; } priv->cancellable = g_cancellable_new (); g_object_set_data (G_OBJECT (priv->xrandr_proxy), "csd-media-keys-manager-xrandr-action", g_strdup (action)); g_dbus_proxy_call (priv->xrandr_proxy, action, g_variant_new ("(x)", timestamp), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, (GAsyncReadyCallback) on_xrandr_action_call_finished, manager); } static gboolean do_video_out_action (CsdMediaKeysManager *manager, gint64 timestamp) { do_xrandr_action (manager, "VideoModeSwitch", timestamp); return FALSE; } static gboolean do_video_rotate_action (CsdMediaKeysManager *manager, gint64 timestamp) { do_xrandr_action (manager, "Rotate", timestamp); return FALSE; } static void do_video_rotate_lock_action (CsdMediaKeysManager *manager, gint64 timestamp) { GSettings *settings; gboolean locked; settings = g_settings_new ("org.cinnamon.settings-daemon.peripherals.touchscreen"); locked = !g_settings_get_boolean (settings, "orientation-lock"); g_settings_set_boolean (settings, "orientation-lock", locked); g_object_unref (settings); show_osd (manager, locked ? "rotation-locked-symbolic" : "rotation-allowed-symbolic", -1, OSD_ALL_OUTPUTS); } static void do_toggle_accessibility_key (const char *key) { GSettings *settings; gboolean state; settings = g_settings_new ("org.cinnamon.desktop.a11y.applications"); state = g_settings_get_boolean (settings, key); g_settings_set_boolean (settings, key, !state); g_object_unref (settings); } static void do_screenreader_action (CsdMediaKeysManager *manager) { do_toggle_accessibility_key ("screen-reader-enabled"); } static void do_on_screen_keyboard_action (CsdMediaKeysManager *manager) { if (manager->priv->connection == NULL || manager->priv->cinnamon_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle osd"); do_toggle_accessibility_key ("screen-keyboard-enabled"); return; } ensure_cancellable (&manager->priv->cinnamon_cancellable); g_dbus_proxy_call (manager->priv->cinnamon_proxy, "ToggleKeyboard", NULL, G_DBUS_CALL_FLAGS_NONE, -1, manager->priv->cinnamon_cancellable, cinnamon_proxy_complete, manager); } static void do_text_size_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { gdouble factor, best, distance; guint i; /* Same values used in the Seeing tab of the Universal Access panel */ static gdouble factors[] = { 0.75, 1.0, 1.25, 1.5 }; /* Figure out the current DPI scaling factor */ factor = g_settings_get_double (manager->priv->interface_settings, "text-scaling-factor"); factor += (type == C_DESKTOP_MEDIA_KEY_INCREASE_TEXT ? 0.25 : -0.25); /* Try to find a matching value */ distance = 1e6; best = 1.0; for (i = 0; i < G_N_ELEMENTS(factors); i++) { gdouble d; d = fabs (factor - factors[i]); if (d < distance) { best = factors[i]; distance = d; } } if (best == 1.0) g_settings_reset (manager->priv->interface_settings, "text-scaling-factor"); else g_settings_set_double (manager->priv->interface_settings, "text-scaling-factor", best); } static void do_toggle_contrast_action (CsdMediaKeysManager *manager) { gboolean high_contrast; char *theme; /* Are we using HighContrast now? */ theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme"); high_contrast = g_str_equal (theme, HIGH_CONTRAST); g_free (theme); if (high_contrast != FALSE) { if (manager->priv->gtk_theme == NULL) g_settings_reset (manager->priv->interface_settings, "gtk-theme"); else g_settings_set (manager->priv->interface_settings, "gtk-theme", manager->priv->gtk_theme); g_settings_set (manager->priv->interface_settings, "icon-theme", manager->priv->icon_theme); } else { g_settings_set (manager->priv->interface_settings, "gtk-theme", HIGH_CONTRAST); g_settings_set (manager->priv->interface_settings, "icon-theme", HIGH_CONTRAST); } } static void do_config_power_action (CsdMediaKeysManager *manager, const gchar *config_key) { CsdPowerActionType action_type; action_type = g_settings_get_enum (manager->priv->power_settings, config_key); switch (action_type) { case CSD_POWER_ACTION_SUSPEND: ; gboolean hybrid = g_settings_get_boolean (manager->priv->cinnamon_session_settings, "prefer-hybrid-sleep"); csd_power_suspend (hybrid); break; case CSD_POWER_ACTION_INTERACTIVE: cinnamon_session_shutdown (manager); break; case CSD_POWER_ACTION_SHUTDOWN: csd_power_poweroff (); break; case CSD_POWER_ACTION_HIBERNATE: csd_power_hibernate (); break; case CSD_POWER_ACTION_BLANK: execute (manager, "cinnamon-screensaver-command --lock", FALSE); break; case CSD_POWER_ACTION_NOTHING: /* these actions cannot be handled by media-keys and * are not used in this context */ break; } } static void update_screen_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; guint percentage; int output_id; GVariant *variant; CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (variant == NULL) { g_warning ("Failed to set new screen percentage: %s", error->message); g_error_free (error); return; } /* update the dialog with the new value */ g_variant_get (variant, "(ui)", &percentage, &output_id); show_osd (manager, "display-brightness-symbolic", percentage, output_id); g_variant_unref (variant); } static void do_screen_brightness_action_real (GObject *source_object, GAsyncResult *res, gpointer user_data) { CsdBrightnessActionData *data = (CsdBrightnessActionData *) user_data; CsdMediaKeysManager *manager = data->manager; GError *error = NULL; GVariant *old_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (old_percentage == NULL) { g_warning ("Failed to get old screen percentage: %s", error->message); g_error_free (error); g_free (data); return; } g_variant_get (old_percentage, "(u)", &data->old_percentage); /* call into the power plugin */ g_dbus_proxy_call (manager->priv->power_screen_proxy, data->type == C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_UP ? "StepUp" : "StepDown", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, update_screen_cb, manager); g_variant_unref (old_percentage); } static void do_screen_brightness_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { if (manager->priv->connection == NULL || manager->priv->power_screen_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle power keys"); return; } CsdBrightnessActionData *data = g_new0 (CsdBrightnessActionData, 1); data->manager = manager; data->type = type; g_dbus_proxy_call (manager->priv->power_screen_proxy, "GetPercentage", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, do_screen_brightness_action_real, data); } static void update_keyboard_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; guint percentage; GVariant *new_percentage; CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (new_percentage == NULL) { g_warning ("Failed to set new keyboard percentage: %s", error->message); g_error_free (error); return; } /* update the dialog with the new value */ g_variant_get (new_percentage, "(u)", &percentage); show_osd (manager, "keyboard-brightness-symbolic", percentage, OSD_ALL_OUTPUTS); g_variant_unref (new_percentage); } static void do_keyboard_brightness_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { const char *cmd; if (manager->priv->connection == NULL || manager->priv->power_keyboard_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle power keys"); return; } switch (type) { case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_UP: cmd = "StepUp"; break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_DOWN: cmd = "StepDown"; break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_TOGGLE: cmd = "Toggle"; break; default: g_assert_not_reached (); } /* call into the power plugin */ g_dbus_proxy_call (manager->priv->power_keyboard_proxy, cmd, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, update_keyboard_cb, manager); } static gboolean do_action (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp) { char *cmd; g_debug ("Launching action for key type '%d' (on device id %d)", type, deviceid); switch (type) { case C_DESKTOP_MEDIA_KEY_TOUCHPAD: do_touchpad_action (manager); break; case C_DESKTOP_MEDIA_KEY_TOUCHPAD_ON: do_touchpad_osd_action (manager, TRUE); break; case C_DESKTOP_MEDIA_KEY_TOUCHPAD_OFF: do_touchpad_osd_action (manager, FALSE); break; case C_DESKTOP_MEDIA_KEY_MUTE: case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN: case C_DESKTOP_MEDIA_KEY_VOLUME_UP: case C_DESKTOP_MEDIA_KEY_MIC_MUTE: do_sound_action (manager, deviceid, type, FALSE); break; case C_DESKTOP_MEDIA_KEY_MUTE_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_MUTE, TRUE); break; case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_VOLUME_DOWN, TRUE); break; case C_DESKTOP_MEDIA_KEY_VOLUME_UP_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_VOLUME_UP, TRUE); break; case C_DESKTOP_MEDIA_KEY_LOGOUT: do_logout_action (manager); break; case C_DESKTOP_MEDIA_KEY_EJECT: do_eject_action (manager); break; case C_DESKTOP_MEDIA_KEY_HOME: do_home_key_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_SEARCH: cmd = NULL; if ((cmd = g_find_program_in_path ("tracker-search-tool"))) do_execute_desktop (manager, "tracker-needle.desktop", timestamp); else do_execute_desktop (manager, "gnome-search-tool.desktop", timestamp); g_free (cmd); break; case C_DESKTOP_MEDIA_KEY_EMAIL: do_url_action (manager, "mailto", timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENSAVER: execute (manager, "cinnamon-screensaver-command --lock", FALSE); break; case C_DESKTOP_MEDIA_KEY_HELP: do_url_action (manager, "ghelp", timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENSHOT: execute (manager, "gnome-screenshot", FALSE); break; case C_DESKTOP_MEDIA_KEY_WINDOW_SCREENSHOT: execute (manager, "gnome-screenshot --window", FALSE); break; case C_DESKTOP_MEDIA_KEY_AREA_SCREENSHOT: execute (manager, "gnome-screenshot --area", FALSE); break; case C_DESKTOP_MEDIA_KEY_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_WINDOW_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --window --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_AREA_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --area --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_TERMINAL: do_terminal_action (manager); break; case C_DESKTOP_MEDIA_KEY_WWW: do_url_action (manager, "http", timestamp); break; case C_DESKTOP_MEDIA_KEY_MEDIA: do_media_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_CALCULATOR: do_calculator_action (manager); break; case C_DESKTOP_MEDIA_KEY_PLAY: return do_multimedia_player_action (manager, NULL, "Play"); case C_DESKTOP_MEDIA_KEY_PAUSE: return do_multimedia_player_action (manager, NULL, "Pause"); case C_DESKTOP_MEDIA_KEY_STOP: return do_multimedia_player_action (manager, NULL, "Stop"); case C_DESKTOP_MEDIA_KEY_PREVIOUS: return do_multimedia_player_action (manager, NULL, "Previous"); case C_DESKTOP_MEDIA_KEY_NEXT: return do_multimedia_player_action (manager, NULL, "Next"); case C_DESKTOP_MEDIA_KEY_REWIND: return do_multimedia_player_action (manager, NULL, "Rewind"); case C_DESKTOP_MEDIA_KEY_FORWARD: return do_multimedia_player_action (manager, NULL, "FastForward"); case C_DESKTOP_MEDIA_KEY_REPEAT: return do_multimedia_player_action (manager, NULL, "Repeat"); case C_DESKTOP_MEDIA_KEY_RANDOM: return do_multimedia_player_action (manager, NULL, "Shuffle"); case C_DESKTOP_MEDIA_KEY_VIDEO_OUT: do_video_out_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_ROTATE_VIDEO: do_video_rotate_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_ROTATE_VIDEO_LOCK: do_video_rotate_lock_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENREADER: do_screenreader_action (manager); break; case C_DESKTOP_MEDIA_KEY_ON_SCREEN_KEYBOARD: do_on_screen_keyboard_action (manager); break; case C_DESKTOP_MEDIA_KEY_INCREASE_TEXT: case C_DESKTOP_MEDIA_KEY_DECREASE_TEXT: do_text_size_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_TOGGLE_CONTRAST: do_toggle_contrast_action (manager); break; case C_DESKTOP_MEDIA_KEY_SHUTDOWN: do_config_power_action (manager, "button-power"); break; case C_DESKTOP_MEDIA_KEY_SUSPEND: do_config_power_action (manager, "button-suspend"); break; case C_DESKTOP_MEDIA_KEY_HIBERNATE: do_config_power_action (manager, "button-hibernate"); break; case C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_UP: case C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_DOWN: do_screen_brightness_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_UP: case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_DOWN: case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_TOGGLE: do_keyboard_brightness_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_BATTERY: do_execute_desktop (manager, "org.gnome.PowerStats.desktop", timestamp); break; /* Note, no default so compiler catches missing keys */ case C_DESKTOP_MEDIA_KEY_SEPARATOR: g_assert_not_reached (); } return FALSE; } static void update_theme_settings (GSettings *settings, const char *key, CsdMediaKeysManager *manager) { char *theme; theme = g_settings_get_string (manager->priv->interface_settings, key); if (g_str_equal (theme, HIGH_CONTRAST)) { g_free (theme); } else { if (g_str_equal (key, "gtk-theme")) { g_free (manager->priv->gtk_theme); manager->priv->gtk_theme = theme; } else { g_free (manager->priv->icon_theme); manager->priv->icon_theme = theme; } } } static gboolean start_media_keys_idle_cb (CsdMediaKeysManager *manager) { g_debug ("Starting media_keys manager"); cinnamon_settings_profile_start (NULL); gvc_mixer_control_open (manager->priv->volume); /* Sound events */ ca_context_create (&manager->priv->ca); ca_context_set_driver (manager->priv->ca, "pulse"); ca_context_change_props (manager->priv->ca, 0, CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", NULL); manager->priv->desktop_session_settings = g_settings_new("org.cinnamon.desktop.session"); manager->priv->cinnamon_session_settings = g_settings_new("org.cinnamon.SessionManager"); /* for the power plugin interface code */ manager->priv->power_settings = g_settings_new (SETTINGS_POWER_DIR); /* Logic from http://git.gnome.org/browse/gnome-shell/tree/js/ui/status/accessibility.js#n163 */ manager->priv->interface_settings = g_settings_new (SETTINGS_INTERFACE_DIR); g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::gtk-theme", G_CALLBACK (update_theme_settings), manager); g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::icon-theme", G_CALLBACK (update_theme_settings), manager); manager->priv->gtk_theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme"); if (g_str_equal (manager->priv->gtk_theme, HIGH_CONTRAST)) { g_free (manager->priv->gtk_theme); manager->priv->gtk_theme = NULL; } manager->priv->icon_theme = g_settings_get_string (manager->priv->interface_settings, "icon-theme"); init_screens (manager); g_debug ("Starting mpris controller"); manager->priv->mpris_controller = mpris_controller_new (); cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_media_keys_manager_start (CsdMediaKeysManager *manager, GError **error) { const char * const subsystems[] = { "input", "usb", "sound", NULL }; cinnamon_settings_profile_start (NULL); #ifdef HAVE_GUDEV manager->priv->streams = g_hash_table_new (g_direct_hash, g_direct_equal); manager->priv->udev_client = g_udev_client_new (subsystems); #endif /* initialise Volume handler * * We do this one here to force checking gstreamer cache, etc. * The rest (grabbing and setting the keys) can happen in an * idle. */ cinnamon_settings_profile_start ("gvc_mixer_control_new"); manager->priv->volume = gvc_mixer_control_new ("Cinnamon Volume Control Media Keys"); g_signal_connect (manager->priv->volume, "state-changed", G_CALLBACK (on_control_state_changed), manager); g_signal_connect (manager->priv->volume, "default-sink-changed", G_CALLBACK (on_control_default_sink_changed), manager); g_signal_connect (manager->priv->volume, "default-source-changed", G_CALLBACK (on_control_default_source_changed), manager); g_signal_connect (manager->priv->volume, "stream-removed", G_CALLBACK (on_control_stream_removed), manager); cinnamon_settings_profile_end ("gvc_mixer_control_new"); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager); register_manager (manager_object); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_media_keys_manager_stop (CsdMediaKeysManager *manager) { CsdMediaKeysManagerPrivate *priv = manager->priv; GList *l; g_debug ("Stopping media_keys manager"); if (priv->bus_cancellable != NULL) { g_cancellable_cancel (priv->bus_cancellable); g_object_unref (priv->bus_cancellable); priv->bus_cancellable = NULL; } if (manager->priv->ca) { ca_context_destroy (manager->priv->ca); manager->priv->ca = NULL; } #ifdef HAVE_GUDEV if (priv->streams) { g_hash_table_destroy (priv->streams); priv->streams = NULL; } if (priv->udev_client) { g_object_unref (priv->udev_client); priv->udev_client = NULL; } #endif /* HAVE_GUDEV */ if (priv->logind_proxy) { g_object_unref (priv->logind_proxy); priv->logind_proxy = NULL; } if (priv->power_settings) { g_object_unref (priv->power_settings); priv->power_settings = NULL; } if (priv->desktop_session_settings) { g_object_unref (priv->desktop_session_settings); priv->desktop_session_settings = NULL; } if (priv->cinnamon_session_settings) { g_object_unref (priv->cinnamon_session_settings); priv->cinnamon_session_settings = NULL; } if (priv->interface_settings) { g_object_unref (priv->interface_settings); priv->interface_settings = NULL; } if (priv->power_screen_proxy) { g_object_unref (priv->power_screen_proxy); priv->power_screen_proxy = NULL; } if (priv->power_keyboard_proxy) { g_object_unref (priv->power_keyboard_proxy); priv->power_keyboard_proxy = NULL; } if (priv->mpris_controller) { g_object_unref (priv->mpris_controller); priv->mpris_controller = NULL; } if (priv->upower_proxy) { g_object_unref (priv->upower_proxy); priv->upower_proxy = NULL; } if (priv->cinnamon_proxy) { g_object_unref (priv->cinnamon_proxy); priv->cinnamon_proxy = NULL; } if (priv->cancellable != NULL) { g_cancellable_cancel (priv->cancellable); g_object_unref (priv->cancellable); priv->cancellable = NULL; } if (priv->name_id != 0) g_bus_unown_name (priv->name_id); if (priv->gnome_name_id != 0) g_bus_unown_name (priv->gnome_name_id); if (priv->introspection_data) { g_dbus_node_info_unref (priv->introspection_data); priv->introspection_data = NULL; } if (priv->kb_introspection_data) { g_dbus_node_info_unref (priv->kb_introspection_data); priv->kb_introspection_data = NULL; } if (priv->connection != NULL) { g_object_unref (priv->connection); priv->connection = NULL; } if (priv->volume_notification != NULL) { notify_notification_close (priv->volume_notification, NULL); g_object_unref (priv->volume_notification); priv->volume_notification = NULL; } if (priv->brightness_notification != NULL) { notify_notification_close (priv->brightness_notification, NULL); g_object_unref (priv->brightness_notification); priv->brightness_notification = NULL; } if (priv->kb_backlight_notification != NULL) { notify_notification_close (priv->kb_backlight_notification, NULL); g_object_unref (priv->kb_backlight_notification); priv->kb_backlight_notification = NULL; } if (priv->cinnamon_cancellable != NULL) { g_cancellable_cancel (priv->cinnamon_cancellable); g_object_unref (priv->cinnamon_cancellable); priv->cinnamon_cancellable = NULL; } if (priv->screens != NULL) { g_slist_free (priv->screens); priv->screens = NULL; } if (priv->stream) { g_object_unref (priv->stream); priv->stream = NULL; } if (priv->volume) { g_object_unref (priv->volume); priv->volume = NULL; } if (priv->dialog != NULL) { gtk_widget_destroy (priv->dialog); priv->dialog = NULL; } if (priv->media_players != NULL) { for (l = priv->media_players; l; l = l->next) { MediaPlayer *mp = l->data; g_free (mp->application); g_free (mp); } g_list_free (priv->media_players); priv->media_players = NULL; } } static GObject * csd_media_keys_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdMediaKeysManager *media_keys_manager; media_keys_manager = CSD_MEDIA_KEYS_MANAGER (G_OBJECT_CLASS (csd_media_keys_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (media_keys_manager); } static void csd_media_keys_manager_class_init (CsdMediaKeysManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_media_keys_manager_constructor; object_class->finalize = csd_media_keys_manager_finalize; g_type_class_add_private (klass, sizeof (CsdMediaKeysManagerPrivate)); } static void inhibit_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit keypresses: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_keys_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_keys_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_keys_fd); g_object_unref (fd_list); g_variant_unref (res); } } static void csd_media_keys_manager_init (CsdMediaKeysManager *manager) { GError *error; GDBusConnection *bus; error = NULL; manager->priv = CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (bus == NULL) { g_warning ("Failed to connect to system bus: %s", error->message); g_error_free (error); return; } manager->priv->logind_proxy = g_dbus_proxy_new_sync (bus, 0, NULL, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, NULL, &error); if (manager->priv->logind_proxy == NULL) { g_warning ("Failed to connect to logind: %s", error->message); g_error_free (error); } g_object_unref (bus); g_debug ("Adding system inhibitors for power keys"); manager->priv->inhibit_keys_fd = -1; g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", g_variant_new ("(ssss)", "handle-power-key:handle-suspend-key:handle-hibernate-key", g_get_user_name (), "Cinnamon handling keypresses", "block"), 0, G_MAXINT, NULL, NULL, inhibit_done, manager); } static void csd_media_keys_manager_finalize (GObject *object) { CsdMediaKeysManager *media_keys_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MEDIA_KEYS_MANAGER (object)); media_keys_manager = CSD_MEDIA_KEYS_MANAGER (object); g_return_if_fail (media_keys_manager->priv != NULL); if (media_keys_manager->priv->start_idle_id != 0) { g_source_remove (media_keys_manager->priv->start_idle_id); media_keys_manager->priv->start_idle_id = 0; } if (media_keys_manager->priv->inhibit_keys_fd != -1) close (media_keys_manager->priv->inhibit_keys_fd); G_OBJECT_CLASS (csd_media_keys_manager_parent_class)->finalize (object); } static void xrandr_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->xrandr_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->xrandr_proxy == NULL) { g_warning ("Failed to get proxy for XRandR operations: %s", error->message); g_error_free (error); } } static void upower_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->upower_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->upower_proxy == NULL) { g_warning ("Failed to get proxy for upower: %s", error->message); g_error_free (error); } } static void power_screen_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->power_screen_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->power_screen_proxy == NULL) { g_warning ("Failed to get proxy for power (screen): %s", error->message); g_error_free (error); } } static void power_keyboard_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->power_keyboard_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->power_keyboard_proxy == NULL) { g_warning ("Failed to get proxy for power (keyboard): %s", error->message); g_error_free (error); } } static void osd_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->cinnamon_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->cinnamon_proxy == NULL) { g_warning ("Failed to get proxy for OSD operations: %s", error->message); g_error_free (error); } } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GDBusConnection *connection; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; g_dbus_connection_register_object (connection, CSD_MEDIA_KEYS_DBUS_PATH, manager->priv->introspection_data->interfaces[0], &interface_vtable, manager, NULL, NULL); manager->priv->gnome_name_id = g_bus_own_name_on_connection (connection, GSD_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); g_dbus_connection_register_object (connection, CINNAMON_KEYBINDINGS_PATH, manager->priv->kb_introspection_data->interfaces[0], &interface_vtable, manager, NULL, NULL); manager->priv->name_id = g_bus_own_name_on_connection (connection, CINNAMON_KEYBINDINGS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon.XRANDR_2", "/org/cinnamon/SettingsDaemon/XRANDR", "org.cinnamon.SettingsDaemon.XRANDR_2", NULL, (GAsyncReadyCallback) xrandr_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon.Power", "/org/cinnamon/SettingsDaemon/Power", "org.cinnamon.SettingsDaemon.Power.Screen", NULL, (GAsyncReadyCallback) power_screen_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon.Power", "/org/cinnamon/SettingsDaemon/Power", "org.cinnamon.SettingsDaemon.Power.Keyboard", NULL, (GAsyncReadyCallback) power_keyboard_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, "org.Cinnamon", "/org/Cinnamon", "org.Cinnamon", NULL, (GAsyncReadyCallback) osd_ready_cb, manager); } static void register_manager (CsdMediaKeysManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->kb_introspection_data = g_dbus_node_info_new_for_xml (kb_introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_assert (manager->priv->kb_introspection_data != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", NULL, (GAsyncReadyCallback) upower_ready_cb, manager); } CsdMediaKeysManager * csd_media_keys_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_MEDIA_KEYS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_MEDIA_KEYS_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/media-keys/csd-media-keys-manager.h000066400000000000000000000052271356401377300265300ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_MEDIA_KEYS_MANAGER_H #define __CSD_MEDIA_KEYS_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_MEDIA_KEYS_MANAGER (csd_media_keys_manager_get_type ()) #define CSD_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManager)) #define CSD_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerClass)) #define CSD_IS_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER)) #define CSD_IS_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MEDIA_KEYS_MANAGER)) #define CSD_MEDIA_KEYS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerClass)) typedef struct CsdMediaKeysManagerPrivate CsdMediaKeysManagerPrivate; typedef struct { GObject parent; CsdMediaKeysManagerPrivate *priv; } CsdMediaKeysManager; typedef struct { GObjectClass parent_class; void (* media_player_key_pressed) (CsdMediaKeysManager *manager, const char *application, const char *key); } CsdMediaKeysManagerClass; GType csd_media_keys_manager_get_type (void); CsdMediaKeysManager * csd_media_keys_manager_new (void); gboolean csd_media_keys_manager_start (CsdMediaKeysManager *manager, GError **error); void csd_media_keys_manager_stop (CsdMediaKeysManager *manager); G_END_DECLS #endif /* __CSD_MEDIA_KEYS_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/media-keys/main.c000066400000000000000000000010351356401377300232310ustar00rootroot00000000000000#define NEW csd_media_keys_manager_new #define START csd_media_keys_manager_start #define STOP csd_media_keys_manager_stop #define MANAGER CsdMediaKeysManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-media-keys-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/media-keys/mpris-controller.c000066400000000000000000000141651356401377300256300ustar00rootroot00000000000000/* * Copyright © 2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 Lesser General Public License * along with this program; if not, see * * Author: Michael Wood */ #include "mpris-controller.h" #include "bus-watch-namespace.h" #include G_DEFINE_TYPE (MprisController, mpris_controller, G_TYPE_OBJECT) #define CONTROLLER_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), MPRIS_TYPE_CONTROLLER, MprisControllerPrivate)) struct _MprisControllerPrivate { GCancellable *cancellable; GDBusProxy *mpris_client_proxy; guint namespace_watcher_id; GSList *other_players; gboolean connecting; }; static void mpris_controller_dispose (GObject *object) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv; g_clear_object (&priv->cancellable); g_clear_object (&priv->mpris_client_proxy); if (priv->namespace_watcher_id) { bus_unwatch_namespace (priv->namespace_watcher_id); priv->namespace_watcher_id = 0; } if (priv->other_players) { g_slist_free_full (priv->other_players, g_free); priv->other_players = NULL; } G_OBJECT_CLASS (mpris_controller_parent_class)->dispose (object); } static void mpris_proxy_call_done (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *ret; if (!(ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error))) { g_warning ("Error calling method %s", error->message); g_clear_error (&error); return; } g_variant_unref (ret); } gboolean mpris_controller_key (MprisController *self, const gchar *key) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (!priv->mpris_client_proxy) return FALSE; if (g_strcmp0 (key, "Play") == 0) key = "PlayPause"; g_debug ("calling %s over dbus to mpris client %s", key, g_dbus_proxy_get_name (priv->mpris_client_proxy)); g_dbus_proxy_call (priv->mpris_client_proxy, key, NULL, 0, -1, priv->cancellable, mpris_proxy_call_done, NULL); return TRUE; } static void mpris_proxy_ready_cb (GObject *object, GAsyncResult *res, gpointer user_data) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (user_data)->priv; GError *error = NULL; priv->mpris_client_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (!priv->mpris_client_proxy) g_warning ("Error connecting to mpris interface %s", error->message); priv->connecting = FALSE; g_clear_error (&error); } static void start_mpris_proxy (MprisController *self, const gchar *name) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; g_debug ("Creating proxy for for %s", name); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, 0, NULL, name, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", priv->cancellable, mpris_proxy_ready_cb, self); priv->connecting = TRUE; } static void mpris_player_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { MprisController *self = user_data; MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (priv->mpris_client_proxy == NULL && !priv->connecting) start_mpris_proxy (self, name); else self->priv->other_players = g_slist_prepend (self->priv->other_players, g_strdup (name)); } static void mpris_player_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { MprisController *self = user_data; MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (priv->mpris_client_proxy && g_strcmp0 (name, g_dbus_proxy_get_name (priv->mpris_client_proxy)) == 0) { g_clear_object (&priv->mpris_client_proxy); /* take the next one if there's one */ if (self->priv->other_players && !priv->connecting) { GSList *first; gchar *name; first = self->priv->other_players; name = first->data; start_mpris_proxy (self, name); self->priv->other_players = self->priv->other_players->next; g_free (name); g_slist_free_1 (first); } } } static void mpris_controller_constructed (GObject *object) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv; priv->namespace_watcher_id = bus_watch_namespace (G_BUS_TYPE_SESSION, "org.mpris.MediaPlayer2", mpris_player_appeared, mpris_player_vanished, MPRIS_CONTROLLER (object), NULL); } static void mpris_controller_class_init (MprisControllerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (MprisControllerPrivate)); object_class->constructed = mpris_controller_constructed; object_class->dispose = mpris_controller_dispose; } static void mpris_controller_init (MprisController *self) { self->priv = CONTROLLER_PRIVATE (self); } MprisController * mpris_controller_new (void) { return g_object_new (MPRIS_TYPE_CONTROLLER, NULL); } cinnamon-settings-daemon-4.4.0/plugins/media-keys/mpris-controller.h000066400000000000000000000036531356401377300256350ustar00rootroot00000000000000/* * Copyright © 2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 Lesser General Public License * along with this program; if not, see * * Author: Michael Wood */ #ifndef __MPRIS_CONTROLLER_H__ #define __MPRIS_CONTROLLER_H__ #include G_BEGIN_DECLS #define MPRIS_TYPE_CONTROLLER mpris_controller_get_type() #define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MPRIS_TYPE_CONTROLLER, MprisController)) #define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MPRIS_TYPE_CONTROLLER, MprisControllerClass)) #define MPRIS_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MPRIS_TYPE_CONTROLLER)) #define MPRIS_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MPRIS_TYPE_CONTROLLER)) #define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MPRIS_TYPE_CONTROLLER, MprisControllerClass)) typedef struct _MprisController MprisController; typedef struct _MprisControllerClass MprisControllerClass; typedef struct _MprisControllerPrivate MprisControllerPrivate; struct _MprisController { GObject parent; MprisControllerPrivate *priv; }; struct _MprisControllerClass { GObjectClass parent_class; }; GType mpris_controller_get_type (void) G_GNUC_CONST; MprisController *mpris_controller_new (void); gboolean mpris_controller_key (MprisController *self, const gchar *key); G_END_DECLS #endif /* __MPRIS_CONTROLLER_H__ */ cinnamon-settings-daemon-4.4.0/plugins/mouse/000077500000000000000000000000001356401377300212425ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/mouse/Makefile.am000066400000000000000000000026671356401377300233110ustar00rootroot00000000000000plugin_name = mouse AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-locate-pointer csd_locate_pointer_SOURCES = \ csd-locate-pointer.h \ csd-locate-pointer.c \ csd-timeline.h \ csd-timeline.c csd_locate_pointer_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MOUSE_CFLAGS) \ $(AM_CFLAGS) csd_locate_pointer_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(MOUSE_LIBS) \ -lm libexec_PROGRAMS += csd-mouse csd_mouse_SOURCES = \ main.c \ csd-mouse-manager.c \ csd-mouse-manager.h csd_mouse_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_mouse_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MOUSE_CFLAGS) \ $(AM_CFLAGS) csd_mouse_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(MOUSE_LIBS) \ -lm desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-mouse.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-mouse.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/mouse/cinnamon-settings-daemon-mouse.desktop.in000066400000000000000000000003471356401377300312750ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - mouse Exec=@libexecdir@/csd-mouse OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-locate-pointer.c000066400000000000000000000356761356401377300251230ustar00rootroot00000000000000/* csd-locate-pointer.c * * Copyright (C) 2008 Carlos Garnacho * * 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 #include "csd-timeline.h" #include "csd-locate-pointer.h" #include #include #include #define ANIMATION_LENGTH 750 #define WINDOW_SIZE 101 #define N_CIRCLES 4 /* All circles are supposed to be moving when progress * reaches 0.5, and each of them are supposed to long * for half of the progress, hence the need of 0.5 to * get the circles interval, and the multiplication * by 2 to know a circle progress */ #define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES) #define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.))) typedef struct CsdLocatePointerData CsdLocatePointerData; struct CsdLocatePointerData { CsdTimeline *timeline; GtkWidget *widget; GdkWindow *window; gdouble progress; }; static CsdLocatePointerData *data = NULL; static void locate_pointer_paint (CsdLocatePointerData *data, cairo_t *cr, gboolean composite) { GdkRGBA color; gdouble progress, circle_progress; gint width, height, i; GtkStyleContext *context; progress = data->progress; width = gdk_window_get_width (data->window); height = gdk_window_get_height (data->window); context = gtk_widget_get_style_context (data->widget); gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); cairo_set_source_rgba (cr, 1., 1., 1., 0.); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); for (i = 0; i <= N_CIRCLES; i++) { if (progress < 0.) break; circle_progress = MIN (1., (progress * 2)); progress -= CIRCLES_PROGRESS_INTERVAL; if (circle_progress >= 1.) continue; if (composite) { cairo_set_source_rgba (cr, color.red, color.green, color.blue, 1 - circle_progress); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_fill (cr); } else { cairo_set_source_rgb (cr, 0., 0., 0.); cairo_set_line_width (cr, 3.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_line_width (cr, 1.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); } } } static gboolean locate_pointer_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; if (gtk_cairo_should_draw_window (cr, data->window)) locate_pointer_paint (data, cr, gtk_widget_is_composited (data->widget)); return TRUE; } static void update_shape (CsdLocatePointerData *data) { cairo_t *cr; cairo_region_t *region; cairo_surface_t *mask; mask = cairo_image_surface_create (CAIRO_FORMAT_A1, WINDOW_SIZE, WINDOW_SIZE); cr = cairo_create (mask); locate_pointer_paint (data, cr, FALSE); region = gdk_cairo_region_create_from_surface (mask); gdk_window_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); cairo_destroy (cr); cairo_surface_destroy (mask); } static void timeline_frame_cb (CsdTimeline *timeline, gdouble progress, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; GdkScreen *screen; GdkDeviceManager *device_manager; gint cursor_x, cursor_y; if (gtk_widget_is_composited (data->widget)) { gdk_window_invalidate_rect (data->window, NULL, FALSE); data->progress = progress; } else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL) { /* only invalidate window each circle interval */ update_shape (data); gdk_window_invalidate_rect (data->window, NULL, FALSE); data->progress += CIRCLES_PROGRESS_INTERVAL; } screen = gdk_window_get_screen (data->window); device_manager = gdk_display_get_device_manager (gdk_window_get_display (data->window)); gdk_window_get_device_position (gdk_screen_get_root_window (screen), gdk_device_manager_get_client_pointer (device_manager), &cursor_x, &cursor_y, NULL); gdk_window_move (data->window, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2); } static void set_transparent_shape (GdkWindow *window) { cairo_region_t *region; region = cairo_region_create (); gdk_window_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); } static void unset_transparent_shape (GdkWindow *window) { gdk_window_shape_combine_region (data->window, NULL, 0, 0); } static void composited_changed (GtkWidget *widget, CsdLocatePointerData *data) { if (!gtk_widget_is_composited (widget)) set_transparent_shape (data->window); else unset_transparent_shape (data->window); } static void timeline_finished_cb (CsdTimeline *timeline, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; /* set transparent shape and hide window */ if (!gtk_widget_is_composited (data->widget)) set_transparent_shape (data->window); gtk_widget_hide (data->widget); gdk_window_hide (data->window); } static void create_window (CsdLocatePointerData *data, GdkScreen *screen) { GdkVisual *visual; GdkWindowAttr attributes; gint attributes_mask; visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); attributes_mask = GDK_WA_X | GDK_WA_Y; if (visual != NULL) attributes_mask = attributes_mask | GDK_WA_VISUAL; attributes.window_type = GDK_WINDOW_TEMP; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = visual; attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; attributes.width = 1; attributes.height = 1; data->window = gdk_window_new (gdk_screen_get_root_window (screen), &attributes, attributes_mask); gdk_window_set_user_data (data->window, data->widget); } static CsdLocatePointerData * csd_locate_pointer_data_new (GdkScreen *screen) { CsdLocatePointerData *data; data = g_new0 (CsdLocatePointerData, 1); /* this widget will never be shown, it's * mainly used to get signals/events from */ data->widget = gtk_invisible_new (); gtk_widget_realize (data->widget); g_signal_connect (G_OBJECT (data->widget), "draw", G_CALLBACK (locate_pointer_draw), data); data->timeline = csd_timeline_new (ANIMATION_LENGTH); g_signal_connect (data->timeline, "frame", G_CALLBACK (timeline_frame_cb), data); g_signal_connect (data->timeline, "finished", G_CALLBACK (timeline_finished_cb), data); create_window (data, screen); return data; } static void move_locate_pointer_window (CsdLocatePointerData *data, GdkScreen *screen) { GdkDeviceManager *device_manager; cairo_region_t *region; gint cursor_x, cursor_y; device_manager = gdk_display_get_device_manager (gdk_window_get_display (data->window)); gdk_window_get_device_position (gdk_screen_get_root_window (screen), gdk_device_manager_get_client_pointer (device_manager), &cursor_x, &cursor_y, NULL); gdk_window_move_resize (data->window, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2, WINDOW_SIZE, WINDOW_SIZE); /* allow events to happen through the window */ region = cairo_region_create (); gdk_window_input_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); } void csd_locate_pointer (GdkScreen *screen) { if (!data) data = csd_locate_pointer_data_new (screen); csd_timeline_pause (data->timeline); csd_timeline_rewind (data->timeline); /* Create again the window if it is not for the current screen */ if (gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_window_get_screen (data->window))) { gdk_window_set_user_data (data->window, NULL); gdk_window_destroy (data->window); create_window (data, screen); } data->progress = 0.; g_signal_connect (data->widget, "composited-changed", G_CALLBACK (composited_changed), data); move_locate_pointer_window (data, screen); composited_changed (data->widget, data); gdk_window_show (data->window); gtk_widget_show (data->widget); csd_timeline_start (data->timeline); } #define KEYBOARD_GROUP_SHIFT 13 #define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14)) /* Owen magic */ static GdkFilterReturn filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XEvent *xev = (XEvent *) xevent; guint keyval; gint group; GdkScreen *screen = (GdkScreen *)data; if (xev->type == ButtonPress) { XAllowEvents (xev->xbutton.display, ReplayPointer, xev->xbutton.time); XUngrabButton (xev->xbutton.display, AnyButton, AnyModifier, xev->xbutton.window); XUngrabKeyboard (xev->xbutton.display, xev->xbutton.time); } if (xev->type == KeyPress || xev->type == KeyRelease) { /* get the keysym */ group = (xev->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT; gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), xev->xkey.keycode, xev->xkey.state, group, &keyval, NULL, NULL, NULL); if (keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R) { if (xev->type == KeyPress) { XAllowEvents (xev->xkey.display, SyncKeyboard, xev->xkey.time); XGrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); } else { XUngrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window); XAllowEvents (xev->xkey.display, AsyncKeyboard, xev->xkey.time); csd_locate_pointer (screen); } } else { XAllowEvents (xev->xkey.display, ReplayKeyboard, xev->xkey.time); XUngrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window); XUngrabKeyboard (xev->xkey.display, xev->xkey.time); } } return GDK_FILTER_CONTINUE; } static void set_locate_pointer (void) { GdkKeymapKey *keys; GdkDisplay *display; GdkScreen *screen; Window xroot; int n_keys; gboolean has_entries; static const guint keyvals[] = { GDK_KEY_Control_L, GDK_KEY_Control_R }; unsigned i,j; display = gdk_display_get_default (); screen = gdk_screen_get_default (); xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)); for (j = 0 ; j < G_N_ELEMENTS (keyvals) ; j++) { has_entries = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyvals[j], &keys, &n_keys); if (has_entries) { for (i = 0; i < n_keys; i++) { gdk_x11_display_error_trap_push (display); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, 0, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, LockMask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, Mod2Mask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, Mod4Mask, xroot, False, GrabModeAsync, GrabModeSync); gdk_x11_display_error_trap_pop_ignored (display); } g_free (keys); gdk_window_add_filter (gdk_screen_get_root_window (screen), filter, screen); } } } int main (int argc, char *argv[]) { gdk_disable_multidevice (); gtk_init (&argc, &argv); set_locate_pointer (); gtk_main (); return 0; } cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-locate-pointer.h000066400000000000000000000015331356401377300251110ustar00rootroot00000000000000/* * Copyright 2001 Jonathan Blandford * * 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, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * Authors: Jonathan Blandford */ #ifndef LOCATE_POINTER_H #define LOCATE_POINTER_H #include void csd_locate_pointer (GdkScreen *screen); #endif cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-mouse-manager.c000066400000000000000000002111211356401377300247130ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef __linux #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-mouse-manager.h" #include "csd-input-helper.h" #include "csd-enums.h" #define CSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerPrivate)) #define SETTINGS_MOUSE_DIR "org.cinnamon.settings-daemon.peripherals.mouse" #define SETTINGS_TOUCHPAD_DIR "org.cinnamon.settings-daemon.peripherals.touchpad" /* Keys for both touchpad and mouse */ #define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */ #define KEY_CUSTOM_ACCELERATION "custom-acceleration" #define KEY_MOTION_ACCELERATION "motion-acceleration" #define KEY_CUSTOM_THRESHOLD "custom-threshold" #define KEY_MOTION_THRESHOLD "motion-threshold" /* Touchpad settings */ #define KEY_TOUCHPAD_DISABLE_W_TYPING "disable-while-typing" #define KEY_TAP_TO_CLICK "tap-to-click" #define KEY_CLICKPAD_CLICK "clickpad-click" #define KEY_SCROLL_METHOD "scrolling-method" #define KEY_HORIZ_SCROLL "horizontal-scrolling" #define KEY_TOUCHPAD_ENABLED "touchpad-enabled" #define KEY_NATURAL_SCROLL_ENABLED "natural-scroll" #define KEY_TOUCHPAD_DISABLE_WITH_MOUSE "disable-with-external-mouse" /* Mouse settings */ #define KEY_LOCATE_POINTER "locate-pointer" #define KEY_DWELL_CLICK_ENABLED "dwell-click-enabled" #define KEY_SECONDARY_CLICK_ENABLED "secondary-click-enabled" #define KEY_MIDDLE_BUTTON_EMULATION "middle-button-enabled" struct CsdMouseManagerPrivate { guint start_idle_id; GSettings *touchpad_settings; GSettings *mouse_settings; GSettings *mouse_a11y_settings; GdkDeviceManager *device_manager; guint device_added_id; guint device_removed_id; GHashTable *blacklist; gboolean mousetweaks_daemon_running; gboolean syndaemon_spawned; GPid syndaemon_pid; gboolean locate_pointer_spawned; GPid locate_pointer_pid; }; static void csd_mouse_manager_finalize (GObject *object); static void set_tap_to_click (GdkDevice *device, gboolean state, gboolean left_handed); static void set_click_actions (GdkDevice *device, gint clickpad_click, gboolean left_handed); static void set_natural_scroll (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll); G_DEFINE_TYPE (CsdMouseManager, csd_mouse_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void csd_mouse_manager_class_init (CsdMouseManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_mouse_manager_finalize; g_type_class_add_private (klass, sizeof (CsdMouseManagerPrivate)); } static XDevice * open_gdk_device (GdkDevice *device) { XDevice *xdevice; int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != 0) return NULL; return xdevice; } static gboolean gdkdevice_is_touchpad (GdkDevice *device) { XDevice *xdevice; gboolean ret = FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return ret; ret = device_is_touchpad (xdevice); xdevice_close (xdevice); return ret; } static gboolean device_is_blacklisted (CsdMouseManager *manager, GdkDevice *device) { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); if (g_hash_table_lookup (manager->priv->blacklist, GINT_TO_POINTER (id)) != NULL) { g_debug ("device %s (%d) is blacklisted", gdk_device_get_name (device), id); return TRUE; } return FALSE; } static gboolean device_is_ignored (CsdMouseManager *manager, GdkDevice *device) { GdkInputSource source; const char *name; if (device_is_blacklisted (manager, device)) return TRUE; source = gdk_device_get_source (device); if (source != GDK_SOURCE_MOUSE && source != GDK_SOURCE_TOUCHPAD && source != GDK_SOURCE_CURSOR) return TRUE; name = gdk_device_get_name (device); if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name)) return TRUE; return FALSE; } static void configure_button_layout (guchar *buttons, gint n_buttons, gboolean left_handed) { const gint left_button = 1; gint right_button; gint i; /* if the button is higher than 2 (3rd button) then it's * probably one direction of a scroll wheel or something else * uninteresting */ right_button = MIN (n_buttons, 3); /* If we change things we need to make sure we only swap buttons. * If we end up with multiple physical buttons assigned to the same * logical button the server will complain. This code assumes physical * button 0 is the physical left mouse button, and that the physical * button other than 0 currently assigned left_button or right_button * is the physical right mouse button. */ /* check if the current mapping satisfies the above assumptions */ if (buttons[left_button - 1] != left_button && buttons[left_button - 1] != right_button) /* The current mapping is weird. Swapping buttons is probably not a * good idea. */ return; /* check if we are left_handed and currently not swapped */ if (left_handed && buttons[left_button - 1] == left_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == right_button) { buttons[i] = left_button; break; } } /* swap the buttons */ buttons[left_button - 1] = right_button; } /* check if we are not left_handed but are swapped */ else if (!left_handed && buttons[left_button - 1] == right_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == left_button) { buttons[i] = right_button; break; } } /* swap the buttons */ buttons[left_button - 1] = left_button; } } static gboolean xinput_device_has_buttons (GdkDevice *device) { int i; XAnyClassInfo *class_info; /* FIXME can we use the XDevice's classes here instead? */ XDeviceInfo *device_info, *info; gint n_devices; int id; /* Find the XDeviceInfo for the GdkDevice */ g_object_get (G_OBJECT (device), "device-id", &id, NULL); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; info = NULL; for (i = 0; i < n_devices; i++) { if (device_info[i].id == id) { info = &device_info[i]; break; } } if (info == NULL) goto bail; class_info = info->inputclassinfo; for (i = 0; i < info->num_classes; i++) { if (class_info->class == ButtonClass) { XButtonInfo *button_info; button_info = (XButtonInfo *) class_info; if (button_info->num_buttons > 0) { XFreeDeviceList (device_info); return TRUE; } } class_info = (XAnyClassInfo *) (((guchar *) class_info) + class_info->length); } bail: XFreeDeviceList (device_info); return FALSE; } static Atom property_from_name (const char *property_name) { Atom prop; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property_name, True); return prop; } static gboolean touchpad_has_single_button (XDevice *device) { Atom type, prop; int format; unsigned long nitems, bytes_after; unsigned char *data; gboolean is_single_button = FALSE; int rc; prop = property_from_name ("Synaptics Capabilities"); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0); if (rc == Success) XFree (data); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return is_single_button; } static gboolean property_exists_on_device (GdkDevice *device, const char * property_name) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; XDevice *xdevice; property = property_from_name (property_name); if (!property) return FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success) XFree(data); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); xdevice_close (xdevice); return rc == Success; } static void property_set_bool (GdkDevice *device, XDevice *xdevice, const char * property_name, int property_index, gboolean enable) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; property = property_from_name (property_name); if (!property) { return; } int value = 0; if (enable) { value = 1; } g_debug ("Setting %s on %s to %d", property_name, gdk_device_get_name (device), value); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems > property_index) { data[property_index] = value; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) { XFree (data); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while setting %s on \"%s\"", property_name, gdk_device_get_name (device)); } } static gboolean property_get_bool (GdkDevice *device, XDevice *xdevice, const char * property_name, int property_index) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; gboolean ret = FALSE; property = property_from_name (property_name); if (!property) { return FALSE; } g_debug ("Getting %s on %s", property_name, gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems > property_index) { ret = data[property_index]; } if (rc == Success) { XFree (data); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while getting %s on \"%s\"", property_name, gdk_device_get_name (device)); } return ret; } static void touchpad_set_bool (GdkDevice *device, const char * property_name, int property_index, gboolean enable) { XDevice *xdevice; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (device_is_touchpad (xdevice)) property_set_bool (device, xdevice, property_name, property_index, enable); xdevice_close (xdevice); } static gboolean touchpad_get_bool (GdkDevice *device, const char * property_name, int property_index) { XDevice *xdevice; gboolean ret = FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return ret; if (device_is_touchpad (xdevice)) ret = property_get_bool (device, xdevice, property_name, property_index); xdevice_close (xdevice); return ret; } static void set_left_handed_legacy_driver (CsdMouseManager *manager, GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { XDevice *xdevice; guchar *buttons; gsize buttons_capacity = 16; gboolean left_handed; gint n_buttons; if (!xinput_device_has_buttons (device)) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting handedness on %s", gdk_device_get_name (device)); buttons = g_new (guchar, buttons_capacity); /* If the device is a touchpad, swap tap buttons * around too, otherwise a tap would be a right-click */ if (device_is_touchpad (xdevice)) { gboolean tap = g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK); gboolean single_button = touchpad_has_single_button (xdevice); left_handed = touchpad_left_handed; if (tap && !single_button) set_tap_to_click (device, tap, left_handed); if (single_button) goto out; } else { left_handed = mouse_left_handed; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, buttons_capacity); while (n_buttons > buttons_capacity) { buttons_capacity = n_buttons; buttons = (guchar *) g_realloc (buttons, buttons_capacity * sizeof (guchar)); n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, buttons_capacity); } configure_button_layout (buttons, n_buttons, left_handed); XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, n_buttons); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); out: xdevice_close (xdevice); g_free (buttons); } static void set_left_handed_libinput (GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { XDevice *xdevice; gboolean want_lefthanded; xdevice = open_gdk_device (device); if (xdevice == NULL) return; want_lefthanded = device_is_touchpad (xdevice) ? touchpad_left_handed : mouse_left_handed; property_set_bool (device, xdevice, "libinput Left Handed Enabled", 0, want_lefthanded); xdevice_close (xdevice); } static void set_left_handed (CsdMouseManager *manager, GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { if (property_exists_on_device (device, "libinput Left Handed Enabled")) set_left_handed_libinput (device, mouse_left_handed, touchpad_left_handed); else set_left_handed_legacy_driver (manager, device, mouse_left_handed, touchpad_left_handed); } static void set_motion_legacy_driver (CsdMouseManager *manager, GdkDevice *device) { XDevice *xdevice; XPtrFeedbackControl feedback; XFeedbackState *states, *state; int num_feedbacks; int numerator, denominator; gfloat motion_acceleration; gboolean custom_acceleration; int motion_threshold; gboolean custom_threshold; GSettings *settings; guint i; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting motion on %s", gdk_device_get_name (device)); if (device_is_touchpad (xdevice)) settings = manager->priv->touchpad_settings; else settings = manager->priv->mouse_settings; /* Calculate acceleration */ motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION); custom_acceleration = g_settings_get_boolean (settings, KEY_CUSTOM_ACCELERATION); if (custom_acceleration) { if (motion_acceleration >= 1.0) { /* we want to get the acceleration, with a resolution of 0.5 */ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) { numerator = floor (motion_acceleration); denominator = 1; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) { numerator = ceil (2.0 * motion_acceleration); denominator = 2; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) { numerator = floor (2.0 *motion_acceleration); denominator = 2; } else { numerator = ceil (motion_acceleration); denominator = 1; } } else if (motion_acceleration < 1.0 && motion_acceleration > 0) { /* This we do to 1/10ths */ numerator = floor (motion_acceleration * 10) + 1; denominator= 10; } else { numerator = -1; denominator = -1; } } else { numerator = -1; denominator = -1; } /* And threshold */ custom_threshold = g_settings_get_boolean (settings, KEY_CUSTOM_THRESHOLD); if (custom_threshold) { motion_threshold = g_settings_get_int (settings, KEY_MOTION_THRESHOLD); } else { motion_threshold = -1; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); /* Get the list of feedbacks for the device */ states = XGetFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, &num_feedbacks); if (states == NULL) goto out; state = (XFeedbackState *) states; for (i = 0; i < num_feedbacks; i++) { if (state->class == PtrFeedbackClass) { /* And tell the device */ feedback.class = PtrFeedbackClass; feedback.length = sizeof (XPtrFeedbackControl); feedback.id = state->id; feedback.threshold = motion_threshold; feedback.accelNum = numerator; feedback.accelDenom = denominator; g_debug ("Setting accel %d/%d, threshold %d for device '%s'", numerator, denominator, motion_threshold, gdk_device_get_name (device)); XChangeFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, DvAccelNum | DvAccelDenom | DvThreshold, (XFeedbackControl *) &feedback); break; } state = (XFeedbackState *) ((char *) state + state->length); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error setting acceleration on \"%s\"", gdk_device_get_name (device)); XFreeFeedbackList (states); out: xdevice_close (xdevice); } static void set_motion_libinput (CsdMouseManager *manager, GdkDevice *device) { int rc; XDevice *xdevice; GSettings *settings; Atom act_type, property, float_type; int act_format; unsigned long nitems, bytes_after; union { unsigned char *c; long *l; } data; gfloat accel; gfloat motion_acceleration; gboolean custom_acceleration; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting motion on %s", gdk_device_get_name (device)); if (device_is_touchpad (xdevice)) settings = manager->priv->touchpad_settings; else settings = manager->priv->mouse_settings; /* Calculate acceleration */ motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION); custom_acceleration = g_settings_get_boolean (settings, KEY_CUSTOM_ACCELERATION); /* panel gives us a range of 1.0-10.0, map to libinput's -1, 1 oldrange = (oldmax - oldmin) newrange = (newmax - newmin) mapped = (value - oldmin) * newrange / oldrange + oldmin */ if (motion_acceleration == -1.0 || !custom_acceleration) /* unset */ accel = 0.0; else accel = (motion_acceleration - 1.0) * 2.0 / 9.0 - 1; float_type = property_from_name ("FLOAT"); if (!float_type) return; property = property_from_name ("libinput Accel Speed"); if (!property) { return; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, float_type, &act_type, &act_format, &nitems, &bytes_after, &data.c); if (rc == Success && act_type == float_type && act_format == 32 && nitems >= 1) { *(float*)data.l = accel; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, float_type, 32, PropModeReplace, data.c, nitems); } if (rc == Success) { XFree (data.c); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while setting accel speed on \"%s\"", gdk_device_get_name (device)); } xdevice_close (xdevice); } static void set_motion (CsdMouseManager *manager, GdkDevice *device) { if (property_exists_on_device (device, "libinput Accel Speed")) set_motion_libinput (manager, device); else set_motion_legacy_driver (manager, device); } static void set_middle_button_evdev (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { Atom prop; XDevice *xdevice; Atom type; int format; unsigned long nitems, bytes_after; unsigned char *data; int rc; prop = property_from_name ("Evdev Middle Button Emulation"); if (!prop) /* no evdev devices */ return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting middle button on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) { data[0] = middle_button ? 1 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, type, format, PropModeReplace, data, nitems); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting middle button emulation on \"%s\"", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } static void set_middle_button_libinput (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { XDevice *xdevice; g_debug ("setting middle button on %s", gdk_device_get_name (device)); xdevice = open_gdk_device (device); if (xdevice == NULL) return; /* we didn't set it for synaptics, so bail out for touchpads */ if (device_is_touchpad (xdevice)) return; property_set_bool (device, xdevice, "libinput Middle Emulation Enabled", 0, middle_button); xdevice_close (xdevice); } static void set_middle_button (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { if (property_from_name ("Evdev Middle Button Emulation")) set_middle_button_evdev (manager, device, middle_button); if (property_from_name ("libinput Middle Emulation Enabled")) set_middle_button_libinput (manager, device, middle_button); } /* Ensure that syndaemon dies together with us, to avoid running several of * them */ static void setup_syndaemon (gpointer user_data) { #ifdef __linux prctl (PR_SET_PDEATHSIG, SIGHUP); #endif } static gboolean have_program_in_path (const char *name) { gchar *path; gboolean result; path = g_find_program_in_path (name); result = (path != NULL); g_free (path); return result; } static void syndaemon_died (GPid pid, gint status, gpointer user_data) { CsdMouseManager *manager = CSD_MOUSE_MANAGER (user_data); g_debug ("syndaemon stopped with status %i", status); g_spawn_close_pid (pid); manager->priv->syndaemon_spawned = FALSE; } static int set_disable_w_typing_synaptics (CsdMouseManager *manager, gboolean state) { if (state && touchpad_is_present ()) { GError *error = NULL; GPtrArray *args; if (manager->priv->syndaemon_spawned) return 0; if (!have_program_in_path ("syndaemon")) return 0; args = g_ptr_array_new (); g_ptr_array_add (args, "syndaemon"); g_ptr_array_add (args, "-i"); g_ptr_array_add (args, "1.0"); g_ptr_array_add (args, "-t"); g_ptr_array_add (args, "-K"); g_ptr_array_add (args, "-R"); g_ptr_array_add (args, NULL); /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid * double-forking, otherwise syndaemon will immediately get * killed again through (PR_SET_PDEATHSIG when the intermediate * process dies */ g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL, &manager->priv->syndaemon_pid, &error); manager->priv->syndaemon_spawned = (error == NULL); g_ptr_array_free (args, FALSE); if (error) { g_warning ("Failed to launch syndaemon: %s", error->message); g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE); g_error_free (error); } else { g_child_watch_add (manager->priv->syndaemon_pid, syndaemon_died, manager); g_debug ("Launched syndaemon"); } } else if (manager->priv->syndaemon_spawned) { kill (manager->priv->syndaemon_pid, SIGHUP); g_spawn_close_pid (manager->priv->syndaemon_pid); manager->priv->syndaemon_spawned = FALSE; g_debug ("Killed syndaemon"); } return 0; } static int set_disable_w_typing_libinput (CsdMouseManager *manager, gboolean state) { GList *devices, *l; /* This is only called once for synaptics but for libinput we need * to loop through the list of devices */ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; touchpad_set_bool (device, "libinput Disable While Typing Enabled", 0, state); } g_list_free (devices); return 0; } static int set_disable_w_typing (CsdMouseManager *manager, gboolean state) { if (property_from_name ("Synaptics Off")) set_disable_w_typing_synaptics (manager, state); if (property_from_name ("libinput Disable While Typing Enabled")) set_disable_w_typing_libinput (manager, state); return 0; } static int set_disable_w_mouse_attached_libinput (CsdMouseManager *manager, gboolean state) { GList *devices, *l; /* This is only called once for synaptics but for libinput we need * to loop through the list of devices */ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (touchpad_get_bool (device, "libinput Send Events Modes Available", 1)) { touchpad_set_bool (device, "libinput Send Events Mode Enabled", 1, state); } } g_list_free (devices); return 0; } static void set_disable_w_mouse_attached (CsdMouseManager *manager, gboolean state) { set_disable_w_mouse_attached_libinput (manager, state); } static void set_tap_to_click_synaptics (GdkDevice *device, gboolean state, gboolean left_handed) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; prop = property_from_name ("Synaptics Tap Action"); if (!prop) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting tap to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) { /* Set MR mapping for corner tapping on the right side*/ data[0] = (state) ? 2 : 0; data[1] = (state) ? 3 : 0; /* Set RLM mapping for 1/2/3 fingers*/ data[4] = (state) ? ((left_handed) ? 3 : 1) : 0; data[5] = (state) ? ((left_handed) ? 1 : 3) : 0; data[6] = (state) ? 2 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting tap to click on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_tap_to_click_libinput (GdkDevice *device, gboolean state) { g_debug ("setting tap to click on %s", gdk_device_get_name (device)); touchpad_set_bool (device, "libinput Tapping Enabled", 0, state); } static void set_tap_to_click (GdkDevice *device, gboolean state, gboolean left_handed) { if (property_from_name ("Synaptics Tap Action")) set_tap_to_click_synaptics (device, state, left_handed); if (property_from_name ("libinput Tapping Enabled")) set_tap_to_click_libinput (device, state); } static void set_click_actions_synaptics (GdkDevice *device, gint clickpad_click, gboolean left_handed) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; gboolean state; prop = property_from_name ("Synaptics Click Action"); if (!prop) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting click action to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); state = (clickpad_click == 2) || (clickpad_click == 3); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) { data[0] = 1; data[1] = (state)? ((left_handed) ? 1 : 3) : 0; data[2] = (state)? 2 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting click actions on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_click_actions_libinput (GdkDevice *device, gint clickpad_click) { int format, rc, rc_default; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data, * data_default; Atom prop, prop_default, type; prop = property_from_name ("libinput Click Method Enabled"); if (!prop) return; prop_default = property_from_name("libinput Click Method Enabled Default"); if (!prop_default && clickpad_click == 3) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting click action to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (clickpad_click == 3) { rc_default = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_default, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data_default); } if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 2 && (rc_default == Success || clickpad_click != 3)) { data[0] = (clickpad_click == 1) || (clickpad_click == 3 && data_default[0]); data[1] = (clickpad_click == 2) || (clickpad_click == 3 && data_default[1]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (clickpad_click == 3 && rc_default == Success) XFree (data_default); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting click actions on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_click_actions (GdkDevice *device, gint clickpad_click, gboolean left_handed) { if (property_from_name ("Synaptics Click Action")) set_click_actions_synaptics (device, clickpad_click, left_handed); if (property_from_name ("libinput Click Method Enabled")) set_click_actions_libinput (device, clickpad_click); } static void set_scrolling_synaptics (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { gboolean want_edge, want_2fg; want_2fg = (scrolling_method == 1 || scrolling_method == 3); want_edge = (scrolling_method == 2 || scrolling_method == 3); touchpad_set_bool (device, "Synaptics Edge Scrolling", 0, want_edge); touchpad_set_bool (device, "Synaptics Edge Scrolling", 1, want_edge && horizontal_scroll); touchpad_set_bool (device, "Synaptics Two-Finger Scrolling", 0, want_2fg); touchpad_set_bool (device, "Synaptics Two-Finger Scrolling", 1, want_2fg && horizontal_scroll); } static void set_scrolling_libinput (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { int format, rc, rc_default; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data, * data_default; Atom prop, prop_default, type; prop = property_from_name ("libinput Scroll Method Enabled"); if (!prop) return; prop_default = property_from_name("libinput Scroll Method Enabled Default"); if (!prop_default && scrolling_method == 3) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting scroll method on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (scrolling_method == 3) { rc_default = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_default, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data_default); } if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3 && (rc_default == Success || scrolling_method != 3)) { data[0] = (scrolling_method == 1) || (scrolling_method == 3 && data_default[0]); data[1] = (scrolling_method == 2) || (scrolling_method == 3 && data_default[1]); data[2] = 0 || (scrolling_method == 3 && data_default[2]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (scrolling_method == 3 && rc_default == Success) XFree (data_default); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting scroll method on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); /* there are versions of libinput around with an undocumented missing T in Horizontal */ if (property_from_name ("libinput Horizonal Scroll Enabled")) touchpad_set_bool (device, "libinput Horizonal Scroll Enabled", 0, horizontal_scroll); else touchpad_set_bool (device, "libinput Horizontal Scroll Enabled", 0, horizontal_scroll); } static void set_scrolling (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { if (property_from_name ("Synaptics Edge Scrolling")) set_scrolling_synaptics (device, scrolling_method, horizontal_scroll); if (property_from_name ("libinput Scroll Method Enabled")) set_scrolling_libinput (device, scrolling_method, horizontal_scroll); } static void set_touchpad_disabled (GdkDevice *device) { int id; XDevice *xdevice; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_debug ("Trying to set device disabled for \"%s\" (%d)", gdk_device_get_name (device), id); xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } if (set_device_enabled (id, FALSE) == FALSE) g_warning ("Error disabling device \"%s\" (%d)", gdk_device_get_name (device), id); else g_debug ("Disabled device \"%s\" (%d)", gdk_device_get_name (device), id); xdevice_close (xdevice); } static void set_touchpad_enabled (int id) { XDevice *xdevice; g_debug ("Trying to set device enabled for %d", id); gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != 0) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } if (set_device_enabled (id, TRUE) == FALSE) g_warning ("Error enabling device \"%d\"", id); else g_debug ("Enabled device %d", id); xdevice_close (xdevice); } static void set_locate_pointer (CsdMouseManager *manager, gboolean state) { if (state) { GError *error = NULL; char *args[2]; if (manager->priv->locate_pointer_spawned) return; args[0] = LIBEXECDIR "/csd-locate-pointer"; args[1] = NULL; g_spawn_async (NULL, args, NULL, 0, NULL, NULL, &manager->priv->locate_pointer_pid, &error); manager->priv->locate_pointer_spawned = (error == NULL); if (error) { g_settings_set_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER, FALSE); g_error_free (error); } } else if (manager->priv->locate_pointer_spawned) { kill (manager->priv->locate_pointer_pid, SIGHUP); g_spawn_close_pid (manager->priv->locate_pointer_pid); manager->priv->locate_pointer_spawned = FALSE; } } static void set_mousetweaks_daemon (CsdMouseManager *manager, gboolean dwell_click_enabled, gboolean secondary_click_enabled) { GError *error = NULL; gchar *comm; gboolean run_daemon = dwell_click_enabled || secondary_click_enabled; if (run_daemon || manager->priv->mousetweaks_daemon_running) comm = g_strdup_printf ("mousetweaks %s", run_daemon ? "" : "-s"); else return; if (run_daemon) manager->priv->mousetweaks_daemon_running = TRUE; if (! g_spawn_command_line_async (comm, &error)) { if (error->code == G_SPAWN_ERROR_NOENT && run_daemon) { if (dwell_click_enabled) { g_settings_set_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED, FALSE); } else if (secondary_click_enabled) { g_settings_set_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED, FALSE); } g_warning("Error enabling mouse accessibility features (mousetweaks is not installed)"); } g_error_free (error); } g_free (comm); } static gboolean get_touchpad_handedness (CsdMouseManager *manager, gboolean mouse_left_handed) { switch (g_settings_get_enum (manager->priv->touchpad_settings, KEY_LEFT_HANDED)) { case CSD_TOUCHPAD_HANDEDNESS_RIGHT: return FALSE; case CSD_TOUCHPAD_HANDEDNESS_LEFT: return TRUE; case CSD_TOUCHPAD_HANDEDNESS_MOUSE: return mouse_left_handed; default: g_assert_not_reached (); } } static void set_mouse_settings (CsdMouseManager *manager, GdkDevice *device) { gboolean mouse_left_handed, touchpad_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed); set_left_handed (manager, device, mouse_left_handed, touchpad_left_handed); set_motion (manager, device); set_middle_button (manager, device, g_settings_get_boolean (manager->priv->mouse_settings, KEY_MIDDLE_BUTTON_EMULATION)); set_tap_to_click (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK), touchpad_left_handed); set_click_actions( device, g_settings_get_int (manager->priv->touchpad_settings, KEY_CLICKPAD_CLICK), touchpad_left_handed); set_scrolling (device, g_settings_get_int (manager->priv->touchpad_settings, KEY_SCROLL_METHOD), g_settings_get_boolean (manager->priv->touchpad_settings, KEY_HORIZ_SCROLL)); if (gdkdevice_is_touchpad (device)) { set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_NATURAL_SCROLL_ENABLED)); } else { set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->mouse_settings, KEY_NATURAL_SCROLL_ENABLED)); } if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED) == FALSE) set_touchpad_disabled (device); } static void set_natural_scroll_synaptics (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { XDevice *xdevice; Atom scrolling_distance, act_type; int rc, act_format; unsigned long nitems, bytes_after; unsigned char *data; glong *ptr; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); scrolling_distance = property_from_name ("Synaptics Scrolling Distance"); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, scrolling_distance, 0, 2, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 32 && nitems >= 2) { ptr = (glong *) data; if (natural_scroll) { ptr[0] = -abs(ptr[0]); ptr[1] = -abs(ptr[1]); } else { ptr[0] = abs(ptr[0]); ptr[1] = abs(ptr[1]); } XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, scrolling_distance, XA_INTEGER, act_format, PropModeReplace, data, nitems); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error setting %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } static void set_natural_scroll_libinput (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); XDevice *xdevice; xdevice = open_gdk_device (device); if (xdevice == NULL) return; property_set_bool (device, xdevice, "libinput Natural Scrolling Enabled", 0, natural_scroll); xdevice_close (xdevice); } static void set_natural_scroll (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { if (property_from_name ("Synaptics Scrolling Distance")) set_natural_scroll_synaptics (manager, device, natural_scroll); if (property_from_name ("libinput Natural Scrolling Enabled")) set_natural_scroll_libinput (manager, device, natural_scroll); } static void mouse_callback (GSettings *settings, const gchar *key, CsdMouseManager *manager) { GList *devices, *l; if (g_str_equal (key, KEY_DWELL_CLICK_ENABLED) || g_str_equal (key, KEY_SECONDARY_CLICK_ENABLED)) { set_mousetweaks_daemon (manager, g_settings_get_boolean (settings, KEY_DWELL_CLICK_ENABLED), g_settings_get_boolean (settings, KEY_SECONDARY_CLICK_ENABLED)); return; } else if (g_str_equal (key, KEY_LOCATE_POINTER)) { set_locate_pointer (manager, g_settings_get_boolean (settings, KEY_LOCATE_POINTER)); return; } devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (gdkdevice_is_touchpad (device)) continue; if (g_str_equal (key, KEY_LEFT_HANDED)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (settings, KEY_LEFT_HANDED); set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) || g_str_equal (key, KEY_CUSTOM_ACCELERATION) || g_str_equal (key, KEY_MOTION_THRESHOLD) || g_str_equal (key, KEY_CUSTOM_THRESHOLD)) { set_motion (manager, device); } else if (g_str_equal (key, KEY_MIDDLE_BUTTON_EMULATION)) { set_middle_button (manager, device, g_settings_get_boolean (settings, KEY_MIDDLE_BUTTON_EMULATION)); } else if (g_str_equal (key, KEY_NATURAL_SCROLL_ENABLED)) { set_natural_scroll (manager, device, g_settings_get_boolean (settings, key)); } } g_list_free (devices); } /* Re-enable touchpad when any other pointing device isn't present. */ static void ensure_touchpad_active (CsdMouseManager *manager) { if (mouse_is_present () == FALSE && touchscreen_is_present () == FALSE && touchpad_is_present ()) g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED, TRUE); } static void touchpad_callback (GSettings *settings, const gchar *key, CsdMouseManager *manager) { GList *devices, *l; if (g_str_equal (key, KEY_TOUCHPAD_DISABLE_W_TYPING)) { set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, key)); return; } if (g_str_equal (key, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)) { set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, key)); return; } devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (!gdkdevice_is_touchpad (device)) continue; if (g_str_equal (key, KEY_TAP_TO_CLICK)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_tap_to_click (device, g_settings_get_boolean (settings, key), get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal(key, KEY_CLICKPAD_CLICK)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_click_actions( device, g_settings_get_int (manager->priv->touchpad_settings, KEY_CLICKPAD_CLICK), get_touchpad_handedness(manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_SCROLL_METHOD) || g_str_equal (key, KEY_HORIZ_SCROLL)) { set_scrolling (device, g_settings_get_int (manager->priv->touchpad_settings, KEY_SCROLL_METHOD), g_settings_get_boolean (manager->priv->touchpad_settings, KEY_HORIZ_SCROLL)); } else if (g_str_equal (key, KEY_TOUCHPAD_ENABLED)) { if (g_settings_get_boolean (settings, key) == FALSE) set_touchpad_disabled (device); else set_touchpad_enabled (gdk_x11_device_get_id (device)); } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) || g_str_equal (key, KEY_CUSTOM_ACCELERATION) || g_str_equal (key, KEY_MOTION_THRESHOLD) || g_str_equal (key, KEY_CUSTOM_THRESHOLD)) { set_motion (manager, device); } else if (g_str_equal (key, KEY_LEFT_HANDED)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_NATURAL_SCROLL_ENABLED)) { set_natural_scroll (manager, device, g_settings_get_boolean (settings, key)); } } g_list_free (devices); if (g_str_equal (key, KEY_TOUCHPAD_ENABLED) && g_settings_get_boolean (settings, key)) { devices = get_disabled_devices (manager->priv->device_manager); for (l = devices; l != NULL; l = l->next) { int device_id; device_id = GPOINTER_TO_INT (l->data); set_touchpad_enabled (device_id); } g_list_free (devices); } } static void device_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdMouseManager *manager) { if (device_is_ignored (manager, device) == FALSE) { if (run_custom_command (device, COMMAND_DEVICE_ADDED) == FALSE) { set_mouse_settings (manager, device); } else { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_insert (manager->priv->blacklist, GINT_TO_POINTER (id), GINT_TO_POINTER (1)); } /* If a touchpad was to appear... */ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)); } } static void device_removed_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdMouseManager *manager) { int id; /* Remove the device from the hash table so that * device_is_ignored () doesn't check for blacklisted devices */ g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_remove (manager->priv->blacklist, GINT_TO_POINTER (id)); if (device_is_ignored (manager, device) == FALSE) { run_custom_command (device, COMMAND_DEVICE_REMOVED); /* If a touchpad was to disappear... */ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); ensure_touchpad_active (manager); } } static void set_devicepresence_handler (CsdMouseManager *manager) { GdkDeviceManager *device_manager; device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (device_added_cb), manager); manager->priv->device_removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed", G_CALLBACK (device_removed_cb), manager); manager->priv->device_manager = device_manager; } static void csd_mouse_manager_init (CsdMouseManager *manager) { manager->priv = CSD_MOUSE_MANAGER_GET_PRIVATE (manager); manager->priv->blacklist = g_hash_table_new (g_direct_hash, g_direct_equal); } static gboolean csd_mouse_manager_idle_cb (CsdMouseManager *manager) { GList *devices, *l; cinnamon_settings_profile_start (NULL); set_devicepresence_handler (manager); manager->priv->mouse_settings = g_settings_new (SETTINGS_MOUSE_DIR); g_signal_connect (manager->priv->mouse_settings, "changed", G_CALLBACK (mouse_callback), manager); manager->priv->mouse_a11y_settings = g_settings_new ("org.cinnamon.desktop.a11y.mouse"); g_signal_connect (manager->priv->mouse_a11y_settings, "changed", G_CALLBACK (mouse_callback), manager); manager->priv->touchpad_settings = g_settings_new (SETTINGS_TOUCHPAD_DIR); g_signal_connect (manager->priv->touchpad_settings, "changed", G_CALLBACK (touchpad_callback), manager); manager->priv->syndaemon_spawned = FALSE; set_locate_pointer (manager, g_settings_get_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER)); set_mousetweaks_daemon (manager, g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED), g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED)); set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)); devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (run_custom_command (device, COMMAND_DEVICE_PRESENT) == FALSE) { set_mouse_settings (manager, device); } else { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_insert (manager->priv->blacklist, GINT_TO_POINTER (id), GINT_TO_POINTER (1)); } } g_list_free (devices); ensure_touchpad_active (manager); if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED)) { devices = get_disabled_devices (manager->priv->device_manager); for (l = devices; l != NULL; l = l->next) { int device_id; device_id = GPOINTER_TO_INT (l->data); set_touchpad_enabled (device_id); } g_list_free (devices); } cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_mouse_manager_start (CsdMouseManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); if (!supports_xinput_devices ()) { g_debug ("XInput is not supported, not applying any settings"); return TRUE; } manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_mouse_manager_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_mouse_manager_stop (CsdMouseManager *manager) { CsdMouseManagerPrivate *p = manager->priv; g_debug ("Stopping mouse manager"); if (manager->priv->start_idle_id != 0) { g_source_remove (manager->priv->start_idle_id); manager->priv->start_idle_id = 0; } if (p->device_manager != NULL) { g_signal_handler_disconnect (p->device_manager, p->device_added_id); g_signal_handler_disconnect (p->device_manager, p->device_removed_id); p->device_manager = NULL; } g_clear_object (&p->mouse_a11y_settings); g_clear_object (&p->mouse_settings); g_clear_object (&p->touchpad_settings); set_locate_pointer (manager, FALSE); } static void csd_mouse_manager_finalize (GObject *object) { CsdMouseManager *mouse_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MOUSE_MANAGER (object)); mouse_manager = CSD_MOUSE_MANAGER (object); g_return_if_fail (mouse_manager->priv != NULL); csd_mouse_manager_stop (mouse_manager); G_OBJECT_CLASS (csd_mouse_manager_parent_class)->finalize (object); } CsdMouseManager * csd_mouse_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_MOUSE_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_MOUSE_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-mouse-manager.h000066400000000000000000000043731356401377300247310ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_MOUSE_MANAGER_H #define __CSD_MOUSE_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_MOUSE_MANAGER (csd_mouse_manager_get_type ()) #define CSD_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManager)) #define CSD_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerClass)) #define CSD_IS_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MOUSE_MANAGER)) #define CSD_IS_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MOUSE_MANAGER)) #define CSD_MOUSE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerClass)) typedef struct CsdMouseManagerPrivate CsdMouseManagerPrivate; typedef struct { GObject parent; CsdMouseManagerPrivate *priv; } CsdMouseManager; typedef struct { GObjectClass parent_class; } CsdMouseManagerClass; GType csd_mouse_manager_get_type (void); CsdMouseManager * csd_mouse_manager_new (void); gboolean csd_mouse_manager_start (CsdMouseManager *manager, GError **error); void csd_mouse_manager_stop (CsdMouseManager *manager); G_END_DECLS #endif /* __CSD_MOUSE_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-timeline.c000066400000000000000000000474111356401377300237720ustar00rootroot00000000000000/* csd-timeline.c * * Copyright (C) 2008 Carlos Garnacho * * 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 #include #include #include "csd-timeline.h" #define CSD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CSD_TYPE_TIMELINE, CsdTimelinePriv)) #define MSECS_PER_SEC 1000 #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) #define DEFAULT_FPS 30 typedef struct CsdTimelinePriv CsdTimelinePriv; struct CsdTimelinePriv { guint duration; guint fps; guint source_id; GTimer *timer; GdkScreen *screen; CsdTimelineProgressType progress_type; CsdTimelineProgressFunc progress_func; guint loop : 1; guint direction : 1; }; enum { PROP_0, PROP_FPS, PROP_DURATION, PROP_LOOP, PROP_DIRECTION, PROP_SCREEN, PROP_PROGRESS_TYPE, }; enum { STARTED, PAUSED, FINISHED, FRAME, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void csd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_timeline_finalize (GObject *object); G_DEFINE_TYPE (CsdTimeline, csd_timeline, G_TYPE_OBJECT) GType csd_timeline_direction_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { CSD_TIMELINE_DIRECTION_FORWARD, "CSD_TIMELINE_DIRECTION_FORWARD", "forward" }, { CSD_TIMELINE_DIRECTION_BACKWARD, "CSD_TIMELINE_DIRECTION_BACKWARD", "backward" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("CsdTimelineDirection"), values); } return type; } GType csd_timeline_progress_type_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { CSD_TIMELINE_PROGRESS_LINEAR, "CSD_TIMELINE_PROGRESS_LINEAR", "linear" }, { CSD_TIMELINE_PROGRESS_SINUSOIDAL, "CSD_TIMELINE_PROGRESS_SINUSOIDAL", "sinusoidal" }, { CSD_TIMELINE_PROGRESS_EXPONENTIAL, "CSD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("CsdTimelineProgressType"), values); } return type; } static void csd_timeline_class_init (CsdTimelineClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->set_property = csd_timeline_set_property; object_class->get_property = csd_timeline_get_property; object_class->finalize = csd_timeline_finalize; g_object_class_install_property (object_class, PROP_FPS, g_param_spec_uint ("fps", "FPS", "Frames per second for the timeline", 1, G_MAXUINT, DEFAULT_FPS, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DURATION, g_param_spec_uint ("duration", "Animation Duration", "Animation Duration", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Whether the timeline loops or not", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("direction", "Direction", "Whether the timeline moves forward or backward in time", CSD_TYPE_TIMELINE_DIRECTION, CSD_TIMELINE_DIRECTION_FORWARD, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("progress-type", "Progress type", "Type of progress through the timeline", CSD_TYPE_TIMELINE_PROGRESS_TYPE, CSD_TIMELINE_PROGRESS_LINEAR, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SCREEN, g_param_spec_object ("screen", "Screen", "Screen to get the settings from", GDK_TYPE_SCREEN, G_PARAM_READWRITE)); signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, paused), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FINISHED] = g_signal_new ("finished", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FRAME] = g_signal_new ("frame", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, frame), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); g_type_class_add_private (class, sizeof (CsdTimelinePriv)); } static void csd_timeline_init (CsdTimeline *timeline) { CsdTimelinePriv *priv; priv = CSD_TIMELINE_GET_PRIV (timeline); priv->fps = DEFAULT_FPS; priv->duration = 0; priv->direction = CSD_TIMELINE_DIRECTION_FORWARD; priv->screen = gdk_screen_get_default (); } static void csd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdTimeline *timeline; timeline = CSD_TIMELINE (object); switch (prop_id) { case PROP_FPS: csd_timeline_set_fps (timeline, g_value_get_uint (value)); break; case PROP_DURATION: csd_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_LOOP: csd_timeline_set_loop (timeline, g_value_get_boolean (value)); break; case PROP_DIRECTION: csd_timeline_set_direction (timeline, g_value_get_enum (value)); break; case PROP_SCREEN: csd_timeline_set_screen (timeline, GDK_SCREEN (g_value_get_object (value))); break; case PROP_PROGRESS_TYPE: csd_timeline_set_progress_type (timeline, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdTimeline *timeline; CsdTimelinePriv *priv; timeline = CSD_TIMELINE (object); priv = CSD_TIMELINE_GET_PRIV (timeline); switch (prop_id) { case PROP_FPS: g_value_set_uint (value, priv->fps); break; case PROP_DURATION: g_value_set_uint (value, priv->duration); break; case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_SCREEN: g_value_set_object (value, priv->screen); break; case PROP_PROGRESS_TYPE: g_value_set_enum (value, priv->progress_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_timeline_finalize (GObject *object) { CsdTimelinePriv *priv; priv = CSD_TIMELINE_GET_PRIV (object); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } if (priv->timer) g_timer_destroy (priv->timer); G_OBJECT_CLASS (csd_timeline_parent_class)->finalize (object); } /* Sinusoidal progress */ static gdouble sinusoidal_progress (gdouble progress) { return (sinf ((progress * G_PI) / 2)); } static gdouble exponential_progress (gdouble progress) { return progress * progress; } static CsdTimelineProgressFunc progress_type_to_func (CsdTimelineProgressType type) { if (type == CSD_TIMELINE_PROGRESS_SINUSOIDAL) return sinusoidal_progress; else if (type == CSD_TIMELINE_PROGRESS_EXPONENTIAL) return exponential_progress; return NULL; } static gboolean csd_timeline_run_frame (CsdTimeline *timeline, gboolean enable_animations) { CsdTimelinePriv *priv; gdouble linear_progress, progress; guint elapsed_time; CsdTimelineProgressFunc progress_func = NULL; priv = CSD_TIMELINE_GET_PRIV (timeline); if (enable_animations) { elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; } else progress = (priv->direction == CSD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; g_signal_emit (timeline, signals [FRAME], 0, CLAMP (progress, 0.0, 1.0)); if ((priv->direction == CSD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) || (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0)) { if (!priv->loop) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } g_signal_emit (timeline, signals [FINISHED], 0); return FALSE; } else csd_timeline_rewind (timeline); } return TRUE; } static gboolean csd_timeline_frame_idle_func (CsdTimeline *timeline) { return csd_timeline_run_frame (timeline, TRUE); } /** * csd_timeline_new: * @duration: duration in milliseconds for the timeline * * Creates a new #CsdTimeline with the specified number of frames. * * Return Value: the newly created #CsdTimeline **/ CsdTimeline * csd_timeline_new (guint duration) { return g_object_new (CSD_TYPE_TIMELINE, "duration", duration, NULL); } CsdTimeline * csd_timeline_new_for_screen (guint duration, GdkScreen *screen) { return g_object_new (CSD_TYPE_TIMELINE, "duration", duration, "screen", screen, NULL); } /** * csd_timeline_start: * @timeline: A #CsdTimeline * * Runs the timeline from the current frame. **/ void csd_timeline_start (CsdTimeline *timeline) { CsdTimelinePriv *priv; GtkSettings *settings; gboolean enable_animations = FALSE; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->screen) { settings = gtk_settings_get_for_screen (priv->screen); g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL); } if (enable_animations) { if (!priv->source_id) { if (priv->timer) g_timer_continue (priv->timer); else priv->timer = g_timer_new (); /* sanity check */ g_assert (priv->fps > 0); g_signal_emit (timeline, signals [STARTED], 0); priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) csd_timeline_frame_idle_func, timeline); } } else { /* If animations are not enabled, only run the last frame, * it take us instantaneously to the last state of the animation. * The only potential flaw happens when people use the ::finished * signal to trigger another animation, or even worse, finally * loop into this animation again. */ g_signal_emit (timeline, signals [STARTED], 0); csd_timeline_run_frame (timeline, FALSE); } } /** * csd_timeline_pause: * @timeline: A #CsdTimeline * * Pauses the timeline. **/ void csd_timeline_pause (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; g_timer_stop (priv->timer); g_signal_emit (timeline, signals [PAUSED], 0); } } /** * csd_timeline_rewind: * @timeline: A #CsdTimeline * * Rewinds the timeline. **/ void csd_timeline_rewind (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); /* destroy and re-create timer if necessary */ if (priv->timer) { g_timer_destroy (priv->timer); if (csd_timeline_is_running (timeline)) priv->timer = g_timer_new (); else priv->timer = NULL; } } /** * csd_timeline_is_running: * @timeline: A #CsdTimeline * * Returns whether the timeline is running or not. * * Return Value: %TRUE if the timeline is running **/ gboolean csd_timeline_is_running (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), FALSE); priv = CSD_TIMELINE_GET_PRIV (timeline); return (priv->source_id != 0); } /** * csd_timeline_get_fps: * @timeline: A #CsdTimeline * * Returns the number of frames per second. * * Return Value: frames per second **/ guint csd_timeline_get_fps (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 1); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->fps; } /** * csd_timeline_set_fps: * @timeline: A #CsdTimeline * @fps: frames per second * * Sets the number of frames per second that * the timeline will play. **/ void csd_timeline_set_fps (CsdTimeline *timeline, guint fps) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); g_return_if_fail (fps > 0); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->fps = fps; if (csd_timeline_is_running (timeline)) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) csd_timeline_run_frame, timeline); } g_object_notify (G_OBJECT (timeline), "fps"); } /** * csd_timeline_get_loop: * @timeline: A #CsdTimeline * * Returns whether the timeline loops to the * beginning when it has reached the end. * * Return Value: %TRUE if the timeline loops **/ gboolean csd_timeline_get_loop (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), FALSE); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->loop; } /** * csd_timeline_set_loop: * @timeline: A #CsdTimeline * @loop: %TRUE to make the timeline loop * * Sets whether the timeline loops to the beginning * when it has reached the end. **/ void csd_timeline_set_loop (CsdTimeline *timeline, gboolean loop) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->loop = loop; g_object_notify (G_OBJECT (timeline), "loop"); } void csd_timeline_set_duration (CsdTimeline *timeline, guint duration) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->duration = duration; g_object_notify (G_OBJECT (timeline), "duration"); } guint csd_timeline_get_duration (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 0); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->duration; } /** * csd_timeline_get_direction: * @timeline: A #CsdTimeline * * Returns the direction of the timeline. * * Return Value: direction **/ CsdTimelineDirection csd_timeline_get_direction (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), CSD_TIMELINE_DIRECTION_FORWARD); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->direction; } /** * csd_timeline_set_direction: * @timeline: A #CsdTimeline * @direction: direction * * Sets the direction of the timeline. **/ void csd_timeline_set_direction (CsdTimeline *timeline, CsdTimelineDirection direction) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->direction = direction; g_object_notify (G_OBJECT (timeline), "direction"); } GdkScreen * csd_timeline_get_screen (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), NULL); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->screen; } void csd_timeline_set_screen (CsdTimeline *timeline, GdkScreen *screen) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); g_return_if_fail (GDK_IS_SCREEN (screen)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->screen) g_object_unref (priv->screen); priv->screen = g_object_ref (screen); g_object_notify (G_OBJECT (timeline), "screen"); } void csd_timeline_set_progress_type (CsdTimeline *timeline, CsdTimelineProgressType type) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->progress_type = type; g_object_notify (G_OBJECT (timeline), "progress-type"); } CsdTimelineProgressType csd_timeline_get_progress_type (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), CSD_TIMELINE_PROGRESS_LINEAR); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->progress_func) return CSD_TIMELINE_PROGRESS_LINEAR; return priv->progress_type; } /** * csd_timeline_set_progress_func: * @timeline: A #CsdTimeline * @progress_func: progress function * * Sets the progress function. This function will be used to calculate * a different progress to pass to the ::frame signal based on the * linear progress through the timeline. Setting progress_func * to %NULL will make the timeline use the default function, * which is just a linear progress. * * All progresses are in the [0.0, 1.0] range. **/ void csd_timeline_set_progress_func (CsdTimeline *timeline, CsdTimelineProgressFunc progress_func) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->progress_func = progress_func; } gdouble csd_timeline_get_progress (CsdTimeline *timeline) { CsdTimelinePriv *priv; CsdTimelineProgressFunc progress_func = NULL; gdouble linear_progress, progress; guint elapsed_time; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 0.0); priv = CSD_TIMELINE_GET_PRIV (timeline); if (!priv->timer) return 0.; elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; return CLAMP (progress, 0., 1.); } cinnamon-settings-daemon-4.4.0/plugins/mouse/csd-timeline.h000066400000000000000000000121051356401377300237670ustar00rootroot00000000000000/* csdtimeline.c * * Copyright (C) 2008 Carlos Garnacho * * 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 __CSD_TIMELINE_H__ #define __CSD_TIMELINE_H__ #include #include G_BEGIN_DECLS #define CSD_TYPE_TIMELINE_DIRECTION (csd_timeline_direction_get_type ()) #define CSD_TYPE_TIMELINE_PROGRESS_TYPE (csd_timeline_progress_type_get_type ()) #define CSD_TYPE_TIMELINE (csd_timeline_get_type ()) #define CSD_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_TIMELINE, CsdTimeline)) #define CSD_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_TIMELINE, CsdTimelineClass)) #define CSD_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_TIMELINE)) #define CSD_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_TIMELINE)) #define CSD_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSD_TYPE_TIMELINE, CsdTimelineClass)) typedef enum { CSD_TIMELINE_DIRECTION_FORWARD, CSD_TIMELINE_DIRECTION_BACKWARD } CsdTimelineDirection; typedef enum { CSD_TIMELINE_PROGRESS_LINEAR, CSD_TIMELINE_PROGRESS_SINUSOIDAL, CSD_TIMELINE_PROGRESS_EXPONENTIAL } CsdTimelineProgressType; typedef struct CsdTimeline CsdTimeline; typedef struct CsdTimelineClass CsdTimelineClass; struct CsdTimeline { GObject parent_instance; }; struct CsdTimelineClass { GObjectClass parent_class; void (* started) (CsdTimeline *timeline); void (* finished) (CsdTimeline *timeline); void (* paused) (CsdTimeline *timeline); void (* frame) (CsdTimeline *timeline, gdouble progress); void (* __csd_reserved1) (void); void (* __csd_reserved2) (void); void (* __csd_reserved3) (void); void (* __csd_reserved4) (void); }; typedef gdouble (*CsdTimelineProgressFunc) (gdouble progress); GType csd_timeline_get_type (void) G_GNUC_CONST; GType csd_timeline_direction_get_type (void) G_GNUC_CONST; GType csd_timeline_progress_type_get_type (void) G_GNUC_CONST; CsdTimeline *csd_timeline_new (guint duration); CsdTimeline *csd_timeline_new_for_screen (guint duration, GdkScreen *screen); void csd_timeline_start (CsdTimeline *timeline); void csd_timeline_pause (CsdTimeline *timeline); void csd_timeline_rewind (CsdTimeline *timeline); gboolean csd_timeline_is_running (CsdTimeline *timeline); guint csd_timeline_get_fps (CsdTimeline *timeline); void csd_timeline_set_fps (CsdTimeline *timeline, guint fps); gboolean csd_timeline_get_loop (CsdTimeline *timeline); void csd_timeline_set_loop (CsdTimeline *timeline, gboolean loop); guint csd_timeline_get_duration (CsdTimeline *timeline); void csd_timeline_set_duration (CsdTimeline *timeline, guint duration); GdkScreen *csd_timeline_get_screen (CsdTimeline *timeline); void csd_timeline_set_screen (CsdTimeline *timeline, GdkScreen *screen); CsdTimelineDirection csd_timeline_get_direction (CsdTimeline *timeline); void csd_timeline_set_direction (CsdTimeline *timeline, CsdTimelineDirection direction); CsdTimelineProgressType csd_timeline_get_progress_type (CsdTimeline *timeline); void csd_timeline_set_progress_type (CsdTimeline *timeline, CsdTimelineProgressType type); void csd_timeline_get_progress_func (CsdTimeline *timeline); void csd_timeline_set_progress_func (CsdTimeline *timeline, CsdTimelineProgressFunc progress_func); gdouble csd_timeline_get_progress (CsdTimeline *timeline); G_END_DECLS #endif /* __CSD_TIMELINE_H__ */ cinnamon-settings-daemon-4.4.0/plugins/mouse/main.c000066400000000000000000000010051356401377300223260ustar00rootroot00000000000000#define NEW csd_mouse_manager_new #define START csd_mouse_manager_start #define STOP csd_mouse_manager_stop #define MANAGER CsdMouseManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-mouse-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/orientation/000077500000000000000000000000001356401377300224455ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/orientation/Makefile.am000066400000000000000000000020351356401377300245010ustar00rootroot00000000000000plugin_name = orientation libexec_PROGRAMS = csd-orientation AM_CFLAGS = $(WARN_CFLAGS) csd_orientation_SOURCES = \ csd-orientation-manager.h \ csd-orientation-manager.c \ main.c csd_orientation_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(ORIENTATION_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_orientation_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(ORIENTATION_LIBS) \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-orientation.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-orientation.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/orientation/cinnamon-settings-daemon-orientation.desktop.in000066400000000000000000000003631356401377300337010ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - orientation Exec=@libexecdir@/csd-orientation OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/orientation/csd-orientation-manager.c000066400000000000000000000417601356401377300273330ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2010,2011 Red Hat, Inc. * * Author: Bastien Nocera * * 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 #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "csd-input-helper.h" #include "cinnamon-settings-profile.h" #include "csd-orientation-manager.h" typedef enum { ORIENTATION_UNDEFINED, ORIENTATION_NORMAL, ORIENTATION_BOTTOM_UP, ORIENTATION_LEFT_UP, ORIENTATION_RIGHT_UP } OrientationUp; #define CSD_ORIENTATION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerPrivate)) struct CsdOrientationManagerPrivate { /* Accelerometer */ guint watch_id; GDBusProxy *iio_proxy; gboolean has_accel; OrientationUp prev_orientation; /* DBus */ GDBusProxy *xrandr_proxy; GCancellable *cancellable; /* Notifications */ GSettings *settings; gboolean orientation_lock; }; #define CONF_SCHEMA "org.cinnamon.settings-daemon.peripherals.touchscreen" #define ORIENTATION_LOCK_KEY "orientation-lock" static void csd_orientation_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdOrientationManager, csd_orientation_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define MPU_THRESHOLD 12000 #define MPU_POLL_INTERVAL 1 static gboolean is_mpu6050 = FALSE; static char *mpu6050_accel_x = NULL; static char *mpu6050_accel_y = NULL; static gboolean mpu_timer(CsdOrientationManager *manager); static void csd_orientation_manager_class_init (CsdOrientationManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_orientation_manager_finalize; g_type_class_add_private (klass, sizeof (CsdOrientationManagerPrivate)); } static void csd_orientation_manager_init (CsdOrientationManager *manager) { manager->priv = CSD_ORIENTATION_MANAGER_GET_PRIVATE (manager); manager->priv->prev_orientation = ORIENTATION_UNDEFINED; } static GnomeRRRotation orientation_to_rotation (OrientationUp orientation) { switch (orientation) { case ORIENTATION_NORMAL: return GNOME_RR_ROTATION_0; case ORIENTATION_BOTTOM_UP: return GNOME_RR_ROTATION_180; case ORIENTATION_LEFT_UP: return GNOME_RR_ROTATION_90; case ORIENTATION_RIGHT_UP: return GNOME_RR_ROTATION_270; default: g_assert_not_reached (); } } static OrientationUp orientation_from_string (const char *orientation) { if (g_strcmp0 (orientation, "normal") == 0) return ORIENTATION_NORMAL; if (g_strcmp0 (orientation, "bottom-up") == 0) return ORIENTATION_BOTTOM_UP; if (g_strcmp0 (orientation, "left-up") == 0) return ORIENTATION_LEFT_UP; if (g_strcmp0 (orientation, "right-up") == 0) return ORIENTATION_RIGHT_UP; return ORIENTATION_UNDEFINED; } static const char * orientation_to_string (OrientationUp o) { switch (o) { case ORIENTATION_UNDEFINED: return "undefined"; case ORIENTATION_NORMAL: return "normal"; case ORIENTATION_BOTTOM_UP: return "bottom-up"; case ORIENTATION_LEFT_UP: return "left-up"; case ORIENTATION_RIGHT_UP: return "right-up"; default: g_assert_not_reached (); } } static OrientationUp get_orientation_from_device (CsdOrientationManager *manager) { GVariant *v; OrientationUp o; v = g_dbus_proxy_get_cached_property (manager->priv->iio_proxy, "AccelerometerOrientation"); if (v == NULL) { g_debug ("Couldn't find orientation for accelerometer"); return ORIENTATION_UNDEFINED; } g_debug ("Found orientation '%s' for accelerometer", g_variant_get_string (v, NULL)); o = orientation_from_string (g_variant_get_string (v, NULL)); g_variant_unref (v); return o; } static void on_xrandr_action_call_finished (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { GError *error = NULL; GVariant *variant; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); g_clear_object (&manager->priv->cancellable); if (variant == NULL) { g_warning ("Unable to call 'RotateTo': %s", error->message); g_error_free (error); } else { g_variant_unref (variant); } } static void do_xrandr_action (CsdOrientationManager *manager, GnomeRRRotation rotation) { CsdOrientationManagerPrivate *priv = manager->priv; GTimeVal tv; gint64 timestamp; if (priv->xrandr_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle XRANDR keys"); return; } if (priv->cancellable != NULL) { g_debug ("xrandr action already in flight"); return; } g_get_current_time (&tv); timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; priv->cancellable = g_cancellable_new (); g_dbus_proxy_call (priv->xrandr_proxy, "RotateTo", g_variant_new ("(ix)", rotation, timestamp), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, (GAsyncReadyCallback) on_xrandr_action_call_finished, manager); } static void do_rotation (CsdOrientationManager *manager) { GnomeRRRotation rotation; if (manager->priv->orientation_lock) { g_debug ("Orientation changed, but we are locked"); return; } if (manager->priv->prev_orientation == ORIENTATION_UNDEFINED) { g_debug ("Not trying to rotate, orientation is undefined"); return; } rotation = orientation_to_rotation (manager->priv->prev_orientation); do_xrandr_action (manager, rotation); } static void orientation_lock_changed_cb (GSettings *settings, gchar *key, CsdOrientationManager *manager) { gboolean new; new = g_settings_get_boolean (settings, ORIENTATION_LOCK_KEY); if (new == manager->priv->orientation_lock) return; manager->priv->orientation_lock = new; if (new == FALSE) { if (is_mpu6050) { g_timeout_add_seconds(MPU_POLL_INTERVAL, (GSourceFunc) mpu_timer, manager); } /* Handle the rotations that could have occurred while * we were locked */ do_rotation (manager); } } static void properties_changed (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer user_data) { CsdOrientationManager *manager = user_data; CsdOrientationManagerPrivate *p = manager->priv; GVariant *v; GVariantDict dict; if (manager->priv->xrandr_proxy == NULL) return; if (changed_properties) g_variant_dict_init (&dict, changed_properties); if (changed_properties == NULL || g_variant_dict_contains (&dict, "HasAccelerometer")) { v = g_dbus_proxy_get_cached_property (p->iio_proxy, "HasAccelerometer"); if (v == NULL) { g_debug ("Couldn't fetch HasAccelerometer property"); return; } p->has_accel = g_variant_get_boolean (v); if (!p->has_accel) p->prev_orientation = ORIENTATION_UNDEFINED; g_variant_unref (v); } if (changed_properties == NULL || g_variant_dict_contains (&dict, "AccelerometerOrientation")) { if (p->has_accel) { OrientationUp orientation; orientation = get_orientation_from_device (manager); if (orientation != p->prev_orientation) { p->prev_orientation = orientation; g_debug ("Orientation changed to '%s', switching screen rotation", orientation_to_string (p->prev_orientation)); do_rotation (manager); } } } } static void xrandr_ready_cb (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { CsdOrientationManagerPrivate *p = manager->priv; GError *error = NULL; manager->priv->xrandr_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->xrandr_proxy == NULL) { g_warning ("Failed to get proxy for XRandR operations: %s", error->message); g_error_free (error); } if (p->iio_proxy == NULL) return; properties_changed (manager->priv->iio_proxy, NULL, NULL, manager); } static int read_sysfs_attr_as_int(const char *filename) { int i, c; char buf[40]; int fd = open(filename, O_RDONLY); if (fd < 0) return 0; c = read(fd, buf, 40); if (c < 0) return 0; close(fd); sscanf(buf, "%d", &i); return i; } static gboolean mpu_timer(CsdOrientationManager *manager) { int x, y; static gboolean first = TRUE; OrientationUp orientation = manager->priv->prev_orientation; if (manager->priv->xrandr_proxy == NULL) return TRUE; x = read_sysfs_attr_as_int(mpu6050_accel_x); y = read_sysfs_attr_as_int(mpu6050_accel_y); if (x > MPU_THRESHOLD) orientation = ORIENTATION_NORMAL; if (x < -MPU_THRESHOLD) orientation = ORIENTATION_BOTTOM_UP; if (y > MPU_THRESHOLD) orientation = ORIENTATION_RIGHT_UP; if (y < -MPU_THRESHOLD) orientation = ORIENTATION_LEFT_UP; if (orientation != manager->priv->prev_orientation || first) { first = FALSE; manager->priv->prev_orientation = orientation; g_debug ("Orientation changed to '%s', switching screen rotation", orientation_to_string (manager->priv->prev_orientation)); do_rotation (manager); } return !manager->priv->orientation_lock; } static void iio_sensor_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { CsdOrientationManager *manager = user_data; CsdOrientationManagerPrivate *p = manager->priv; GError *error = NULL; p->iio_proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "net.hadess.SensorProxy", "/net/hadess/SensorProxy", "net.hadess.SensorProxy", NULL, &error); if (p->iio_proxy == NULL) { g_warning ("Failed to access net.hadess.SensorProxy after it appeared"); return; } g_dbus_proxy_call_sync (p->iio_proxy, "ClaimAccelerometer", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_signal_connect (G_OBJECT (manager->priv->iio_proxy), "g-properties-changed", G_CALLBACK (properties_changed), manager); properties_changed (manager->priv->iio_proxy, NULL, NULL, manager); } static void iio_sensor_vanished_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdOrientationManager *manager = user_data; g_clear_object (&manager->priv->iio_proxy); manager->priv->has_accel = FALSE; manager->priv->prev_orientation = ORIENTATION_UNDEFINED; } gboolean csd_orientation_manager_start (CsdOrientationManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new (CONF_SCHEMA); g_signal_connect (G_OBJECT (manager->priv->settings), "changed::" ORIENTATION_LOCK_KEY, G_CALLBACK (orientation_lock_changed_cb), manager); manager->priv->orientation_lock = g_settings_get_boolean (manager->priv->settings, ORIENTATION_LOCK_KEY); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon.XRANDR_2", "/org/cinnamon/SettingsDaemon/XRANDR", "org.cinnamon.SettingsDaemon.XRANDR_2", NULL, (GAsyncReadyCallback) xrandr_ready_cb, manager); manager->priv->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, "net.hadess.SensorProxy", G_BUS_NAME_WATCHER_FLAGS_NONE, iio_sensor_appeared_cb, iio_sensor_vanished_cb, manager, NULL); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_orientation_manager_stop (CsdOrientationManager *manager) { CsdOrientationManagerPrivate *p = manager->priv; g_debug ("Stopping orientation manager"); if (p->watch_id > 0) { g_bus_unwatch_name (p->watch_id); p->watch_id = 0; } if (p->iio_proxy) { g_dbus_proxy_call_sync (p->iio_proxy, "ReleaseAccelerometer", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_clear_object (&p->iio_proxy); } g_clear_object (&p->xrandr_proxy); g_clear_object (&p->settings); p->has_accel = FALSE; if (p->cancellable) { g_cancellable_cancel (p->cancellable); g_clear_object (&p->cancellable); } } static void csd_orientation_manager_finalize (GObject *object) { CsdOrientationManager *orientation_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_ORIENTATION_MANAGER (object)); orientation_manager = CSD_ORIENTATION_MANAGER (object); g_return_if_fail (orientation_manager->priv != NULL); csd_orientation_manager_stop (orientation_manager); G_OBJECT_CLASS (csd_orientation_manager_parent_class)->finalize (object); } CsdOrientationManager * csd_orientation_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_ORIENTATION_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_ORIENTATION_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/orientation/csd-orientation-manager.h000066400000000000000000000047231356401377300273360ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2010 Red Hat, 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 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 __CSD_ORIENTATION_MANAGER_H #define __CSD_ORIENTATION_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_ORIENTATION_MANAGER (csd_orientation_manager_get_type ()) #define CSD_ORIENTATION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManager)) #define CSD_ORIENTATION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerClass)) #define CSD_IS_ORIENTATION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_ORIENTATION_MANAGER)) #define CSD_IS_ORIENTATION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_ORIENTATION_MANAGER)) #define CSD_ORIENTATION_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerClass)) typedef struct CsdOrientationManagerPrivate CsdOrientationManagerPrivate; typedef struct { GObject parent; CsdOrientationManagerPrivate *priv; } CsdOrientationManager; typedef struct { GObjectClass parent_class; } CsdOrientationManagerClass; GType csd_orientation_manager_get_type (void); CsdOrientationManager * csd_orientation_manager_new (void); gboolean csd_orientation_manager_start (CsdOrientationManager *manager, GError **error); void csd_orientation_manager_stop (CsdOrientationManager *manager); G_END_DECLS #endif /* __CSD_ORIENTATION_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/orientation/main.c000066400000000000000000000010431356401377300235330ustar00rootroot00000000000000#define NEW csd_orientation_manager_new #define START csd_orientation_manager_start #define STOP csd_orientation_manager_stop #define MANAGER CsdOrientationManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-orientation-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/power/000077500000000000000000000000001356401377300212465ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/power/Makefile.am000066400000000000000000000072351356401377300233110ustar00rootroot00000000000000plugin_name = power AM_CFLAGS = $(WARN_CFLAGS) org.cinnamon.settings-daemon.plugins.power.policy.in: org.cinnamon.settings-daemon.plugins.power.policy.in.in Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ @INTLTOOL_POLICY_RULE@ polkit_policydir = $(datadir)/polkit-1/actions polkit_policy_in_files = org.cinnamon.settings-daemon.plugins.power.policy.in polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy) # so it always gets included in the tarball csd_backlight_helper_SOURCES = \ csd-backlight-helper.c csd-power-proxy.h : Makefile.am org.cinnamon.SettingsDaemon.Power.xml gdbus-codegen \ --c-namespace Csd \ --annotate "org.cinnamon.SettingsDaemon.Power" org.gtk.GDBus.C.Name "Power" \ --generate-c-code csd-power-proxy \ org.cinnamon.SettingsDaemon.Power.xml \ $(NULL) csd-power-proxy.c : csd-power-proxy.h csd-power-screen-proxy.h : Makefile.am org.cinnamon.SettingsDaemon.Power.Screen.xml gdbus-codegen \ --c-namespace Csd \ --annotate "org.cinnamon.SettingsDaemon.Power.Screen" org.gtk.GDBus.C.Name "Screen" \ --generate-c-code csd-power-screen-proxy \ org.cinnamon.SettingsDaemon.Power.Screen.xml \ $(NULL) csd-power-screen-proxy.c : csd-power-screen-proxy.h csd-power-keyboard-proxy.h : Makefile.am org.cinnamon.SettingsDaemon.Power.Keyboard.xml gdbus-codegen \ --c-namespace Csd \ --annotate "org.cinnamon.SettingsDaemon.Power.Keyboard" org.gtk.GDBus.C.Name "Keyboard" \ --generate-c-code csd-power-keyboard-proxy \ org.cinnamon.SettingsDaemon.Power.Keyboard.xml \ $(NULL) csd-power-keyboard-proxy.c : csd-power-keyboard-proxy.h libexec_PROGRAMS = csd-power csd_power_SOURCES = \ gpm-common.c \ gpm-common.h \ gpm-phone.c \ gpm-phone.h \ gpm-idletime.c \ gpm-idletime.h \ csd-power-proxy.c \ csd-power-proxy.h \ csd-power-screen-proxy.c \ csd-power-screen-proxy.h \ csd-power-keyboard-proxy.c \ csd-power-keyboard-proxy.h \ csd-power-manager.c \ csd-power-manager.h \ main.c csd_power_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(POWER_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_power_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DSBINDIR=\"$(sbindir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ $(AM_CPPFLAGS) csd_power_LDADD = \ -lm \ $(top_builddir)/plugins/common/libcommon.la \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(POWER_LIBS) \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-power.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-power.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) \ $(csd_backlight_helper_SOURCES) if HAVE_GUDEV libexec_PROGRAMS += \ csd-backlight-helper csd_backlight_helper_LDFLAGS = \ $(BACKLIGHT_HELPER_LIBS) \ -lm csd_backlight_helper_CFLAGS = \ $(WARN_CFLAGS) \ $(BACKLIGHT_HELPER_CFLAGS) EXTRA_DIST += \ org.cinnamon.settings-daemon.plugins.power.policy.in.in endif clean-local: rm -f *~ CLEANFILES = \ $(desktop_DATA) \ org.cinnamon.settings-daemon.plugins.power.policy \ org.cinnamon.settings-daemon.plugins.power.policy.in cinnamon-settings-daemon-4.4.0/plugins/power/cinnamon-settings-daemon-power.desktop.in000066400000000000000000000003471356401377300313050ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - power Exec=@libexecdir@/csd-power OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/power/csd-backlight-helper.c000066400000000000000000000162311356401377300253710ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #define CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS 0 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_FAILED 1 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID 3 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_INVALID_USER 4 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_NO_DEVICES 5 #define CSD_POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power" static gchar * csd_backlight_helper_get_type (GList *devices, const gchar *type) { const gchar *type_tmp; GList *d; for (d = devices; d != NULL; d = d->next) { type_tmp = g_udev_device_get_sysfs_attr (d->data, "type"); if (g_strcmp0 (type_tmp, type) == 0) return g_strdup (g_udev_device_get_sysfs_path (d->data)); } return NULL; } static gchar * csd_backlight_helper_get_best_backlight (gchar** preference_list) { gchar *path = NULL; GList *devices; GUdevClient *client; client = g_udev_client_new (NULL); devices = g_udev_client_query_by_subsystem (client, "backlight"); if (devices == NULL) goto out; /* setup our gsettings interface */ if (preference_list == NULL || preference_list[0] == NULL) { g_print("%s\n%s\n", "Warning: no backlight sources have been configured.", "Check " CSD_POWER_SETTINGS_SCHEMA " to configure some."); goto out; } int i = 0; for (i=0; preference_list[i] != NULL; i++) { path = csd_backlight_helper_get_type (devices, preference_list[i]); if (path != NULL) goto out; } out: g_object_unref (client); g_list_foreach (devices, (GFunc) g_object_unref, NULL); g_list_free (devices); return path; } static gboolean csd_backlight_helper_write (const gchar *filename, gint value, GError **error) { gchar *text = NULL; gint retval; gint length; gint fd = -1; gboolean ret = TRUE; fd = open (filename, O_WRONLY); if (fd < 0) { ret = FALSE; g_set_error (error, 1, 0, "failed to open filename: %s", filename); goto out; } /* convert to text */ text = g_strdup_printf ("%i", value); length = strlen (text); /* write to device file */ retval = write (fd, text, length); if (retval != length) { ret = FALSE; g_set_error (error, 1, 0, "writing '%s' to %s failed", text, filename); goto out; } out: if (fd >= 0) close (fd); g_free (text); return ret; } int main (int argc, char *argv[]) { GOptionContext *context; gint uid; gint euid; guint retval = 0; GError *error = NULL; gboolean ret = FALSE; gint set_brightness = -1; gboolean get_brightness = FALSE; gboolean get_max_brightness = FALSE; gchar *filename = NULL; gchar *filename_file = NULL; gchar *contents = NULL; gchar** backlight_preference_order = NULL; const GOptionEntry options[] = { { "set-brightness", '\0', 0, G_OPTION_ARG_INT, &set_brightness, /* command line argument */ "Set the current brightness", NULL }, { "get-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_brightness, /* command line argument */ "Get the current brightness", NULL }, { "get-max-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_max_brightness, /* command line argument */ "Get the number of brightness levels supported", NULL }, { "backlight-preference", 'b', 0, G_OPTION_ARG_STRING_ARRAY, &backlight_preference_order, /* command line argument */ "Set a backlight control search preference", NULL }, { NULL} }; context = g_option_context_new (NULL); g_option_context_set_summary (context, "Cinnamon Settings Daemon Backlight Helper"); g_option_context_add_main_entries (context, options, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); #ifndef __linux__ /* the g-s-d plugin should only call this helper on linux */ g_critical ("Attempting to call gsb-backlight-helper on non-Linux"); g_assert_not_reached (); #endif /* no input */ if (set_brightness == -1 && !get_brightness && !get_max_brightness) { g_print ("%s\n", "No valid option was specified"); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* find device */ filename = csd_backlight_helper_get_best_backlight (backlight_preference_order); if (filename == NULL) { retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_NO_DEVICES; g_print ("%s: %s\n", "Could not get or set the value of the backlight", "No backlight devices present"); goto out; } /* GetBrightness */ if (get_brightness) { filename_file = g_build_filename (filename, "brightness", NULL); ret = g_file_get_contents (filename_file, &contents, NULL, &error); if (!ret) { g_print ("%s: %s\n", "Could not get the value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* just print the contents to stdout */ g_print ("%s", contents); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; goto out; } /* GetSteps */ if (get_max_brightness) { filename_file = g_build_filename (filename, "max_brightness", NULL); ret = g_file_get_contents (filename_file, &contents, NULL, &error); if (!ret) { g_print ("%s: %s\n", "Could not get the maximum value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* just print the contents to stdout */ g_print ("%s", contents); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; goto out; } /* check calling UID */ uid = getuid (); euid = geteuid (); if (uid != 0 || euid != 0) { g_print ("%s\n", "This program can only be used by the root user"); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* SetBrightness */ if (set_brightness != -1) { filename_file = g_build_filename (filename, "brightness", NULL); ret = csd_backlight_helper_write (filename_file, set_brightness, &error); if (!ret) { g_print ("%s: %s\n", "Could not set the value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } } /* success */ retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; out: g_free (filename); g_free (filename_file); g_free (contents); return retval; } cinnamon-settings-daemon-4.4.0/plugins/power/csd-power-manager.c000066400000000000000000005631741356401377300247450ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * Copyright (C) 2011 Ritesh Khadgaray * * 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 #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "gpm-common.h" #include "gpm-phone.h" #include "gpm-idletime.h" #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-enums.h" #include "csd-power-manager.h" #include "csd-power-helper.h" #include "csd-power-proxy.h" #include "csd-power-screen-proxy.h" #include "csd-power-keyboard-proxy.h" #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_PATH_PRESENCE "/org/gnome/SessionManager/Presence" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_INTERFACE_PRESENCE "org.gnome.SessionManager.Presence" #define UPOWER_DBUS_NAME "org.freedesktop.UPower" #define UPOWER_DBUS_PATH_KBDBACKLIGHT "/org/freedesktop/UPower/KbdBacklight" #define UPOWER_DBUS_INTERFACE_KBDBACKLIGHT "org.freedesktop.UPower.KbdBacklight" #define CSD_POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power" #define CSD_XRANDR_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.xrandr" #define CSD_SESSION_SETTINGS_SCHEMA "org.cinnamon.desktop.session" #define CSD_CINNAMON_SESSION_SCHEMA "org.cinnamon.SessionManager" #define CSD_POWER_DBUS_PATH "/org/cinnamon/SettingsDaemon/Power" #define CSD_POWER_DBUS_INTERFACE "org.cinnamon.SettingsDaemon.Power" #define CSD_POWER_DBUS_INTERFACE_SCREEN "org.cinnamon.SettingsDaemon.Power.Screen" #define CSD_POWER_DBUS_INTERFACE_KEYBOARD "org.cinnamon.SettingsDaemon.Power.Keyboard" #define GS_DBUS_NAME "org.cinnamon.ScreenSaver" #define GS_DBUS_PATH "/org/cinnamon/ScreenSaver" #define GS_DBUS_INTERFACE "org.cinnamon.ScreenSaver" #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_NEVER 0 /* ms */ #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_SHORT 10 * 1000 /* ms */ #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG 30 * 1000 /* ms */ #define CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT 5 /* seconds */ #define CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT 30 /* seconds */ #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" /* Keep this in sync with gnome-shell */ #define SCREENSAVER_FADE_TIME 10 /* seconds */ #define XSCREENSAVER_WATCHDOG_TIMEOUT 120 /* seconds */ enum { CSD_POWER_IDLETIME_NULL_ID, CSD_POWER_IDLETIME_DIM_ID, CSD_POWER_IDLETIME_BLANK_ID, CSD_POWER_IDLETIME_SLEEP_ID }; /* on ACPI machines we have 4-16 levels, on others it's ~150 */ #define BRIGHTNESS_STEP_AMOUNT(max) ((max) < 20 ? 1 : (max) / 20) /* take a discrete value with offset and convert to percentage */ static int abs_to_percentage (int min, int max, int value) { g_return_val_if_fail (max > min, -1); g_return_val_if_fail (value >= min, -1); g_return_val_if_fail (value <= max, -1); return (((value - min) * 100) / (max - min)); } #define ABS_TO_PERCENTAGE(min, max, value) abs_to_percentage(min, max, value) #define PERCENTAGE_TO_ABS(min, max, value) (min + (((max - min) * value) / 100)) #define CSD_POWER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManagerPrivate)) typedef enum { CSD_POWER_IDLE_MODE_NORMAL, CSD_POWER_IDLE_MODE_DIM, CSD_POWER_IDLE_MODE_BLANK, CSD_POWER_IDLE_MODE_SLEEP } CsdPowerIdleMode; struct CsdPowerManagerPrivate { CinnamonSettingsSession *session; guint p_name_id; guint s_name_id; guint k_name_id; CsdPower *power_iface; CsdScreen *screen_iface; CsdKeyboard *keyboard_iface; gboolean lid_is_closed; gboolean on_battery; GSettings *settings; GSettings *settings_screensaver; GSettings *settings_xrandr; GSettings *settings_desktop_session; GSettings *settings_cinnamon_session; UpClient *up_client; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusProxy *upower_kbd_proxy; gboolean backlight_helper_force; gchar* backlight_helper_preference_args; gint kbd_brightness_now; gint kbd_brightness_max; gint kbd_brightness_old; gint kbd_brightness_pre_dim; GnomeRRScreen *x11_screen; gboolean use_time_primary; gchar *previous_summary; GIcon *previous_icon; GpmPhone *phone; GPtrArray *devices_array; guint action_percentage; guint action_time; guint critical_percentage; guint critical_time; guint low_percentage; guint low_time; gint pre_dim_brightness; /* level, not percentage */ UpDevice *device_composite; NotifyNotification *notification_discharging; NotifyNotification *notification_low; ca_context *canberra_context; ca_proplist *critical_alert_loop_props; guint32 critical_alert_timeout_id; GDBusProxy *screensaver_proxy; GDBusProxy *session_proxy; GDBusProxy *session_presence_proxy; GpmIdletime *idletime; CsdPowerIdleMode current_idle_mode; guint lid_close_safety_timer_id; GtkStatusIcon *status_icon; guint xscreensaver_watchdog_timer_id; gboolean is_virtual_machine; /* logind stuff */ GDBusProxy *logind_proxy; gboolean inhibit_lid_switch_enabled; gint inhibit_lid_switch_fd; gboolean inhibit_lid_switch_taken; gint inhibit_suspend_fd; gboolean inhibit_suspend_taken; guint inhibit_lid_switch_timer_id; }; enum { PROP_0, }; static void csd_power_manager_finalize (GObject *object); static UpDevice *engine_get_composite_device (CsdPowerManager *manager, UpDevice *original_device); static UpDevice *engine_update_composite_device (CsdPowerManager *manager, UpDevice *original_device); static GIcon *engine_get_icon (CsdPowerManager *manager); static gchar *engine_get_summary (CsdPowerManager *manager); static gboolean external_monitor_is_connected (GnomeRRScreen *screen); static void do_power_action_type (CsdPowerManager *manager, CsdPowerActionType action_type); static void do_lid_closed_action (CsdPowerManager *manager); static void inhibit_lid_switch (CsdPowerManager *manager); static void uninhibit_lid_switch (CsdPowerManager *manager); static void lock_screensaver (CsdPowerManager *manager); static void kill_lid_close_safety_timer (CsdPowerManager *manager); int backlight_get_output_id (CsdPowerManager *manager); #if UP_CHECK_VERSION(0,99,0) static void device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager); #endif G_DEFINE_TYPE (CsdPowerManager, csd_power_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; GQuark csd_power_manager_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("csd_power_manager_error"); return quark; } static gboolean play_loop_timeout_cb (CsdPowerManager *manager) { ca_context *context; context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); ca_context_play_full (context, 0, manager->priv->critical_alert_loop_props, NULL, NULL); return TRUE; } static gboolean play_loop_stop (CsdPowerManager *manager) { if (manager->priv->critical_alert_timeout_id == 0) { g_warning ("no sound loop present to stop"); return FALSE; } if (manager->priv->critical_alert_timeout_id) { g_source_remove (manager->priv->critical_alert_timeout_id); manager->priv->critical_alert_timeout_id = 0; } ca_proplist_destroy (manager->priv->critical_alert_loop_props); manager->priv->critical_alert_loop_props = NULL; manager->priv->critical_alert_timeout_id = 0; return TRUE; } static gboolean play_loop_start (CsdPowerManager *manager, const gchar *id, const gchar *desc, gboolean force, guint timeout) { ca_context *context; if (timeout == 0) { g_warning ("received invalid timeout"); return FALSE; } /* if a sound loop is already running, stop the existing loop */ if (manager->priv->critical_alert_timeout_id != 0) { g_warning ("was instructed to play a sound loop with one already playing"); play_loop_stop (manager); } ca_proplist_create (&(manager->priv->critical_alert_loop_props)); ca_proplist_sets (manager->priv->critical_alert_loop_props, CA_PROP_EVENT_ID, id); ca_proplist_sets (manager->priv->critical_alert_loop_props, CA_PROP_EVENT_DESCRIPTION, desc); manager->priv->critical_alert_timeout_id = g_timeout_add_seconds (timeout, (GSourceFunc) play_loop_timeout_cb, manager); g_source_set_name_by_id (manager->priv->critical_alert_timeout_id, "[CsdPowerManager] play-loop"); /* play the sound, using sounds from the naming spec */ context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); ca_context_play (context, 0, CA_PROP_EVENT_ID, id, CA_PROP_EVENT_DESCRIPTION, desc, NULL); return TRUE; } static gboolean should_lock_on_suspend (CsdPowerManager *manager) { gboolean lock; lock = g_settings_get_boolean (manager->priv->settings, "lock-on-suspend"); return lock; } static void notify_close_if_showing (NotifyNotification *notification) { gboolean ret; GError *error = NULL; if (notification == NULL) return; ret = notify_notification_close (notification, &error); if (!ret) { g_warning ("failed to close notification: %s", error->message); g_error_free (error); } } static const gchar * get_first_themed_icon_name (GIcon *icon) { const gchar* const *icon_names; const gchar *icon_name = NULL; /* no icon */ if (icon == NULL) goto out; /* just use the first icon */ icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon)); if (icon_names != NULL) icon_name = icon_names[0]; out: return icon_name; } typedef enum { WARNING_NONE = 0, WARNING_DISCHARGING = 1, WARNING_LOW = 2, WARNING_CRITICAL = 3, WARNING_ACTION = 4 } CsdPowerManagerWarning; static void engine_emit_changed (CsdPowerManager *manager, gboolean icon_changed, gboolean state_changed) { /* not yet connected to the bus */ if (manager->priv->power_iface == NULL) return; if (icon_changed) { GIcon *gicon; gchar *gicon_str; gicon = engine_get_icon (manager); gicon_str = g_icon_to_string (gicon); csd_power_set_icon (manager->priv->power_iface, gicon_str); g_free (gicon_str); g_object_unref (gicon); } if (state_changed) { gchar *tooltip; tooltip = engine_get_summary (manager); csd_power_set_tooltip (manager->priv->power_iface, tooltip); g_free (tooltip); } } static CsdPowerManagerWarning engine_get_warning_csr (CsdPowerManager *manager, UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 26.0f) return WARNING_LOW; else if (percentage < 13.0f) return WARNING_CRITICAL; return WARNING_NONE; } static CsdPowerManagerWarning engine_get_warning_percentage (CsdPowerManager *manager, UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage <= manager->priv->action_percentage) return WARNING_ACTION; if (percentage <= manager->priv->critical_percentage) return WARNING_CRITICAL; if (percentage <= manager->priv->low_percentage) return WARNING_LOW; return WARNING_NONE; } static CsdPowerManagerWarning engine_get_warning_time (CsdPowerManager *manager, UpDevice *device) { UpDeviceKind kind; gint64 time_to_empty; /* get device properties */ g_object_get (device, "kind", &kind, "time-to-empty", &time_to_empty, NULL); /* this is probably an error condition */ if (time_to_empty == 0) { g_debug ("time zero, falling back to percentage for %s", up_device_kind_to_string (kind)); return engine_get_warning_percentage (manager, device); } if (time_to_empty <= manager->priv->action_time) return WARNING_ACTION; if (time_to_empty <= manager->priv->critical_time) return WARNING_CRITICAL; if (time_to_empty <= manager->priv->low_time) return WARNING_LOW; return WARNING_NONE; } /** * This gets the possible engine state for the device according to the * policy, which could be per-percent, or per-time. **/ static CsdPowerManagerWarning engine_get_warning (CsdPowerManager *manager, UpDevice *device) { UpDeviceKind kind; UpDeviceState state; CsdPowerManagerWarning warning_type; /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, NULL); /* default to no engine */ warning_type = WARNING_NONE; /* if the device in question is on ac, don't give a warning */ if (state == UP_DEVICE_STATE_CHARGING) goto out; if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD) { warning_type = engine_get_warning_csr (manager, device); } else if (kind == UP_DEVICE_KIND_UPS || kind == UP_DEVICE_KIND_MEDIA_PLAYER || kind == UP_DEVICE_KIND_TABLET || kind == UP_DEVICE_KIND_COMPUTER || kind == UP_DEVICE_KIND_PDA) { warning_type = engine_get_warning_percentage (manager, device); } else if (kind == UP_DEVICE_KIND_PHONE) { warning_type = engine_get_warning_percentage (manager, device); } else if (kind == UP_DEVICE_KIND_BATTERY) { /* only use the time when it is accurate, and settings is not disabled */ if (manager->priv->use_time_primary) warning_type = engine_get_warning_time (manager, device); else warning_type = engine_get_warning_percentage (manager, device); } /* If we have no important engines, we should test for discharging */ if (warning_type == WARNING_NONE) { if (state == UP_DEVICE_STATE_DISCHARGING) warning_type = WARNING_DISCHARGING; } out: return warning_type; } static gchar * engine_get_summary (CsdPowerManager *manager) { guint i; GPtrArray *array; UpDevice *device; UpDeviceState state; GString *tooltip = NULL; gchar *part; gboolean is_present; /* need to get AC state */ tooltip = g_string_new (""); /* do we have specific device types? */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "is-present", &is_present, "state", &state, NULL); if (!is_present) continue; if (state == UP_DEVICE_STATE_EMPTY) continue; part = gpm_upower_get_device_summary (device); if (part != NULL) g_string_append_printf (tooltip, "%s\n", part); g_free (part); } /* remove the last \n */ g_string_truncate (tooltip, tooltip->len-1); g_debug ("tooltip: %s", tooltip->str); return g_string_free (tooltip, FALSE); } static GIcon * engine_get_icon_priv (CsdPowerManager *manager, UpDeviceKind device_kind, CsdPowerManagerWarning warning, gboolean use_state) { guint i; GPtrArray *array; UpDevice *device; CsdPowerManagerWarning warning_temp; UpDeviceKind kind; UpDeviceState state; gboolean is_present; /* do we have specific device types? */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "is-present", &is_present, NULL); /* if battery then use composite device to cope with multiple batteries */ if (kind == UP_DEVICE_KIND_BATTERY) device = engine_get_composite_device (manager, device); warning_temp = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-warning-old")); if (kind == device_kind && is_present) { if (warning != WARNING_NONE) { if (warning_temp == warning) return gpm_upower_get_device_icon (device, TRUE); continue; } if (use_state) { if (state == UP_DEVICE_STATE_CHARGING || state == UP_DEVICE_STATE_DISCHARGING) return gpm_upower_get_device_icon (device, TRUE); continue; } return gpm_upower_get_device_icon (device, TRUE); } } return NULL; } static GIcon * engine_get_icon (CsdPowerManager *manager) { GIcon *icon = NULL; /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_LOW, FALSE); if (icon != NULL) return icon; /* we try (DIS)CHARGING: BATTERY, UPS */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, TRUE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, TRUE); if (icon != NULL) return icon; /* we try PRESENT: BATTERY, UPS */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, FALSE); if (icon != NULL) return icon; /* do not show an icon */ return NULL; } static gboolean engine_recalculate_state_icon (CsdPowerManager *manager) { GIcon *icon; /* show a different icon if we are disconnected */ icon = engine_get_icon (manager); gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); if (icon == NULL) { /* none before, now none */ if (manager->priv->previous_icon == NULL) return FALSE; g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = NULL; return TRUE; } /* no icon before, now icon */ if (manager->priv->previous_icon == NULL) { /* set fallback icon */ gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon); manager->priv->previous_icon = icon; return TRUE; } /* icon before, now different */ if (!g_icon_equal (manager->priv->previous_icon, icon)) { /* set fallback icon */ gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon); g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = icon; return TRUE; } g_debug ("no change"); /* nothing to do */ g_object_unref (icon); return FALSE; } static gboolean engine_recalculate_state_summary (CsdPowerManager *manager) { gchar *summary; summary = engine_get_summary (manager); if (manager->priv->previous_summary == NULL) { manager->priv->previous_summary = summary; /* set fallback tooltip */ gtk_status_icon_set_tooltip_text (manager->priv->status_icon, summary); return TRUE; } if (strcmp (manager->priv->previous_summary, summary) != 0) { g_free (manager->priv->previous_summary); manager->priv->previous_summary = summary; /* set fallback tooltip */ gtk_status_icon_set_tooltip_text (manager->priv->status_icon, summary); return TRUE; } g_debug ("no change"); /* nothing to do */ g_free (summary); return FALSE; } static void engine_recalculate_state (CsdPowerManager *manager) { gboolean icon_changed = FALSE; gboolean state_changed = FALSE; icon_changed = engine_recalculate_state_icon (manager); state_changed = engine_recalculate_state_summary (manager); /* only emit if the icon or summary has changed */ if (icon_changed || state_changed) engine_emit_changed (manager, icon_changed, state_changed); } static UpDevice * engine_get_composite_device (CsdPowerManager *manager, UpDevice *original_device) { guint battery_devices = 0; GPtrArray *array; UpDevice *device; UpDeviceKind kind; UpDeviceKind original_kind; guint i; /* get the type of the original device */ g_object_get (original_device, "kind", &original_kind, NULL); /* find out how many batteries in the system */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, NULL); if (kind == original_kind) battery_devices++; } /* just use the original device if only one primary battery */ if (battery_devices <= 1) { g_debug ("using original device as only one primary battery"); device = original_device; goto out; } /* use the composite device */ device = manager->priv->device_composite; out: /* return composite device or original device */ return device; } static UpDevice * engine_update_composite_device (CsdPowerManager *manager, UpDevice *original_device) { guint i; gdouble percentage = 0.0; gdouble energy = 0.0; gdouble energy_full = 0.0; gdouble energy_rate = 0.0; gdouble energy_total = 0.0; gdouble energy_full_total = 0.0; gdouble energy_rate_total = 0.0; gint64 time_to_empty = 0; gint64 time_to_full = 0; guint battery_devices = 0; gboolean is_charging = FALSE; gboolean is_discharging = FALSE; gboolean is_fully_charged = TRUE; GPtrArray *array; UpDevice *device; UpDeviceState state; UpDeviceKind kind; UpDeviceKind original_kind; /* get the type of the original device */ g_object_get (original_device, "kind", &original_kind, NULL); /* update the composite device */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, "state", &state, "energy", &energy, "energy-full", &energy_full, "energy-rate", &energy_rate, NULL); if (kind != original_kind) continue; /* one of these will be charging or discharging */ if (state == UP_DEVICE_STATE_CHARGING) is_charging = TRUE; if (state == UP_DEVICE_STATE_DISCHARGING) is_discharging = TRUE; if (state != UP_DEVICE_STATE_FULLY_CHARGED) is_fully_charged = FALSE; /* sum up composite */ energy_total += energy; energy_full_total += energy_full; energy_rate_total += energy_rate; battery_devices++; } /* just use the original device if only one primary battery */ if (battery_devices == 1) { g_debug ("using original device as only one primary battery"); device = original_device; goto out; } /* use percentage weighted for each battery capacity */ if (energy_full_total > 0.0) percentage = 100.0 * energy_total / energy_full_total; /* set composite state */ if (is_charging) state = UP_DEVICE_STATE_CHARGING; else if (is_discharging) state = UP_DEVICE_STATE_DISCHARGING; else if (is_fully_charged) state = UP_DEVICE_STATE_FULLY_CHARGED; else state = UP_DEVICE_STATE_UNKNOWN; /* calculate a quick and dirty time remaining value */ if (energy_rate_total > 0) { if (state == UP_DEVICE_STATE_DISCHARGING) time_to_empty = 3600 * (energy_total / energy_rate_total); else if (state == UP_DEVICE_STATE_CHARGING) time_to_full = 3600 * ((energy_full_total - energy_total) / energy_rate_total); } /* okay, we can use the composite device */ device = manager->priv->device_composite; g_debug ("printing composite device"); g_object_set (device, "energy", energy, "energy-full", energy_full, "energy-rate", energy_rate, "time-to-empty", time_to_empty, "time-to-full", time_to_full, "percentage", percentage, "state", state, NULL); /* force update of icon */ if (engine_recalculate_state_icon (manager)) engine_emit_changed (manager, TRUE, FALSE); out: /* return composite device or original device */ return device; } static void engine_device_add (CsdPowerManager *manager, UpDevice *device) { CsdPowerManagerWarning warning; UpDeviceState state; UpDeviceKind kind; UpDevice *composite; /* assign warning */ warning = engine_get_warning (manager, device); g_object_set_data (G_OBJECT(device), "engine-warning-old", GUINT_TO_POINTER(warning)); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, NULL); /* add old state for transitions */ g_debug ("adding %s with state %s", up_device_get_object_path (device), up_device_state_to_string (state)); g_object_set_data (G_OBJECT(device), "engine-state-old", GUINT_TO_POINTER(state)); if (kind == UP_DEVICE_KIND_BATTERY) { g_debug ("updating because we added a device"); composite = engine_update_composite_device (manager, device); /* get the same values for the composite device */ warning = engine_get_warning (manager, composite); g_object_set_data (G_OBJECT(composite), "engine-warning-old", GUINT_TO_POINTER(warning)); g_object_get (composite, "state", &state, NULL); g_object_set_data (G_OBJECT(composite), "engine-state-old", GUINT_TO_POINTER(state)); } #if UP_CHECK_VERSION(0,99,0) g_ptr_array_add (manager->priv->devices_array, g_object_ref(device)); g_signal_connect (device, "notify", G_CALLBACK (device_properties_changed_cb), manager); #endif } static gboolean engine_coldplug (CsdPowerManager *manager) { guint i; GPtrArray *array = NULL; UpDevice *device; #if ! UP_CHECK_VERSION(0,99,0) gboolean ret; GError *error = NULL; /* get devices from UPower */ ret = up_client_enumerate_devices_sync (manager->priv->up_client, NULL, &error); if (!ret) { g_warning ("failed to get device list: %s", error->message); g_error_free (error); goto out; } #endif /* connected mobile phones */ gpm_phone_coldplug (manager->priv->phone); engine_recalculate_state (manager); /* add to database */ array = up_client_get_devices (manager->priv->up_client); for (i = 0; array != NULL && i < array->len; i++) { device = g_ptr_array_index (array, i); engine_device_add (manager, device); } #if ! UP_CHECK_VERSION(0,99,0) out: #endif if (array != NULL) g_ptr_array_unref (array); /* never repeat */ return FALSE; } static void engine_device_added_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) { /* add to list */ g_ptr_array_add (manager->priv->devices_array, g_object_ref (device)); engine_recalculate_state (manager); } static void #if UP_CHECK_VERSION(0,99,0) engine_device_removed_cb (UpClient *client, const char *object_path, CsdPowerManager *manager) { guint i; for (i = 0; i < manager->priv->devices_array->len; i++) { UpDevice *device = g_ptr_array_index (manager->priv->devices_array, i); if (g_strcmp0 (object_path, up_device_get_object_path (device)) == 0) { g_ptr_array_remove_index (manager->priv->devices_array, i); break; } } engine_recalculate_state (manager); } #else engine_device_removed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) { gboolean ret; ret = g_ptr_array_remove (manager->priv->devices_array, device); if (!ret) return; engine_recalculate_state (manager); } #endif static void on_notification_closed (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static void create_notification (const char *summary, const char *body, const char *icon, NotifyNotification **weak_pointer_location) { NotifyNotification *notification; notification = notify_notification_new (summary, body, icon); *weak_pointer_location = notification; g_object_add_weak_pointer (G_OBJECT (notification), (gpointer *) weak_pointer_location); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); } static void engine_ups_discharging (CsdPowerManager *manager, UpDevice *device) { const gchar *title; gboolean ret; gchar *remaining_text = NULL; gdouble percentage; GError *error = NULL; GIcon *icon = NULL; gint64 time_to_empty; GString *message; UpDeviceKind kind; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); if (kind != UP_DEVICE_KIND_UPS) return; /* only show text if there is a valid time */ if (time_to_empty > 0) remaining_text = gpm_get_timestring (time_to_empty); /* TRANSLATORS: UPS is now discharging */ title = _("UPS Discharging"); message = g_string_new (""); if (remaining_text != NULL) { /* TRANSLATORS: tell the user how much time they have got */ g_string_append_printf (message, _("%s of UPS backup power remaining"), remaining_text); } else { g_string_append (message, gpm_device_to_localised_string (device)); } g_string_append_printf (message, " (%.0f%%)", percentage); icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_discharging); /* create a new notification */ create_notification (title, message->str, get_first_themed_icon_name (icon), &manager->priv->notification_discharging); notify_notification_set_timeout (manager->priv->notification_discharging, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_discharging, NOTIFY_URGENCY_NORMAL); /* TRANSLATORS: this is the notification application name */ notify_notification_set_app_name (manager->priv->notification_discharging, _("Power")); notify_notification_set_hint (manager->priv->notification_discharging, "transient", g_variant_new_boolean (TRUE)); /* try to show */ ret = notify_notification_show (manager->priv->notification_discharging, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_discharging); } g_string_free (message, TRUE); if (icon != NULL) g_object_unref (icon); g_free (remaining_text); } static CsdPowerActionType manager_critical_action_get (CsdPowerManager *manager, gboolean is_ups) { CsdPowerActionType policy; policy = g_settings_get_enum (manager->priv->settings, "critical-battery-action"); if (policy == CSD_POWER_ACTION_SUSPEND) { if (is_ups == FALSE #if ! UP_CHECK_VERSION(0,99,0) && up_client_get_can_suspend (manager->priv->up_client) #endif ) return policy; return CSD_POWER_ACTION_SHUTDOWN; } else if (policy == CSD_POWER_ACTION_HIBERNATE) { #if ! UP_CHECK_VERSION(0,99,0) if (up_client_get_can_hibernate (manager->priv->up_client)) #endif return policy; return CSD_POWER_ACTION_SHUTDOWN; } return policy; } static gboolean manager_critical_action_do (CsdPowerManager *manager, gboolean is_ups) { CsdPowerActionType action_type; /* stop playing the alert as it's too late to do anything now */ if (manager->priv->critical_alert_timeout_id > 0) play_loop_stop (manager); action_type = manager_critical_action_get (manager, is_ups); do_power_action_type (manager, action_type); return FALSE; } static gboolean manager_critical_action_do_cb (CsdPowerManager *manager) { manager_critical_action_do (manager, FALSE); return FALSE; } static gboolean manager_critical_ups_action_do_cb (CsdPowerManager *manager) { manager_critical_action_do (manager, TRUE); return FALSE; } static gboolean engine_just_laptop_battery (CsdPowerManager *manager) { UpDevice *device; UpDeviceKind kind; GPtrArray *array; gboolean ret = TRUE; guint i; /* find if there are any other device types that mean we have to * be more specific in our wording */ array = manager->priv->devices_array; for (i=0; ilen; i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, NULL); if (kind != UP_DEVICE_KIND_BATTERY) { ret = FALSE; break; } } return ret; } static void engine_charge_low (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; gchar *tmp; gchar *remaining_text; gdouble percentage; GIcon *icon = NULL; gint64 time_to_empty; UpDeviceKind kind; GError *error = NULL; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* if the user has no other batteries, drop the "Laptop" wording */ ret = engine_just_laptop_battery (manager); if (ret) { /* TRANSLATORS: laptop battery low, and we only have one battery */ title = _("Battery low"); } else { /* TRANSLATORS: laptop battery low, and we have more than one kind of battery */ title = _("Laptop battery low"); } tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: tell the user how much time they have got */ message = g_strdup_printf (_("Approximately %s remaining (%.0f%%)"), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_UPS) { /* TRANSLATORS: UPS is starting to get a little low */ title = _("UPS low"); tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: tell the user how much time they have got */ message = g_strdup_printf (_("Approximately %s of remaining UPS backup power (%.0f%%)"), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_MOUSE) { /* TRANSLATORS: mouse is getting a little low */ title = _("Mouse battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Wireless mouse is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_KEYBOARD) { /* TRANSLATORS: keyboard is getting a little low */ title = _("Keyboard battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Wireless keyboard is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_PDA) { /* TRANSLATORS: PDA is getting a little low */ title = _("PDA battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("PDA is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_PHONE) { /* TRANSLATORS: cell phone (mobile) is getting a little low */ title = _("Cell phone battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Cell phone is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { /* TRANSLATORS: media player, e.g. mp3 is getting a little low */ title = _("Media player battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Media player is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_TABLET) { /* TRANSLATORS: graphics tablet, e.g. wacom is getting a little low */ title = _("Tablet battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Tablet is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_COMPUTER) { /* TRANSLATORS: computer, e.g. ipad is getting a little low */ title = _("Attached computer battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Attached computer is low in power (%.0f%%)"), percentage); } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_NORMAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); notify_notification_set_hint (manager->priv->notification_low, "transient", g_variant_new_boolean (TRUE)); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-low", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is low"), NULL); out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void engine_charge_critical (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; gdouble percentage; GIcon *icon = NULL; gint64 time_to_empty; CsdPowerActionType policy; UpDeviceKind kind; GError *error = NULL; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring critically low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* if the user has no other batteries, drop the "Laptop" wording */ ret = engine_just_laptop_battery (manager); if (ret) { /* TRANSLATORS: laptop battery critically low, and only have one kind of battery */ title = _("Battery critically low"); } else { /* TRANSLATORS: laptop battery critically low, and we have more than one type of battery */ title = _("Laptop battery critically low"); } /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, FALSE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: tell the use to insert the plug, as we're not going to do anything */ message = g_strdup (_("Plug in your AC adapter to avoid losing data.")); } else if (policy == CSD_POWER_ACTION_SUSPEND) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will suspend very soon unless it is plugged in.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will hibernate very soon unless it is plugged in.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will shutdown very soon unless it is plugged in.")); } } else if (kind == UP_DEVICE_KIND_UPS) { gchar *remaining_text; gchar *tmp; /* TRANSLATORS: the UPS is very low */ title = _("UPS critically low"); tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Approximately %s of remaining UPS power (%.0f%%). " "Restore AC power to your computer to avoid losing data."), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_MOUSE) { /* TRANSLATORS: the mouse battery is very low */ title = _("Mouse battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Wireless mouse is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_KEYBOARD) { /* TRANSLATORS: the keyboard battery is very low */ title = _("Keyboard battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Wireless keyboard is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_PDA) { /* TRANSLATORS: the PDA battery is very low */ title = _("PDA battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("PDA is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_PHONE) { /* TRANSLATORS: the cell battery is very low */ title = _("Cell phone battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Cell phone is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { /* TRANSLATORS: the cell battery is very low */ title = _("Cell phone battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Media player is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_TABLET) { /* TRANSLATORS: the cell battery is very low */ title = _("Tablet battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Tablet is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_COMPUTER) { /* TRANSLATORS: the cell battery is very low */ title = _("Attached computer battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Attached computer is very low in power (%.0f%%). " "The device will soon shutdown if not charged."), percentage); } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_CRITICAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } switch (kind) { case UP_DEVICE_KIND_BATTERY: case UP_DEVICE_KIND_UPS: g_debug ("critical charge level reached, starting sound loop"); play_loop_start (manager, "battery-caution", _("Battery is critically low"), TRUE, CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT); break; default: /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-caution", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL); break; } out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void engine_charge_action (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; GError *error = NULL; GIcon *icon = NULL; CsdPowerActionType policy; guint timer_id; UpDeviceKind kind; /* get device properties */ g_object_get (device, "kind", &kind, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring critically low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* TRANSLATORS: laptop battery is really, really, low */ title = _("Laptop battery critically low"); /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, FALSE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: computer will shutdown without saving data */ message = g_strdup (_("The battery is below the critical level and " "this computer will power-off when the " "battery becomes completely empty.")); } else if (policy == CSD_POWER_ACTION_SUSPEND) { /* TRANSLATORS: computer will suspend */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to suspend.\n" "NOTE: A small amount of power is required " "to keep your computer in a suspended state.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: computer will hibernate */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to hibernate.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: computer will just shutdown */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to shutdown.")); } /* wait 20 seconds for user-panic */ timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_action_do_cb, manager); g_source_set_name_by_id (timer_id, "[CsdPowerManager] battery critical-action"); } else if (kind == UP_DEVICE_KIND_UPS) { /* TRANSLATORS: UPS is really, really, low */ title = _("UPS critically low"); /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, TRUE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: computer will shutdown without saving data */ message = g_strdup (_("UPS is below the critical level and " "this computer will power-off when the " "UPS becomes completely empty.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: computer will hibernate */ message = g_strdup (_("UPS is below the critical level and " "this computer is about to hibernate.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: computer will just shutdown */ message = g_strdup (_("UPS is below the critical level and " "this computer is about to shutdown.")); } /* wait 20 seconds for user-panic */ timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_ups_action_do_cb, manager); g_source_set_name_by_id (timer_id, "[CsdPowerManager] ups critical-action"); } /* not all types have actions */ if (title == NULL) { g_free (message); return; } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_CRITICAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-caution", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL); out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void #if UP_CHECK_VERSION(0,99,0) device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager) #else engine_device_changed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) #endif { UpDeviceKind kind; UpDeviceState state; UpDeviceState state_old; CsdPowerManagerWarning warning_old; CsdPowerManagerWarning warning; /* get device properties */ g_object_get (device, "kind", &kind, NULL); /* if battery then use composite device to cope with multiple batteries */ if (kind == UP_DEVICE_KIND_BATTERY) { g_debug ("updating because %s changed", up_device_get_object_path (device)); device = engine_update_composite_device (manager, device); } /* get device properties (may be composite) */ g_object_get (device, "state", &state, NULL); g_debug ("%s state is now %s", up_device_get_object_path (device), up_device_state_to_string (state)); /* see if any interesting state changes have happened */ state_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-state-old")); if (state_old != state) { if (state == UP_DEVICE_STATE_DISCHARGING) { g_debug ("discharging"); engine_ups_discharging (manager, device); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED || state == UP_DEVICE_STATE_CHARGING) { g_debug ("fully charged or charging, hiding notifications if any"); notify_close_if_showing (manager->priv->notification_low); notify_close_if_showing (manager->priv->notification_discharging); } /* save new state */ g_object_set_data (G_OBJECT(device), "engine-state-old", GUINT_TO_POINTER(state)); } /* check the warning state has not changed */ warning_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-warning-old")); warning = engine_get_warning (manager, device); if (warning != warning_old) { if (warning == WARNING_LOW) { g_debug ("** EMIT: charge-low"); engine_charge_low (manager, device); } else if (warning == WARNING_CRITICAL) { g_debug ("** EMIT: charge-critical"); engine_charge_critical (manager, device); } else if (warning == WARNING_ACTION) { g_debug ("charge-action"); engine_charge_action (manager, device); } /* save new state */ g_object_set_data (G_OBJECT(device), "engine-warning-old", GUINT_TO_POINTER(warning)); } engine_recalculate_state (manager); } static UpDevice * engine_get_primary_device (CsdPowerManager *manager) { guint i; UpDevice *device = NULL; UpDevice *device_tmp; UpDeviceKind kind; UpDeviceState state; gboolean is_present; for (i=0; ipriv->devices_array->len; i++) { device_tmp = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device_tmp, "kind", &kind, "state", &state, "is-present", &is_present, NULL); /* not present */ if (!is_present) continue; /* not discharging */ if (state != UP_DEVICE_STATE_DISCHARGING) continue; /* not battery */ if (kind != UP_DEVICE_KIND_BATTERY) continue; /* use composite device to cope with multiple batteries */ device = g_object_ref (engine_get_composite_device (manager, device_tmp)); break; } return device; } static void phone_device_added_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { UpDevice *device; device = up_device_new (); g_debug ("phone added %i", idx); /* get device properties */ g_object_set (device, "kind", UP_DEVICE_KIND_PHONE, "is-rechargeable", TRUE, "native-path", g_strdup_printf ("dummy:phone_%i", idx), "is-present", TRUE, NULL); /* state changed */ engine_device_add (manager, device); g_ptr_array_add (manager->priv->devices_array, g_object_ref (device)); engine_recalculate_state (manager); } static void phone_device_removed_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { guint i; UpDevice *device; UpDeviceKind kind; g_debug ("phone removed %i", idx); for (i=0; ipriv->devices_array->len; i++) { device = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device, "kind", &kind, NULL); if (kind == UP_DEVICE_KIND_PHONE) { g_ptr_array_remove_index (manager->priv->devices_array, i); break; } } /* state changed */ engine_recalculate_state (manager); } static void phone_device_refresh_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { guint i; UpDevice *device; UpDeviceKind kind; UpDeviceState state; gboolean is_present; gdouble percentage; g_debug ("phone refresh %i", idx); for (i=0; ipriv->devices_array->len; i++) { device = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, NULL); if (kind == UP_DEVICE_KIND_PHONE) { is_present = gpm_phone_get_present (phone, idx); state = gpm_phone_get_on_ac (phone, idx) ? UP_DEVICE_STATE_CHARGING : UP_DEVICE_STATE_DISCHARGING; percentage = gpm_phone_get_percentage (phone, idx); break; } } /* state changed */ engine_recalculate_state (manager); } static void cinnamon_session_shutdown_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("couldn't shutdown using cinnamon-session: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void cinnamon_session_shutdown (void) { GError *error = NULL; GDBusProxy *proxy; /* ask cinnamon-session to show the shutdown dialog with a timeout */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to cinnamon-session: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Shutdown", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, cinnamon_session_shutdown_cb, NULL); g_object_unref (proxy); } static void turn_monitors_off (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, &error); if (!ret) { g_warning ("failed to turn the panel off for policy action: %s", error->message); g_error_free (error); } } static void do_power_action_type (CsdPowerManager *manager, CsdPowerActionType action_type) { switch (action_type) { case CSD_POWER_ACTION_SUSPEND: if (should_lock_on_suspend (manager)) { lock_screensaver (manager); } turn_monitors_off (manager); gboolean hybrid = g_settings_get_boolean (manager->priv->settings_cinnamon_session, "prefer-hybrid-sleep"); csd_power_suspend (hybrid); break; case CSD_POWER_ACTION_INTERACTIVE: cinnamon_session_shutdown (); break; case CSD_POWER_ACTION_HIBERNATE: if (should_lock_on_suspend (manager)) { lock_screensaver (manager); } turn_monitors_off (manager); csd_power_hibernate (); break; case CSD_POWER_ACTION_SHUTDOWN: /* this is only used on critically low battery where * hibernate is not available and is marginally better * than just powering down the computer mid-write */ csd_power_poweroff (); break; case CSD_POWER_ACTION_BLANK: /* Lock first or else xrandr might reconfigure stuff and the ss's coverage * may be incorrect upon return. */ lock_screensaver (manager); turn_monitors_off (manager); break; case CSD_POWER_ACTION_NOTHING: break; } } static gboolean upower_kbd_get_percentage (CsdPowerManager *manager, GError **error) { GVariant *k_now = NULL; k_now = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy, "GetBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (k_now != NULL) { g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now); g_variant_unref (k_now); return TRUE; } return FALSE; } static void upower_kbd_emit_changed (CsdPowerManager *manager) { /* not yet connected to the bus */ if (manager->priv->keyboard_iface == NULL) return; csd_keyboard_emit_changed (manager->priv->keyboard_iface); } static gboolean upower_kbd_set_brightness (CsdPowerManager *manager, guint value, GError **error) { GVariant *retval; /* same as before */ if (manager->priv->kbd_brightness_now == value) return TRUE; /* update h/w value */ retval = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy, "SetBrightness", g_variant_new ("(i)", (gint) value), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (retval == NULL) return FALSE; /* save new value */ manager->priv->kbd_brightness_now = value; g_variant_unref (retval); upower_kbd_emit_changed(manager); return TRUE; } static gboolean upower_kbd_toggle (CsdPowerManager *manager, GError **error) { gboolean ret; if (manager->priv->kbd_brightness_old >= 0) { g_debug ("keyboard toggle off"); ret = upower_kbd_set_brightness (manager, manager->priv->kbd_brightness_old, error); if (ret) { /* succeeded, set to -1 since now no old value */ manager->priv->kbd_brightness_old = -1; } } else { g_debug ("keyboard toggle on"); /* save the current value to restore later when untoggling */ manager->priv->kbd_brightness_old = manager->priv->kbd_brightness_now; ret = upower_kbd_set_brightness (manager, 0, error); if (!ret) { /* failed, reset back to -1 */ manager->priv->kbd_brightness_old = -1; } } upower_kbd_emit_changed(manager); return ret; } static void upower_kbd_handle_changed (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); g_debug("keyboard changed signal"); if (g_strcmp0 (signal_name, "BrightnessChangedWithSource") == 0) { g_debug ("Received upower kbdbacklight BrightnessChangedWithSource"); const gchar *source; gint brightness; g_variant_get (parameters, "(i&s)", &brightness, &source); if (g_strcmp0 (source, "external") == 0) { return; } manager->priv->kbd_brightness_now = brightness; upower_kbd_emit_changed(manager); } } static gboolean suspend_on_lid_close (CsdPowerManager *manager) { CsdXrandrBootBehaviour val; if (!external_monitor_is_connected (manager->priv->x11_screen)) return TRUE; val = g_settings_get_enum (manager->priv->settings_xrandr, "default-monitors-setup"); return val == CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING; } static gboolean inhibit_lid_switch_timer_cb (CsdPowerManager *manager) { if (suspend_on_lid_close (manager)) { g_debug ("no external monitors for a while; uninhibiting lid close"); uninhibit_lid_switch (manager); manager->priv->inhibit_lid_switch_timer_id = 0; return G_SOURCE_REMOVE; } g_debug ("external monitor still there; trying again later"); return G_SOURCE_CONTINUE; } /* Sets up a timer to be triggered some seconds after closing the laptop lid * when the laptop is *not* suspended for some reason. We'll check conditions * again in the timeout handler to see if we can suspend then. */ static void setup_inhibit_lid_switch_timer (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_timer_id != 0) { g_debug ("lid close safety timer already set up"); return; } g_debug ("setting up lid close safety timer"); manager->priv->inhibit_lid_switch_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT, (GSourceFunc) inhibit_lid_switch_timer_cb, manager); g_source_set_name_by_id (manager->priv->inhibit_lid_switch_timer_id, "[CsdPowerManager] lid close safety timer"); } static void restart_inhibit_lid_switch_timer (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_timer_id != 0) { g_debug ("restarting lid close safety timer"); g_source_remove (manager->priv->inhibit_lid_switch_timer_id); manager->priv->inhibit_lid_switch_timer_id = 0; setup_inhibit_lid_switch_timer (manager); } } static gboolean randr_output_is_on (GnomeRROutput *output) { GnomeRRCrtc *crtc; crtc = gnome_rr_output_get_crtc (output); if (!crtc) return FALSE; return gnome_rr_crtc_get_current_mode (crtc) != NULL; } static gboolean external_monitor_is_connected (GnomeRRScreen *screen) { GnomeRROutput **outputs; guint i; /* see if we have more than one screen plugged in */ outputs = gnome_rr_screen_list_outputs (screen); for (i = 0; outputs[i] != NULL; i++) { if (randr_output_is_on (outputs[i]) && !gnome_rr_output_is_laptop (outputs[i])) return TRUE; } return FALSE; } static void on_randr_event (GnomeRRScreen *screen, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); if (suspend_on_lid_close (manager)) { restart_inhibit_lid_switch_timer (manager); return; } /* when a second monitor is plugged in, we take the * handle-lid-switch inhibitor lock of logind to prevent * it from suspending. * * Uninhibiting is done in the inhibit_lid_switch_timer, * since we want to give users a few seconds when unplugging * and replugging an external monitor, not suspend right away. */ inhibit_lid_switch (manager); setup_inhibit_lid_switch_timer (manager); } static void do_lid_open_action (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* play a sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "lid-open", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Lid has been opened"), NULL); /* ensure we turn the panel back on after lid open */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on after lid open: %s", error->message); g_clear_error (&error); } /* only toggle keyboard if present and already toggled off */ if (manager->priv->upower_kbd_proxy != NULL && manager->priv->kbd_brightness_old != -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight on: %s", error->message); g_error_free (error); } } kill_lid_close_safety_timer (manager); } static gboolean is_on (GnomeRROutput *output) { GnomeRRCrtc *crtc; crtc = gnome_rr_output_get_crtc (output); if (!crtc) return FALSE; return gnome_rr_crtc_get_current_mode (crtc) != NULL; } static gboolean non_laptop_outputs_are_all_off (GnomeRRScreen *screen) { GnomeRROutput **outputs; int i; outputs = gnome_rr_screen_list_outputs (screen); for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_laptop (outputs[i])) continue; if (is_on (outputs[i])) return FALSE; } return TRUE; } /* Timeout callback used to check conditions when the laptop's lid is closed but * the machine is not suspended yet. We try to suspend again, so that the laptop * won't overheat if placed in a backpack. */ static gboolean lid_close_safety_timer_cb (CsdPowerManager *manager) { manager->priv->lid_close_safety_timer_id = 0; g_debug ("lid has been closed for a while; trying to suspend again"); do_lid_closed_action (manager); return FALSE; } /* Sets up a timer to be triggered some seconds after closing the laptop lid * when the laptop is *not* suspended for some reason. We'll check conditions * again in the timeout handler to see if we can suspend then. */ static void setup_lid_close_safety_timer (CsdPowerManager *manager) { if (manager->priv->lid_close_safety_timer_id != 0) return; manager->priv->lid_close_safety_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT, (GSourceFunc) lid_close_safety_timer_cb, manager); g_source_set_name_by_id (manager->priv->lid_close_safety_timer_id, "[CsdPowerManager] lid close safety timer"); } static void kill_lid_close_safety_timer (CsdPowerManager *manager) { if (manager->priv->lid_close_safety_timer_id != 0) { g_source_remove (manager->priv->lid_close_safety_timer_id); manager->priv->lid_close_safety_timer_id = 0; } } static void suspend_with_lid_closed (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; CsdPowerActionType action_type; /* we have different settings depending on AC state */ if (up_client_get_on_battery (manager->priv->up_client)) { action_type = g_settings_get_enum (manager->priv->settings, "lid-close-battery-action"); } else { action_type = g_settings_get_enum (manager->priv->settings, "lid-close-ac-action"); } /* check we won't melt when the lid is closed */ if (action_type != CSD_POWER_ACTION_SUSPEND && action_type != CSD_POWER_ACTION_HIBERNATE) { #if ! UP_CHECK_VERSION(0,99,0) if (up_client_get_lid_force_sleep (manager->priv->up_client)) { g_warning ("to prevent damage, now forcing suspend"); do_power_action_type (manager, CSD_POWER_ACTION_SUSPEND); return; } #endif } /* only toggle keyboard if present and not already toggled */ if (manager->priv->upower_kbd_proxy && manager->priv->kbd_brightness_old == -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight off: %s", error->message); g_error_free (error); } } do_power_action_type (manager, action_type); } static void do_lid_closed_action (CsdPowerManager *manager) { /* play a sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "lid-close", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Lid has been closed"), NULL); /* refresh RANDR so we get an accurate view of what monitors are plugged in when the lid is closed */ gnome_rr_screen_refresh (manager->priv->x11_screen, NULL); /* NULL-GError */ /* perform policy action */ if (g_settings_get_boolean (manager->priv->settings, "lid-close-suspend-with-external-monitor") || non_laptop_outputs_are_all_off (manager->priv->x11_screen)) { g_debug ("lid is closed; suspending or hibernating"); suspend_with_lid_closed (manager); } else { g_debug ("lid is closed; not suspending nor hibernating since some external monitor outputs are still active"); setup_lid_close_safety_timer (manager); } } static void #if UP_CHECK_VERSION(0,99,0) lid_state_changed_cb (UpClient *client, GParamSpec *pspec, CsdPowerManager *manager) #else up_client_changed_cb (UpClient *client, CsdPowerManager *manager) #endif { gboolean lid_is_closed; gboolean on_battery; on_battery = up_client_get_on_battery(client); if (!on_battery) { /* if we are playing a critical charge sound loop on AC, stop it */ if (manager->priv->critical_alert_timeout_id > 0) { g_debug ("stopping alert loop due to ac being present"); play_loop_stop (manager); } notify_close_if_showing (manager->priv->notification_low); } /* same state */ lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client); if (manager->priv->lid_is_closed == lid_is_closed && manager->priv->on_battery == on_battery) return; manager->priv->lid_is_closed = lid_is_closed; manager->priv->on_battery = on_battery; /* fake a keypress */ if (lid_is_closed) do_lid_closed_action (manager); else do_lid_open_action (manager); } typedef enum { SESSION_STATUS_CODE_AVAILABLE = 0, SESSION_STATUS_CODE_INVISIBLE, SESSION_STATUS_CODE_BUSY, SESSION_STATUS_CODE_IDLE, SESSION_STATUS_CODE_UNKNOWN } SessionStatusCode; typedef enum { SESSION_INHIBIT_MASK_LOGOUT = 1, SESSION_INHIBIT_MASK_SWITCH = 2, SESSION_INHIBIT_MASK_SUSPEND = 4, SESSION_INHIBIT_MASK_IDLE = 8 } SessionInhibitMask; static const gchar * idle_mode_to_string (CsdPowerIdleMode mode) { if (mode == CSD_POWER_IDLE_MODE_NORMAL) return "normal"; if (mode == CSD_POWER_IDLE_MODE_DIM) return "dim"; if (mode == CSD_POWER_IDLE_MODE_BLANK) return "blank"; if (mode == CSD_POWER_IDLE_MODE_SLEEP) return "sleep"; return "unknown"; } static GnomeRROutput * get_primary_output (CsdPowerManager *manager) { GnomeRROutput *output = NULL; GnomeRROutput **outputs; guint i; /* search all X11 outputs for the device id */ outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen); if (outputs == NULL) goto out; for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_connected (outputs[i]) && gnome_rr_output_is_laptop (outputs[i]) && gnome_rr_output_get_backlight_min (outputs[i]) >= 0 && gnome_rr_output_get_backlight_max (outputs[i]) > 0) { output = outputs[i]; break; } } out: return output; } static void backlight_override_settings_refresh (CsdPowerManager *manager) { int i = 0; /* update all the stored backlight override properties * this is called on startup and by engine_settings_key_changed_cb */ manager->priv->backlight_helper_force = g_settings_get_boolean (manager->priv->settings, "backlight-helper-force"); /* concatenate all the search preferences into a single argument string */ gchar** backlight_preference_order = g_settings_get_strv (manager->priv->settings, "backlight-helper-preference-order"); gchar* tmp1 = NULL; gchar* tmp2 = NULL; if (backlight_preference_order[0] != NULL) { tmp1 = g_strdup_printf("-b %s", backlight_preference_order[0]); } for (i=1; backlight_preference_order[i] != NULL; i++ ) { tmp2 = tmp1; tmp1 = g_strdup_printf("%s -b %s", tmp2, backlight_preference_order[i]); g_free(tmp2); } tmp2 = manager->priv->backlight_helper_preference_args; manager->priv->backlight_helper_preference_args = tmp1; g_free(tmp2); tmp2 = NULL; g_free(backlight_preference_order); backlight_preference_order = NULL; } /** * backlight_helper_get_value: * * Gets a brightness value from the PolicyKit helper. * * Return value: the signed integer value from the helper, or -1 * for failure. If -1 then @error is set. **/ static gint64 backlight_helper_get_value (const gchar *argument, CsdPowerManager* manager, GError **error) { gboolean ret; gchar *stdout_data = NULL; gint exit_status = 0; gint64 value = -1; gchar *command = NULL; gchar *endptr = NULL; #ifndef __linux__ /* non-Linux platforms won't have /sys/class/backlight */ g_set_error_literal (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "The sysfs backlight helper is only for Linux"); goto out; #endif /* get the data */ command = g_strdup_printf (LIBEXECDIR "/csd-backlight-helper --%s %s", argument, manager->priv->backlight_helper_preference_args); ret = g_spawn_command_line_sync (command, &stdout_data, NULL, &exit_status, error); g_debug ("executed %s retval: %i", command, exit_status); if (!ret) goto out; if (WEXITSTATUS (exit_status) != 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "csd-backlight-helper failed: %s", stdout_data ? stdout_data : "No reason"); goto out; } /* parse */ value = g_ascii_strtoll (stdout_data, &endptr, 10); /* parsing error */ if (endptr == stdout_data) { value = -1; g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "failed to parse value: %s", stdout_data); goto out; } /* out of range */ if (value > G_MAXINT) { value = -1; g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "value out of range: %s", stdout_data); goto out; } /* Fetching the value failed, for some other reason */ if (value < 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "value negative, but helper did not fail: %s", stdout_data); goto out; } out: g_free (command); g_free (stdout_data); return value; } /** * backlight_helper_set_value: * * Sets a brightness value using the PolicyKit helper. * * Return value: Success. If FALSE then @error is set. **/ static gboolean backlight_helper_set_value (const gchar *argument, gint value, CsdPowerManager* manager, GError **error) { gboolean ret; gint exit_status = 0; gchar *command = NULL; #ifndef __linux__ /* non-Linux platforms won't have /sys/class/backlight */ g_set_error_literal (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "The sysfs backlight helper is only for Linux"); goto out; #endif /* get the data */ command = g_strdup_printf ("pkexec " LIBEXECDIR "/csd-backlight-helper --%s %i %s", argument, value, manager->priv->backlight_helper_preference_args); ret = g_spawn_command_line_sync (command, NULL, NULL, &exit_status, error); g_debug ("executed %s retval: %i", command, exit_status); if (!ret || WEXITSTATUS (exit_status) != 0) goto out; out: g_free (command); return ret; } int backlight_get_output_id (CsdPowerManager *manager) { GnomeRROutput *output = NULL; GnomeRROutput **outputs; GnomeRRCrtc *crtc; GdkScreen *gdk_screen; gint x, y; guint i; outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen); if (outputs == NULL) return -1; for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_connected (outputs[i]) && gnome_rr_output_is_laptop (outputs[i])) { output = outputs[i]; break; } } if (output == NULL) return -1; crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) return -1; gdk_screen = gdk_screen_get_default (); gnome_rr_crtc_get_position (crtc, &x, &y); return gdk_screen_get_monitor_at_point (gdk_screen, x, y); } static gint backlight_get_abs (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { return gnome_rr_output_get_backlight (output, error); } } /* fall back to the polkit helper */ return backlight_helper_get_value ("get-brightness", manager, error); } static gint backlight_get_percentage (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gint now; gint value = -1; gint min = 0; gint max; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; value = ABS_TO_PERCENTAGE (min, max, now); goto out; } } /* fall back to the polkit helper */ max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; value = ABS_TO_PERCENTAGE (min, max, now); out: return value; } static gint backlight_get_min (CsdPowerManager *manager) { /* if we have no xbacklight device, then hardcode zero as sysfs * offsets everything to 0 as min */ /* user override means we will be using sysfs */ if (manager->priv->backlight_helper_force) return 0; GnomeRROutput *output; output = get_primary_output (manager); if (output == NULL) return 0; /* get xbacklight value, which maybe non-zero */ return gnome_rr_output_get_backlight_min (output); } static gint backlight_get_max (CsdPowerManager *manager, GError **error) { gint value; GnomeRROutput *output; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { value = gnome_rr_output_get_backlight_max (output); if (value < 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "failed to get backlight max"); } return value; } } /* fall back to the polkit helper */ return backlight_helper_get_value ("get-max-brightness", manager, error); } static void backlight_emit_changed (CsdPowerManager *manager) { /* not yet connected to the bus */ if (manager->priv->screen_iface == NULL) return; csd_screen_emit_changed (manager->priv->screen_iface); } static gboolean backlight_set_percentage (CsdPowerManager *manager, guint value, gboolean emit_changed, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint min = 0; gint max; guint discrete; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); if (min < 0 || max < 0) { g_warning ("no xrandr backlight capability"); goto out; } discrete = PERCENTAGE_TO_ABS (min, max, value); ret = gnome_rr_output_set_backlight (output, discrete, error); goto out; } } /* fall back to the polkit helper */ max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; discrete = PERCENTAGE_TO_ABS (min, max, value); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); out: if (ret && emit_changed) backlight_emit_changed (manager); return ret; } static gint backlight_step_up (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint percentage_value = -1; gint min = 0; gint max; gint now; gint step; guint discrete; GnomeRRCrtc *crtc; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "no crtc for %s", gnome_rr_output_get_name (output)); goto out; } min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MIN (now + step, max); ret = gnome_rr_output_set_backlight (output, discrete, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); goto out; } } /* fall back to the polkit helper */ now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MIN (now + step, max); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); out: if (ret) backlight_emit_changed (manager); return percentage_value; } static gint backlight_step_down (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint percentage_value = -1; gint min = 0; gint max; gint now; gint step; guint discrete; GnomeRRCrtc *crtc; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "no crtc for %s", gnome_rr_output_get_name (output)); goto out; } min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MAX (now - step, 0); ret = gnome_rr_output_set_backlight (output, discrete, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); goto out; } } /* fall back to the polkit helper */ now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MAX (now - step, 0); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); out: if (ret) backlight_emit_changed (manager); return percentage_value; } static gint backlight_set_abs (CsdPowerManager *manager, guint value, gboolean emit_changed, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { ret = gnome_rr_output_set_backlight (output, value, error); goto out; } } /* fall back to the polkit helper */ ret = backlight_helper_set_value ("set-brightness", value, manager, error); out: if (ret && emit_changed) backlight_emit_changed (manager); return ret; } static gboolean display_backlight_dim (CsdPowerManager *manager, gint idle_percentage, GError **error) { gint min; gint max; gint now; gint idle; gboolean ret = FALSE; now = backlight_get_abs (manager, error); if (now < 0) { goto out; } /* is the dim brightness actually *dimmer* than the * brightness we have now? */ min = backlight_get_min (manager); max = backlight_get_max (manager, error); if (max < 0) { goto out; } idle = PERCENTAGE_TO_ABS (min, max, idle_percentage); if (idle > now) { g_debug ("brightness already now %i/%i, so " "ignoring dim to %i/%i", now, max, idle, max); ret = TRUE; goto out; } ret = backlight_set_abs (manager, idle, FALSE, error); if (!ret) { goto out; } /* save for undim */ manager->priv->pre_dim_brightness = now; out: return ret; } static gboolean kbd_backlight_dim (CsdPowerManager *manager, gint idle_percentage, GError **error) { gboolean ret; gint idle; gint max; gint now; if (manager->priv->upower_kbd_proxy == NULL) return TRUE; now = manager->priv->kbd_brightness_now; max = manager->priv->kbd_brightness_max; idle = PERCENTAGE_TO_ABS (0, max, idle_percentage); if (idle > now) { g_debug ("kbd brightness already now %i/%i, so " "ignoring dim to %i/%i", now, max, idle, max); return TRUE; } ret = upower_kbd_set_brightness (manager, idle, error); if (!ret) return FALSE; /* save for undim */ manager->priv->kbd_brightness_pre_dim = now; return TRUE; } static void idle_set_mode (CsdPowerManager *manager, CsdPowerIdleMode mode) { gboolean ret = FALSE; GError *error = NULL; gint idle_percentage; CsdPowerActionType action_type; CinnamonSettingsSessionState state; if (mode == manager->priv->current_idle_mode) return; /* Ignore attempts to set "less idle" modes */ if (mode < manager->priv->current_idle_mode && mode != CSD_POWER_IDLE_MODE_NORMAL) return; /* ensure we're still on an active console */ state = cinnamon_settings_session_get_state (manager->priv->session); if (state == CINNAMON_SETTINGS_SESSION_STATE_INACTIVE) { g_debug ("ignoring state transition to %s as inactive", idle_mode_to_string (mode)); return; } manager->priv->current_idle_mode = mode; g_debug ("Doing a state transition: %s", idle_mode_to_string (mode)); /* don't do any power saving if we're a VM */ if (manager->priv->is_virtual_machine) { g_debug ("ignoring state transition to %s as virtual machine", idle_mode_to_string (mode)); return; } /* save current brightness, and set dim level */ if (mode == CSD_POWER_IDLE_MODE_DIM) { /* have we disabled the action */ if (up_client_get_on_battery (manager->priv->up_client)) { ret = g_settings_get_boolean (manager->priv->settings, "idle-dim-battery"); } else { ret = g_settings_get_boolean (manager->priv->settings, "idle-dim-ac"); } if (!ret) { g_debug ("not dimming due to policy"); return; } /* display backlight */ idle_percentage = g_settings_get_int (manager->priv->settings, "idle-brightness"); ret = display_backlight_dim (manager, idle_percentage, &error); if (!ret) { g_warning ("failed to set dim backlight to %i%%: %s", idle_percentage, error->message); g_clear_error (&error); } /* keyboard backlight */ ret = kbd_backlight_dim (manager, idle_percentage, &error); if (!ret) { g_warning ("failed to set dim kbd backlight to %i%%: %s", idle_percentage, error->message); g_clear_error (&error); } /* turn off screen and kbd */ } else if (mode == CSD_POWER_IDLE_MODE_BLANK) { ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, &error); if (!ret) { g_warning ("failed to turn the panel off: %s", error->message); g_clear_error (&error); } /* only toggle keyboard if present and not already toggled */ if (manager->priv->upower_kbd_proxy && manager->priv->kbd_brightness_old == -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight off: %s", error->message); g_error_free (error); } } /* sleep */ } else if (mode == CSD_POWER_IDLE_MODE_SLEEP) { if (up_client_get_on_battery (manager->priv->up_client)) { action_type = g_settings_get_enum (manager->priv->settings, "sleep-inactive-battery-type"); } else { action_type = g_settings_get_enum (manager->priv->settings, "sleep-inactive-ac-type"); } do_power_action_type (manager, action_type); /* turn on screen and restore user-selected brightness level */ } else if (mode == CSD_POWER_IDLE_MODE_NORMAL) { ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on: %s", error->message); g_clear_error (&error); } /* reset brightness if we dimmed */ if (manager->priv->pre_dim_brightness >= 0) { ret = backlight_set_abs (manager, manager->priv->pre_dim_brightness, FALSE, &error); if (!ret) { g_warning ("failed to restore backlight to %i: %s", manager->priv->pre_dim_brightness, error->message); g_clear_error (&error); } else { manager->priv->pre_dim_brightness = -1; } } /* only toggle keyboard if present and already toggled off */ if (manager->priv->upower_kbd_proxy && manager->priv->kbd_brightness_old != -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight on: %s", error->message); g_clear_error (&error); } } /* reset kbd brightness if we dimmed */ if (manager->priv->kbd_brightness_pre_dim >= 0) { ret = upower_kbd_set_brightness (manager, manager->priv->kbd_brightness_pre_dim, &error); if (!ret) { g_warning ("failed to restore kbd backlight to %i: %s", manager->priv->kbd_brightness_pre_dim, error->message); g_error_free (error); } manager->priv->kbd_brightness_pre_dim = -1; } } } static gboolean idle_is_session_inhibited (CsdPowerManager *manager, guint mask) { gboolean ret; GVariant *retval = NULL; GError *error = NULL; /* not yet connected to cinnamon-session */ if (manager->priv->session_proxy == NULL) { g_debug ("session inhibition not available, cinnamon-session is not available"); return FALSE; } retval = g_dbus_proxy_call_sync (manager->priv->session_proxy, "IsInhibited", g_variant_new ("(u)", mask), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (retval == NULL) { /* abort as the DBUS method failed */ g_warning ("IsInhibited failed: %s", error->message); g_error_free (error); return FALSE; } g_variant_get (retval, "(b)", &ret); g_variant_unref (retval); return ret; } /** * idle_adjust_timeout: * @idle_time: Current idle time, in seconds. * @timeout: The new timeout we want to set, in seconds. * * On slow machines, or machines that have lots to load duing login, * the current idle time could be bigger than the requested timeout. * In this case the scheduled idle timeout will never fire, unless * some user activity (keyboard, mouse) resets the current idle time. * Instead of relying on user activity to correct this issue, we need * to adjust timeout, as related to current idle time, so the idle * timeout will fire as designed. * * Return value: timeout to set, adjusted acccording to current idle time. **/ static guint idle_adjust_timeout (guint idle_time, guint timeout) { /* allow 2 sec margin for messaging delay. */ idle_time += 2; /* Double timeout until it's larger than current idle time. * Give up for ultra slow machines. (86400 sec = 24 hours) */ while (timeout < idle_time && timeout < 86400 && timeout > 0) { timeout *= 2; } return timeout; } /** * @timeout: The new timeout we want to set, in seconds **/ static void idle_set_timeout_dim (CsdPowerManager *manager, guint timeout) { guint idle_time; gboolean is_idle_inhibited; /* are we inhibited from going idle */ is_idle_inhibited = idle_is_session_inhibited (manager, SESSION_INHIBIT_MASK_IDLE); if (is_idle_inhibited) { g_debug ("inhibited, so using normal state"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID); return; } idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000; g_debug ("Setting dim idle timeout: %ds", timeout); if (timeout > 0) { gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID, idle_adjust_timeout (idle_time, timeout) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID); } return; } static void refresh_idle_dim_settings (CsdPowerManager *manager) { gint timeout_dim; timeout_dim = g_settings_get_int (manager->priv->settings, "idle-dim-time"); g_debug ("idle dim set with timeout %i", timeout_dim); idle_set_timeout_dim (manager, timeout_dim); } /** * idle_adjust_timeout_blank: * @idle_time: current idle time, in seconds. * @timeout: the new timeout we want to set, in seconds. * * Same as idle_adjust_timeout(), but also accounts for the duration * of the fading animation in the screensaver (so that blanking happens * exactly at the end of it, if configured with the same timeouts) */ static guint idle_adjust_timeout_blank (guint idle_time, guint timeout) { return idle_adjust_timeout (idle_time, timeout + SCREENSAVER_FADE_TIME); } static void idle_configure (CsdPowerManager *manager) { gboolean is_idle_inhibited; guint current_idle_time; guint timeout_blank; guint timeout_sleep; gboolean on_battery; /* are we inhibited from going idle */ is_idle_inhibited = idle_is_session_inhibited (manager, SESSION_INHIBIT_MASK_IDLE); if (is_idle_inhibited) { g_debug ("inhibited, so using normal state"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID); refresh_idle_dim_settings (manager); return; } current_idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000; /* set up blank callback even when session is not idle, * but only if we actually want to blank. */ on_battery = up_client_get_on_battery (manager->priv->up_client); if (on_battery) { timeout_blank = g_settings_get_int (manager->priv->settings, "sleep-display-battery"); } else { timeout_blank = g_settings_get_int (manager->priv->settings, "sleep-display-ac"); } if (timeout_blank != 0) { g_debug ("setting up blank callback for %is", timeout_blank); gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID, idle_adjust_timeout_blank (current_idle_time, timeout_blank) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID); } gboolean is_sleep_inhibited = idle_is_session_inhibited (manager, SESSION_INHIBIT_MASK_SUSPEND); /* only do the sleep timeout when the session is idle * and we aren't inhibited from sleeping */ if (on_battery) { timeout_sleep = g_settings_get_int (manager->priv->settings, "sleep-inactive-battery-timeout"); } else { timeout_sleep = g_settings_get_int (manager->priv->settings, "sleep-inactive-ac-timeout"); } if (!is_sleep_inhibited && timeout_sleep != 0) { g_debug ("setting up sleep callback %is", timeout_sleep); gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID, idle_adjust_timeout (current_idle_time, timeout_sleep) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID); } refresh_idle_dim_settings (manager); } #if UP_CHECK_VERSION(0,99,0) static void up_client_on_battery_cb (UpClient *client, GParamSpec *pspec, CsdPowerManager *manager) { idle_configure (manager); lid_state_changed_cb(client, pspec, manager); } #endif static void csd_power_manager_class_init (CsdPowerManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_power_manager_finalize; g_type_class_add_private (klass, sizeof (CsdPowerManagerPrivate)); } static void lock_screensaver (CsdPowerManager *manager) { GError *error; gboolean ret; g_debug ("Locking screen before sleep/hibernate"); /* do this sync to ensure it's on the screen when we start suspending */ error = NULL; ret = g_spawn_command_line_sync ("cinnamon-screensaver-command --lock", NULL, NULL, NULL, &error); if (!ret) { g_warning ("Couldn't lock screen: %s", error->message); g_error_free (error); } } static void idle_dbus_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); if (g_strcmp0 (signal_name, "InhibitorAdded") == 0 || g_strcmp0 (signal_name, "InhibitorRemoved") == 0) { g_debug ("Received gnome session inhibitor change"); idle_configure (manager); } if (g_strcmp0 (signal_name, "StatusChanged") == 0) { guint status; g_variant_get (parameters, "(u)", &status); g_dbus_proxy_set_cached_property (proxy, "status", g_variant_new ("u", status)); g_debug ("Received gnome session status change"); idle_configure (manager); } } static void session_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->session_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->session_proxy == NULL) { g_warning ("Could not connect to cinnamon-session: %s", error->message); g_error_free (error); } else { g_signal_connect (manager->priv->session_proxy, "g-signal", G_CALLBACK (idle_dbus_signal_cb), manager); } idle_configure (manager); } static void session_presence_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->session_presence_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->session_presence_proxy == NULL) { g_warning ("Could not connect to gnome-sesson: %s", error->message); g_error_free (error); return; } g_signal_connect (manager->priv->session_presence_proxy, "g-signal", G_CALLBACK (idle_dbus_signal_cb), manager); } static void power_keyboard_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *k_now = NULL; GVariant *k_max = NULL; GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->upower_kbd_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->upower_kbd_proxy == NULL) { g_warning ("Could not connect to UPower: %s", error->message); g_error_free (error); goto out; } k_now = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy, "GetBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (k_now == NULL) { if (error->domain != G_DBUS_ERROR || error->code != G_DBUS_ERROR_UNKNOWN_METHOD) { g_warning ("Failed to get brightness: %s", error->message); } g_error_free (error); goto out; } k_max = g_dbus_proxy_call_sync (manager->priv->upower_kbd_proxy, "GetMaxBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (k_max == NULL) { g_warning ("Failed to get max brightness: %s", error->message); g_error_free (error); goto out; } g_signal_connect (manager->priv->upower_kbd_proxy, "g-signal", G_CALLBACK(upower_kbd_handle_changed), manager); g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now); g_variant_get (k_max, "(i)", &manager->priv->kbd_brightness_max); /* Set keyboard brightness to zero if the current value is out of valid range. Unlike display brightness, keyboard backlight brightness should be dim by default.*/ if ((manager->priv->kbd_brightness_now < 0) || (manager->priv->kbd_brightness_now > manager->priv->kbd_brightness_max)) { gboolean ret; ret = upower_kbd_set_brightness (manager, 0, &error); if (!ret) { g_warning ("failed to initialize kbd backlight to %i: %s", 0, error->message); g_error_free (error); } } out: if (k_now != NULL) g_variant_unref (k_now); if (k_max != NULL) g_variant_unref (k_max); } static void idle_idletime_alarm_expired_cb (GpmIdletime *idletime, guint alarm_id, CsdPowerManager *manager) { g_debug ("idletime alarm: %i", alarm_id); switch (alarm_id) { case CSD_POWER_IDLETIME_DIM_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_DIM); break; case CSD_POWER_IDLETIME_BLANK_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_BLANK); break; case CSD_POWER_IDLETIME_SLEEP_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_SLEEP); break; } } static void idle_idletime_reset_cb (GpmIdletime *idletime, CsdPowerManager *manager) { g_debug ("idletime reset"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); } static void engine_settings_key_changed_cb (GSettings *settings, const gchar *key, CsdPowerManager *manager) { /* note: you *have* to check if your key was changed here before * doing anything here. this gets invoked on module stop, and * will crash c-s-d if you don't. */ if (g_strcmp0 (key, "use-time-for-policy") == 0) { manager->priv->use_time_primary = g_settings_get_boolean (settings, key); return; } if (g_strcmp0 (key, "idle-dim-time") == 0) { refresh_idle_dim_settings (manager); return; } if (g_str_has_prefix (key, "sleep-inactive") || g_str_has_prefix (key, "sleep-display")) { idle_configure (manager); return; } if (g_str_has_prefix (key, "backlight-helper")) { backlight_override_settings_refresh (manager); return; } } static void engine_session_active_changed_cb (CinnamonSettingsSession *session, GParamSpec *pspec, CsdPowerManager *manager) { /* when doing the fast-user-switch into a new account, * ensure the new account is undimmed and with the backlight on */ idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); } /* This timer goes off every few minutes, whether the user is idle or not, to try and clean up anything that has gone wrong. It calls disable_builtin_screensaver() so that if xset has been used, or some other program (like xlock) has messed with the XSetScreenSaver() settings, they will be set back to sensible values (if a server extension is in use, messing with xlock can cause the screensaver to never get a wakeup event, and could cause monitor power-saving to occur, and all manner of heinousness.) This code was originally part of cinnamon-screensaver, see http://git.gnome.org/browse/cinnamon-screensaver/tree/src/gs-watcher-x11.c?id=fec00b12ec46c86334cfd36b37771cc4632f0d4d#n530 */ static gboolean disable_builtin_screensaver (gpointer unused) { int current_server_timeout, current_server_interval; int current_prefer_blank, current_allow_exp; int desired_server_timeout, desired_server_interval; int desired_prefer_blank, desired_allow_exp; XGetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), ¤t_server_timeout, ¤t_server_interval, ¤t_prefer_blank, ¤t_allow_exp); desired_server_timeout = current_server_timeout; desired_server_interval = current_server_interval; desired_prefer_blank = current_prefer_blank; desired_allow_exp = current_allow_exp; desired_server_interval = 0; /* I suspect (but am not sure) that DontAllowExposures might have something to do with powering off the monitor as well, at least on some systems that don't support XDPMS? Who know... */ desired_allow_exp = AllowExposures; /* When we're not using an extension, set the server-side timeout to 0, so that the server never gets involved with screen blanking, and we do it all ourselves. (However, when we *are* using an extension, we tell the server when to notify us, and rather than blanking the screen, the server will send us an X event telling us to blank.) */ desired_server_timeout = 0; if (desired_server_timeout != current_server_timeout || desired_server_interval != current_server_interval || desired_prefer_blank != current_prefer_blank || desired_allow_exp != current_allow_exp) { g_debug ("disabling server builtin screensaver:" " (xset s %d %d; xset s %s; xset s %s)", desired_server_timeout, desired_server_interval, (desired_prefer_blank ? "blank" : "noblank"), (desired_allow_exp ? "expose" : "noexpose")); XSetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), desired_server_timeout, desired_server_interval, desired_prefer_blank, desired_allow_exp); XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); } return TRUE; } static void inhibit_lid_switch_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit lid switch: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_lid_switch_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_lid_switch_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_lid_switch_fd); g_object_unref (fd_list); g_variant_unref (res); } } static void inhibit_lid_switch (CsdPowerManager *manager) { if (!manager->priv->inhibit_lid_switch_enabled) { // The users asks us not to interfere with what logind does // w.r.t. handling the lid switch g_debug ("inhibiting lid-switch disabled"); return; } GVariant *params; if (manager->priv->inhibit_lid_switch_taken) { g_debug ("already inhibited lid-switch"); return; } g_debug ("Adding lid switch system inhibitor"); manager->priv->inhibit_lid_switch_taken = TRUE; params = g_variant_new ("(ssss)", "handle-lid-switch", g_get_user_name (), "Multiple displays attached", "block"); g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", params, 0, G_MAXINT, NULL, NULL, inhibit_lid_switch_done, manager); } static void uninhibit_lid_switch (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_fd == -1) { g_debug ("no lid-switch inhibitor"); return; } g_debug ("Removing lid switch system inhibitor"); close (manager->priv->inhibit_lid_switch_fd); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_lid_switch_taken = FALSE; } static void inhibit_suspend_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit suspend: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_suspend_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_suspend_fd); g_object_unref (fd_list); g_variant_unref (res); } } /* We take a delay inhibitor here, which causes logind to send a * PrepareToSleep signal, which gives us a chance to lock the screen * and do some other preparations. */ static void inhibit_suspend (CsdPowerManager *manager) { if (manager->priv->inhibit_suspend_taken) { g_debug ("already inhibited lid-switch"); return; } g_debug ("Adding suspend delay inhibitor"); manager->priv->inhibit_suspend_taken = TRUE; g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", g_variant_new ("(ssss)", "sleep", g_get_user_name (), "Cinnamon needs to lock the screen", "delay"), 0, G_MAXINT, NULL, NULL, inhibit_suspend_done, manager); } static void uninhibit_suspend (CsdPowerManager *manager) { if (manager->priv->inhibit_suspend_fd == -1) { g_debug ("no suspend delay inhibitor"); return; } g_debug ("Removing suspend delay inhibitor"); close (manager->priv->inhibit_suspend_fd); manager->priv->inhibit_suspend_fd = -1; manager->priv->inhibit_suspend_taken = FALSE; } static void handle_suspend_actions (CsdPowerManager *manager) { /* Is this even necessary? We lock ahead of the suspend initiation, * during do_power_action_type(). This is a signal from logind or * upower that we're about to suspend. That may have originated in * this module, or elsewhere (cinnamon-session via menu or user * applet. Lock is handled there as well... but just in case I * suppose.) */ if (should_lock_on_suspend (manager)) { lock_screensaver (manager); } /* lift the delay inhibit, so logind can proceed */ uninhibit_suspend (manager); } static void handle_resume_actions (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* this displays the unlock dialogue so the user doesn't have * to move the mouse or press any key before the window comes up */ g_dbus_connection_call (manager->priv->connection, GS_DBUS_NAME, GS_DBUS_PATH, GS_DBUS_INTERFACE, "SimulateUserActivity", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); /* close existing notifications on resume, the system power * state is probably different now */ notify_close_if_showing (manager->priv->notification_low); notify_close_if_showing (manager->priv->notification_discharging); /* ensure we turn the panel back on after resume */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on after resume: %s", error->message); g_error_free (error); } /* set up the delay again */ inhibit_suspend (manager); } #if ! UP_CHECK_VERSION(0,99,0) static void upower_notify_sleep_cb (UpClient *client, UpSleepKind sleep_kind, CsdPowerManager *manager) { handle_suspend_actions (manager); } static void upower_notify_resume_cb (UpClient *client, UpSleepKind sleep_kind, CsdPowerManager *manager) { handle_resume_actions (manager); } #endif static void logind_proxy_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); gboolean is_about_to_suspend; if (g_strcmp0 (signal_name, "PrepareForSleep") != 0) return; g_variant_get (parameters, "(b)", &is_about_to_suspend); if (is_about_to_suspend) { handle_suspend_actions (manager); } else { handle_resume_actions (manager); } } static gboolean is_hardware_a_virtual_machine (void) { const gchar *str; gboolean ret = FALSE; GError *error = NULL; GVariant *inner; GVariant *variant = NULL; GDBusConnection *connection; connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (connection == NULL) { g_warning ("system bus not available: %s", error->message); g_error_free (error); goto out; } variant = g_dbus_connection_call_sync (connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", "org.freedesktop.systemd1.Manager", "Virtualization"), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_debug ("Failed to get property '%s': %s", "Virtualization", error->message); g_error_free (error); goto out; } /* on bare-metal hardware this is the empty string, * otherwise an identifier such as "kvm", "vmware", etc. */ g_variant_get (variant, "(v)", &inner); str = g_variant_get_string (inner, NULL); if (str != NULL && str[0] != '\0') ret = TRUE; out: if (connection != NULL) g_object_unref (connection); if (variant != NULL) g_variant_unref (variant); return ret; } gboolean csd_power_manager_start (CsdPowerManager *manager, GError **error) { gboolean ret; g_debug ("Starting power manager"); cinnamon_settings_profile_start (NULL); /* coldplug the list of screens */ manager->priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (manager->priv->x11_screen == NULL) return FALSE; /* Set up the logind proxy */ manager->priv->logind_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, NULL, error); g_signal_connect (manager->priv->logind_proxy, "g-signal", G_CALLBACK (logind_proxy_signal_cb), manager); /* Set up a delay inhibitor to be informed about suspend attempts */ inhibit_suspend (manager); /* track the active session */ manager->priv->session = cinnamon_settings_session_new (); g_signal_connect (manager->priv->session, "notify::state", G_CALLBACK (engine_session_active_changed_cb), manager); manager->priv->kbd_brightness_old = -1; manager->priv->kbd_brightness_pre_dim = -1; manager->priv->pre_dim_brightness = -1; manager->priv->settings = g_settings_new (CSD_POWER_SETTINGS_SCHEMA); g_signal_connect (manager->priv->settings, "changed", G_CALLBACK (engine_settings_key_changed_cb), manager); manager->priv->settings_screensaver = g_settings_new ("org.cinnamon.desktop.screensaver"); manager->priv->settings_xrandr = g_settings_new (CSD_XRANDR_SETTINGS_SCHEMA); manager->priv->settings_desktop_session = g_settings_new (CSD_SESSION_SETTINGS_SCHEMA); manager->priv->settings_cinnamon_session = g_settings_new (CSD_CINNAMON_SESSION_SCHEMA); manager->priv->inhibit_lid_switch_enabled = g_settings_get_boolean (manager->priv->settings, "inhibit-lid-switch"); /* Disable logind's lid handling while g-s-d is active */ inhibit_lid_switch (manager); manager->priv->up_client = up_client_new (); #if ! UP_CHECK_VERSION(0,99,0) g_signal_connect (manager->priv->up_client, "notify-sleep", G_CALLBACK (upower_notify_sleep_cb), manager); g_signal_connect (manager->priv->up_client, "notify-resume", G_CALLBACK (upower_notify_resume_cb), manager); #endif manager->priv->lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client); manager->priv->on_battery = up_client_get_on_battery(manager->priv->up_client); g_signal_connect (manager->priv->up_client, "device-added", G_CALLBACK (engine_device_added_cb), manager); g_signal_connect (manager->priv->up_client, "device-removed", G_CALLBACK (engine_device_removed_cb), manager); #if UP_CHECK_VERSION(0,99,0) g_signal_connect_after (manager->priv->up_client, "notify::lid-is-closed", G_CALLBACK (lid_state_changed_cb), manager); g_signal_connect (manager->priv->up_client, "notify::on-battery", G_CALLBACK (up_client_on_battery_cb), manager); #else g_signal_connect (manager->priv->up_client, "device-changed", G_CALLBACK (engine_device_changed_cb), manager); g_signal_connect_after (manager->priv->up_client, "changed", G_CALLBACK (up_client_changed_cb), manager); #endif /* use the fallback name from gnome-power-manager so the shell * blocks this, and uses the power extension instead */ manager->priv->status_icon = gtk_status_icon_new (); gtk_status_icon_set_name (manager->priv->status_icon, "gnome-power-manager"); /* TRANSLATORS: this is the title of the power manager status icon * that is only shown in fallback mode */ gtk_status_icon_set_title (manager->priv->status_icon, _("Power Manager")); gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); /* connect to UPower for keyboard backlight control */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, UPOWER_DBUS_NAME, UPOWER_DBUS_PATH_KBDBACKLIGHT, UPOWER_DBUS_INTERFACE_KBDBACKLIGHT, NULL, power_keyboard_proxy_ready_cb, manager); /* connect to the session */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, NULL, session_proxy_ready_cb, manager); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, 0, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH_PRESENCE, GNOME_SESSION_DBUS_INTERFACE_PRESENCE, NULL, session_presence_proxy_ready_cb, manager); manager->priv->devices_array = g_ptr_array_new_with_free_func (g_object_unref); manager->priv->canberra_context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); manager->priv->phone = gpm_phone_new (); g_signal_connect (manager->priv->phone, "device-added", G_CALLBACK (phone_device_added_cb), manager); g_signal_connect (manager->priv->phone, "device-removed", G_CALLBACK (phone_device_removed_cb), manager); g_signal_connect (manager->priv->phone, "device-refresh", G_CALLBACK (phone_device_refresh_cb), manager); /* create a fake virtual composite battery */ manager->priv->device_composite = up_device_new (); g_object_set (manager->priv->device_composite, "kind", UP_DEVICE_KIND_BATTERY, "is-rechargeable", TRUE, "native-path", "dummy:composite_battery", "power-supply", TRUE, "is-present", TRUE, NULL); /* get backlight setting overrides */ manager->priv->backlight_helper_preference_args = NULL; backlight_override_settings_refresh (manager); /* get percentage policy */ manager->priv->low_percentage = g_settings_get_int (manager->priv->settings, "percentage-low"); manager->priv->critical_percentage = g_settings_get_int (manager->priv->settings, "percentage-critical"); manager->priv->action_percentage = g_settings_get_int (manager->priv->settings, "percentage-action"); /* get time policy */ manager->priv->low_time = g_settings_get_int (manager->priv->settings, "time-low"); manager->priv->critical_time = g_settings_get_int (manager->priv->settings, "time-critical"); manager->priv->action_time = g_settings_get_int (manager->priv->settings, "time-action"); /* we can disable this if the time remaining is inaccurate or just plain wrong */ manager->priv->use_time_primary = g_settings_get_boolean (manager->priv->settings, "use-time-for-policy"); /* create IDLETIME watcher */ manager->priv->idletime = gpm_idletime_new (); g_signal_connect (manager->priv->idletime, "reset", G_CALLBACK (idle_idletime_reset_cb), manager); g_signal_connect (manager->priv->idletime, "alarm-expired", G_CALLBACK (idle_idletime_alarm_expired_cb), manager); /* set up the screens */ g_signal_connect (manager->priv->x11_screen, "changed", G_CALLBACK (on_randr_event), manager); on_randr_event (manager->priv->x11_screen, manager); /* ensure the default dpms timeouts are cleared */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, error); if (!ret) { g_warning ("Failed set DPMS mode: %s", (*error)->message); g_clear_error (error); } /* coldplug the engine */ engine_coldplug (manager); /* Make sure that Xorg's DPMS extension never gets in our way. The defaults seem to have changed in Xorg 1.14 * being "0" by default to being "600" by default * https://bugzilla.gnome.org/show_bug.cgi?id=709114 */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); int dummy; if (DPMSQueryExtension(GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &dummy, &dummy)) { DPMSSetTimeouts (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), 0, 0, 0); } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); manager->priv->xscreensaver_watchdog_timer_id = g_timeout_add_seconds (XSCREENSAVER_WATCHDOG_TIMEOUT, disable_builtin_screensaver, NULL); /* don't blank inside a VM */ manager->priv->is_virtual_machine = is_hardware_a_virtual_machine (); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_power_manager_stop (CsdPowerManager *manager) { g_debug ("Stopping power manager"); if (manager->priv->bus_cancellable != NULL) { g_cancellable_cancel (manager->priv->bus_cancellable); g_object_unref (manager->priv->bus_cancellable); manager->priv->bus_cancellable = NULL; } kill_lid_close_safety_timer (manager); g_signal_handlers_disconnect_by_data (manager->priv->up_client, manager); if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->settings_screensaver != NULL) { g_object_unref (manager->priv->settings_screensaver); manager->priv->settings_screensaver = NULL; } if (manager->priv->settings_xrandr != NULL) { g_object_unref (manager->priv->settings_xrandr); manager->priv->settings_xrandr = NULL; } if (manager->priv->settings_desktop_session != NULL) { g_object_unref (manager->priv->settings_desktop_session); manager->priv->settings_desktop_session = NULL; } if (manager->priv->settings_cinnamon_session != NULL) { g_object_unref (manager->priv->settings_cinnamon_session); manager->priv->settings_cinnamon_session = NULL; } if (manager->priv->up_client != NULL) { g_object_unref (manager->priv->up_client); manager->priv->up_client = NULL; } if (manager->priv->inhibit_lid_switch_fd != -1) { close (manager->priv->inhibit_lid_switch_fd); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_lid_switch_taken = FALSE; } if (manager->priv->inhibit_suspend_fd != -1) { close (manager->priv->inhibit_suspend_fd); manager->priv->inhibit_suspend_fd = -1; manager->priv->inhibit_suspend_taken = FALSE; } if (manager->priv->logind_proxy != NULL) { g_object_unref (manager->priv->logind_proxy); manager->priv->logind_proxy = NULL; } g_free (manager->priv->backlight_helper_preference_args); manager->priv->backlight_helper_preference_args = NULL; if (manager->priv->x11_screen != NULL) { g_object_unref (manager->priv->x11_screen); manager->priv->x11_screen = NULL; } g_ptr_array_unref (manager->priv->devices_array); manager->priv->devices_array = NULL; if (manager->priv->phone != NULL) { g_object_unref (manager->priv->phone); manager->priv->phone = NULL; } if (manager->priv->device_composite != NULL) { g_object_unref (manager->priv->device_composite); manager->priv->device_composite = NULL; } if (manager->priv->previous_icon != NULL) { g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = NULL; } g_free (manager->priv->previous_summary); manager->priv->previous_summary = NULL; if (manager->priv->session_proxy != NULL) { g_object_unref (manager->priv->session_proxy); manager->priv->session_proxy = NULL; } if (manager->priv->session_presence_proxy != NULL) { g_object_unref (manager->priv->session_presence_proxy); manager->priv->session_presence_proxy = NULL; } if (manager->priv->critical_alert_timeout_id > 0) { g_source_remove (manager->priv->critical_alert_timeout_id); manager->priv->critical_alert_timeout_id = 0; } g_signal_handlers_disconnect_by_func (manager->priv->idletime, idle_idletime_reset_cb, manager); g_signal_handlers_disconnect_by_func (manager->priv->idletime, idle_idletime_alarm_expired_cb, manager); if (manager->priv->idletime != NULL) { g_object_unref (manager->priv->idletime); manager->priv->idletime = NULL; } if (manager->priv->status_icon != NULL) { g_object_unref (manager->priv->status_icon); manager->priv->status_icon = NULL; } if (manager->priv->xscreensaver_watchdog_timer_id > 0) { g_source_remove (manager->priv->xscreensaver_watchdog_timer_id); manager->priv->xscreensaver_watchdog_timer_id = 0; } g_clear_object (&manager->priv->power_iface); g_clear_object (&manager->priv->screen_iface); g_clear_object (&manager->priv->keyboard_iface); } static void csd_power_manager_init (CsdPowerManager *manager) { manager->priv = CSD_POWER_MANAGER_GET_PRIVATE (manager); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_suspend_fd = -1; } static void csd_power_manager_finalize (GObject *object) { CsdPowerManager *manager; manager = CSD_POWER_MANAGER (object); g_return_if_fail (manager->priv != NULL); if (manager->priv->p_name_id != 0) g_bus_unown_name (manager->priv->p_name_id); if (manager->priv->s_name_id != 0) g_bus_unown_name (manager->priv->s_name_id); if (manager->priv->k_name_id != 0) g_bus_unown_name (manager->priv->k_name_id); G_OBJECT_CLASS (csd_power_manager_parent_class)->finalize (object); } #if !UP_CHECK_VERSION(0,99,0) #define UP_DEVICE_LEVEL_NONE 1 #endif static GVariant * device_to_variant_blob (UpDevice *device) { const gchar *object_path, *vendor, *model; gchar *device_icon; gdouble percentage; GIcon *icon; guint64 time_empty, time_full; guint64 time_state = 0; GVariant *value; UpDeviceKind kind; UpDeviceState state; gint battery_level; icon = gpm_upower_get_device_icon (device, TRUE); device_icon = g_icon_to_string (icon); g_object_get (device, "vendor", &vendor, "model", &model, "kind", &kind, "percentage", &percentage, "state", &state, "time-to-empty", &time_empty, "time-to-full", &time_full, NULL); /* upower < 0.99.5 compatibility */ if (g_object_class_find_property (G_OBJECT_GET_CLASS (device), "battery-level")) { g_object_get (device, "battery-level", &battery_level, NULL); } else { battery_level = UP_DEVICE_LEVEL_NONE; } /* only return time for these simple states */ if (state == UP_DEVICE_STATE_DISCHARGING) time_state = time_empty; else if (state == UP_DEVICE_STATE_CHARGING) time_state = time_full; /* get an object path, even for the composite device */ object_path = up_device_get_object_path (device); if (object_path == NULL) object_path = CSD_POWER_DBUS_PATH; /* format complex object */ value = g_variant_new ("(sssusduut)", object_path, vendor, model, kind, device_icon, percentage, state, battery_level, time_state); g_free (device_icon); g_object_unref (icon); return value; } /* returns new level */ static void handle_method_call_keyboard (CsdPowerManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { gint step; gint value = -1; gboolean ret; guint percentage; GError *error = NULL; if (g_strcmp0 (method_name, "GetPercentage") == 0) { g_debug ("keyboard get percentage"); ret = upower_kbd_get_percentage (manager, &error); value = manager->priv->kbd_brightness_now; } else if (g_strcmp0 (method_name, "SetPercentage") == 0) { g_debug ("keyboard set percentage"); guint value_tmp; g_variant_get (parameters, "(u)", &percentage); value_tmp = PERCENTAGE_TO_ABS (0, manager->priv->kbd_brightness_max, percentage); ret = upower_kbd_set_brightness (manager, value_tmp, &error); if (ret) value = value_tmp; } else if (g_strcmp0 (method_name, "StepUp") == 0) { g_debug ("keyboard step up"); step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max); value = MIN (manager->priv->kbd_brightness_now + step, manager->priv->kbd_brightness_max); ret = upower_kbd_set_brightness (manager, value, &error); } else if (g_strcmp0 (method_name, "StepDown") == 0) { g_debug ("keyboard step down"); step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max); value = MAX (manager->priv->kbd_brightness_now - step, 0); ret = upower_kbd_set_brightness (manager, value, &error); } else if (g_strcmp0 (method_name, "GetStep") == 0) { g_debug ("keyboard get step"); value = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max); ret = (value > 0); } else if (g_strcmp0 (method_name, "Toggle") == 0) { ret = upower_kbd_toggle (manager, &error); value = manager->priv->kbd_brightness_now; } else { g_assert_not_reached (); } /* return value */ if (!ret) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else { percentage = ABS_TO_PERCENTAGE (0, manager->priv->kbd_brightness_max, value); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", percentage)); } } static void handle_method_call_screen (CsdPowerManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { gboolean ret = FALSE; gint value = -1; guint value_tmp; GError *error = NULL; if ((g_strcmp0 (method_name, "GetPercentage") == 0) || (g_strcmp0 (method_name, "SetPercentage") == 0)) { if (g_strcmp0 (method_name, "GetPercentage") == 0) { g_debug ("screen get percentage"); value = backlight_get_percentage (manager, &error); } else if (g_strcmp0 (method_name, "SetPercentage") == 0) { g_debug ("screen set percentage"); g_variant_get (parameters, "(u)", &value_tmp); ret = backlight_set_percentage (manager, value_tmp, TRUE, &error); if (ret) value = value_tmp; } /* return value */ if (value < 0) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else { g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", value)); } } else if ((g_strcmp0 (method_name, "StepUp") == 0) || (g_strcmp0 (method_name, "StepDown") == 0)) { if (g_strcmp0 (method_name, "StepUp") == 0) { g_debug ("screen step up"); value = backlight_step_up (manager, &error); } else if (g_strcmp0 (method_name, "StepDown") == 0) { g_debug ("screen step down"); value = backlight_step_down (manager, &error); } /* return value */ if (value < 0) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else { g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ui)", value, backlight_get_output_id (manager))); } } else { g_assert_not_reached (); } } static gboolean screen_iface_method_cb (CsdScreen *object, GDBusMethodInvocation *invocation, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); handle_method_call_screen (manager, g_dbus_method_invocation_get_method_name (invocation), g_dbus_method_invocation_get_parameters (invocation), invocation); return TRUE; } static gboolean screen_iface_set_method_cb (CsdScreen *object, GDBusMethodInvocation *invocation, guint percent, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); handle_method_call_screen (manager, g_dbus_method_invocation_get_method_name (invocation), g_dbus_method_invocation_get_parameters (invocation), invocation); return TRUE; } static gboolean keyboard_iface_method_cb (CsdScreen *object, GDBusMethodInvocation *invocation, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); handle_method_call_keyboard (manager, g_dbus_method_invocation_get_method_name (invocation), g_dbus_method_invocation_get_parameters (invocation), invocation); return TRUE; } static gboolean keyboard_iface_set_method_cb (CsdScreen *object, GDBusMethodInvocation *invocation, guint percent, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); handle_method_call_keyboard (manager, g_dbus_method_invocation_get_method_name (invocation), g_dbus_method_invocation_get_parameters (invocation), invocation); return TRUE; } static gboolean power_iface_handle_get_primary_device (CsdPower *object, GDBusMethodInvocation *invocation, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); UpDevice *device; GVariant *tuple = NULL; GVariant *value = NULL; g_debug ("Handling Power interface method GetPrimaryDevice"); /* get the virtual device */ device = engine_get_primary_device (manager); if (device == NULL) { g_dbus_method_invocation_return_dbus_error (invocation, "org.cinnamon.SettingsDaemon.Power.Failed", "There is no primary device."); return TRUE; } /* return the value */ value = device_to_variant_blob (device); tuple = g_variant_new_tuple (&value, 1); g_dbus_method_invocation_return_value (invocation, tuple); g_object_unref (device); return TRUE; } static gboolean power_iface_handle_get_devices (CsdPower *object, GDBusMethodInvocation *invocation, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); UpDevice *device; GPtrArray *array; guint i; GVariantBuilder *builder; GVariant *tuple = NULL; GVariant *value = NULL; g_debug ("Handling Power interface method GetDevices"); /* create builder */ builder = g_variant_builder_new (G_VARIANT_TYPE("a(sssusduut)")); /* add each tuple to the array */ array = manager->priv->devices_array; for (i=0; ilen; i++) { device = g_ptr_array_index (array, i); value = device_to_variant_blob (device); g_variant_builder_add_value (builder, value); } /* return the value */ value = g_variant_builder_end (builder); tuple = g_variant_new_tuple (&value, 1); g_dbus_method_invocation_return_value (invocation, tuple); g_variant_builder_unref (builder); return TRUE; } static void power_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdPower *iface; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); iface = csd_power_skeleton_new (); g_signal_connect (iface, "handle-get-primary-device", G_CALLBACK (power_iface_handle_get_primary_device), manager); g_signal_connect (iface, "handle-get-devices", G_CALLBACK (power_iface_handle_get_devices), manager); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface), connection, CSD_POWER_DBUS_PATH, NULL); manager->priv->power_iface = iface; engine_recalculate_state (manager); } static void screen_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdScreen *iface; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); iface = csd_screen_skeleton_new (); g_signal_connect (iface, "handle-get-percentage", G_CALLBACK (screen_iface_method_cb), manager); g_signal_connect (iface, "handle-set-percentage", G_CALLBACK (screen_iface_set_method_cb), manager); g_signal_connect (iface, "handle-step-down", G_CALLBACK (screen_iface_method_cb), manager); g_signal_connect (iface, "handle-step-up", G_CALLBACK (screen_iface_method_cb), manager); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface), connection, CSD_POWER_DBUS_PATH, NULL); manager->priv->screen_iface = iface; backlight_emit_changed (manager); } static void keyboard_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdKeyboard *iface; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); iface = csd_keyboard_skeleton_new (); g_signal_connect (iface, "handle-get-percentage", G_CALLBACK (keyboard_iface_method_cb), manager); g_signal_connect (iface, "handle-set-percentage", G_CALLBACK (keyboard_iface_set_method_cb), manager); g_signal_connect (iface, "handle-step-down", G_CALLBACK (keyboard_iface_method_cb), manager); g_signal_connect (iface, "handle-step-up", G_CALLBACK (keyboard_iface_method_cb), manager); g_signal_connect (iface, "handle-get-step", G_CALLBACK (keyboard_iface_method_cb), manager); g_signal_connect (iface, "handle-toggle", G_CALLBACK (keyboard_iface_method_cb), manager); g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (iface), connection, CSD_POWER_DBUS_PATH, NULL); manager->priv->keyboard_iface = iface; upower_kbd_emit_changed (manager); } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdPowerManager *manager) { GDBusConnection *connection; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; manager->priv->p_name_id = g_bus_own_name_on_connection (connection, CSD_POWER_DBUS_INTERFACE, G_BUS_NAME_OWNER_FLAGS_NONE, power_name_acquired, NULL, manager, NULL); manager->priv->s_name_id = g_bus_own_name_on_connection (connection, CSD_POWER_DBUS_INTERFACE_SCREEN, G_BUS_NAME_OWNER_FLAGS_NONE, screen_name_acquired, NULL, manager, NULL); manager->priv->k_name_id = g_bus_own_name_on_connection (connection, CSD_POWER_DBUS_INTERFACE_KEYBOARD, G_BUS_NAME_OWNER_FLAGS_NONE, keyboard_name_acquired, NULL, manager, NULL); } static void register_manager_dbus (CsdPowerManager *manager) { manager->priv->bus_cancellable = g_cancellable_new (); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } CsdPowerManager * csd_power_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_POWER_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return CSD_POWER_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/power/csd-power-manager.h000066400000000000000000000046751356401377300247460ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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 __CSD_POWER_MANAGER_H #define __CSD_POWER_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_POWER_MANAGER (csd_power_manager_get_type ()) #define CSD_POWER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManager)) #define CSD_POWER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_POWER_MANAGER, CsdPowerManagerClass)) #define CSD_IS_POWER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_POWER_MANAGER)) #define CSD_IS_POWER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_POWER_MANAGER)) #define CSD_POWER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManagerClass)) #define CSD_POWER_MANAGER_ERROR (csd_power_manager_error_quark ()) typedef struct CsdPowerManagerPrivate CsdPowerManagerPrivate; typedef struct { GObject parent; CsdPowerManagerPrivate *priv; } CsdPowerManager; typedef struct { GObjectClass parent_class; } CsdPowerManagerClass; enum { CSD_POWER_MANAGER_ERROR_FAILED }; GType csd_power_manager_get_type (void); GQuark csd_power_manager_error_quark (void); CsdPowerManager * csd_power_manager_new (void); gboolean csd_power_manager_start (CsdPowerManager *manager, GError **error); void csd_power_manager_stop (CsdPowerManager *manager); G_END_DECLS #endif /* __CSD_POWER_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/power/gpm-common.c000066400000000000000000001206041356401377300234660ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "gpm-common.h" #define GPM_UP_TIME_PRECISION 5*60 #define GPM_UP_TEXT_MIN_TIME 120 /** * Return value: The time string, e.g. "2 hours 3 minutes" **/ gchar * gpm_get_timestring (guint time_secs) { char* timestring = NULL; gint hours; gint minutes; /* Add 0.5 to do rounding */ minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); if (minutes == 0) { timestring = g_strdup (_("Unknown time")); return timestring; } if (minutes < 60) { timestring = g_strdup_printf (ngettext ("%i minute", "%i minutes", minutes), minutes); return timestring; } hours = minutes / 60; minutes = minutes % 60; if (minutes == 0) timestring = g_strdup_printf (ngettext ( "%i hour", "%i hours", hours), hours); else /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" * Swap order with "%2$s %2$i %1$s %1$i if needed */ timestring = g_strdup_printf (_("%i %s %i %s"), hours, ngettext ("hour", "hours", hours), minutes, ngettext ("minute", "minutes", minutes)); return timestring; } static const gchar * gpm_upower_get_device_icon_index (UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 10) return "000"; else if (percentage < 30) return "020"; else if (percentage < 50) return "040"; else if (percentage < 70) return "060"; else if (percentage < 90) return "080"; return "100"; } static const gchar * gpm_upower_get_device_icon_suffix (UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 10) return "caution"; else if (percentage < 30) return "low"; else if (percentage < 60) return "good"; return "full"; } GIcon * gpm_upower_get_device_icon (UpDevice *device, gboolean use_symbolic) { GString *filename; gchar **iconnames; const gchar *kind_str; const gchar *suffix_str; const gchar *index_str; UpDeviceKind kind; UpDeviceState state; gboolean is_present; gdouble percentage; GIcon *icon = NULL; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, NULL); /* get correct icon prefix */ filename = g_string_new (NULL); /* get the icon from some simple rules */ if (kind == UP_DEVICE_KIND_LINE_POWER) { if (use_symbolic) g_string_append (filename, "ac-adapter-symbolic;"); g_string_append (filename, "ac-adapter;"); } else if (kind == UP_DEVICE_KIND_MONITOR) { if (use_symbolic) g_string_append (filename, "gpm-monitor-symbolic;"); g_string_append (filename, "gpm-monitor;"); } else { kind_str = up_device_kind_to_string (kind); if (!is_present) { if (use_symbolic) g_string_append (filename, "battery-missing-symbolic;"); g_string_append_printf (filename, "gpm-%s-missing;", kind_str); g_string_append_printf (filename, "gpm-%s-000;", kind_str); g_string_append (filename, "battery-missing;"); } else { switch (state) { case UP_DEVICE_STATE_EMPTY: if (use_symbolic) g_string_append (filename, "battery-empty-symbolic;"); g_string_append_printf (filename, "gpm-%s-empty;", kind_str); g_string_append_printf (filename, "gpm-%s-000;", kind_str); g_string_append (filename, "battery-empty;"); break; case UP_DEVICE_STATE_FULLY_CHARGED: if (use_symbolic) { g_string_append (filename, "battery-full-charged-symbolic;"); g_string_append (filename, "battery-full-charging-symbolic;"); } g_string_append_printf (filename, "gpm-%s-full;", kind_str); g_string_append_printf (filename, "gpm-%s-100;", kind_str); g_string_append (filename, "battery-full-charged;"); g_string_append (filename, "battery-full-charging;"); break; case UP_DEVICE_STATE_CHARGING: case UP_DEVICE_STATE_PENDING_CHARGE: suffix_str = gpm_upower_get_device_icon_suffix (device); index_str = gpm_upower_get_device_icon_index (device); if (use_symbolic) g_string_append_printf (filename, "battery-%s-charging-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s-charging;", kind_str, index_str); g_string_append_printf (filename, "battery-%s-charging;", suffix_str); break; case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: suffix_str = gpm_upower_get_device_icon_suffix (device); index_str = gpm_upower_get_device_icon_index (device); if (use_symbolic) g_string_append_printf (filename, "battery-%s-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s;", kind_str, index_str); g_string_append_printf (filename, "battery-%s;", suffix_str); break; case UP_DEVICE_STATE_UNKNOWN: case UP_DEVICE_STATE_LAST: default: if (use_symbolic) g_string_append (filename, "battery-missing-symbolic;"); g_string_append (filename, "gpm-battery-missing;"); g_string_append (filename, "battery-missing;"); } } } /* nothing matched */ if (filename->len == 0) { g_warning ("nothing matched, falling back to default icon"); g_string_append (filename, "dialog-warning;"); } g_debug ("got filename: %s", filename->str); iconnames = g_strsplit (filename->str, ";", -1); icon = g_themed_icon_new_from_names (iconnames, -1); g_strfreev (iconnames); g_string_free (filename, TRUE); return icon; } /** * gpm_precision_round_down: * @value: The input value * @smallest: The smallest increment allowed * * 101, 10 100 * 95, 10 90 * 0, 10 0 * 112, 10 110 * 100, 10 100 **/ static gint gpm_precision_round_down (gfloat value, gint smallest) { gfloat division; if (fabs (value) < 0.01) return 0; if (smallest == 0) { g_warning ("divisor zero"); return 0; } division = (gfloat) value / (gfloat) smallest; division = floorf (division); division *= smallest; return (gint) division; } gchar * gpm_upower_get_device_summary (UpDevice *device) { const gchar *kind_desc = NULL; const gchar *device_desc = NULL; GString *description; guint time_to_full_round; guint time_to_empty_round; gchar *time_to_full_str = NULL; gchar *time_to_empty_str = NULL; UpDeviceKind kind; UpDeviceState state; gdouble percentage; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, NULL); description = g_string_new (NULL); kind_desc = gpm_device_kind_to_localised_string (kind, 1); device_desc = gpm_device_to_localised_string (device); /* not installed */ if (!is_present) { g_string_append (description, device_desc); goto out; } /* don't display all the extra stuff for keyboards and mice */ if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_PDA) { g_string_append (description, kind_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } /* we care if we are on AC */ if (kind == UP_DEVICE_KIND_PHONE) { if (state == UP_DEVICE_STATE_CHARGING || !(state == UP_DEVICE_STATE_DISCHARGING)) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } g_string_append (description, kind_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } /* precalculate so we don't get Unknown time remaining */ time_to_full_round = gpm_precision_round_down (time_to_full, GPM_UP_TIME_PRECISION); time_to_empty_round = gpm_precision_round_down (time_to_empty, GPM_UP_TIME_PRECISION); /* we always display "Laptop battery 16 minutes remaining" as we need to clarify what device we are referring to */ if (state == UP_DEVICE_STATE_FULLY_CHARGED) { g_string_append (description, device_desc); if (kind == UP_DEVICE_KIND_BATTERY && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = gpm_get_timestring (time_to_empty_round); g_string_append (description, " - "); /* TRANSLATORS: The laptop battery is charged, and we know a time. * The parameter is the time, e.g. 7 hours 6 minutes */ g_string_append_printf (description, _("provides %s laptop runtime"), time_to_empty_str); } goto out; } if (state == UP_DEVICE_STATE_DISCHARGING) { if (time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = gpm_get_timestring (time_to_empty_round); /* TRANSLATORS: the device is discharging, and we have a time remaining * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. 7 hours 6 minutes */ g_string_append_printf (description, _("%s %s remaining"), kind_desc, time_to_empty_str); g_string_append_printf (description, " (%.0f%%)", percentage); } else { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); } goto out; } if (state == UP_DEVICE_STATE_CHARGING) { if (time_to_full_round > GPM_UP_TEXT_MIN_TIME && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { /* display both discharge and charge time */ time_to_full_str = gpm_get_timestring (time_to_full_round); time_to_empty_str = gpm_get_timestring (time_to_empty_round); /* TRANSLATORS: device is charging, and we have a time to full and a percentage * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("%s %s until charged"), kind_desc, time_to_full_str); g_string_append_printf (description, " (%.0f%%)", percentage); g_string_append (description, " - "); /* TRANSLATORS: the device is charging, and we have a time to full and empty. * The parameter is a time string, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("provides %s battery runtime"), time_to_empty_str); } else if (time_to_full_round > GPM_UP_TEXT_MIN_TIME) { /* display only charge time */ time_to_full_str = gpm_get_timestring (time_to_full_round); /* TRANSLATORS: device is charging, and we have a time to full and a percentage. * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("%s %s until charged"), kind_desc, time_to_full_str); g_string_append_printf (description, " (%.0f%%)", percentage); } else { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); } goto out; } if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } if (state == UP_DEVICE_STATE_PENDING_CHARGE) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } if (state == UP_DEVICE_STATE_EMPTY) { g_string_append (description, device_desc); goto out; } /* fallback */ g_warning ("in an undefined state we are not charging or " "discharging and the batteries are also not charged"); g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); out: g_free (time_to_full_str); g_free (time_to_empty_str); return g_string_free (description, FALSE); } gchar * gpm_upower_get_device_description (UpDevice *device) { GString *details; const gchar *text; gchar *time_str; UpDeviceKind kind; UpDeviceState state; UpDeviceTechnology technology; gdouble percentage; gdouble capacity; gdouble energy; gdouble energy_full; gdouble energy_full_design; gdouble energy_rate; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; gchar *vendor = NULL; gchar *serial = NULL; gchar *model = NULL; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, "technology", &technology, "capacity", &capacity, "energy", &energy, "energy-full", &energy_full, "energy-full-design", &energy_full_design, "energy-rate", &energy_rate, "vendor", &vendor, "serial", &serial, "model", &model, NULL); details = g_string_new (""); text = gpm_device_kind_to_localised_string (kind, 1); /* TRANSLATORS: the type of data, e.g. Laptop battery */ g_string_append_printf (details, "%s %s\n", _("Product:"), text); if (!is_present) { /* TRANSLATORS: device is missing */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Missing")); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: device is charged */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charged")); } else if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: device is charging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charging")); } else if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: device is discharging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Discharging")); } if (percentage >= 0) { /* TRANSLATORS: percentage */ g_string_append_printf (details, "%s %.1f%%\n", _("Percentage charge:"), percentage); } if (vendor) { /* TRANSLATORS: manufacturer */ g_string_append_printf (details, "%s %s\n", _("Vendor:"), vendor); } if (technology != UP_DEVICE_TECHNOLOGY_UNKNOWN) { text = gpm_device_technology_to_localised_string (technology); /* TRANSLATORS: how the battery is made, e.g. Lithium Ion */ g_string_append_printf (details, "%s %s\n", _("Technology:"), text); } if (serial) { /* TRANSLATORS: serial number of the battery */ g_string_append_printf (details, "%s %s\n", _("Serial number:"), serial); } if (model) { /* TRANSLATORS: model number of the battery */ g_string_append_printf (details, "%s %s\n", _("Model:"), model); } if (time_to_full > 0) { time_str = gpm_get_timestring (time_to_full); /* TRANSLATORS: time to fully charged */ g_string_append_printf (details, "%s %s\n", _("Charge time:"), time_str); g_free (time_str); } if (time_to_empty > 0) { time_str = gpm_get_timestring (time_to_empty); /* TRANSLATORS: time to empty */ g_string_append_printf (details, "%s %s\n", _("Discharge time:"), time_str); g_free (time_str); } if (capacity > 0) { const gchar *condition; if (capacity > 99) { /* TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity */ condition = _("Excellent"); } else if (capacity > 90) { condition = _("Good"); } else if (capacity > 70) { condition = _("Fair"); } else { condition = _("Poor"); } /* TRANSLATORS: %.1f is a percentage and %s the condition (Excellent, Good, ...) */ g_string_append_printf (details, "%s %.1f%% (%s)\n", _("Capacity:"), capacity, condition); } if (kind == UP_DEVICE_KIND_BATTERY) { if (energy > 0) { /* TRANSLATORS: current charge */ g_string_append_printf (details, "%s %.1f Wh\n", _("Current charge:"), energy); } if (energy_full > 0 && energy_full_design != energy_full) { /* TRANSLATORS: last full is the charge the battery was seen to charge to */ g_string_append_printf (details, "%s %.1f Wh\n", _("Last full charge:"), energy_full); } if (energy_full_design > 0) { /* Translators: */ /* TRANSLATORS: Design charge is the amount of charge the battery is designed to have when brand new */ g_string_append_printf (details, "%s %.1f Wh\n", _("Design charge:"), energy_full_design); } if (energy_rate > 0) { /* TRANSLATORS: the charge or discharge rate */ g_string_append_printf (details, "%s %.1f W\n", _("Charge rate:"), energy_rate); } } if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD) { if (energy > 0) { /* TRANSLATORS: the current charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Current charge:"), energy); } if (energy_full_design > 0) { /* TRANSLATORS: the design charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Design charge:"), energy_full_design); } } /* remove the last \n */ g_string_truncate (details, details->len-1); g_free (vendor); g_free (serial); g_free (model); return g_string_free (details, FALSE); } const gchar * gpm_device_kind_to_localised_string (UpDeviceKind kind, guint number) { const gchar *text = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: /* TRANSLATORS: system power cord */ text = ngettext ("AC adapter", "AC adapters", number); break; case UP_DEVICE_KIND_BATTERY: /* TRANSLATORS: laptop primary battery */ text = ngettext ("Laptop battery", "Laptop batteries", number); break; case UP_DEVICE_KIND_UPS: /* TRANSLATORS: battery-backed AC power source */ text = ngettext ("UPS", "UPSs", number); break; case UP_DEVICE_KIND_MONITOR: /* TRANSLATORS: a monitor is a device to measure voltage and current */ text = ngettext ("Monitor", "Monitors", number); break; case UP_DEVICE_KIND_MOUSE: /* TRANSLATORS: wireless mice with internal batteries */ text = ngettext ("Mouse", "Mice", number); break; case UP_DEVICE_KIND_KEYBOARD: /* TRANSLATORS: wireless keyboard with internal battery */ text = ngettext ("Keyboard", "Keyboards", number); break; case UP_DEVICE_KIND_PDA: /* TRANSLATORS: portable device */ text = ngettext ("PDA", "PDAs", number); break; case UP_DEVICE_KIND_PHONE: /* TRANSLATORS: cell phone (mobile...) */ text = ngettext ("Cell phone", "Cell phones", number); break; case UP_DEVICE_KIND_MEDIA_PLAYER: /* TRANSLATORS: media player, mp3 etc */ text = ngettext ("Media player", "Media players", number); break; case UP_DEVICE_KIND_TABLET: /* TRANSLATORS: tablet device */ text = ngettext ("Tablet", "Tablets", number); break; case UP_DEVICE_KIND_COMPUTER: /* TRANSLATORS: tablet device */ text = ngettext ("Computer", "Computers", number); break; #if UP_CHECK_VERSION(0,99,6) case UP_DEVICE_KIND_GAMING_INPUT: /* TRANSLATORS: gaming peripherals */ text = ngettext ("Game controller", "Game controllers", number); break; #endif case UP_DEVICE_KIND_UNKNOWN: text = ngettext ("Unknown device", "Unknown devices", number); break; case UP_DEVICE_KIND_LAST: default: g_warning ("enum unrecognised: %i", kind); text = up_device_kind_to_string (kind); } return text; } const gchar * gpm_device_kind_to_icon (UpDeviceKind kind) { const gchar *icon = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: icon = "ac-adapter"; break; case UP_DEVICE_KIND_BATTERY: icon = "battery"; break; case UP_DEVICE_KIND_UPS: icon = "network-wired"; break; case UP_DEVICE_KIND_MONITOR: icon = "application-certificate"; break; case UP_DEVICE_KIND_MOUSE: icon = "input-mouse"; break; case UP_DEVICE_KIND_KEYBOARD: icon = "input-keyboard"; break; case UP_DEVICE_KIND_PDA: icon = "pda"; break; case UP_DEVICE_KIND_PHONE: icon = "phone"; break; case UP_DEVICE_KIND_MEDIA_PLAYER: icon = "multimedia-player"; break; case UP_DEVICE_KIND_TABLET: icon = "input-tablet"; break; case UP_DEVICE_KIND_COMPUTER: icon = "computer-apple-ipad"; break; #if UP_CHECK_VERSION(0,99,6) case UP_DEVICE_KIND_GAMING_INPUT: icon = "input-gaming"; break; #endif case UP_DEVICE_KIND_UNKNOWN: icon = "gtk-help"; break; case UP_DEVICE_KIND_LAST: default: g_warning ("enum unrecognised: %i", kind); icon = "gtk-help"; } return icon; } const gchar * gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum) { const gchar *technology = NULL; switch (technology_enum) { case UP_DEVICE_TECHNOLOGY_LITHIUM_ION: /* TRANSLATORS: battery technology */ technology = _("Lithium Ion"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER: /* TRANSLATORS: battery technology */ technology = _("Lithium Polymer"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE: /* TRANSLATORS: battery technology */ technology = _("Lithium Iron Phosphate"); break; case UP_DEVICE_TECHNOLOGY_LEAD_ACID: /* TRANSLATORS: battery technology */ technology = _("Lead acid"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM: /* TRANSLATORS: battery technology */ technology = _("Nickel Cadmium"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE: /* TRANSLATORS: battery technology */ technology = _("Nickel metal hydride"); break; case UP_DEVICE_TECHNOLOGY_UNKNOWN: /* TRANSLATORS: battery technology */ technology = _("Unknown technology"); break; case UP_DEVICE_TECHNOLOGY_LAST: default: g_assert_not_reached (); break; } return technology; } const gchar * gpm_device_state_to_localised_string (UpDeviceState state) { const gchar *state_string = NULL; switch (state) { case UP_DEVICE_STATE_CHARGING: /* TRANSLATORS: battery state */ state_string = _("Charging"); break; case UP_DEVICE_STATE_DISCHARGING: /* TRANSLATORS: battery state */ state_string = _("Discharging"); break; case UP_DEVICE_STATE_EMPTY: /* TRANSLATORS: battery state */ state_string = _("Empty"); break; case UP_DEVICE_STATE_FULLY_CHARGED: /* TRANSLATORS: battery state */ state_string = _("Charged"); break; case UP_DEVICE_STATE_PENDING_CHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to charge"); break; case UP_DEVICE_STATE_PENDING_DISCHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to discharge"); break; case UP_DEVICE_STATE_UNKNOWN: /* TRANSLATORS: battery state */ state_string = _("Unknown"); break; case UP_DEVICE_STATE_LAST: default: g_assert_not_reached (); break; } return state_string; } const gchar * gpm_device_to_localised_string (UpDevice *device) { UpDeviceState state; UpDeviceKind kind; gboolean present; /* get device parameters */ g_object_get (device, "is-present", &present, "kind", &kind, "state", &state, NULL); /* laptop battery */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!present) { /* TRANSLATORS: device not present */ return _("Laptop battery not present"); } if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Laptop battery is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Laptop battery is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Laptop battery is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Laptop battery is charged"); } if (state == UP_DEVICE_STATE_PENDING_CHARGE) { /* TRANSLATORS: battery state */ return _("Laptop battery is waiting to charge"); } if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { /* TRANSLATORS: battery state */ return _("Laptop battery is waiting to discharge"); } } /* UPS */ if (kind == UP_DEVICE_KIND_UPS) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("UPS is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("UPS is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("UPS is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("UPS is charged"); } } /* mouse */ if (kind == UP_DEVICE_KIND_MOUSE) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Mouse is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Mouse is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Mouse is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Mouse is charged"); } } /* keyboard */ if (kind == UP_DEVICE_KIND_KEYBOARD) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Keyboard is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Keyboard is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Keyboard is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Keyboard is charged"); } } /* PDA */ if (kind == UP_DEVICE_KIND_PDA) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("PDA is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("PDA is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("PDA is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("PDA is charged"); } } /* phone */ if (kind == UP_DEVICE_KIND_PHONE) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Cell phone is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Cell phone is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Cell phone is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Cell phone is charged"); } } /* media player */ if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Media player is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Media player is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Media player is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Media player is charged"); } } /* tablet */ if (kind == UP_DEVICE_KIND_TABLET) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Tablet is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Tablet is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Tablet is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Tablet is charged"); } } /* computer */ if (kind == UP_DEVICE_KIND_COMPUTER) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Computer is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Computer is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Computer is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Computer is charged"); } } #if UP_CHECK_VERSION(0,99,6) /* computer */ if (kind == UP_DEVICE_KIND_GAMING_INPUT) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Game controller is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Game controller is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Game controller is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Game controller is charged"); } } #endif return gpm_device_kind_to_localised_string (kind, 1); } cinnamon-settings-daemon-4.4.0/plugins/power/gpm-common.h000066400000000000000000000037171356401377300235000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPMCOMMON_H #define __GPMCOMMON_H #include #include G_BEGIN_DECLS gchar *gpm_get_timestring (guint time); const gchar *gpm_device_to_localised_string (UpDevice *device); const gchar *gpm_device_kind_to_localised_string (UpDeviceKind kind, guint number); const gchar *gpm_device_kind_to_icon (UpDeviceKind kind); const gchar *gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum); const gchar *gpm_device_state_to_localised_string (UpDeviceState state); GIcon *gpm_upower_get_device_icon (UpDevice *device, gboolean use_symbolic); gchar *gpm_upower_get_device_summary (UpDevice *device); gchar *gpm_upower_get_device_description (UpDevice *device); G_END_DECLS #endif /* __GPMCOMMON_H */ cinnamon-settings-daemon-4.4.0/plugins/power/gpm-idletime.c000066400000000000000000000374631356401377300240040ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "gpm-idletime.h" static void gpm_idletime_finalize (GObject *object); #define GPM_IDLETIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_IDLETIME_TYPE, GpmIdletimePrivate)) struct GpmIdletimePrivate { gint sync_event; gboolean reset_set; XSyncCounter idle_counter; GPtrArray *array; Display *dpy; }; typedef struct { guint id; XSyncValue timeout; XSyncAlarm xalarm; GpmIdletime *idletime; } GpmIdletimeAlarm; enum { SIGNAL_ALARM_EXPIRED, SIGNAL_RESET, LAST_SIGNAL }; typedef enum { GPM_IDLETIME_ALARM_TYPE_POSITIVE, GPM_IDLETIME_ALARM_TYPE_NEGATIVE, GPM_IDLETIME_ALARM_TYPE_DISABLED } GpmIdletimeAlarmType; static guint signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GpmIdletime, gpm_idletime, G_TYPE_OBJECT) static gint64 gpm_idletime_xsyncvalue_to_int64 (XSyncValue value) { return ((guint64) XSyncValueHigh32 (value)) << 32 | (guint64) XSyncValueLow32 (value); } /* gets the IDLETIME counter value, or 0 for invalid */ gint64 gpm_idletime_get_time (GpmIdletime *idletime) { XSyncValue value; /* we don't have IDLETIME support */ if (!idletime->priv->idle_counter) return 0; /* NX explodes if you query the counter */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); XSyncQueryCounter (idletime->priv->dpy, idletime->priv->idle_counter, &value); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) return 0; return gpm_idletime_xsyncvalue_to_int64 (value); } static void gpm_idletime_xsync_alarm_set (GpmIdletime *idletime, GpmIdletimeAlarm *alarm_item, GpmIdletimeAlarmType alarm_type) { XSyncAlarmAttributes attr; XSyncValue delta; unsigned int flags; XSyncTestType test; /* just remove it */ if (alarm_type == GPM_IDLETIME_ALARM_TYPE_DISABLED) { if (alarm_item->xalarm) { XSyncDestroyAlarm (idletime->priv->dpy, alarm_item->xalarm); alarm_item->xalarm = None; } return; } /* which way do we do the test? */ if (alarm_type == GPM_IDLETIME_ALARM_TYPE_POSITIVE) test = XSyncPositiveTransition; else test = XSyncNegativeTransition; XSyncIntToValue (&delta, 0); attr.trigger.counter = idletime->priv->idle_counter; attr.trigger.value_type = XSyncAbsolute; attr.trigger.test_type = test; attr.trigger.wait_value = alarm_item->timeout; attr.delta = delta; flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta; if (alarm_item->xalarm) { XSyncChangeAlarm (idletime->priv->dpy, alarm_item->xalarm, flags, &attr); } else { alarm_item->xalarm = XSyncCreateAlarm (idletime->priv->dpy, flags, &attr); } } void gpm_idletime_alarm_reset_all (GpmIdletime *idletime) { guint i; GpmIdletimeAlarm *alarm_item; g_return_if_fail (GPM_IS_IDLETIME (idletime)); if (!idletime->priv->reset_set) return; /* reset all the alarms (except the reset alarm) to their timeouts */ for (i=1; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_POSITIVE); } /* set the reset alarm to be disabled */ alarm_item = g_ptr_array_index (idletime->priv->array, 0); gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_DISABLED); /* emit signal so say we've reset all timers */ g_signal_emit (idletime, signals [SIGNAL_RESET], 0); /* we need to be reset again on the next event */ idletime->priv->reset_set = FALSE; } static GpmIdletimeAlarm * gpm_idletime_alarm_find_id (GpmIdletime *idletime, guint id) { guint i; GpmIdletimeAlarm *alarm_item; for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); if (alarm_item->id == id) return alarm_item; } return NULL; } static void gpm_idletime_set_reset_alarm (GpmIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { GpmIdletimeAlarm *alarm_item; int overflow; XSyncValue add; gint64 current, reset_threshold; alarm_item = gpm_idletime_alarm_find_id (idletime, 0); if (!idletime->priv->reset_set) { /* don't match on the current value because * XSyncNegativeComparison means less or equal. */ XSyncIntToValue (&add, -1); XSyncValueAdd (&alarm_item->timeout, alarm_event->counter_value, add, &overflow); /* set the reset alarm to fire the next time * idletime->priv->idle_counter < the current counter value */ gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_NEGATIVE); /* don't try to set this again if multiple timers are * going off in sequence */ idletime->priv->reset_set = TRUE; current = gpm_idletime_get_time (idletime); reset_threshold = gpm_idletime_xsyncvalue_to_int64 (alarm_item->timeout); if (current < reset_threshold) { /* We've missed the alarm already */ gpm_idletime_alarm_reset_all (idletime); } } } static GpmIdletimeAlarm * gpm_idletime_alarm_find_event (GpmIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { guint i; GpmIdletimeAlarm *alarm_item; for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); if (alarm_event->alarm == alarm_item->xalarm) return alarm_item; } return NULL; } static GdkFilterReturn gpm_idletime_event_filter_cb (GdkXEvent *gdkxevent, GdkEvent *event, gpointer data) { GpmIdletimeAlarm *alarm_item; XEvent *xevent = (XEvent *) gdkxevent; GpmIdletime *idletime = (GpmIdletime *) data; XSyncAlarmNotifyEvent *alarm_event; /* no point continuing */ if (xevent->type != idletime->priv->sync_event + XSyncAlarmNotify) return GDK_FILTER_CONTINUE; alarm_event = (XSyncAlarmNotifyEvent *) xevent; /* did we match one of our alarms? */ alarm_item = gpm_idletime_alarm_find_event (idletime, alarm_event); if (alarm_item == NULL) return GDK_FILTER_CONTINUE; /* are we the reset alarm? */ if (alarm_item->id == 0) { gpm_idletime_alarm_reset_all (idletime); goto out; } /* emit */ g_signal_emit (alarm_item->idletime, signals[SIGNAL_ALARM_EXPIRED], 0, alarm_item->id); /* we need the first alarm to go off to set the reset alarm */ gpm_idletime_set_reset_alarm (idletime, alarm_event); out: /* don't propagate */ return GDK_FILTER_REMOVE; } static GpmIdletimeAlarm * gpm_idletime_alarm_new (GpmIdletime *idletime, guint id) { GpmIdletimeAlarm *alarm_item; /* create a new alarm */ alarm_item = g_new0 (GpmIdletimeAlarm, 1); /* set the default values */ alarm_item->id = id; alarm_item->xalarm = None; alarm_item->idletime = g_object_ref (idletime); return alarm_item; } gboolean gpm_idletime_alarm_set (GpmIdletime *idletime, guint id, guint timeout) { GpmIdletimeAlarm *alarm_item; g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (id != 0, FALSE); if (timeout == 0) { gpm_idletime_alarm_remove (idletime, id); return FALSE; } /* see if we already created an alarm with this ID */ alarm_item = gpm_idletime_alarm_find_id (idletime, id); if (alarm_item == NULL) { /* create a new alarm */ alarm_item = gpm_idletime_alarm_new (idletime, id); g_ptr_array_add (idletime->priv->array, alarm_item); } /* set the timeout */ XSyncIntToValue (&alarm_item->timeout, (gint)timeout); /* set, and start the timer */ gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_POSITIVE); return TRUE; } static gboolean gpm_idletime_alarm_free (GpmIdletime *idletime, GpmIdletimeAlarm *alarm_item) { g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (alarm_item != NULL, FALSE); if (alarm_item->xalarm) { XSyncDestroyAlarm (idletime->priv->dpy, alarm_item->xalarm); } g_object_unref (alarm_item->idletime); g_free (alarm_item); g_ptr_array_remove (idletime->priv->array, alarm_item); return TRUE; } gboolean gpm_idletime_alarm_remove (GpmIdletime *idletime, guint id) { GpmIdletimeAlarm *alarm_item; g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); alarm_item = gpm_idletime_alarm_find_id (idletime, id); if (alarm_item == NULL) return FALSE; gpm_idletime_alarm_free (idletime, alarm_item); return TRUE; } static void gpm_idletime_class_init (GpmIdletimeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gpm_idletime_finalize; g_type_class_add_private (klass, sizeof (GpmIdletimePrivate)); signals [SIGNAL_ALARM_EXPIRED] = g_signal_new ("alarm-expired", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmIdletimeClass, alarm_expired), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [SIGNAL_RESET] = g_signal_new ("reset", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmIdletimeClass, reset), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void gpm_idletime_init (GpmIdletime *idletime) { int sync_error; int ncounters; XSyncSystemCounter *counters; GpmIdletimeAlarm *alarm_item; gint major, minor; guint i; idletime->priv = GPM_IDLETIME_GET_PRIVATE (idletime); idletime->priv->array = g_ptr_array_new (); idletime->priv->reset_set = FALSE; idletime->priv->idle_counter = None; idletime->priv->sync_event = 0; idletime->priv->dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default()); /* get the sync event */ if (!XSyncQueryExtension (idletime->priv->dpy, &idletime->priv->sync_event, &sync_error)) { g_warning ("No Sync extension."); return; } /* check XSync is compatible with the server version */ if (!XSyncInitialize (idletime->priv->dpy, &major, &minor)) { g_warning ("Sync extension not compatible."); return; } counters = XSyncListSystemCounters (idletime->priv->dpy, &ncounters); for (i = 0; i < ncounters && !idletime->priv->idle_counter; i++) { if (strcmp(counters[i].name, "IDLETIME") == 0) idletime->priv->idle_counter = counters[i].counter; } XSyncFreeSystemCounterList (counters); /* arh. we don't have IDLETIME support */ if (!idletime->priv->idle_counter) { g_warning ("No idle counter"); return; } /* catch the timer alarm */ gdk_window_add_filter (NULL, gpm_idletime_event_filter_cb, idletime); /* create a reset alarm */ alarm_item = gpm_idletime_alarm_new (idletime, 0); g_ptr_array_add (idletime->priv->array, alarm_item); } static void gpm_idletime_finalize (GObject *object) { guint i; GpmIdletime *idletime; GpmIdletimeAlarm *alarm_item; g_return_if_fail (object != NULL); g_return_if_fail (GPM_IS_IDLETIME (object)); idletime = GPM_IDLETIME (object); idletime->priv = GPM_IDLETIME_GET_PRIVATE (idletime); /* remove filter */ gdk_window_remove_filter (NULL, gpm_idletime_event_filter_cb, idletime); /* free all counters, including reset counter */ for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); gpm_idletime_alarm_free (idletime, alarm_item); } g_ptr_array_free (idletime->priv->array, TRUE); G_OBJECT_CLASS (gpm_idletime_parent_class)->finalize (object); } GpmIdletime * gpm_idletime_new (void) { return g_object_new (GPM_IDLETIME_TYPE, NULL); } cinnamon-settings-daemon-4.4.0/plugins/power/gpm-idletime.h000066400000000000000000000054401356401377300237770ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPM_IDLETIME_H #define __GPM_IDLETIME_H #include G_BEGIN_DECLS #define GPM_IDLETIME_TYPE (gpm_idletime_get_type ()) #define GPM_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_IDLETIME_TYPE, GpmIdletime)) #define GPM_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_IDLETIME_TYPE, GpmIdletimeClass)) #define GPM_IS_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_IDLETIME_TYPE)) #define GPM_IS_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_IDLETIME_TYPE)) #define GPM_IDLETIME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_IDLETIME_TYPE, GpmIdletimeClass)) typedef struct GpmIdletimePrivate GpmIdletimePrivate; typedef struct { GObject parent; GpmIdletimePrivate *priv; } GpmIdletime; typedef struct { GObjectClass parent_class; void (* alarm_expired) (GpmIdletime *idletime, guint timer_id); void (* reset) (GpmIdletime *idletime); } GpmIdletimeClass; GType gpm_idletime_get_type (void); GpmIdletime *gpm_idletime_new (void); void gpm_idletime_alarm_reset_all (GpmIdletime *idletime); gboolean gpm_idletime_alarm_set (GpmIdletime *idletime, guint alarm_id, guint timeout); gboolean gpm_idletime_alarm_remove (GpmIdletime *idletime, guint alarm_id); gint64 gpm_idletime_get_time (GpmIdletime *idletime); G_END_DECLS #endif /* __GPM_IDLETIME_H */ cinnamon-settings-daemon-4.4.0/plugins/power/gpm-phone.c000066400000000000000000000263321356401377300233120ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "gpm-phone.h" static void gpm_phone_finalize (GObject *object); #define GPM_PHONE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_PHONE, GpmPhonePrivate)) struct GpmPhonePrivate { GDBusProxy *proxy; GDBusConnection *connection; guint watch_id; gboolean present; guint percentage; gboolean onac; }; enum { DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REFRESH, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static gpointer gpm_phone_object = NULL; G_DEFINE_TYPE (GpmPhone, gpm_phone, G_TYPE_OBJECT) gboolean gpm_phone_coldplug (GpmPhone *phone) { GError *error = NULL; GVariant *reply; gboolean ret; g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); if (phone->priv->proxy == NULL) return FALSE; reply = g_dbus_proxy_call_sync (phone->priv->proxy, "Coldplug", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error != NULL) { g_warning ("DEBUG: ERROR: %s", error->message); g_error_free (error); } if (reply != NULL) { ret = TRUE; g_variant_unref (reply); } else ret = FALSE; return ret; } gboolean gpm_phone_get_present (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->present; } guint gpm_phone_get_percentage (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); return phone->priv->percentage; } gboolean gpm_phone_get_on_ac (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->onac; } guint gpm_phone_get_num_batteries (GpmPhone *phone) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); if (phone->priv->present) return 1; return 0; } static void gpm_phone_battery_state_changed (GDBusProxy *proxy, guint idx, guint percentage, gboolean on_ac, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); g_debug ("got BatteryStateChanged %i = %i (%i)", idx, percentage, on_ac); phone->priv->percentage = percentage; phone->priv->onac = on_ac; phone->priv->present = TRUE; g_debug ("emitting device-refresh : (%i)", idx); g_signal_emit (phone, signals [DEVICE_REFRESH], 0, idx); } static void gpm_phone_num_batteries_changed (GDBusProxy *proxy, guint number, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); g_debug ("got NumberBatteriesChanged %i", number); if (number > 1) { g_warning ("number not 0 or 1, not valid!"); return; } /* are we removed? */ if (number == 0) { phone->priv->present = FALSE; phone->priv->percentage = 0; phone->priv->onac = FALSE; g_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); return; } if (phone->priv->present) { g_warning ("duplicate NumberBatteriesChanged with no change"); return; } /* reset to defaults until we get BatteryStateChanged */ phone->priv->present = TRUE; phone->priv->percentage = 0; phone->priv->onac = FALSE; g_debug ("emitting device-added : (%i)", 0); g_signal_emit (phone, signals [DEVICE_ADDED], 0, 0); } static void gpm_phone_generic_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { GpmPhone *self = GPM_PHONE (user_data); if (!g_strcmp0 (signal_name, "BatteryStateChanged")) { guint idx, percentage; gboolean on_ac; g_variant_get (parameters, "(uub)", &idx, &percentage, &on_ac); gpm_phone_battery_state_changed (proxy, idx, percentage, on_ac, self); return; } if (!g_strcmp0 (signal_name, "NumberBatteriesChanged")) { guint number; g_variant_get (parameters, "(u)", &number); gpm_phone_num_batteries_changed (proxy, number, self); return; } /* not a signal we're interested in */ } static void gpm_phone_class_init (GpmPhoneClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gpm_phone_finalize; g_type_class_add_private (klass, sizeof (GpmPhonePrivate)); signals [DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REFRESH] = g_signal_new ("device-refresh", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_refresh), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } static void gpm_phone_service_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, GpmPhone *phone) { GError *error = NULL; g_return_if_fail (GPM_IS_PHONE (phone)); if (phone->priv->connection == NULL) { g_debug ("get connection"); g_clear_error (&error); phone->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (phone->priv->connection == NULL) { g_warning ("Could not connect to DBUS daemon: %s", error->message); g_error_free (error); phone->priv->connection = NULL; return; } } if (phone->priv->proxy == NULL) { g_debug ("get proxy"); g_clear_error (&error); phone->priv->proxy = g_dbus_proxy_new_sync (phone->priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CINNAMON_PHONE_MANAGER_DBUS_SERVICE, CINNAMON_PHONE_MANAGER_DBUS_PATH, CINNAMON_PHONE_MANAGER_DBUS_INTERFACE, NULL, &error); if (phone->priv->proxy == NULL) { g_warning ("Cannot connect, maybe the daemon is not running: %s", error->message); g_error_free (error); phone->priv->proxy = NULL; return; } g_signal_connect (phone->priv->proxy, "g-signal", G_CALLBACK(gpm_phone_generic_signal_cb), phone); } } static void gpm_phone_service_vanished_cb (GDBusConnection *connection, const gchar *name, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); if (phone->priv->proxy == NULL) return; g_debug ("removing proxy"); g_object_unref (phone->priv->proxy); phone->priv->proxy = NULL; if (phone->priv->present) { phone->priv->present = FALSE; phone->priv->percentage = 0; g_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); } } static void gpm_phone_init (GpmPhone *phone) { phone->priv = GPM_PHONE_GET_PRIVATE (phone); phone->priv->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, CINNAMON_PHONE_MANAGER_DBUS_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE, (GBusNameAppearedCallback) gpm_phone_service_appeared_cb, (GBusNameVanishedCallback) gpm_phone_service_vanished_cb, phone, NULL); } static void gpm_phone_finalize (GObject *object) { GpmPhone *phone; g_return_if_fail (GPM_IS_PHONE (object)); phone = GPM_PHONE (object); phone->priv = GPM_PHONE_GET_PRIVATE (phone); if (phone->priv->proxy != NULL) g_object_unref (phone->priv->proxy); g_bus_unwatch_name (phone->priv->watch_id); G_OBJECT_CLASS (gpm_phone_parent_class)->finalize (object); } GpmPhone * gpm_phone_new (void) { if (gpm_phone_object != NULL) { g_object_ref (gpm_phone_object); } else { gpm_phone_object = g_object_new (GPM_TYPE_PHONE, NULL); g_object_add_weak_pointer (gpm_phone_object, &gpm_phone_object); } return GPM_PHONE (gpm_phone_object); } cinnamon-settings-daemon-4.4.0/plugins/power/gpm-phone.h000066400000000000000000000062731356401377300233210ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPMPHONE_H #define __GPMPHONE_H #include G_BEGIN_DECLS #define GPM_TYPE_PHONE (gpm_phone_get_type ()) #define GPM_PHONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_PHONE, GpmPhone)) #define GPM_PHONE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_PHONE, GpmPhoneClass)) #define GPM_IS_PHONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_PHONE)) #define GPM_IS_PHONE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_PHONE)) #define GPM_PHONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_PHONE, GpmPhoneClass)) #define CINNAMON_PHONE_MANAGER_DBUS_SERVICE "org.cinnamon.phone" #define CINNAMON_PHONE_MANAGER_DBUS_PATH "/org/cinnamon/phone/Manager" #define CINNAMON_PHONE_MANAGER_DBUS_INTERFACE "org.cinnamon.phone.Manager" typedef struct GpmPhonePrivate GpmPhonePrivate; typedef struct { GObject parent; GpmPhonePrivate *priv; } GpmPhone; typedef struct { GObjectClass parent_class; void (* device_added) (GpmPhone *phone, guint idx); void (* device_removed) (GpmPhone *phone, guint idx); void (* device_refresh) (GpmPhone *phone, guint idx); } GpmPhoneClass; GType gpm_phone_get_type (void); GpmPhone *gpm_phone_new (void); gboolean gpm_phone_get_present (GpmPhone *phone, guint idx); guint gpm_phone_get_percentage (GpmPhone *phone, guint idx); gboolean gpm_phone_get_on_ac (GpmPhone *phone, guint idx); guint gpm_phone_get_num_batteries (GpmPhone *phone); gboolean gpm_phone_coldplug (GpmPhone *phone); G_END_DECLS #endif /* __GPMPHONE_H */ cinnamon-settings-daemon-4.4.0/plugins/power/main.c000066400000000000000000000010051356401377300223320ustar00rootroot00000000000000#define NEW csd_power_manager_new #define START csd_power_manager_start #define STOP csd_power_manager_stop #define MANAGER CsdPowerManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-power-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/power/org.cinnamon.SettingsDaemon.Power.Keyboard.xml000066400000000000000000000017331356401377300321410ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/plugins/power/org.cinnamon.SettingsDaemon.Power.Screen.xml000066400000000000000000000016071356401377300316200ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/plugins/power/org.cinnamon.SettingsDaemon.Power.xml000066400000000000000000000011671356401377300304030ustar00rootroot00000000000000 cinnamon-settings-daemon-4.4.0/plugins/power/org.cinnamon.settings-daemon.plugins.power.policy.in.in000066400000000000000000000022351356401377300340060ustar00rootroot00000000000000 Cinnamon Settings Daemon http://git.gnome.org/browse/cinnamon-settings-daemon battery <_description>Modify the laptop brightness <_message>Authentication is required to modify the laptop brightness no no yes @libexecdir@/csd-backlight-helper cinnamon-settings-daemon-4.4.0/plugins/print-notifications/000077500000000000000000000000001356401377300241155ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/print-notifications/Makefile.am000066400000000000000000000027331356401377300261560ustar00rootroot00000000000000plugin_name = print-notifications AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-printer csd_printer_SOURCES = \ csd-printer.c csd_printer_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CFLAGS) csd_printer_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(CUPS_LIBS) \ $(LIBNOTIFY_LIBS) libexec_PROGRAMS += csd-print-notifications csd_print_notifications_SOURCES = \ csd-print-notifications-manager.c \ csd-print-notifications-manager.h \ main.c csd_print_notifications_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_print_notifications_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_print_notifications_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(CUPS_LIBS) \ $(LIBNOTIFY_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-print-notifications.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-print-notifications.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-print-notifications.desktop.in000066400000000000000000000004031356401377300367350ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/print-notifications[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - print-notifications Exec=@libexecdir@/csd-print-notifications OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/print-notifications/csd-print-notifications-manager.c000066400000000000000000002164751356401377300324620ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Red Hat, 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 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-print-notifications-manager.h" #define CSD_PRINT_NOTIFICATIONS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER, CsdPrintNotificationsManagerPrivate)) #define CUPS_DBUS_NAME "org.cups.cupsd.Notifier" #define CUPS_DBUS_PATH "/org/cups/cupsd/Notifier" #define CUPS_DBUS_INTERFACE "org.cups.cupsd.Notifier" #define RENEW_INTERVAL 3500 #define SUBSCRIPTION_DURATION 3600 #define CONNECTING_TIMEOUT 60 #define REASON_TIMEOUT 15000 #define CUPS_CONNECTION_TEST_INTERVAL 300 #define CHECK_INTERVAL 60 /* secs */ #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5) #define HAVE_CUPS_1_6 1 #endif #ifndef HAVE_CUPS_1_6 #define ippGetStatusCode(ipp) ipp->request.status.status_code #define ippGetInteger(attr, element) attr->values[element].integer #define ippGetString(attr, element, language) attr->values[element].string.text #define ippGetName(attr) attr->name #define ippGetCount(attr) attr->num_values #define ippGetBoolean(attr, index) attr->values[index].boolean static ipp_attribute_t * ippNextAttribute (ipp_t *ipp) { if (!ipp || !ipp->current) return (NULL); return (ipp->current = ipp->current->next); } #endif struct CsdPrintNotificationsManagerPrivate { GDBusConnection *cups_bus_connection; gint subscription_id; cups_dest_t *dests; gint num_dests; gboolean scp_handler_spawned; GPid scp_handler_pid; GList *timeouts; GHashTable *printing_printers; GList *active_notifications; guint cups_connection_timeout_id; guint check_source_id; guint cups_dbus_subscription_id; guint renew_source_id; gint last_notify_sequence_number; guint start_idle_id; }; static void csd_print_notifications_manager_finalize (GObject *object); static gboolean cups_connection_test (gpointer user_data); static gboolean process_new_notifications (gpointer user_data); G_DEFINE_TYPE (CsdPrintNotificationsManager, csd_print_notifications_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static const char * password_cb (const char *prompt, http_t *http, const char *method, const char *resource, void *user_data) { return NULL; } static char * get_dest_attr (const char *dest_name, const char *attr, cups_dest_t *dests, int num_dests) { cups_dest_t *dest; const char *value; char *ret; if (dest_name == NULL) return NULL; ret = NULL; dest = cupsGetDest (dest_name, NULL, num_dests, dests); if (dest == NULL) { g_debug ("Unable to find a printer named '%s'", dest_name); goto out; } value = cupsGetOption (attr, dest->num_options, dest->options); if (value == NULL) { g_debug ("Unable to get %s for '%s'", attr, dest_name); goto out; } ret = g_strdup (value); out: return ret; } static gboolean is_local_dest (const char *name, cups_dest_t *dests, int num_dests) { char *type_str; cups_ptype_t type; gboolean is_remote; is_remote = TRUE; type_str = get_dest_attr (name, "printer-type", dests, num_dests); if (type_str == NULL) { goto out; } type = atoi (type_str); is_remote = type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT); g_free (type_str); out: return !is_remote; } static gboolean server_is_local (const gchar *server_name) { if (server_name != NULL && (g_ascii_strncasecmp (server_name, "localhost", 9) == 0 || g_ascii_strncasecmp (server_name, "127.0.0.1", 9) == 0 || g_ascii_strncasecmp (server_name, "::1", 3) == 0 || server_name[0] == '/')) { return TRUE; } else { return FALSE; } } static int strcmp0(const void *a, const void *b) { return g_strcmp0 (*((gchar **) a), *((gchar **) b)); } typedef struct { gchar *printer_name; gchar *primary_text; gchar *secondary_text; guint timeout_id; CsdPrintNotificationsManager *manager; } TimeoutData; typedef struct { gchar *printer_name; gchar *reason; NotifyNotification *notification; gulong notification_close_id; CsdPrintNotificationsManager *manager; } ReasonData; static void free_timeout_data (gpointer user_data) { TimeoutData *data = (TimeoutData *) user_data; if (data) { g_free (data->printer_name); g_free (data->primary_text); g_free (data->secondary_text); g_free (data); } } static void free_reason_data (gpointer user_data) { ReasonData *data = (ReasonData *) user_data; if (data) { if (data->notification_close_id > 0 && g_signal_handler_is_connected (data->notification, data->notification_close_id)) g_signal_handler_disconnect (data->notification, data->notification_close_id); g_object_unref (data->notification); g_free (data->printer_name); g_free (data->reason); g_free (data); } } static void notification_closed_cb (NotifyNotification *notification, gpointer user_data) { ReasonData *data = (ReasonData *) user_data; if (data) { data->manager->priv->active_notifications = g_list_remove (data->manager->priv->active_notifications, data); free_reason_data (data); } } static gboolean show_notification (gpointer user_data) { NotifyNotification *notification; TimeoutData *data = (TimeoutData *) user_data; ReasonData *reason_data; GList *tmp; if (!data) return FALSE; notification = notify_notification_new (data->primary_text, data->secondary_text, "printer-symbolic"); notify_notification_set_app_name (notification, _("Printers")); notify_notification_set_hint (notification, "resident", g_variant_new_boolean (TRUE)); notify_notification_set_timeout (notification, REASON_TIMEOUT); reason_data = g_new0 (ReasonData, 1); reason_data->printer_name = g_strdup (data->printer_name); reason_data->reason = g_strdup ("connecting-to-device"); reason_data->notification = notification; reason_data->manager = data->manager; reason_data->notification_close_id = g_signal_connect (notification, "closed", G_CALLBACK (notification_closed_cb), reason_data); reason_data->manager->priv->active_notifications = g_list_append (reason_data->manager->priv->active_notifications, reason_data); notify_notification_show (notification, NULL); tmp = g_list_find (data->manager->priv->timeouts, data); if (tmp) { data->manager->priv->timeouts = g_list_remove_link (data->manager->priv->timeouts, tmp); g_list_free_full (tmp, free_timeout_data); } return FALSE; } static gboolean reason_is_blacklisted (const gchar *reason) { if (g_str_equal (reason, "none")) return TRUE; if (g_str_equal (reason, "other")) return TRUE; if (g_str_equal (reason, "com.apple.print.recoverable")) return TRUE; /* https://bugzilla.redhat.com/show_bug.cgi?id=883401 */ if (g_str_has_prefix (reason, "cups-remote-")) return TRUE; /* https://bugzilla.redhat.com/show_bug.cgi?id=1207154 */ if (g_str_equal (reason, "cups-waiting-for-job-completed")) return TRUE; return FALSE; } static void on_cups_notification (GDBusConnection *connection, const char *sender_name, const char *object_path, const char *interface_name, const char *signal_name, GVariant *parameters, gpointer user_data) { process_new_notifications (user_data); } static gchar * get_statuses_second (guint i, const gchar *printer_name) { gchar *status; switch (i) { case 0: /* Translators: The printer is low on toner (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' is low on toner."), printer_name); break; case 1: /* Translators: The printer has no toner left (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' has no toner left."), printer_name); break; case 2: /* Translators: The printer is in the process of connecting to a shared network output device (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' may not be connected."), printer_name); break; case 3: /* Translators: One or more covers on the printer are open (same as in system-config-printer) */ status = g_strdup_printf (_("The cover is open on printer '%s'."), printer_name); break; case 4: /* Translators: A filter or backend is not installed (same as in system-config-printer) */ status = g_strdup_printf (_("There is a missing print filter for " "printer '%s'."), printer_name); break; case 5: /* Translators: One or more doors on the printer are open (same as in system-config-printer) */ status = g_strdup_printf (_("The door is open on printer '%s'."), printer_name); break; case 6: /* Translators: "marker" is one color bin of the printer */ status = g_strdup_printf (_("Printer '%s' is low on a marker supply."), printer_name); break; case 7: /* Translators: "marker" is one color bin of the printer */ status = g_strdup_printf (_("Printer '%s' is out of a marker supply."), printer_name); break; case 8: /* Translators: At least one input tray is low on media (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' is low on paper."), printer_name); break; case 9: /* Translators: At least one input tray is empty (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' is out of paper."), printer_name); break; case 10: /* Translators: The printer is offline (same as in system-config-printer) */ status = g_strdup_printf (_("Printer '%s' is currently off-line."), printer_name); break; case 11: /* Translators: The printer has detected an error (same as in system-config-printer) */ status = g_strdup_printf (_("There is a problem on printer '%s'."), printer_name); break; default: g_assert_not_reached (); } return status; } static void process_cups_notification (CsdPrintNotificationsManager *manager, const char *notify_subscribed_event, const char *notify_text, const char *notify_printer_uri, const char *printer_name, gint printer_state, const char *printer_state_reasons, gboolean printer_is_accepting_jobs, guint notify_job_id, gint job_state, const char *job_state_reasons, const char *job_name, gint job_impressions_completed) { ipp_attribute_t *attr; gboolean my_job = FALSE; gboolean known_reason; http_t *http; gchar *primary_text = NULL; gchar *secondary_text = NULL; gchar *job_uri = NULL; ipp_t *request, *response; static const char * const reasons[] = { "toner-low", "toner-empty", "connecting-to-device", "cover-open", "cups-missing-filter", "door-open", "marker-supply-low", "marker-supply-empty", "media-low", "media-empty", "offline", "other"}; static const char * statuses_first[] = { /* Translators: The printer is low on toner (same as in system-config-printer) */ N_("Toner low"), /* Translators: The printer has no toner left (same as in system-config-printer) */ N_("Toner empty"), /* Translators: The printer is in the process of connecting to a shared network output device (same as in system-config-printer) */ N_("Not connected?"), /* Translators: One or more covers on the printer are open (same as in system-config-printer) */ N_("Cover open"), /* Translators: A filter or backend is not installed (same as in system-config-printer) */ N_("Printer configuration error"), /* Translators: One or more doors on the printer are open (same as in system-config-printer) */ N_("Door open"), /* Translators: "marker" is one color bin of the printer */ N_("Marker supply low"), /* Translators: "marker" is one color bin of the printer */ N_("Out of a marker supply"), /* Translators: At least one input tray is low on media (same as in system-config-printer) */ N_("Paper low"), /* Translators: At least one input tray is empty (same as in system-config-printer) */ N_("Out of paper"), /* Translators: The printer is offline (same as in system-config-printer) */ N_("Printer off-line"), /* Translators: The printer has detected an error (same as in system-config-printer) */ N_("Printer error") }; if (g_strcmp0 (notify_subscribed_event, "printer-added") != 0 && g_strcmp0 (notify_subscribed_event, "printer-deleted") != 0 && g_strcmp0 (notify_subscribed_event, "printer-state-changed") != 0 && g_strcmp0 (notify_subscribed_event, "job-completed") != 0 && g_strcmp0 (notify_subscribed_event, "job-state-changed") != 0 && g_strcmp0 (notify_subscribed_event, "job-created") != 0) return; if (notify_job_id > 0) { if ((http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ())) == NULL) { g_debug ("Connection to CUPS server \'%s\' failed.", cupsServer ()); } else { job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", notify_job_id); request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, job_uri); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "job-originating-user-name"); response = cupsDoRequest (http, request, "/"); if (response) { if (ippGetStatusCode (response) <= IPP_OK_CONFLICT && (attr = ippFindAttribute(response, "job-originating-user-name", IPP_TAG_NAME))) { if (g_strcmp0 (ippGetString (attr, 0, NULL), cupsUser ()) == 0) my_job = TRUE; } ippDelete(response); } g_free (job_uri); httpClose (http); } } if (g_strcmp0 (notify_subscribed_event, "printer-added") == 0) { cupsFreeDests (manager->priv->num_dests, manager->priv->dests); manager->priv->num_dests = cupsGetDests (&manager->priv->dests); if (is_local_dest (printer_name, manager->priv->dests, manager->priv->num_dests)) { /* Translators: New printer has been added */ primary_text = g_strdup (_("Printer added")); secondary_text = g_strdup (printer_name); } } else if (g_strcmp0 (notify_subscribed_event, "printer-deleted") == 0) { cupsFreeDests (manager->priv->num_dests, manager->priv->dests); manager->priv->num_dests = cupsGetDests (&manager->priv->dests); } else if (g_strcmp0 (notify_subscribed_event, "job-completed") == 0 && my_job) { g_hash_table_remove (manager->priv->printing_printers, printer_name); switch (job_state) { case IPP_JOB_PENDING: case IPP_JOB_HELD: case IPP_JOB_PROCESSING: break; case IPP_JOB_STOPPED: /* Translators: A print job has been stopped */ primary_text = g_strdup (C_("print job state", "Printing stopped")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_CANCELED: /* Translators: A print job has been canceled */ primary_text = g_strdup (C_("print job state", "Printing canceled")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_ABORTED: /* Translators: A print job has been aborted */ primary_text = g_strdup (C_("print job state", "Printing aborted")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_COMPLETED: /* Translators: A print job has been completed */ primary_text = g_strdup (C_("print job state", "Printing completed")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; } } else if (g_strcmp0 (notify_subscribed_event, "job-state-changed") == 0 && my_job) { switch (job_state) { case IPP_JOB_PROCESSING: g_hash_table_insert (manager->priv->printing_printers, g_strdup (printer_name), NULL); /* Translators: A job is printing */ primary_text = g_strdup (C_("print job state", "Printing")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_STOPPED: g_hash_table_remove (manager->priv->printing_printers, printer_name); /* Translators: A print job has been stopped */ primary_text = g_strdup (C_("print job state", "Printing stopped")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_CANCELED: g_hash_table_remove (manager->priv->printing_printers, printer_name); /* Translators: A print job has been canceled */ primary_text = g_strdup (C_("print job state", "Printing canceled")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_ABORTED: g_hash_table_remove (manager->priv->printing_printers, printer_name); /* Translators: A print job has been aborted */ primary_text = g_strdup (C_("print job state", "Printing aborted")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; case IPP_JOB_COMPLETED: g_hash_table_remove (manager->priv->printing_printers, printer_name); /* Translators: A print job has been completed */ primary_text = g_strdup (C_("print job state", "Printing completed")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); break; default: break; } } else if (g_strcmp0 (notify_subscribed_event, "job-created") == 0 && my_job) { if (job_state == IPP_JOB_PROCESSING) { g_hash_table_insert (manager->priv->printing_printers, g_strdup (printer_name), NULL); /* Translators: A job is printing */ primary_text = g_strdup (C_("print job state", "Printing")); /* Translators: "print-job xy" on a printer */ secondary_text = g_strdup_printf (C_("print job", "'%s' on %s"), job_name, printer_name); } } else if (g_strcmp0 (notify_subscribed_event, "printer-state-changed") == 0) { cups_dest_t *dest = NULL; const gchar *tmp_printer_state_reasons = NULL; GSList *added_reasons = NULL; GSList *tmp_list = NULL; GList *tmp; gchar **old_state_reasons = NULL; gchar **new_state_reasons = NULL; gint i, j; /* Remove timeout which shows notification about possible disconnection of printer * if "connecting-to-device" has vanished. */ if (printer_state_reasons == NULL || g_strrstr (printer_state_reasons, "connecting-to-device") == NULL) { TimeoutData *data; for (tmp = manager->priv->timeouts; tmp; tmp = g_list_next (tmp)) { data = (TimeoutData *) tmp->data; if (g_strcmp0 (printer_name, data->printer_name) == 0) { g_source_remove (data->timeout_id); manager->priv->timeouts = g_list_remove_link (manager->priv->timeouts, tmp); g_list_free_full (tmp, free_timeout_data); break; } } } for (tmp = manager->priv->active_notifications; tmp; tmp = g_list_next (tmp)) { ReasonData *reason_data = (ReasonData *) tmp->data; GList *remove_list; if (printer_state_reasons == NULL || (g_strcmp0 (printer_name, reason_data->printer_name) == 0 && g_strrstr (printer_state_reasons, reason_data->reason) == NULL)) { if (reason_data->notification_close_id > 0 && g_signal_handler_is_connected (reason_data->notification, reason_data->notification_close_id)) { g_signal_handler_disconnect (reason_data->notification, reason_data->notification_close_id); reason_data->notification_close_id = 0; } notify_notification_close (reason_data->notification, NULL); remove_list = tmp; tmp = g_list_next (tmp); manager->priv->active_notifications = g_list_remove_link (manager->priv->active_notifications, remove_list); g_list_free_full (remove_list, free_reason_data); } } /* Check whether we are printing on this printer right now. */ if (g_hash_table_lookup_extended (manager->priv->printing_printers, printer_name, NULL, NULL)) { dest = cupsGetDest (printer_name, NULL, manager->priv->num_dests, manager->priv->dests); if (dest) tmp_printer_state_reasons = cupsGetOption ("printer-state-reasons", dest->num_options, dest->options); if (tmp_printer_state_reasons) old_state_reasons = g_strsplit (tmp_printer_state_reasons, ",", -1); cupsFreeDests (manager->priv->num_dests, manager->priv->dests); manager->priv->num_dests = cupsGetDests (&manager->priv->dests); dest = cupsGetDest (printer_name, NULL, manager->priv->num_dests, manager->priv->dests); if (dest) tmp_printer_state_reasons = cupsGetOption ("printer-state-reasons", dest->num_options, dest->options); if (tmp_printer_state_reasons) new_state_reasons = g_strsplit (tmp_printer_state_reasons, ",", -1); if (new_state_reasons) qsort (new_state_reasons, g_strv_length (new_state_reasons), sizeof (gchar *), strcmp0); if (old_state_reasons) { qsort (old_state_reasons, g_strv_length (old_state_reasons), sizeof (gchar *), strcmp0); j = 0; for (i = 0; new_state_reasons && i < g_strv_length (new_state_reasons); i++) { while (old_state_reasons[j] && g_strcmp0 (old_state_reasons[j], new_state_reasons[i]) < 0) j++; if (old_state_reasons[j] == NULL || g_strcmp0 (old_state_reasons[j], new_state_reasons[i]) != 0) added_reasons = g_slist_append (added_reasons, new_state_reasons[i]); } } else { for (i = 0; new_state_reasons && i < g_strv_length (new_state_reasons); i++) { added_reasons = g_slist_append (added_reasons, new_state_reasons[i]); } } for (tmp_list = added_reasons; tmp_list; tmp_list = tmp_list->next) { gchar *data = (gchar *) tmp_list->data; known_reason = FALSE; for (j = 0; j < G_N_ELEMENTS (reasons); j++) { if (strncmp (data, reasons[j], strlen (reasons[j])) == 0) { NotifyNotification *notification; known_reason = TRUE; if (g_strcmp0 (reasons[j], "connecting-to-device") == 0) { TimeoutData *data; data = g_new0 (TimeoutData, 1); data->printer_name = g_strdup (printer_name); data->primary_text = g_strdup ( _(statuses_first[j])); data->secondary_text = get_statuses_second (j, printer_name); data->manager = manager; data->timeout_id = g_timeout_add_seconds (CONNECTING_TIMEOUT, show_notification, data); g_source_set_name_by_id (data->timeout_id, "[cinnamon-settings-daemon] show_notification"); manager->priv->timeouts = g_list_append (manager->priv->timeouts, data); } else { ReasonData *reason_data; gchar *second_row = get_statuses_second (j, printer_name); notification = notify_notification_new ( _(statuses_first[j]), second_row, "printer-symbolic"); notify_notification_set_app_name (notification, _("Printers")); notify_notification_set_hint (notification, "resident", g_variant_new_boolean (TRUE)); notify_notification_set_timeout (notification, REASON_TIMEOUT); reason_data = g_new0 (ReasonData, 1); reason_data->printer_name = g_strdup (printer_name); reason_data->reason = g_strdup (reasons[j]); reason_data->notification = notification; reason_data->manager = manager; reason_data->notification_close_id = g_signal_connect (notification, "closed", G_CALLBACK (notification_closed_cb), reason_data); manager->priv->active_notifications = g_list_append (manager->priv->active_notifications, reason_data); notify_notification_show (notification, NULL); g_free (second_row); } } } if (!known_reason && !reason_is_blacklisted (data)) { NotifyNotification *notification; ReasonData *reason_data; gchar *first_row; gchar *second_row; gchar *text = NULL; gchar *ppd_file_name; ppd_file_t *ppd_file; char buffer[8192]; ppd_file_name = g_strdup (cupsGetPPD (printer_name)); if (ppd_file_name) { ppd_file = ppdOpenFile (ppd_file_name); if (ppd_file) { gchar **tmpv; static const char * const schemes[] = { "text", "http", "help", "file" }; tmpv = g_new0 (gchar *, G_N_ELEMENTS (schemes) + 1); i = 0; for (j = 0; j < G_N_ELEMENTS (schemes); j++) { if (ppdLocalizeIPPReason (ppd_file, data, schemes[j], buffer, sizeof (buffer))) { tmpv[i++] = g_strdup (buffer); } } if (i > 0) text = g_strjoinv (", ", tmpv); g_strfreev (tmpv); ppdClose (ppd_file); } g_unlink (ppd_file_name); g_free (ppd_file_name); } if (g_str_has_suffix (data, "-report")) /* Translators: This is a title of a report notification for a printer */ first_row = g_strdup (_("Printer report")); else if (g_str_has_suffix (data, "-warning")) /* Translators: This is a title of a warning notification for a printer */ first_row = g_strdup (_("Printer warning")); else /* Translators: This is a title of an error notification for a printer */ first_row = g_strdup (_("Printer error")); if (text == NULL) text = g_strdup (data); /* Translators: "Printer 'MyPrinterName': 'Description of the report/warning/error from a PPD file'." */ second_row = g_strdup_printf (_("Printer '%s': '%s'."), printer_name, text); g_free (text); notification = notify_notification_new (first_row, second_row, "printer-symbolic"); notify_notification_set_app_name (notification, _("Printers")); notify_notification_set_hint (notification, "resident", g_variant_new_boolean (TRUE)); notify_notification_set_timeout (notification, REASON_TIMEOUT); reason_data = g_new0 (ReasonData, 1); reason_data->printer_name = g_strdup (printer_name); reason_data->reason = g_strdup (data); reason_data->notification = notification; reason_data->manager = manager; reason_data->notification_close_id = g_signal_connect (notification, "closed", G_CALLBACK (notification_closed_cb), reason_data); manager->priv->active_notifications = g_list_append (manager->priv->active_notifications, reason_data); notify_notification_show (notification, NULL); g_free (first_row); g_free (second_row); } } g_slist_free (added_reasons); } if (new_state_reasons) g_strfreev (new_state_reasons); if (old_state_reasons) g_strfreev (old_state_reasons); } if (primary_text) { NotifyNotification *notification; notification = notify_notification_new (primary_text, secondary_text, "printer-symbolic"); notify_notification_set_app_name (notification, _("Printers")); notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_show (notification, NULL); g_object_unref (notification); g_free (primary_text); g_free (secondary_text); } } static gboolean process_new_notifications (gpointer user_data) { CsdPrintNotificationsManager *manager = (CsdPrintNotificationsManager *) user_data; ipp_attribute_t *attr; const gchar *notify_subscribed_event = NULL; const gchar *printer_name = NULL; const gchar *notify_text = NULL; const gchar *notify_printer_uri = NULL; const gchar *job_state_reasons = NULL; const gchar *job_name = NULL; const char *attr_name; gboolean printer_is_accepting_jobs = FALSE; gchar *printer_state_reasons = NULL; gchar **reasons; guint notify_job_id = 0; ipp_t *request; ipp_t *response; gint printer_state = -1; gint job_state = -1; gint job_impressions_completed = -1; gint notify_sequence_number = -1; gint i; request = ippNewRequest (IPP_GET_NOTIFICATIONS); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-ids", manager->priv->subscription_id); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/printers/"); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, "/jobs/"); ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-sequence-numbers", manager->priv->last_notify_sequence_number + 1); response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/"); for (attr = ippFindAttribute (response, "notify-sequence-number", IPP_TAG_INTEGER); attr != NULL; attr = ippNextAttribute (response)) { attr_name = ippGetName (attr); if (g_strcmp0 (attr_name, "notify-sequence-number") == 0) { notify_sequence_number = ippGetInteger (attr, 0); if (notify_sequence_number > manager->priv->last_notify_sequence_number) manager->priv->last_notify_sequence_number = notify_sequence_number; if (notify_subscribed_event != NULL) { process_cups_notification (manager, notify_subscribed_event, notify_text, notify_printer_uri, printer_name, printer_state, printer_state_reasons, printer_is_accepting_jobs, notify_job_id, job_state, job_state_reasons, job_name, job_impressions_completed); g_clear_pointer (&printer_state_reasons, g_free); g_clear_pointer (&job_state_reasons, g_free); } notify_subscribed_event = NULL; notify_text = NULL; notify_printer_uri = NULL; printer_name = NULL; printer_state = -1; printer_state_reasons = NULL; printer_is_accepting_jobs = FALSE; notify_job_id = 0; job_state = -1; job_state_reasons = NULL; job_name = NULL; job_impressions_completed = -1; } else if (g_strcmp0 (attr_name, "notify-subscribed-event") == 0) { notify_subscribed_event = ippGetString (attr, 0, NULL); } else if (g_strcmp0 (attr_name, "notify-text") == 0) { notify_text = ippGetString (attr, 0, NULL); } else if (g_strcmp0 (attr_name, "notify-printer-uri") == 0) { notify_printer_uri = ippGetString (attr, 0, NULL); } else if (g_strcmp0 (attr_name, "printer-name") == 0) { printer_name = ippGetString (attr, 0, NULL); } else if (g_strcmp0 (attr_name, "printer-state") == 0) { printer_state = ippGetInteger (attr, 0); } else if (g_strcmp0 (attr_name, "printer-state-reasons") == 0) { reasons = g_new0 (gchar *, ippGetCount (attr) + 1); for (i = 0; i < ippGetCount (attr); i++) reasons[i] = g_strdup (ippGetString (attr, i, NULL)); printer_state_reasons = g_strjoinv (",", reasons); g_strfreev (reasons); } else if (g_strcmp0 (attr_name, "printer-is-accepting-jobs") == 0) { printer_is_accepting_jobs = ippGetBoolean (attr, 0); } else if (g_strcmp0 (attr_name, "notify-job-id") == 0) { notify_job_id = ippGetInteger (attr, 0); } else if (g_strcmp0 (attr_name, "job-state") == 0) { job_state = ippGetInteger (attr, 0); } else if (g_strcmp0 (attr_name, "job-state-reasons") == 0) { reasons = g_new0 (gchar *, ippGetCount (attr) + 1); for (i = 0; i < ippGetCount (attr); i++) reasons[i] = g_strdup (ippGetString (attr, i, NULL)); job_state_reasons = g_strjoinv (",", reasons); g_strfreev (reasons); } else if (g_strcmp0 (attr_name, "job-name") == 0) { job_name = ippGetString (attr, 0, NULL); } else if (g_strcmp0 (attr_name, "job-impressions-completed") == 0) { job_impressions_completed = ippGetInteger (attr, 0); } } if (notify_subscribed_event != NULL) { process_cups_notification (manager, notify_subscribed_event, notify_text, notify_printer_uri, printer_name, printer_state, printer_state_reasons, printer_is_accepting_jobs, notify_job_id, job_state, job_state_reasons, job_name, job_impressions_completed); g_clear_pointer (&printer_state_reasons, g_free); g_clear_pointer (&job_state_reasons, g_free); } if (response != NULL) ippDelete (response); return TRUE; } static void scp_handler (CsdPrintNotificationsManager *manager, gboolean start) { if (start) { GError *error = NULL; char *args[2]; if (manager->priv->scp_handler_spawned) return; args[0] = LIBEXECDIR "/csd-printer"; args[1] = NULL; g_spawn_async (NULL, args, NULL, 0, NULL, NULL, &manager->priv->scp_handler_pid, &error); manager->priv->scp_handler_spawned = (error == NULL); if (error) { g_warning ("Could not execute system-config-printer-udev handler: %s", error->message); g_error_free (error); } } else if (manager->priv->scp_handler_spawned) { kill (manager->priv->scp_handler_pid, SIGHUP); g_spawn_close_pid (manager->priv->scp_handler_pid); manager->priv->scp_handler_spawned = FALSE; } } static void cancel_subscription (gint id) { http_t *http; ipp_t *request; if (id >= 0 && ((http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ())) != NULL)) { request = ippNewRequest (IPP_CANCEL_SUBSCRIPTION); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-id", id); ippDelete (cupsDoRequest (http, request, "/")); httpClose (http); } } static gboolean renew_subscription (gpointer data) { CsdPrintNotificationsManager *manager = (CsdPrintNotificationsManager *) data; ipp_attribute_t *attr = NULL; http_t *http; ipp_t *request; ipp_t *response; gint num_events = 7; static const char * const events[] = { "job-created", "job-completed", "job-state-changed", "job-state", "printer-added", "printer-deleted", "printer-state-changed"}; if ((http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ())) == NULL) { g_debug ("Connection to CUPS server \'%s\' failed.", cupsServer ()); } else { if (manager->priv->subscription_id >= 0) { request = ippNewRequest (IPP_RENEW_SUBSCRIPTION); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-subscription-id", manager->priv->subscription_id); ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", SUBSCRIPTION_DURATION); ippDelete (cupsDoRequest (http, request, "/")); } else { request = ippNewRequest (IPP_CREATE_PRINTER_SUBSCRIPTION); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "/"); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); ippAddStrings (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", num_events, NULL, events); ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-pull-method", NULL, "ippget"); if (server_is_local (cupsServer ())) { ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-recipient-uri", NULL, "dbus://"); } ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-lease-duration", SUBSCRIPTION_DURATION); response = cupsDoRequest (http, request, "/"); if (response != NULL && ippGetStatusCode (response) <= IPP_OK_CONFLICT) { if ((attr = ippFindAttribute (response, "notify-subscription-id", IPP_TAG_INTEGER)) == NULL) g_debug ("No notify-subscription-id in response!\n"); else manager->priv->subscription_id = ippGetInteger (attr, 0); } if (response) ippDelete (response); } httpClose (http); } return TRUE; } static void renew_subscription_with_connection_test_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GSocketConnection *connection; GError *error = NULL; connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object), res, &error); if (connection) { g_debug ("Test connection to CUPS server \'%s:%d\' succeeded.", cupsServer (), ippPort ()); g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); g_object_unref (connection); renew_subscription (user_data); } else { g_debug ("Test connection to CUPS server \'%s:%d\' failed.", cupsServer (), ippPort ()); } } static gboolean renew_subscription_with_connection_test (gpointer user_data) { GSocketClient *client; gchar *address; int port; port = ippPort (); address = g_strdup_printf ("%s:%d", cupsServer (), port); if (address && address[0] != '/') { client = g_socket_client_new (); g_debug ("Initiating test connection to CUPS server \'%s:%d\'.", cupsServer (), port); g_socket_client_connect_to_host_async (client, address, port, NULL, renew_subscription_with_connection_test_cb, user_data); g_object_unref (client); } else { renew_subscription (user_data); } g_free (address); return TRUE; } static void renew_subscription_timeout_enable (CsdPrintNotificationsManager *manager, gboolean enable, gboolean with_connection_test) { if (manager->priv->renew_source_id > 0) g_source_remove (manager->priv->renew_source_id); if (enable) { renew_subscription (manager); if (with_connection_test) { manager->priv->renew_source_id = g_timeout_add_seconds (RENEW_INTERVAL, renew_subscription_with_connection_test, manager); g_source_set_name_by_id (manager->priv->renew_source_id, "[cinnamon-settings-daemon] renew_subscription_with_connection_test"); } else { manager->priv->renew_source_id = g_timeout_add_seconds (RENEW_INTERVAL, renew_subscription, manager); g_source_set_name_by_id (manager->priv->renew_source_id, "[cinnamon-settings-daemon] renew_subscription"); } } else { manager->priv->renew_source_id = 0; } } static void cups_connection_test_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { CsdPrintNotificationsManager *manager = (CsdPrintNotificationsManager *) user_data; GSocketConnection *connection; GError *error = NULL; connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object), res, &error); if (connection) { g_debug ("Test connection to CUPS server \'%s:%d\' succeeded.", cupsServer (), ippPort ()); g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); g_object_unref (connection); manager->priv->num_dests = cupsGetDests (&manager->priv->dests); g_debug ("Got dests from remote CUPS server."); renew_subscription_timeout_enable (manager, TRUE, TRUE); manager->priv->check_source_id = g_timeout_add_seconds (CHECK_INTERVAL, process_new_notifications, manager); g_source_set_name_by_id (manager->priv->check_source_id, "[cinnamon-settings-daemon] process_new_notifications"); } else { g_debug ("Test connection to CUPS server \'%s:%d\' failed.", cupsServer (), ippPort ()); if (manager->priv->cups_connection_timeout_id == 0) { manager->priv->cups_connection_timeout_id = g_timeout_add_seconds (CUPS_CONNECTION_TEST_INTERVAL, cups_connection_test, manager); g_source_set_name_by_id (manager->priv->cups_connection_timeout_id, "[cinnamon-settings-daemon] cups_connection_test"); } } } static gboolean cups_connection_test (gpointer user_data) { CsdPrintNotificationsManager *manager = (CsdPrintNotificationsManager *) user_data; GSocketClient *client; gchar *address; int port = ippPort (); if (!manager->priv->dests) { address = g_strdup_printf ("%s:%d", cupsServer (), port); client = g_socket_client_new (); g_debug ("Initiating test connection to CUPS server \'%s:%d\'.", cupsServer (), port); g_socket_client_connect_to_host_async (client, address, port, NULL, cups_connection_test_cb, manager); g_object_unref (client); g_free (address); } if (manager->priv->dests) { manager->priv->cups_connection_timeout_id = 0; return FALSE; } else { return TRUE; } } static void csd_print_notifications_manager_got_dbus_connection (GObject *source_object, GAsyncResult *res, gpointer user_data) { CsdPrintNotificationsManager *manager = (CsdPrintNotificationsManager *) user_data; GError *error = NULL; manager->priv->cups_bus_connection = g_bus_get_finish (res, &error); if (manager->priv->cups_bus_connection != NULL) { manager->priv->cups_dbus_subscription_id = g_dbus_connection_signal_subscribe (manager->priv->cups_bus_connection, NULL, CUPS_DBUS_INTERFACE, NULL, CUPS_DBUS_PATH, NULL, 0, on_cups_notification, manager, NULL); } else { g_warning ("Connection to message bus failed: %s", error->message); g_error_free (error); } } static gboolean csd_print_notifications_manager_start_idle (gpointer data) { CsdPrintNotificationsManager *manager = data; cinnamon_settings_profile_start (NULL); manager->priv->printing_printers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* * Set a password callback which cancels authentication * before we prepare a correct solution (see bug #725440). */ cupsSetPasswordCB2 (password_cb, NULL); if (server_is_local (cupsServer ())) { manager->priv->num_dests = cupsGetDests (&manager->priv->dests); g_debug ("Got dests from local CUPS server."); renew_subscription_timeout_enable (manager, TRUE, FALSE); g_bus_get (G_BUS_TYPE_SYSTEM, NULL, csd_print_notifications_manager_got_dbus_connection, data); } else { cups_connection_test (manager); } scp_handler (manager, TRUE); cinnamon_settings_profile_end (NULL); return G_SOURCE_REMOVE; } gboolean csd_print_notifications_manager_start (CsdPrintNotificationsManager *manager, GError **error) { g_debug ("Starting print-notifications manager"); cinnamon_settings_profile_start (NULL); manager->priv->subscription_id = -1; manager->priv->dests = NULL; manager->priv->num_dests = 0; manager->priv->scp_handler_spawned = FALSE; manager->priv->timeouts = NULL; manager->priv->printing_printers = NULL; manager->priv->active_notifications = NULL; manager->priv->cups_bus_connection = NULL; manager->priv->cups_connection_timeout_id = 0; manager->priv->last_notify_sequence_number = -1; manager->priv->start_idle_id = g_idle_add (csd_print_notifications_manager_start_idle, manager); g_source_set_name_by_id (manager->priv->start_idle_id, "[cinnamon-settings-daemon] csd_print_notifications_manager_start_idle"); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_print_notifications_manager_stop (CsdPrintNotificationsManager *manager) { TimeoutData *data; ReasonData *reason_data; GList *tmp; g_debug ("Stopping print-notifications manager"); cupsFreeDests (manager->priv->num_dests, manager->priv->dests); manager->priv->num_dests = 0; manager->priv->dests = NULL; if (manager->priv->cups_dbus_subscription_id > 0 && manager->priv->cups_bus_connection != NULL) { g_dbus_connection_signal_unsubscribe (manager->priv->cups_bus_connection, manager->priv->cups_dbus_subscription_id); manager->priv->cups_dbus_subscription_id = 0; } renew_subscription_timeout_enable (manager, FALSE, FALSE); if (manager->priv->check_source_id > 0) { g_source_remove (manager->priv->check_source_id); manager->priv->check_source_id = 0; } if (manager->priv->subscription_id >= 0) cancel_subscription (manager->priv->subscription_id); g_clear_pointer (&manager->priv->printing_printers, g_hash_table_destroy); g_clear_object (&manager->priv->cups_bus_connection); for (tmp = manager->priv->timeouts; tmp; tmp = g_list_next (tmp)) { data = (TimeoutData *) tmp->data; if (data) g_source_remove (data->timeout_id); } g_list_free_full (manager->priv->timeouts, free_timeout_data); for (tmp = manager->priv->active_notifications; tmp; tmp = g_list_next (tmp)) { reason_data = (ReasonData *) tmp->data; if (reason_data) { if (reason_data->notification_close_id > 0 && g_signal_handler_is_connected (reason_data->notification, reason_data->notification_close_id)) { g_signal_handler_disconnect (reason_data->notification, reason_data->notification_close_id); reason_data->notification_close_id = 0; } notify_notification_close (reason_data->notification, NULL); } } g_list_free_full (manager->priv->active_notifications, free_reason_data); scp_handler (manager, FALSE); } static void csd_print_notifications_manager_class_init (CsdPrintNotificationsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_print_notifications_manager_finalize; notify_init ("cinnamon-settings-daemon"); g_type_class_add_private (klass, sizeof (CsdPrintNotificationsManagerPrivate)); } static void csd_print_notifications_manager_init (CsdPrintNotificationsManager *manager) { manager->priv = CSD_PRINT_NOTIFICATIONS_MANAGER_GET_PRIVATE (manager); } static void csd_print_notifications_manager_finalize (GObject *object) { CsdPrintNotificationsManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_PRINT_NOTIFICATIONS_MANAGER (object)); manager = CSD_PRINT_NOTIFICATIONS_MANAGER (object); g_return_if_fail (manager->priv != NULL); csd_print_notifications_manager_stop (manager); if (manager->priv->start_idle_id != 0) g_source_remove (manager->priv->start_idle_id); G_OBJECT_CLASS (csd_print_notifications_manager_parent_class)->finalize (object); } CsdPrintNotificationsManager * csd_print_notifications_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_PRINT_NOTIFICATIONS_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/print-notifications/csd-print-notifications-manager.h000066400000000000000000000051121356401377300324470ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 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, see . * */ #ifndef __CSD_PRINT_NOTIFICATIONS_MANAGER_H #define __CSD_PRINT_NOTIFICATIONS_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER (csd_print_notifications_manager_get_type ()) #define CSD_PRINT_NOTIFICATIONS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER, CsdPrintNotificationsManager)) #define CSD_PRINT_NOTIFICATIONS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER, CsdPrintNotificationsManagerClass)) #define CSD_IS_PRINT_NOTIFICATIONS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER)) #define CSD_IS_PRINT_NOTIFICATIONS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER)) #define CSD_PRINT_NOTIFICATIONS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_PRINT_NOTIFICATIONS_MANAGER, CsdPrintNotificationsManagerClass)) typedef struct CsdPrintNotificationsManagerPrivate CsdPrintNotificationsManagerPrivate; typedef struct { GObject parent; CsdPrintNotificationsManagerPrivate *priv; } CsdPrintNotificationsManager; typedef struct { GObjectClass parent_class; } CsdPrintNotificationsManagerClass; GType csd_print_notifications_manager_get_type (void); CsdPrintNotificationsManager *csd_print_notifications_manager_new (void); gboolean csd_print_notifications_manager_start (CsdPrintNotificationsManager *manager, GError **error); void csd_print_notifications_manager_stop (CsdPrintNotificationsManager *manager); G_END_DECLS #endif /* __CSD_PRINT_NOTIFICATIONS_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/print-notifications/csd-printer.c000066400000000000000000001473641356401377300265320ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Red Hat, 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 . * */ #include "config.h" #include #include #include #include #include #include #include #include static GDBusNodeInfo *npn_introspection_data = NULL; static GDBusNodeInfo *pdi_introspection_data = NULL; #define SCP_DBUS_NPN_NAME "com.redhat.NewPrinterNotification" #define SCP_DBUS_NPN_PATH "/com/redhat/NewPrinterNotification" #define SCP_DBUS_NPN_INTERFACE "com.redhat.NewPrinterNotification" #define SCP_DBUS_PDI_NAME "com.redhat.PrinterDriversInstaller" #define SCP_DBUS_PDI_PATH "/com/redhat/PrinterDriversInstaller" #define SCP_DBUS_PDI_INTERFACE "com.redhat.PrinterDriversInstaller" #define PACKAGE_KIT_BUS "org.freedesktop.PackageKit" #define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit" #define PACKAGE_KIT_MODIFY_IFACE "org.freedesktop.PackageKit.Modify" #define PACKAGE_KIT_QUERY_IFACE "org.freedesktop.PackageKit.Query" #define SCP_BUS "org.fedoraproject.Config.Printing" #define SCP_PATH "/org/fedoraproject/Config/Printing" #define SCP_IFACE "org.fedoraproject.Config.Printing" #define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism" #define ALLOWED_CHARACTERS "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" #define DBUS_TIMEOUT 60000 #define DBUS_INSTALL_TIMEOUT 3600000 #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_IFACE "org.gnome.SessionManager" #define GNOME_SESSION_CLIENT_PRIVATE_DBUS_IFACE "org.gnome.SessionManager.ClientPrivate" #define GNOME_SESSION_PRESENCE_DBUS_PATH "/org/gnome/SessionManager/Presence" #define GNOME_SESSION_PRESENCE_DBUS_IFACE "org.gnome.SessionManager.Presence" #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5) #define HAVE_CUPS_1_6 1 #endif #ifndef HAVE_CUPS_1_6 #define ippGetState(ipp) ipp->state #endif enum { PRESENCE_STATUS_AVAILABLE = 0, PRESENCE_STATUS_INVISIBLE, PRESENCE_STATUS_BUSY, PRESENCE_STATUS_IDLE, PRESENCE_STATUS_UNKNOWN }; static const gchar npn_introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " ""; static const gchar pdi_introspection_xml[] = "" " " " " " " " " " " " " " " ""; static GMainLoop *main_loop; static guint npn_registration_id; static guint pdi_registration_id; static guint npn_owner_id; static guint pdi_owner_id; static GHashTable * get_missing_executables (const gchar *ppd_file_name) { GHashTable *executables = NULL; GDBusProxy *proxy; GVariant *output; GVariant *array; GError *error = NULL; gint i; if (!ppd_file_name) return NULL; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, SCP_BUS, SCP_PATH, SCP_IFACE, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return NULL; } output = g_dbus_proxy_call_sync (proxy, "MissingExecutables", g_variant_new ("(s)", ppd_file_name), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output && g_variant_n_children (output) == 1) { array = g_variant_get_child_value (output, 0); if (array) { executables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (i = 0; i < g_variant_n_children (array); i++) { g_hash_table_insert (executables, g_strdup (g_variant_get_string ( g_variant_get_child_value (array, i), NULL)), NULL); } } } if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); return executables; } static GHashTable * find_packages_for_executables (GHashTable *executables) { GHashTableIter exec_iter; GHashTable *packages = NULL; GDBusProxy *proxy; GVariant *output; gpointer key, value; GError *error = NULL; if (!executables || g_hash_table_size (executables) <= 0) return NULL; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, PACKAGE_KIT_BUS, PACKAGE_KIT_PATH, PACKAGE_KIT_QUERY_IFACE, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return NULL; } packages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_hash_table_iter_init (&exec_iter, executables); while (g_hash_table_iter_next (&exec_iter, &key, &value)) { output = g_dbus_proxy_call_sync (proxy, "SearchFile", g_variant_new ("(ss)", (gchar *) key, ""), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output) { gboolean installed; gchar *package; g_variant_get (output, "(bs)", &installed, &package); if (!installed) g_hash_table_insert (packages, g_strdup (package), NULL); g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } } g_object_unref (proxy); return packages; } static void install_packages (GHashTable *packages) { GVariantBuilder array_builder; GHashTableIter pkg_iter; GDBusProxy *proxy; GVariant *output; gpointer key, value; GError *error = NULL; if (!packages || g_hash_table_size (packages) <= 0) return; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, PACKAGE_KIT_BUS, PACKAGE_KIT_PATH, PACKAGE_KIT_MODIFY_IFACE, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return; } g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as")); g_hash_table_iter_init (&pkg_iter, packages); while (g_hash_table_iter_next (&pkg_iter, &key, &value)) { g_variant_builder_add (&array_builder, "s", (gchar *) key); } output = g_dbus_proxy_call_sync (proxy, "InstallPackageNames", g_variant_new ("(uass)", 0, &array_builder, "hide-finished"), G_DBUS_CALL_FLAGS_NONE, DBUS_INSTALL_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); } static gchar * get_best_ppd (gchar *device_id, gchar *device_make_and_model, gchar *device_uri) { GDBusProxy *proxy; GVariant *output; GVariant *array; GVariant *tuple; GError *error = NULL; gchar *ppd_name = NULL; gint i, j; static const char * const match_levels[] = { "exact-cmd", "exact", "close", "generic", "none"}; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, SCP_BUS, SCP_PATH, SCP_IFACE, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return NULL; } output = g_dbus_proxy_call_sync (proxy, "GetBestDrivers", g_variant_new ("(sss)", device_id ? device_id : "", device_make_and_model ? device_make_and_model : "", device_uri ? device_uri : ""), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output && g_variant_n_children (output) >= 1) { array = g_variant_get_child_value (output, 0); if (array) for (j = 0; j < G_N_ELEMENTS (match_levels) && ppd_name == NULL; j++) for (i = 0; i < g_variant_n_children (array) && ppd_name == NULL; i++) { tuple = g_variant_get_child_value (array, i); if (tuple && g_variant_n_children (tuple) == 2) { if (g_strcmp0 (g_variant_get_string ( g_variant_get_child_value (tuple, 1), NULL), match_levels[j]) == 0) ppd_name = g_strdup (g_variant_get_string ( g_variant_get_child_value (tuple, 0), NULL)); } } } if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); return ppd_name; } static gchar * get_tag_value (const gchar *tag_string, const gchar *tag_name) { gchar **tag_string_splitted; gchar *tag_value = NULL; gint tag_name_length; gint i; if (!tag_string || !tag_name) return NULL; tag_name_length = strlen (tag_name); tag_string_splitted = g_strsplit (tag_string, ";", 0); if (tag_string_splitted) { for (i = 0; i < g_strv_length (tag_string_splitted); i++) if (g_ascii_strncasecmp (tag_string_splitted[i], tag_name, tag_name_length) == 0) if (strlen (tag_string_splitted[i]) > tag_name_length + 1) tag_value = g_strdup (tag_string_splitted[i] + tag_name_length + 1); g_strfreev (tag_string_splitted); } return tag_value; } static gchar * create_name (gchar *device_id) { cups_dest_t *dests; gboolean already_present = FALSE; gchar *name = NULL; gchar *new_name = NULL; gint num_dests; gint name_index = 2; gint j; g_return_val_if_fail (device_id != NULL, NULL); name = get_tag_value (device_id, "mdl"); if (!name) name = get_tag_value (device_id, "model"); if (name) name = g_strcanon (name, ALLOWED_CHARACTERS, '-'); num_dests = cupsGetDests (&dests); do { if (already_present) { new_name = g_strdup_printf ("%s-%d", name, name_index); name_index++; } else { new_name = g_strdup (name); } already_present = FALSE; for (j = 0; j < num_dests; j++) if (g_strcmp0 (dests[j].name, new_name) == 0) already_present = TRUE; if (already_present) { g_free (new_name); } else { g_free (name); name = new_name; } } while (already_present); cupsFreeDests (num_dests, dests); return name; } static gboolean add_printer (gchar *printer_name, gchar *device_uri, gchar *ppd_name, gchar *info, gchar *location) { cups_dest_t *dests; GDBusProxy *proxy; gboolean success = FALSE; GVariant *output; GError *error = NULL; gint num_dests; gint i; if (!printer_name || !device_uri || !ppd_name) return FALSE; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, MECHANISM_BUS, "/", MECHANISM_BUS, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return FALSE; } output = g_dbus_proxy_call_sync (proxy, "PrinterAdd", g_variant_new ("(sssss)", printer_name, device_uri, ppd_name, info ? info : "", location ? location : ""), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); num_dests = cupsGetDests (&dests); for (i = 0; i < num_dests; i++) if (g_strcmp0 (dests[i].name, printer_name) == 0) success = TRUE; cupsFreeDests (num_dests, dests); return success; } static gboolean printer_set_enabled (const gchar *printer_name, gboolean enabled) { GDBusProxy *proxy; gboolean result = TRUE; GVariant *output; GError *error = NULL; if (!printer_name) return FALSE; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, MECHANISM_BUS, "/", MECHANISM_BUS, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return FALSE; } output = g_dbus_proxy_call_sync (proxy, "PrinterSetEnabled", g_variant_new ("(sb)", printer_name, enabled), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); result = FALSE; } g_object_unref (proxy); return result; } static gboolean printer_set_accepting_jobs (const gchar *printer_name, gboolean accepting_jobs, const gchar *reason) { GDBusProxy *proxy; gboolean result = TRUE; GVariant *output; GError *error = NULL; if (!printer_name) return FALSE; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, MECHANISM_BUS, "/", MECHANISM_BUS, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return FALSE; } output = g_dbus_proxy_call_sync (proxy, "PrinterSetAcceptJobs", g_variant_new ("(sbs)", printer_name, accepting_jobs, reason ? reason : ""), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); result = FALSE; } g_object_unref (proxy); return result; } static ipp_t * execute_maintenance_command (const char *printer_name, const char *command, const char *title) { http_t *http; GError *error = NULL; ipp_t *request = NULL; ipp_t *response = NULL; gchar *file_name = NULL; char *uri; int fd = -1; http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ()); if (!http) return NULL; request = ippNewRequest (IPP_PRINT_JOB); uri = g_strdup_printf ("ipp://localhost/printers/%s", printer_name); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); g_free (uri); ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); ippAddString (request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-command"); fd = g_file_open_tmp ("ccXXXXXX", &file_name, &error); if (fd != -1) { FILE *file; file = fdopen (fd, "w"); fprintf (file, "#CUPS-COMMAND\n"); fprintf (file, "%s\n", command); fclose (file); response = cupsDoFileRequest (http, request, "/", file_name); g_unlink (file_name); } else { g_warning ("%s", error->message); g_error_free (error); } g_free (file_name); httpClose (http); return response; } static char * get_dest_attr (const char *dest_name, const char *attr) { cups_dest_t *dests; int num_dests; cups_dest_t *dest; const char *value; char *ret; if (dest_name == NULL) return NULL; ret = NULL; num_dests = cupsGetDests (&dests); if (num_dests < 1) { g_debug ("Unable to get printer destinations"); return NULL; } dest = cupsGetDest (dest_name, NULL, num_dests, dests); if (dest == NULL) { g_debug ("Unable to find a printer named '%s'", dest_name); goto out; } value = cupsGetOption (attr, dest->num_options, dest->options); if (value == NULL) { g_debug ("Unable to get %s for '%s'", attr, dest_name); goto out; } ret = g_strdup (value); out: cupsFreeDests (num_dests, dests); return ret; } static void printer_autoconfigure (gchar *printer_name) { gchar *commands; gchar *commands_lowercase; ipp_t *response = NULL; if (!printer_name) return; commands = get_dest_attr (printer_name, "printer-commands"); commands_lowercase = g_ascii_strdown (commands, -1); if (g_strrstr (commands_lowercase, "autoconfigure")) { response = execute_maintenance_command (printer_name, "AutoConfigure", ("Automatic configuration")); if (response) { if (ippGetState (response) == IPP_ERROR) g_warning ("An error has occured during automatic configuration of new printer."); ippDelete (response); } } g_free (commands); g_free (commands_lowercase); } /* Returns default page size for current locale */ static const gchar * get_page_size_from_locale (void) { if (g_str_equal (gtk_paper_size_get_default (), GTK_PAPER_NAME_LETTER)) return "Letter"; else return "A4"; } static void set_default_paper_size (const gchar *printer_name, const gchar *ppd_file_name) { GDBusProxy *proxy; GVariant *output; GError *error = NULL; GVariantBuilder *builder; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, MECHANISM_BUS, "/", MECHANISM_BUS, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); return; } /* Set default media size according to the locale * FIXME: Handle more than A4 and Letter: * https://bugzilla.gnome.org/show_bug.cgi?id=660769 */ builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); g_variant_builder_add (builder, "s", get_page_size_from_locale ()); output = g_dbus_proxy_call_sync (proxy, "PrinterAddOption", g_variant_new ("(ssas)", printer_name ? printer_name : "", "PageSize", builder), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { if (!(error->domain == G_DBUS_ERROR && (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN || error->code == G_DBUS_ERROR_UNKNOWN_METHOD))) g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); } /* * Setup new printer and returns TRUE if successful. */ static gboolean setup_printer (gchar *device_id, gchar *device_make_and_model, gchar *device_uri) { gboolean success = FALSE; gchar *ppd_name; gchar *printer_name; ppd_name = get_best_ppd (device_id, device_make_and_model, device_uri); printer_name = create_name (device_id); if (!ppd_name || !printer_name || !device_uri) { g_free (ppd_name); g_free (printer_name); return FALSE; } success = add_printer (printer_name, device_uri, ppd_name, NULL, NULL); /* Set some options of the new printer */ if (success) { const char *ppd_file_name; printer_set_accepting_jobs (printer_name, TRUE, NULL); printer_set_enabled (printer_name, TRUE); printer_autoconfigure (printer_name); ppd_file_name = cupsGetPPD (printer_name); if (ppd_file_name) { GHashTable *executables; GHashTable *packages; set_default_paper_size (printer_name, ppd_file_name); executables = get_missing_executables (ppd_file_name); packages = find_packages_for_executables (executables); install_packages (packages); if (executables) g_hash_table_destroy (executables); if (packages) g_hash_table_destroy (packages); g_unlink (ppd_file_name); } } g_free (printer_name); g_free (ppd_name); return success; } static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { gchar *primary_text = NULL; gchar *secondary_text = NULL; gchar *name = NULL; gchar *mfg = NULL; gchar *mdl = NULL; gchar *des = NULL; gchar *cmd = NULL; gchar *device = NULL; gchar *device_id; gchar *make_and_model; gint status = 0; if (g_strcmp0 (method_name, "GetReady") == 0) { /* Translators: We are configuring new printer */ primary_text = g_strdup (_("Configuring new printer")); /* Translators: Just wait */ secondary_text = g_strdup (_("Please wait...")); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "NewPrinter") == 0) { if (g_variant_n_children (parameters) == 6) { g_variant_get (parameters, "(i&s&s&s&s&s)", &status, &name, &mfg, &mdl, &des, &cmd); } if (g_strrstr (name, "/")) { /* name is a URI, no queue was generated, because no suitable * driver was found */ device_id = g_strdup_printf ("MFG:%s;MDL:%s;DES:%s;CMD:%s;", mfg, mdl, des, cmd); make_and_model = g_strdup_printf ("%s %s", mfg, mdl); if (!setup_printer (device_id, make_and_model, name)) { /* Translators: We have no driver installed for this printer */ primary_text = g_strdup (_("Missing printer driver")); if ((mfg && mdl) || des) { if (mfg && mdl) device = g_strdup_printf ("%s %s", mfg, mdl); else device = g_strdup (des); /* Translators: We have no driver installed for the device */ secondary_text = g_strdup_printf (_("No printer driver for %s."), device); g_free (device); } else /* Translators: We have no driver installed for this printer */ secondary_text = g_strdup (_("No driver for this printer.")); } g_free (make_and_model); g_free (device_id); } else { /* name is the name of the queue which hal_lpadmin has set up * automatically. */ const char *ppd_file_name; ppd_file_name = cupsGetPPD (name); if (ppd_file_name) { GHashTable *executables; GHashTable *packages; executables = get_missing_executables (ppd_file_name); packages = find_packages_for_executables (executables); install_packages (packages); if (executables) g_hash_table_destroy (executables); if (packages) g_hash_table_destroy (packages); g_unlink (ppd_file_name); } } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "InstallDrivers") == 0) { GDBusProxy *proxy; GError *error = NULL; if (g_variant_n_children (parameters) == 3) { g_variant_get (parameters, "(&s&s&s)", &mfg, &mdl, &cmd); } if (mfg && mdl) device = g_strdup_printf ("MFG:%s;MDL:%s;", mfg, mdl); proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, PACKAGE_KIT_BUS, PACKAGE_KIT_PATH, PACKAGE_KIT_MODIFY_IFACE, NULL, &error); if (!proxy) { g_warning ("%s", error->message); g_error_free (error); } if (proxy && device) { GVariantBuilder *builder; GVariant *output; builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); g_variant_builder_add (builder, "s", device); output = g_dbus_proxy_call_sync (proxy, "InstallPrinterDrivers", g_variant_new ("(uass)", 0, builder, "hide-finished"), G_DBUS_CALL_FLAGS_NONE, DBUS_INSTALL_TIMEOUT, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); } g_dbus_method_invocation_return_value (invocation, NULL); } if (primary_text) { NotifyNotification *notification; notification = notify_notification_new (primary_text, secondary_text, "printer-symbolic"); notify_notification_set_app_name (notification, _("Printers")); notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_show (notification, NULL); g_object_unref (notification); g_free (primary_text); g_free (secondary_text); } } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, NULL }; static void unregister_objects () { GDBusConnection *system_connection; GError *error = NULL; system_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (npn_registration_id > 0) { g_dbus_connection_unregister_object (system_connection, npn_registration_id); npn_registration_id = 0; } if (pdi_registration_id > 0) { g_dbus_connection_unregister_object (system_connection, pdi_registration_id); pdi_registration_id = 0; } } static void unown_names () { if (npn_owner_id > 0) { g_bus_unown_name (npn_owner_id); npn_owner_id = 0; } if (pdi_owner_id > 0) { g_bus_unown_name (pdi_owner_id); pdi_owner_id = 0; } } static void on_npn_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { GError *error = NULL; npn_registration_id = g_dbus_connection_register_object (connection, SCP_DBUS_NPN_PATH, npn_introspection_data->interfaces[0], &interface_vtable, NULL, NULL, &error); if (npn_registration_id == 0) { g_warning ("Failed to register object: %s\n", error->message); g_error_free (error); } } static void on_pdi_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { GError *error = NULL; pdi_registration_id = g_dbus_connection_register_object (connection, SCP_DBUS_PDI_PATH, pdi_introspection_data->interfaces[0], &interface_vtable, NULL, NULL, &error); if (pdi_registration_id == 0) { g_warning ("Failed to register object: %s\n", error->message); g_error_free (error); } } static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { } static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { unregister_objects (); } static void session_signal_handler (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { guint new_status; g_variant_get (parameters, "(u)", &new_status); if (new_status == PRESENCE_STATUS_IDLE || new_status == PRESENCE_STATUS_AVAILABLE) { unregister_objects (); unown_names (); if (new_status == PRESENCE_STATUS_AVAILABLE) { npn_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, SCP_DBUS_NPN_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_npn_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); pdi_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, SCP_DBUS_PDI_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_pdi_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); } } } static void client_signal_handler (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { GDBusProxy *proxy; GError *error = NULL; GVariant *output; if (g_strcmp0 (signal_name, "QueryEndSession") == 0 || g_strcmp0 (signal_name, "EndSession") == 0) { proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, sender_name, object_path, interface_name, NULL, &error); if (proxy) { output = g_dbus_proxy_call_sync (proxy, "EndSessionResponse", g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (output) { g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); } else { g_warning ("%s", error->message); g_error_free (error); } if (g_strcmp0 (signal_name, "EndSession") == 0) { g_main_loop_quit (main_loop); g_debug ("Exiting csd-printer"); } } } static gchar * register_gnome_session_client (const gchar *app_id, const gchar *client_startup_id) { GDBusProxy *proxy; GVariant *output = NULL; GError *error = NULL; const gchar *client_id = NULL; gchar *result = NULL; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_IFACE, NULL, &error); if (proxy) { output = g_dbus_proxy_call_sync (proxy, "RegisterClient", g_variant_new ("(ss)", app_id, client_startup_id), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (output) { g_variant_get (output, "(o)", &client_id); if (client_id) result = g_strdup (client_id); g_variant_unref (output); } else { g_warning ("%s", error->message); g_error_free (error); } g_object_unref (proxy); } else { g_warning ("%s", error->message); g_error_free (error); } return result; } int main (int argc, char *argv[]) { GDBusConnection *connection; gboolean client_signal_subscription_set = FALSE; GError *error = NULL; guint client_signal_subscription_id; guint session_signal_subscription_id; gchar *object_path; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); setlocale (LC_ALL, ""); npn_registration_id = 0; pdi_registration_id = 0; npn_owner_id = 0; pdi_owner_id = 0; notify_init ("cinnamon-settings-daemon-printer"); npn_introspection_data = g_dbus_node_info_new_for_xml (npn_introspection_xml, &error); if (npn_introspection_data == NULL) { g_warning ("Error parsing introspection XML: %s\n", error->message); g_error_free (error); goto error; } pdi_introspection_data = g_dbus_node_info_new_for_xml (pdi_introspection_xml, &error); if (pdi_introspection_data == NULL) { g_warning ("Error parsing introspection XML: %s\n", error->message); g_error_free (error); goto error; } connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); session_signal_subscription_id = g_dbus_connection_signal_subscribe (connection, NULL, GNOME_SESSION_PRESENCE_DBUS_IFACE, "StatusChanged", GNOME_SESSION_PRESENCE_DBUS_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE, session_signal_handler, NULL, NULL); object_path = register_gnome_session_client ("csd-printer", ""); if (object_path) { client_signal_subscription_id = g_dbus_connection_signal_subscribe (connection, NULL, GNOME_SESSION_CLIENT_PRIVATE_DBUS_IFACE, NULL, object_path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, client_signal_handler, NULL, NULL); client_signal_subscription_set = TRUE; } if (npn_owner_id == 0) npn_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, SCP_DBUS_NPN_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_npn_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); if (pdi_owner_id == 0) pdi_owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, SCP_DBUS_PDI_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE, on_pdi_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); unregister_objects (); unown_names (); if (client_signal_subscription_set) g_dbus_connection_signal_unsubscribe (connection, client_signal_subscription_id); g_dbus_connection_signal_unsubscribe (connection, session_signal_subscription_id); g_free (object_path); g_dbus_node_info_unref (npn_introspection_data); g_dbus_node_info_unref (pdi_introspection_data); return 0; error: if (npn_introspection_data) g_dbus_node_info_unref (npn_introspection_data); if (pdi_introspection_data) g_dbus_node_info_unref (pdi_introspection_data); return 1; } cinnamon-settings-daemon-4.4.0/plugins/print-notifications/main.c000066400000000000000000000011121356401377300252000ustar00rootroot00000000000000#define NEW csd_print_notifications_manager_new #define START csd_print_notifications_manager_start #define STOP csd_print_notifications_manager_stop #define MANAGER CsdPrintNotificationsManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-print-notifications-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy/000077500000000000000000000000001356401377300236115ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy/Makefile.am000066400000000000000000000022571356401377300256530ustar00rootroot00000000000000plugin_name = screensaver-proxy AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-screensaver-proxy csd_screensaver_proxy_SOURCES = \ main.c \ csd-screensaver-proxy-manager.c \ csd-screensaver-proxy-manager.h csd_screensaver_proxy_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_screensaver_proxy_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_screensaver_proxy_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-screensaver-proxy.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-screensaver-proxy.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-screensaver-proxy.desktop.in000066400000000000000000000003771356401377300361370ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - screensaver-proxy Exec=@libexecdir@/csd-screensaver-proxy OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy/csd-screensaver-proxy-manager.c000066400000000000000000000470421356401377300316420ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * 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 #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-session.h" #include "cinnamon-settings-profile.h" #include "csd-screensaver-proxy-manager.h" #define CSD_SCREENSAVER_PROXY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerPrivate)) /* As available in: * https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml * and documented in: * https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/ksmserver/screenlocker/interface.h */ static const gchar introspection_xml[] = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; static const gchar introspection_xml2[] = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; #define CSD_SCREENSAVER_PROXY_DBUS_SERVICE "org.freedesktop.ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_PATH "/org/freedesktop/ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_PATH2 "/ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_INTERFACE "org.freedesktop.ScreenSaver" #define GSM_INHIBITOR_FLAG_IDLE 1 << 3 struct CsdScreensaverProxyManagerPrivate { GDBusProxy *session; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusNodeInfo *introspection_data; GDBusNodeInfo *introspection_data2; guint name_id; GHashTable *watch_ht; /* key = sender, value = name watch id */ GHashTable *cookie_ht; /* key = cookie, value = sender */ }; static void csd_screensaver_proxy_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdScreensaverProxyManager, csd_screensaver_proxy_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_OBJECT "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" static GDBusProxy * cinnamon_settings_session_get_session_proxy (void) { static GDBusProxy *session_proxy; GError *error = NULL; if (session_proxy != NULL) { g_object_ref (session_proxy); } else { session_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_OBJECT, GNOME_SESSION_DBUS_INTERFACE, NULL, &error); if (error) { g_warning ("Failed to connect to the session manager: %s", error->message); g_error_free (error); } else { g_object_add_weak_pointer (G_OBJECT (session_proxy), (gpointer*)&session_proxy); } } return session_proxy; } static void name_vanished_cb (GDBusConnection *connection, const gchar *name, CsdScreensaverProxyManager *manager) { GHashTableIter iter; gpointer cookie_ptr; const char *sender; /* Look for all the cookies under that name, * and call uninhibit for them */ g_hash_table_iter_init (&iter, manager->priv->cookie_ht); while (g_hash_table_iter_next (&iter, &cookie_ptr, (gpointer *) &sender)) { if (g_strcmp0 (sender, name) == 0) { guint cookie = GPOINTER_TO_UINT (cookie_ptr); g_dbus_proxy_call_sync (manager->priv->session, "Uninhibit", g_variant_new ("(u)", cookie), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_debug ("Removing cookie %u for sender %s", cookie, sender); g_hash_table_iter_remove (&iter); } } g_hash_table_remove (manager->priv->watch_ht, sender); } static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { CsdScreensaverProxyManager *manager = CSD_SCREENSAVER_PROXY_MANAGER (user_data); /* Check session pointer as a proxy for whether the manager is in the start or stop state */ if (manager->priv->session == NULL) { return; } g_debug ("Calling method '%s.%s' for ScreenSaver Proxy", interface_name, method_name); if (g_strcmp0 (method_name, "Inhibit") == 0) { GVariant *ret; const char *app_id; const char *reason; guint cookie; g_variant_get (parameters, "(ss)", &app_id, &reason); ret = g_dbus_proxy_call_sync (manager->priv->session, "Inhibit", g_variant_new ("(susu)", app_id, 0, reason, GSM_INHIBITOR_FLAG_IDLE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_variant_get (ret, "(u)", &cookie); g_hash_table_insert (manager->priv->cookie_ht, GUINT_TO_POINTER (cookie), g_strdup (sender)); if (g_hash_table_lookup (manager->priv->watch_ht, sender) == NULL) { guint watch_id; watch_id = g_bus_watch_name_on_connection (manager->priv->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, (GBusNameVanishedCallback) name_vanished_cb, manager, NULL); g_hash_table_insert (manager->priv->watch_ht, g_strdup (sender), GUINT_TO_POINTER (watch_id)); } g_dbus_method_invocation_return_value (invocation, ret); } else if (g_strcmp0 (method_name, "UnInhibit") == 0) { guint cookie; g_variant_get (parameters, "(u)", &cookie); g_dbus_proxy_call_sync (manager->priv->session, "Uninhibit", parameters, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "Throttle") == 0) { g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "UnThrottle") == 0) { g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "Lock") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "SimulateUserActivity") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetActive") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetActiveTime") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetSessionIdleTime") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "SetActive") == 0) { goto unimplemented; } return; unimplemented: g_dbus_method_invocation_return_dbus_error (invocation, "org.freedesktop.DBus.Error.NotSupported", "This method is not implemented"); } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, /* GetProperty */ NULL, /* SetProperty */ }; static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdScreensaverProxyManager *manager) { GDBusConnection *connection; GDBusInterfaceInfo **infos; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; infos = manager->priv->introspection_data->interfaces; g_dbus_connection_register_object (connection, CSD_SCREENSAVER_PROXY_DBUS_PATH, infos[0], &interface_vtable, manager, NULL, NULL); infos = manager->priv->introspection_data2->interfaces; g_dbus_connection_register_object (connection, CSD_SCREENSAVER_PROXY_DBUS_PATH2, infos[0], &interface_vtable, manager, NULL, NULL); manager->priv->name_id = g_bus_own_name_on_connection (manager->priv->connection, CSD_SCREENSAVER_PROXY_DBUS_SERVICE, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); } static void register_manager_dbus (CsdScreensaverProxyManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->introspection_data2 = g_dbus_node_info_new_for_xml (introspection_xml2, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_assert (manager->priv->introspection_data2 != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } gboolean csd_screensaver_proxy_manager_start (CsdScreensaverProxyManager *manager, GError **error) { g_debug ("Starting screensaver-proxy manager"); cinnamon_settings_profile_start (NULL); manager->priv->session = cinnamon_settings_session_get_session_proxy (); manager->priv->watch_ht = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_bus_unwatch_name); manager->priv->cookie_ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_screensaver_proxy_manager_stop (CsdScreensaverProxyManager *manager) { g_debug ("Stopping screensaver_proxy manager"); if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->watch_ht != NULL) { g_hash_table_destroy (manager->priv->watch_ht); manager->priv->watch_ht = NULL; } if (manager->priv->cookie_ht != NULL) { g_hash_table_destroy (manager->priv->cookie_ht); manager->priv->cookie_ht = NULL; } } static void csd_screensaver_proxy_manager_class_init (CsdScreensaverProxyManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_screensaver_proxy_manager_finalize; g_type_class_add_private (klass, sizeof (CsdScreensaverProxyManagerPrivate)); } static void csd_screensaver_proxy_manager_init (CsdScreensaverProxyManager *manager) { manager->priv = CSD_SCREENSAVER_PROXY_MANAGER_GET_PRIVATE (manager); } static void csd_screensaver_proxy_manager_finalize (GObject *object) { CsdScreensaverProxyManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SCREENSAVER_PROXY_MANAGER (object)); manager = CSD_SCREENSAVER_PROXY_MANAGER (object); g_return_if_fail (manager->priv != NULL); if (manager->priv->name_id != 0) { g_bus_unown_name (manager->priv->name_id); manager->priv->name_id = 0; } if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->bus_cancellable != NULL) { g_object_unref (manager->priv->bus_cancellable); manager->priv->bus_cancellable = NULL; } if (manager->priv->introspection_data != NULL) { g_dbus_node_info_unref (manager->priv->introspection_data); manager->priv->introspection_data = NULL; } if (manager->priv->introspection_data2 != NULL) { g_dbus_node_info_unref (manager->priv->introspection_data2); manager->priv->introspection_data2 = NULL; } G_OBJECT_CLASS (csd_screensaver_proxy_manager_parent_class)->finalize (object); } CsdScreensaverProxyManager * csd_screensaver_proxy_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_SCREENSAVER_PROXY_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return CSD_SCREENSAVER_PROXY_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy/csd-screensaver-proxy-manager.h000066400000000000000000000051721356401377300316450ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * 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 __CSD_SCREENSAVER_PROXY_MANAGER_H #define __CSD_SCREENSAVER_PROXY_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_SCREENSAVER_PROXY_MANAGER (csd_screensaver_proxy_manager_get_type ()) #define CSD_SCREENSAVER_PROXY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManager)) #define CSD_SCREENSAVER_PROXY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerClass)) #define CSD_IS_SCREENSAVER_PROXY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER)) #define CSD_IS_SCREENSAVER_PROXY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SCREENSAVER_PROXY_MANAGER)) #define CSD_SCREENSAVER_PROXY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerClass)) typedef struct CsdScreensaverProxyManagerPrivate CsdScreensaverProxyManagerPrivate; typedef struct { GObject parent; CsdScreensaverProxyManagerPrivate *priv; } CsdScreensaverProxyManager; typedef struct { GObjectClass parent_class; } CsdScreensaverProxyManagerClass; GType csd_screensaver_proxy_manager_get_type (void); CsdScreensaverProxyManager *csd_screensaver_proxy_manager_new (void); gboolean csd_screensaver_proxy_manager_start (CsdScreensaverProxyManager *manager, GError **error); void csd_screensaver_proxy_manager_stop (CsdScreensaverProxyManager *manager); G_END_DECLS #endif /* __CSD_SCREENSAVER_PROXY_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/screensaver-proxy/main.c000066400000000000000000000011001356401377300246710ustar00rootroot00000000000000#define NEW csd_screensaver_proxy_manager_new #define START csd_screensaver_proxy_manager_start #define STOP csd_screensaver_proxy_manager_stop #define MANAGER CsdScreensaverProxyManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-screensaver-proxy-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/smartcard/000077500000000000000000000000001356401377300220725ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/smartcard/Makefile.am000066400000000000000000000021611356401377300241260ustar00rootroot00000000000000plugin_name = smartcard AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-smartcard csd_smartcard_SOURCES = \ csd-smartcard-manager.h \ csd-smartcard-manager.c \ csd-smartcard.h \ csd-smartcard.c \ main.c csd_smartcard_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DLIBDIR=\""$(libdir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(NSS_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_smartcard_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(NSS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-smartcard.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-smartcard.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA)cinnamon-settings-daemon-4.4.0/plugins/smartcard/cinnamon-settings-daemon-smartcard.desktop.in000066400000000000000000000003571356401377300327560ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - smartcard Exec=@libexecdir@/csd-smartcard OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/smartcard/csd-smartcard-manager.c000066400000000000000000001436321356401377300264060ustar00rootroot00000000000000/* csd-smartcard-manager.c - object for monitoring smartcard insertion and * removal events * * Copyright (C) 2006, 2009 Red Hat, 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Written By: Ray Strode */ #include "config.h" #include "csd-smartcard-manager.h" #define SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef CSD_SMARTCARD_MANAGER_DRIVER #define CSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so" #endif #ifndef CSD_SMARTCARD_MANAGER_NSS_DB #define CSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" #endif #ifndef CSD_MAX_OPEN_FILE_DESCRIPTORS #define CSD_MAX_OPEN_FILE_DESCRIPTORS 1024 #endif #ifndef CSD_OPEN_FILE_DESCRIPTORS_DIR #define CSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd" #endif typedef enum _CsdSmartcardManagerState CsdSmartcardManagerState; typedef struct _CsdSmartcardManagerWorker CsdSmartcardManagerWorker; enum _CsdSmartcardManagerState { CSD_SMARTCARD_MANAGER_STATE_STOPPED = 0, CSD_SMARTCARD_MANAGER_STATE_STARTING, CSD_SMARTCARD_MANAGER_STATE_STARTED, CSD_SMARTCARD_MANAGER_STATE_STOPPING, }; struct _CsdSmartcardManagerPrivate { CsdSmartcardManagerState state; GList *modules; char *module_path; GList *workers; GPid smartcard_event_watcher_pid; GHashTable *smartcards; guint poll_timeout_id; guint32 is_unstoppable : 1; guint32 nss_is_loaded : 1; }; struct _CsdSmartcardManagerWorker { CsdSmartcardManager *manager; int manager_fd; GThread *thread; SECMODModule *module; GHashTable *smartcards; int fd; GSource *event_source; guint32 nss_is_loaded : 1; }; static void csd_smartcard_manager_finalize (GObject *object); static void csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *service_class); static void csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *service_class); static void csd_smartcard_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_smartcard_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_smartcard_manager_set_module_path (CsdSmartcardManager *manager, const char *module_path); static void csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager, CsdSmartcard *card); static void csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager_class, CsdSmartcard *card); static gboolean csd_smartcard_manager_stop_now (CsdSmartcardManager *manager); static void csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager); static CsdSmartcardManagerWorker *csd_smartcard_manager_create_worker (CsdSmartcardManager *manager, SECMODModule *module); static CsdSmartcardManagerWorker * csd_smartcard_manager_worker_new (CsdSmartcardManager *manager, int worker_fd, int manager_fd, SECMODModule *module); static void csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *worker); static gboolean open_pipe (int *write_fd, int *read_fd); static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes); static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes); static CsdSmartcard *read_smartcard (int fd, SECMODModule *module); static gboolean write_smartcard (int fd, CsdSmartcard *card); enum { PROP_0 = 0, PROP_MODULE_PATH, NUMBER_OF_PROPERTIES }; enum { SMARTCARD_INSERTED = 0, SMARTCARD_REMOVED, ERROR, NUMBER_OF_SIGNALS }; static guint csd_smartcard_manager_signals[NUMBER_OF_SIGNALS]; G_DEFINE_TYPE (CsdSmartcardManager, csd_smartcard_manager, G_TYPE_OBJECT); static void csd_smartcard_manager_class_init (CsdSmartcardManagerClass *manager_class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (manager_class); gobject_class->finalize = csd_smartcard_manager_finalize; csd_smartcard_manager_class_install_signals (manager_class); csd_smartcard_manager_class_install_properties (manager_class); g_type_class_add_private (manager_class, sizeof (CsdSmartcardManagerPrivate)); } static void csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *card_class) { GObjectClass *object_class; GParamSpec *param_spec; object_class = G_OBJECT_CLASS (card_class); object_class->set_property = csd_smartcard_manager_set_property; object_class->get_property = csd_smartcard_manager_get_property; param_spec = g_param_spec_string ("module-path", "Module Path", "path to smartcard PKCS #11 driver", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec); } static void csd_smartcard_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object); switch (prop_id) { case PROP_MODULE_PATH: csd_smartcard_manager_set_module_path (manager, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_smartcard_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object); char *module_path; switch (prop_id) { case PROP_MODULE_PATH: module_path = csd_smartcard_manager_get_module_path (manager); g_value_set_string (value, module_path); g_free (module_path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } char * csd_smartcard_manager_get_module_path (CsdSmartcardManager *manager) { return manager->priv->module_path; } static void csd_smartcard_manager_set_module_path (CsdSmartcardManager *manager, const char *module_path) { if ((manager->priv->module_path == NULL) && (module_path == NULL)) { return; } if (((manager->priv->module_path == NULL) || (module_path == NULL) || (strcmp (manager->priv->module_path, module_path) != 0))) { g_free (manager->priv->module_path); manager->priv->module_path = g_strdup (module_path); g_object_notify (G_OBJECT (manager), "module-path"); } } static void csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager, CsdSmartcard *card) { g_debug ("informing smartcard of its removal"); _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); g_debug ("done"); } static void csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager, CsdSmartcard *card) { g_debug ("informing smartcard of its insertion"); _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); g_debug ("done"); } static void csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); csd_smartcard_manager_signals[SMARTCARD_INSERTED] = g_signal_new ("smartcard-inserted", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, smartcard_inserted), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->smartcard_inserted = csd_smartcard_manager_card_inserted_handler; csd_smartcard_manager_signals[SMARTCARD_REMOVED] = g_signal_new ("smartcard-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, smartcard_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->smartcard_removed = csd_smartcard_manager_card_removed_handler; csd_smartcard_manager_signals[ERROR] = g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, error), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->error = NULL; } static gboolean slot_id_equal (CK_SLOT_ID *slot_id_1, CK_SLOT_ID *slot_id_2) { g_assert (slot_id_1 != NULL); g_assert (slot_id_2 != NULL); return *slot_id_1 == *slot_id_2; } static gboolean slot_id_hash (CK_SLOT_ID *slot_id) { guint32 upper_bits, lower_bits; int temp; if (sizeof (CK_SLOT_ID) == sizeof (int)) { return g_int_hash (slot_id); } upper_bits = ((*slot_id) >> 31) - 1; lower_bits = (*slot_id) & 0xffffffff; /* The upper bits are almost certainly always zero, * so let's degenerate to g_int_hash for the * (very) common case */ temp = lower_bits + upper_bits; return upper_bits + g_int_hash (&temp); } static void csd_smartcard_manager_init (CsdSmartcardManager *manager) { g_debug ("initializing smartcard manager"); manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerPrivate); manager->priv->poll_timeout_id = 0; manager->priv->is_unstoppable = FALSE; manager->priv->smartcards = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); } static void csd_smartcard_manager_finalize (GObject *object) { CsdSmartcardManager *manager; GObjectClass *gobject_class; manager = CSD_SMARTCARD_MANAGER (object); gobject_class = G_OBJECT_CLASS (csd_smartcard_manager_parent_class); csd_smartcard_manager_stop_now (manager); g_hash_table_destroy (manager->priv->smartcards); manager->priv->smartcards = NULL; gobject_class->finalize (object); } GQuark csd_smartcard_manager_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) { error_quark = g_quark_from_static_string ("csd-smartcard-manager-error-quark"); } return error_quark; } CsdSmartcardManager * csd_smartcard_manager_new_default (void) { return csd_smartcard_manager_new (NULL); } CsdSmartcardManager * csd_smartcard_manager_new (const char *module_path) { CsdSmartcardManager *instance; instance = CSD_SMARTCARD_MANAGER (g_object_new (CSD_TYPE_SMARTCARD_MANAGER, "module-path", module_path, NULL)); return instance; } static void csd_smartcard_manager_emit_error (CsdSmartcardManager *manager, GError *error) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[ERROR], 0, error); manager->priv->is_unstoppable = FALSE; } static void csd_smartcard_manager_emit_smartcard_inserted (CsdSmartcardManager *manager, CsdSmartcard *card) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_INSERTED], 0, card); manager->priv->is_unstoppable = FALSE; } static void csd_smartcard_manager_emit_smartcard_removed (CsdSmartcardManager *manager, CsdSmartcard *card) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_REMOVED], 0, card); manager->priv->is_unstoppable = FALSE; } static gboolean csd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, GIOCondition condition, CsdSmartcardManagerWorker *worker) { CsdSmartcard *card; CsdSmartcardManager *manager; gboolean should_stop; guchar event_type; char *card_name; int fd; manager = worker->manager; g_debug ("event!"); card = NULL; should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR); if (should_stop) { g_debug ("received %s on event socket, stopping " "manager...", (condition & G_IO_HUP) && (condition & G_IO_ERR)? "error and hangup" : (condition & G_IO_HUP)? "hangup" : "error"); } if (!(condition & G_IO_IN)) { g_debug ("nevermind outta here!"); goto out; } fd = g_io_channel_unix_get_fd (io_channel); event_type = '\0'; if (!read_bytes (fd, &event_type, 1)) { g_debug ("could not read event type, stopping"); should_stop = TRUE; goto out; } card = read_smartcard (fd, worker->module); if (card == NULL) { g_debug ("could not read card, stopping"); should_stop = TRUE; goto out; } card_name = csd_smartcard_get_name (card); g_debug ("card '%s' had event %c", card_name, event_type); switch (event_type) { case 'I': g_hash_table_replace (manager->priv->smartcards, card_name, card); card_name = NULL; csd_smartcard_manager_emit_smartcard_inserted (manager, card); card = NULL; break; case 'R': csd_smartcard_manager_emit_smartcard_removed (manager, card); if (!g_hash_table_remove (manager->priv->smartcards, card_name)) { g_debug ("got removal event of unknown card!"); } g_free (card_name); card_name = NULL; card = NULL; break; default: g_free (card_name); card_name = NULL; g_object_unref (card); should_stop = TRUE; break; } out: if (should_stop) { GError *error; error = g_error_new (CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); csd_smartcard_manager_emit_error (manager, error); g_error_free (error); csd_smartcard_manager_stop_now (manager); return FALSE; } return TRUE; } static void stop_manager (CsdSmartcardManager *manager) { manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STOPPED; if (manager->priv->nss_is_loaded) { NSS_Shutdown (); manager->priv->nss_is_loaded = FALSE; } g_debug ("smartcard manager stopped"); } static void stop_worker (CsdSmartcardManagerWorker *worker) { CsdSmartcardManager *manager; manager = worker->manager; if (worker->event_source != NULL) { g_source_destroy (worker->event_source); worker->event_source = NULL; } if (worker->thread != NULL) { SECMOD_CancelWait (worker->module); worker->thread = NULL; } SECMOD_DestroyModule (worker->module); manager->priv->workers = g_list_remove (manager->priv->workers, worker); if (manager->priv->workers == NULL && manager->priv->state != CSD_SMARTCARD_MANAGER_STATE_STOPPED) { stop_manager (manager); } } static void csd_smartcard_manager_event_processing_stopped_handler (CsdSmartcardManagerWorker *worker) { worker->event_source = NULL; stop_worker (worker); } static gboolean open_pipe (int *write_fd, int *read_fd) { int pipe_fds[2] = { -1, -1 }; g_assert (write_fd != NULL); g_assert (read_fd != NULL); if (pipe (pipe_fds) < 0) { return FALSE; } if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) { close (pipe_fds[0]); close (pipe_fds[1]); return FALSE; } if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) { close (pipe_fds[0]); close (pipe_fds[1]); return FALSE; } *read_fd = pipe_fds[0]; *write_fd = pipe_fds[1]; return TRUE; } static void csd_smartcard_manager_stop_watching_for_events (CsdSmartcardManager *manager) { GList *node; node = manager->priv->workers; while (node != NULL) { CsdSmartcardManagerWorker *worker; GList *next_node; worker = (CsdSmartcardManagerWorker *) node->data; next_node = node->next; stop_worker (worker); node = next_node; } } static gboolean load_nss (GError **error) { SECStatus status = SECSuccess; static const guint32 flags = NSS_INIT_READONLY | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD; g_debug ("attempting to load NSS database '%s'", CSD_SMARTCARD_MANAGER_NSS_DB); PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); status = NSS_Initialize (CSD_SMARTCARD_MANAGER_NSS_DB, "", "", SECMOD_DB, flags); if (status != SECSuccess) { gsize error_message_size; char *error_message; error_message_size = PR_GetErrorTextLength (); if (error_message_size == 0) { g_debug ("NSS security system could not be initialized"); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, _("NSS security system could not be initialized")); goto out; } error_message = g_slice_alloc0 (error_message_size); PR_GetErrorText (error_message); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, "%s", error_message); g_debug ("NSS security system could not be initialized - %s", error_message); g_slice_free1 (error_message_size, error_message); goto out; } g_debug ("NSS database successfully loaded"); return TRUE; out: g_debug ("NSS database couldn't be successfully loaded"); return FALSE; } static GList * get_available_modules (CsdSmartcardManager *manager) { SECMODModuleList *module_list, *tmp; GList *modules; g_debug ("Getting list of suitable modules"); module_list = SECMOD_GetDefaultModuleList (); modules = NULL; for (tmp = module_list; tmp != NULL; tmp = tmp->next) { if (!SECMOD_HasRemovableSlots (tmp->module) || !tmp->module->loaded) continue; g_debug ("Using module '%s'", tmp->module->commonName); modules = g_list_prepend (modules, SECMOD_ReferenceModule (tmp->module)); } return modules; } static gboolean load_driver (CsdSmartcardManager *manager, char *module_path, GError **error) { GList *modules; char *module_spec; gboolean module_explicitly_specified; g_debug ("attempting to load driver..."); modules = NULL; module_explicitly_specified = module_path != NULL; if (module_explicitly_specified) { SECMODModule *module; module_spec = g_strdup_printf ("library=\"%s\"", module_path); g_debug ("loading smartcard driver using spec '%s'", module_spec); module = SECMOD_LoadUserModule (module_spec, NULL /* parent */, FALSE /* recurse */); g_free (module_spec); module_spec = NULL; if (SECMOD_HasRemovableSlots (module) && module->loaded) { modules = g_list_prepend (modules, module); } else { g_debug ("fallback module found but not %s", SECMOD_HasRemovableSlots (module)? "removable" : "loaded"); SECMOD_DestroyModule (module); } } else { SECMODListLock *lock; lock = SECMOD_GetDefaultModuleListLock (); if (lock != NULL) { SECMOD_GetReadLock (lock); modules = get_available_modules (manager); SECMOD_ReleaseReadLock (lock); } /* fallback to compiled in driver path */ if (modules == NULL) { SECMODModule *module; module_path = CSD_SMARTCARD_MANAGER_DRIVER; module_spec = g_strdup_printf ("library=\"%s\"", module_path); g_debug ("loading smartcard driver using spec '%s'", module_spec); module = SECMOD_LoadUserModule (module_spec, NULL /* parent */, FALSE /* recurse */); g_free (module_spec); module_spec = NULL; if (SECMOD_HasRemovableSlots (module) && module->loaded) { modules = g_list_prepend (modules, module); } else { g_debug ("fallback module found but not loaded"); SECMOD_DestroyModule (module); } } } if (!module_explicitly_specified && modules == NULL) { g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, _("no suitable smartcard driver could be found")); } else if (modules == NULL) { gsize error_message_size; char *error_message; error_message_size = PR_GetErrorTextLength (); if (error_message_size == 0) { g_debug ("smartcard driver '%s' could not be loaded", module_path); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, _("smartcard driver '%s' could not be " "loaded"), module_path); goto out; } error_message = g_slice_alloc0 (error_message_size); PR_GetErrorText (error_message); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, "%s", error_message); g_debug ("smartcard driver '%s' could not be loaded - %s", module_path, error_message); g_slice_free1 (error_message_size, error_message); } manager->priv->modules = modules; out: return manager->priv->modules != NULL; } static void csd_smartcard_manager_get_all_cards (CsdSmartcardManager *manager) { GList *node; int i; node = manager->priv->workers; while (node != NULL) { CsdSmartcardManagerWorker *worker; worker = (CsdSmartcardManagerWorker *) node->data; for (i = 0; i < worker->module->slotCount; i++) { CsdSmartcard *card; CK_SLOT_ID slot_id; int slot_series; char *card_name; slot_id = PK11_GetSlotID (worker->module->slots[i]); slot_series = PK11_GetSlotSeries (worker->module->slots[i]); card = _csd_smartcard_new (worker->module, slot_id, slot_series); card_name = csd_smartcard_get_name (card); g_hash_table_replace (manager->priv->smartcards, card_name, card); } node = node->next; } } static CsdSmartcardManagerWorker * start_worker (CsdSmartcardManager *manager, SECMODModule *module, GError **error) { GIOChannel *io_channel; GSource *source; CsdSmartcardManagerWorker *worker; worker = csd_smartcard_manager_create_worker (manager, module); if (worker == NULL) { g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, _("could not watch for incoming card events - %s"), g_strerror (errno)); goto out; } io_channel = g_io_channel_unix_new (worker->manager_fd); source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); g_io_channel_unref (io_channel); io_channel = NULL; worker->event_source = source; g_source_set_callback (worker->event_source, (GSourceFunc) (GIOFunc) csd_smartcard_manager_check_for_and_process_events, worker, (GDestroyNotify) csd_smartcard_manager_event_processing_stopped_handler); g_source_attach (worker->event_source, NULL); g_source_unref (worker->event_source); out: return worker; } static void start_workers (CsdSmartcardManager *manager) { GList *node; node = manager->priv->modules; while (node != NULL) { SECMODModule *module; CsdSmartcardManagerWorker *worker; GError *error; module = (SECMODModule *) node->data; error = NULL; worker = start_worker (manager, module, &error); if (worker == NULL) { g_warning ("%s", error->message); g_error_free (error); } else { manager->priv->workers = g_list_prepend (manager->priv->workers, worker); } node = node->next; } } gboolean csd_smartcard_manager_start (CsdSmartcardManager *manager, GError **error) { GError *nss_error; if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED) { g_debug ("smartcard manager already started"); return TRUE; } manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STARTING; nss_error = NULL; if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) { g_propagate_error (error, nss_error); goto out; } manager->priv->nss_is_loaded = TRUE; if (manager->priv->modules == NULL) { if (!load_driver (manager, manager->priv->module_path, &nss_error)) { g_propagate_error (error, nss_error); goto out; } } start_workers (manager); /* populate the hash with cards that are already inserted */ csd_smartcard_manager_get_all_cards (manager); manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STARTED; out: /* don't leave it in a half started state */ if (manager->priv->state != CSD_SMARTCARD_MANAGER_STATE_STARTED) { g_debug ("smartcard manager could not be completely started"); csd_smartcard_manager_stop (manager); } else { g_debug ("smartcard manager started"); } return manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED; } static gboolean csd_smartcard_manager_stop_now (CsdSmartcardManager *manager) { if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) { return FALSE; } csd_smartcard_manager_stop_watching_for_events (manager); return FALSE; } static void csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager) { manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STOPPING; g_idle_add ((GSourceFunc) csd_smartcard_manager_stop_now, manager); } void csd_smartcard_manager_stop (CsdSmartcardManager *manager) { if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) { return; } if (manager->priv->is_unstoppable) { csd_smartcard_manager_queue_stop (manager); return; } csd_smartcard_manager_stop_now (manager); } static void csd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, CsdSmartcard *card, gboolean *is_inserted) { g_assert (is_inserted != NULL); if (csd_smartcard_is_login_card (card)) { *is_inserted = TRUE; } } gboolean csd_smartcard_manager_login_card_is_inserted (CsdSmartcardManager *manager) { gboolean is_inserted; is_inserted = FALSE; g_hash_table_foreach (manager->priv->smartcards, (GHFunc) csd_smartcard_manager_check_for_login_card, &is_inserted); return is_inserted; } static CsdSmartcardManagerWorker * csd_smartcard_manager_worker_new (CsdSmartcardManager *manager, int worker_fd, int manager_fd, SECMODModule *module) { CsdSmartcardManagerWorker *worker; worker = g_slice_new0 (CsdSmartcardManagerWorker); worker->manager = manager; worker->fd = worker_fd; worker->manager_fd = manager_fd; worker->module = module; worker->smartcards = g_hash_table_new_full ((GHashFunc) slot_id_hash, (GEqualFunc) slot_id_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); return worker; } static void csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *worker) { if (worker->smartcards != NULL) { g_hash_table_destroy (worker->smartcards); worker->smartcards = NULL; } g_slice_free (CsdSmartcardManagerWorker, worker); } static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes) { size_t bytes_left; size_t total_bytes_read; ssize_t bytes_read; bytes_left = (size_t) num_bytes; total_bytes_read = 0; do { bytes_read = read (fd, (char *) bytes + total_bytes_read, bytes_left); g_assert (bytes_read <= (ssize_t) bytes_left); if (bytes_read <= 0) { if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) { continue; } bytes_left = 0; } else { bytes_left -= bytes_read; total_bytes_read += bytes_read; } } while (bytes_left > 0); if (total_bytes_read < (size_t) num_bytes) { return FALSE; } return TRUE; } static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes) { size_t bytes_left; size_t total_bytes_written; ssize_t bytes_written; bytes_left = (size_t) num_bytes; total_bytes_written = 0; do { bytes_written = write (fd, (char *) bytes + total_bytes_written, bytes_left); g_assert (bytes_written <= (ssize_t) bytes_left); if (bytes_written <= 0) { if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) { continue; } bytes_left = 0; } else { bytes_left -= bytes_written; total_bytes_written += bytes_written; } } while (bytes_left > 0); if (total_bytes_written < (size_t) num_bytes) { return FALSE; } return TRUE; } static CsdSmartcard * read_smartcard (int fd, SECMODModule *module) { CsdSmartcard *card; char *card_name; gsize card_name_size; card_name_size = 0; if (!read_bytes (fd, &card_name_size, sizeof (card_name_size))) { return NULL; } card_name = g_slice_alloc0 (card_name_size); if (!read_bytes (fd, card_name, card_name_size)) { g_slice_free1 (card_name_size, card_name); return NULL; } card = _csd_smartcard_new_from_name (module, card_name); g_slice_free1 (card_name_size, card_name); return card; } static gboolean write_smartcard (int fd, CsdSmartcard *card) { gsize card_name_size; char *card_name; card_name = csd_smartcard_get_name (card); card_name_size = strlen (card_name) + 1; if (!write_bytes (fd, &card_name_size, sizeof (card_name_size))) { g_free (card_name); return FALSE; } if (!write_bytes (fd, card_name, card_name_size)) { g_free (card_name); return FALSE; } g_free (card_name); return TRUE; } static gboolean csd_smartcard_manager_worker_emit_smartcard_removed (CsdSmartcardManagerWorker *worker, CsdSmartcard *card, GError **error) { g_debug ("card '%s' removed!", csd_smartcard_get_name (card)); if (!write_bytes (worker->fd, "R", 1)) { goto error_out; } if (!write_smartcard (worker->fd, card)) { goto error_out; } return TRUE; error_out: g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, "%s", g_strerror (errno)); return FALSE; } static gboolean csd_smartcard_manager_worker_emit_smartcard_inserted (CsdSmartcardManagerWorker *worker, CsdSmartcard *card, GError **error) { g_debug ("card '%s' inserted!", csd_smartcard_get_name (card)); if (!write_bytes (worker->fd, "I", 1)) { goto error_out; } if (!write_smartcard (worker->fd, card)) { goto error_out; } return TRUE; error_out: g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, "%s", g_strerror (errno)); return FALSE; } static gboolean csd_smartcard_manager_worker_watch_for_and_process_event (CsdSmartcardManagerWorker *worker, GError **error) { PK11SlotInfo *slot; CK_SLOT_ID slot_id, *key = NULL; int slot_series, card_slot_series; CsdSmartcard *card; GError *processing_error; gboolean ret; g_debug ("waiting for card event"); ret = FALSE; slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); processing_error = NULL; if (slot == NULL) { int error_code; error_code = PORT_GetError (); if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) { g_debug ("spurious event occurred"); return TRUE; } /* FIXME: is there a function to convert from a PORT error * code to a translated string? */ g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, _("encountered unexpected error while " "waiting for smartcard events")); goto out; } /* the slot id and series together uniquely identify a card. * You can never have two cards with the same slot id at the * same time, however (I think), so we can key off of it. */ slot_id = PK11_GetSlotID (slot); slot_series = PK11_GetSlotSeries (slot); /* First check to see if there is a card that we're currently * tracking in the slot. */ key = g_new (CK_SLOT_ID, 1); *key = slot_id; card = g_hash_table_lookup (worker->smartcards, key); if (card != NULL) { card_slot_series = csd_smartcard_get_slot_series (card); } else { card_slot_series = -1; } if (PK11_IsPresent (slot)) { /* Now, check to see if their is a new card in the slot. * If there was a different card in the slot now than * there was before, then we need to emit a removed signal * for the old card (we don't want unpaired insertion events). */ if ((card != NULL) && card_slot_series != slot_series) { if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } card = _csd_smartcard_new (worker->module, slot_id, slot_series); g_hash_table_replace (worker->smartcards, key, card); key = NULL; if (!csd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } else { /* if we aren't tracking the card, just discard the event. * We don't want unpaired remove events. Note on startup * NSS will generate an "insertion" event if a card is * already inserted in the slot. */ if ((card != NULL)) { /* FIXME: i'm not sure about this code. Maybe we * shouldn't do this at all, or maybe we should do it * n times (where n = slot_series - card_slot_series + 1) * * Right now, i'm just doing it once. */ if ((slot_series - card_slot_series) > 1) { if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } g_hash_table_remove (worker->smartcards, key); card = _csd_smartcard_new (worker->module, slot_id, slot_series); g_hash_table_replace (worker->smartcards, key, card); key = NULL; if (!csd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } g_hash_table_remove (worker->smartcards, key); card = NULL; } else { g_debug ("got spurious remove event"); } } ret = TRUE; out: g_free (key); PK11_FreeSlot (slot); return ret; } static void csd_smartcard_manager_worker_run (CsdSmartcardManagerWorker *worker) { GError *error; gboolean should_continue; do { error = NULL; should_continue = csd_smartcard_manager_worker_watch_for_and_process_event (worker, &error); } while (should_continue); if (error != NULL) { g_debug ("could not process card event - %s", error->message); g_error_free (error); } csd_smartcard_manager_worker_free (worker); } static CsdSmartcardManagerWorker * csd_smartcard_manager_create_worker (CsdSmartcardManager *manager, SECMODModule *module) { CsdSmartcardManagerWorker *worker; int write_fd, read_fd; write_fd = -1; read_fd = -1; if (!open_pipe (&write_fd, &read_fd)) { return NULL; } worker = csd_smartcard_manager_worker_new (manager, write_fd, read_fd, module); worker->thread = g_thread_create ((GThreadFunc) csd_smartcard_manager_worker_run, worker, FALSE, NULL); if (worker->thread == NULL) { csd_smartcard_manager_worker_free (worker); return NULL; } return worker; } #ifdef CSD_SMARTCARD_MANAGER_ENABLE_TEST #include static GMainLoop *event_loop; static gboolean should_exit_on_next_remove = FALSE; static gboolean on_timeout (CsdSmartcardManager *manager) { GError *error; g_print ("Re-enabling manager.\n"); if (!csd_smartcard_manager_start (manager, &error)) { g_warning ("could not start smartcard manager - %s", error->message); g_error_free (error); return TRUE; } g_print ("Please re-insert smartcard\n"); should_exit_on_next_remove = TRUE; return FALSE; } static void on_device_inserted (CsdSmartcardManager *manager, CsdSmartcard *card) { g_print ("smartcard inserted!\n"); g_print ("Please remove it.\n"); } static void on_device_removed (CsdSmartcardManager *manager, CsdSmartcard *card) { g_print ("smartcard removed!\n"); if (should_exit_on_next_remove) { g_main_loop_quit (event_loop); } else { g_print ("disabling manager for 2 seconds\n"); csd_smartcard_manager_stop (manager); g_timeout_add_seconds (2, (GSourceFunc) on_timeout, manager); } } int main (int argc, char *argv[]) { CsdSmartcardManager *manager; GError *error; g_log_set_always_fatal (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); g_message ("creating instance of 'smartcard manager' object..."); manager = csd_smartcard_manager_new (NULL); g_message ("'smartcard manager' object created successfully"); g_signal_connect (manager, "smartcard-inserted", G_CALLBACK (on_device_inserted), NULL); g_signal_connect (manager, "smartcard-removed", G_CALLBACK (on_device_removed), NULL); g_message ("starting listener..."); error = NULL; if (!csd_smartcard_manager_start (manager, &error)) { g_warning ("could not start smartcard manager - %s", error->message); g_error_free (error); return 1; } event_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (event_loop); g_main_loop_unref (event_loop); event_loop = NULL; g_message ("destroying previously created 'smartcard manager' object..."); g_object_unref (manager); manager = NULL; g_message ("'smartcard manager' object destroyed successfully"); return 0; } #endif cinnamon-settings-daemon-4.4.0/plugins/smartcard/csd-smartcard-manager.h000066400000000000000000000071631356401377300264110ustar00rootroot00000000000000/* csd-smartcard-manager.h - object for monitoring smartcard insertion and * removal events * * Copyright (C) 2006, 2009 Red Hat, 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Written by: Ray Strode */ #ifndef CSD_SMARTCARD_MANAGER_H #define CSD_SMARTCARD_MANAGER_H #define CSD_SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include G_BEGIN_DECLS #define CSD_TYPE_SMARTCARD_MANAGER (csd_smartcard_manager_get_type ()) #define CSD_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManager)) #define CSD_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerClass)) #define CSD_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER)) #define CSD_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER)) #define CSD_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerClass)) #define CSD_SMARTCARD_MANAGER_ERROR (csd_smartcard_manager_error_quark ()) typedef struct _CsdSmartcardManager CsdSmartcardManager; typedef struct _CsdSmartcardManagerClass CsdSmartcardManagerClass; typedef struct _CsdSmartcardManagerPrivate CsdSmartcardManagerPrivate; typedef enum _CsdSmartcardManagerError CsdSmartcardManagerError; struct _CsdSmartcardManager { GObject parent; /*< private > */ CsdSmartcardManagerPrivate *priv; }; struct _CsdSmartcardManagerClass { GObjectClass parent_class; /* Signals */ void (*smartcard_inserted) (CsdSmartcardManager *manager, CsdSmartcard *token); void (*smartcard_removed) (CsdSmartcardManager *manager, CsdSmartcard *token); void (*error) (CsdSmartcardManager *manager, GError *error); }; enum _CsdSmartcardManagerError { CSD_SMARTCARD_MANAGER_ERROR_GENERIC = 0, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS }; GType csd_smartcard_manager_get_type (void) G_GNUC_CONST; GQuark csd_smartcard_manager_error_quark (void) G_GNUC_CONST; CsdSmartcardManager *csd_smartcard_manager_new_default (void); CsdSmartcardManager *csd_smartcard_manager_new (const char *module); gboolean csd_smartcard_manager_start (CsdSmartcardManager *manager, GError **error); void csd_smartcard_manager_stop (CsdSmartcardManager *manager); char *csd_smartcard_manager_get_module_path (CsdSmartcardManager *manager); gboolean csd_smartcard_manager_login_card_is_inserted (CsdSmartcardManager *manager); G_END_DECLS #endif /* CSD_SMARTCARD_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/smartcard/csd-smartcard.c000066400000000000000000000442431356401377300247740ustar00rootroot00000000000000/* csd-smartcard.c - smartcard object * * Copyright (C) 2006 Ray Strode * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #define CSD_SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include #include #include #include #include #include #include #include #include #include struct _CsdSmartcardPrivate { SECMODModule *module; CsdSmartcardState state; CK_SLOT_ID slot_id; int slot_series; PK11SlotInfo *slot; char *name; CERTCertificate *signing_certificate; CERTCertificate *encryption_certificate; }; static void csd_smartcard_finalize (GObject *object); static void csd_smartcard_class_install_signals (CsdSmartcardClass *card_class); static void csd_smartcard_class_install_properties (CsdSmartcardClass *card_class); static void csd_smartcard_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_smartcard_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_smartcard_set_name (CsdSmartcard *card, const char *name); static void csd_smartcard_set_slot_id (CsdSmartcard *card, int slot_id); static void csd_smartcard_set_slot_series (CsdSmartcard *card, int slot_series); static void csd_smartcard_set_module (CsdSmartcard *card, SECMODModule *module); static PK11SlotInfo *csd_smartcard_find_slot_from_id (CsdSmartcard *card, int slot_id); static PK11SlotInfo *csd_smartcard_find_slot_from_card_name (CsdSmartcard *card, const char *card_name); #ifndef CSD_SMARTCARD_DEFAULT_SLOT_ID #define CSD_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1) #endif #ifndef CSD_SMARTCARD_DEFAULT_SLOT_SERIES #define CSD_SMARTCARD_DEFAULT_SLOT_SERIES -1 #endif enum { PROP_0 = 0, PROP_NAME, PROP_SLOT_ID, PROP_SLOT_SERIES, PROP_MODULE, NUMBER_OF_PROPERTIES }; enum { INSERTED, REMOVED, NUMBER_OF_SIGNALS }; static guint csd_smartcard_signals[NUMBER_OF_SIGNALS]; G_DEFINE_TYPE (CsdSmartcard, csd_smartcard, G_TYPE_OBJECT); static void csd_smartcard_class_init (CsdSmartcardClass *card_class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (card_class); gobject_class->finalize = csd_smartcard_finalize; csd_smartcard_class_install_signals (card_class); csd_smartcard_class_install_properties (card_class); g_type_class_add_private (card_class, sizeof (CsdSmartcardPrivate)); } static void csd_smartcard_class_install_signals (CsdSmartcardClass *card_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (card_class); csd_smartcard_signals[INSERTED] = g_signal_new ("inserted", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardClass, inserted), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); csd_smartcard_signals[REMOVED] = g_signal_new ("removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardClass, removed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void csd_smartcard_class_install_properties (CsdSmartcardClass *card_class) { GObjectClass *object_class; GParamSpec *param_spec; object_class = G_OBJECT_CLASS (card_class); object_class->set_property = csd_smartcard_set_property; object_class->get_property = csd_smartcard_get_property; param_spec = g_param_spec_ulong ("slot-id", "Slot ID", "The slot the card is in", 1, G_MAXULONG, CSD_SMARTCARD_DEFAULT_SLOT_ID, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec); param_spec = g_param_spec_int ("slot-series", "Slot Series", "per-slot card identifier", -1, G_MAXINT, CSD_SMARTCARD_DEFAULT_SLOT_SERIES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec); param_spec = g_param_spec_string ("name", "name", "name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_NAME, param_spec); param_spec = g_param_spec_pointer ("module", "Module", "smartcard driver", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_MODULE, param_spec); } static void csd_smartcard_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdSmartcard *card = CSD_SMARTCARD (object); switch (prop_id) { case PROP_NAME: csd_smartcard_set_name (card, g_value_get_string (value)); break; case PROP_SLOT_ID: csd_smartcard_set_slot_id (card, g_value_get_ulong (value)); break; case PROP_SLOT_SERIES: csd_smartcard_set_slot_series (card, g_value_get_int (value)); break; case PROP_MODULE: csd_smartcard_set_module (card, (SECMODModule *) g_value_get_pointer (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } CK_SLOT_ID csd_smartcard_get_slot_id (CsdSmartcard *card) { return card->priv->slot_id; } CsdSmartcardState csd_smartcard_get_state (CsdSmartcard *card) { return card->priv->state; } char * csd_smartcard_get_name (CsdSmartcard *card) { return g_strdup (card->priv->name); } gboolean csd_smartcard_is_login_card (CsdSmartcard *card) { const char *login_card_name; login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME"); if ((login_card_name == NULL) || (card->priv->name == NULL)) { return FALSE; } if (strcmp (card->priv->name, login_card_name) == 0) { return TRUE; } return FALSE; } static void csd_smartcard_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdSmartcard *card = CSD_SMARTCARD (object); switch (prop_id) { case PROP_NAME: g_value_take_string (value, csd_smartcard_get_name (card)); break; case PROP_SLOT_ID: g_value_set_ulong (value, (gulong) csd_smartcard_get_slot_id (card)); break; case PROP_SLOT_SERIES: g_value_set_int (value, csd_smartcard_get_slot_series (card)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_smartcard_set_name (CsdSmartcard *card, const char *name) { if (name == NULL) { return; } if ((card->priv->name == NULL) || (strcmp (card->priv->name, name) != 0)) { g_free (card->priv->name); card->priv->name = g_strdup (name); if (card->priv->slot == NULL) { card->priv->slot = csd_smartcard_find_slot_from_card_name (card, card->priv->name); if (card->priv->slot != NULL) { int slot_id, slot_series; slot_id = PK11_GetSlotID (card->priv->slot); if (slot_id != card->priv->slot_id) { csd_smartcard_set_slot_id (card, slot_id); } slot_series = PK11_GetSlotSeries (card->priv->slot); if (slot_series != card->priv->slot_series) { csd_smartcard_set_slot_series (card, slot_series); } _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); } else { _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); } } g_object_notify (G_OBJECT (card), "name"); } } static void csd_smartcard_set_slot_id (CsdSmartcard *card, int slot_id) { if (card->priv->slot_id != slot_id) { card->priv->slot_id = slot_id; if (card->priv->slot == NULL) { card->priv->slot = csd_smartcard_find_slot_from_id (card, card->priv->slot_id); if (card->priv->slot != NULL) { const char *card_name; card_name = PK11_GetTokenName (card->priv->slot); if ((card->priv->name == NULL) || ((card_name != NULL) && (strcmp (card_name, card->priv->name) != 0))) { csd_smartcard_set_name (card, card_name); } _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); } else { _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); } } g_object_notify (G_OBJECT (card), "slot-id"); } } static void csd_smartcard_set_slot_series (CsdSmartcard *card, int slot_series) { if (card->priv->slot_series != slot_series) { card->priv->slot_series = slot_series; g_object_notify (G_OBJECT (card), "slot-series"); } } static void csd_smartcard_set_module (CsdSmartcard *card, SECMODModule *module) { gboolean should_notify; if (card->priv->module != module) { should_notify = TRUE; } else { should_notify = FALSE; } if (card->priv->module != NULL) { SECMOD_DestroyModule (card->priv->module); card->priv->module = NULL; } if (module != NULL) { card->priv->module = SECMOD_ReferenceModule (module); } if (should_notify) { g_object_notify (G_OBJECT (card), "module"); } } int csd_smartcard_get_slot_series (CsdSmartcard *card) { return card->priv->slot_series; } static void csd_smartcard_init (CsdSmartcard *card) { g_debug ("initializing smartcard "); card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card, CSD_TYPE_SMARTCARD, CsdSmartcardPrivate); } static void csd_smartcard_finalize (GObject *object) { CsdSmartcard *card; GObjectClass *gobject_class; card = CSD_SMARTCARD (object); g_free (card->priv->name); csd_smartcard_set_module (card, NULL); gobject_class = G_OBJECT_CLASS (csd_smartcard_parent_class); gobject_class->finalize (object); } GQuark csd_smartcard_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) { error_quark = g_quark_from_static_string ("csd-smartcard-error-quark"); } return error_quark; } CsdSmartcard * _csd_smartcard_new (SECMODModule *module, CK_SLOT_ID slot_id, int slot_series) { CsdSmartcard *card; g_return_val_if_fail (module != NULL, NULL); g_return_val_if_fail (slot_id >= 1, NULL); g_return_val_if_fail (slot_series > 0, NULL); g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL); card = CSD_SMARTCARD (g_object_new (CSD_TYPE_SMARTCARD, "module", module, "slot-id", (gulong) slot_id, "slot-series", slot_series, NULL)); return card; } CsdSmartcard * _csd_smartcard_new_from_name (SECMODModule *module, const char *name) { CsdSmartcard *card; g_return_val_if_fail (module != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); card = CSD_SMARTCARD (g_object_new (CSD_TYPE_SMARTCARD, "module", module, "name", name, NULL)); return card; } void _csd_smartcard_set_state (CsdSmartcard *card, CsdSmartcardState state) { /* csd_smartcard_fetch_certificates (card); */ if (card->priv->state != state) { card->priv->state = state; if (state == CSD_SMARTCARD_STATE_INSERTED) { g_signal_emit (card, csd_smartcard_signals[INSERTED], 0); } else if (state == CSD_SMARTCARD_STATE_REMOVED) { g_signal_emit (card, csd_smartcard_signals[REMOVED], 0); } else { g_assert_not_reached (); } } } /* So we could conceivably make the closure data a pointer to the card * or something similar and then emit signals when we want passwords, * but it's probably easier to just get the password up front and use * it. So we just take the passed in g_malloc'd (well probably, who knows) * and strdup it using NSPR's memory allocation routines. */ static char * csd_smartcard_password_handler (PK11SlotInfo *slot, PRBool is_retrying, const char *password) { if (is_retrying) { return NULL; } return password != NULL? PL_strdup (password): NULL; } gboolean csd_smartcard_unlock (CsdSmartcard *card, const char *password) { SECStatus status; PK11_SetPasswordFunc ((PK11PasswordFunc) csd_smartcard_password_handler); /* we pass PR_TRUE to load certificates */ status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password); if (status != SECSuccess) { g_debug ("could not unlock card - %d", status); return FALSE; } return TRUE; } static PK11SlotInfo * csd_smartcard_find_slot_from_card_name (CsdSmartcard *card, const char *card_name) { int i; for (i = 0; i < card->priv->module->slotCount; i++) { const char *slot_card_name; slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]); if ((slot_card_name != NULL) && (strcmp (slot_card_name, card_name) == 0)) { return card->priv->module->slots[i]; } } return NULL; } static PK11SlotInfo * csd_smartcard_find_slot_from_id (CsdSmartcard *card, int slot_id) { int i; for (i = 0; i < card->priv->module->slotCount; i++) { if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) { return card->priv->module->slots[i]; } } return NULL; } cinnamon-settings-daemon-4.4.0/plugins/smartcard/csd-smartcard.h000066400000000000000000000065651356401377300250060ustar00rootroot00000000000000/* securitycard.h - api for reading and writing data to a security card * * Copyright (C) 2006 Ray Strode * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef CSD_SMARTCARD_H #define CSD_SMARTCARD_H #include #include #include G_BEGIN_DECLS #define CSD_TYPE_SMARTCARD (csd_smartcard_get_type ()) #define CSD_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_SMARTCARD, CsdSmartcard)) #define CSD_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_SMARTCARD, CsdSmartcardClass)) #define CSD_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_SMARTCARD)) #define CSD_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_SMARTCARD)) #define CSD_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSD_TYPE_SMARTCARD, CsdSmartcardClass)) #define CSD_SMARTCARD_ERROR (csd_smartcard_error_quark ()) typedef struct _CsdSmartcardClass CsdSmartcardClass; typedef struct _CsdSmartcard CsdSmartcard; typedef struct _CsdSmartcardPrivate CsdSmartcardPrivate; typedef enum _CsdSmartcardError CsdSmartcardError; typedef enum _CsdSmartcardState CsdSmartcardState; typedef struct _CsdSmartcardRequest CsdSmartcardRequest; struct _CsdSmartcard { GObject parent; /*< private > */ CsdSmartcardPrivate *priv; }; struct _CsdSmartcardClass { GObjectClass parent_class; void (* inserted) (CsdSmartcard *card); void (* removed) (CsdSmartcard *card); }; enum _CsdSmartcardError { CSD_SMARTCARD_ERROR_GENERIC = 0, }; enum _CsdSmartcardState { CSD_SMARTCARD_STATE_INSERTED = 0, CSD_SMARTCARD_STATE_REMOVED, }; GType csd_smartcard_get_type (void) G_GNUC_CONST; GQuark csd_smartcard_error_quark (void) G_GNUC_CONST; CK_SLOT_ID csd_smartcard_get_slot_id (CsdSmartcard *card); gint csd_smartcard_get_slot_series (CsdSmartcard *card); CsdSmartcardState csd_smartcard_get_state (CsdSmartcard *card); char *csd_smartcard_get_name (CsdSmartcard *card); gboolean csd_smartcard_is_login_card (CsdSmartcard *card); gboolean csd_smartcard_unlock (CsdSmartcard *card, const char *password); /* don't under any circumstances call these functions */ #ifdef CSD_SMARTCARD_ENABLE_INTERNAL_API CsdSmartcard *_csd_smartcard_new (SECMODModule *module, CK_SLOT_ID slot_id, gint slot_series); CsdSmartcard *_csd_smartcard_new_from_name (SECMODModule *module, const char *name); void _csd_smartcard_set_state (CsdSmartcard *card, CsdSmartcardState state); #endif G_END_DECLS #endif /* CSD_SMARTCARD_H */ cinnamon-settings-daemon-4.4.0/plugins/smartcard/main.c000066400000000000000000000010411356401377300231560ustar00rootroot00000000000000#define NEW csd_smartcard_manager_new_default #define START csd_smartcard_manager_start #define STOP csd_smartcard_manager_stop #define MANAGER CsdSmartcardManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-smartcard-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/sound/000077500000000000000000000000001356401377300212425ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/sound/Makefile.am000066400000000000000000000017361356401377300233050ustar00rootroot00000000000000plugin_name = sound AM_CFLAGS = $(WARN_CFLAGS) libexec_PROGRAMS = csd-sound csd_sound_SOURCES = \ csd-sound-manager.h \ csd-sound-manager.c \ main.c csd_sound_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(SOUND_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_sound_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SOUND_LIBS) \ $(SETTINGS_PLUGIN_LIBS) desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-sound.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-sound.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST = \ $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) DISTCLEANFILES = \ $(desktop_DATA) cinnamon-settings-daemon-4.4.0/plugins/sound/cinnamon-settings-daemon-sound.desktop.in000066400000000000000000000003471356401377300312750ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - sound Exec=@libexecdir@/csd-sound OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-4.4.0/plugins/sound/csd-sound-manager.c000066400000000000000000000512031356401377300247160ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Lennart Poettering * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "csd-sound-manager.h" #include "cinnamon-settings-profile.h" #define CSD_SOUND_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerPrivate)) #define SOUND_HANDLER_DBUS_PATH "/org/cinnamon/SettingsDaemon/Sound" #define SOUND_HANDLER_DBUS_NAME "org.cinnamon.SettingsDaemon.Sound" #define PLAY_ONCE_FLAG 8675309 static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; struct CsdSoundManagerPrivate { GSettings *settings; guint name_id; GList *monitors; guint timeout; GDBusNodeInfo *idata; ca_context *ca; GCancellable *bus_cancellable; GDBusConnection *connection; /* DBus users pass an ID with the sound string * We can use this as a flag also to denote a sound * that we only ever want played once (i.e. initial desktop * welcome sound) */ GList *onetime_sounds; }; static void csd_sound_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdSoundManager, csd_sound_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean should_play (CsdSoundManager *manager, guint id, const gchar *str) { if (id != PLAY_ONCE_FLAG) return TRUE; GList *l; gboolean already_ran = FALSE; for (l = manager->priv->onetime_sounds; l; l = l->next) { if (g_strcmp0 (l->data, str) == 0) { already_ran = TRUE; break; } } if (!already_ran) { manager->priv->onetime_sounds = g_list_prepend (manager->priv->onetime_sounds, g_strdup (str)); } return !already_ran; } static void handle_sound_request (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { CsdSoundManager *manager = (CsdSoundManager *) user_data; g_debug ("Calling method '%s' for sound", method_name); if (g_strcmp0 (method_name, "PlaySound") == 0) { const char *sound_name; guint id; g_variant_get (parameters, "(u&s)", &id, &sound_name); if (should_play (manager, id, sound_name)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_EVENT_ID, sound_name, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundWithChannel") == 0) { const char *sound_name; const char *channel_name; guint id; g_variant_get (parameters, "(u&s&s)", &id, &sound_name, &channel_name); if (should_play (manager, id, sound_name)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_EVENT_ID, sound_name, CA_PROP_MEDIA_ROLE, "test", CA_PROP_CANBERRA_FORCE_CHANNEL, channel_name, NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundFile") == 0) { const char *sound_file; guint id; g_variant_get (parameters, "(u&s)", &id, &sound_file); if (should_play (manager, id, sound_file)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_MEDIA_FILENAME, sound_file, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundFileVolume") == 0) { const char *sound_file; guint id; const char *volume; g_variant_get (parameters, "(u&s&s)", &id, &sound_file, &volume); if (should_play (manager, id, sound_file)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_MEDIA_FILENAME, sound_file, CA_PROP_CANBERRA_VOLUME, volume, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "CancelSound") == 0) { guint id; g_variant_get (parameters, "(u)", &id); ca_context_cancel (manager->priv->ca, id); g_dbus_method_invocation_return_value (invocation, NULL); } } static const GDBusInterfaceVTable interface_vtable = { handle_sound_request, NULL, /* Get Property */ NULL, /* Set Property */ }; static void sample_info_cb (pa_context *c, const pa_sample_info *i, int eol, void *userdata) { pa_operation *o; if (!i) return; g_debug ("Found sample %s", i->name); /* We only flush those samples which have an XDG sound name * attached, because only those originate from themeing */ if (!(pa_proplist_gets (i->proplist, PA_PROP_EVENT_ID))) return; g_debug ("Dropping sample %s from cache", i->name); if (!(o = pa_context_remove_sample (c, i->name, NULL, NULL))) { g_debug ("pa_context_remove_sample (): %s", pa_strerror (pa_context_errno (c))); return; } pa_operation_unref (o); /* We won't wait until the operation is actually executed to * speed things up a bit.*/ } static void flush_cache (void) { pa_mainloop *ml = NULL; pa_context *c = NULL; pa_proplist *pl = NULL; pa_operation *o = NULL; g_debug ("Flushing sample cache"); if (!(ml = pa_mainloop_new ())) { g_debug ("Failed to allocate pa_mainloop"); goto fail; } if (!(pl = pa_proplist_new ())) { g_debug ("Failed to allocate pa_proplist"); goto fail; } pa_proplist_sets (pl, PA_PROP_APPLICATION_NAME, PACKAGE_NAME); pa_proplist_sets (pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); pa_proplist_sets (pl, PA_PROP_APPLICATION_ID, "org.cinnamon.SettingsDaemon.Sound"); if (!(c = pa_context_new_with_proplist (pa_mainloop_get_api (ml), PACKAGE_NAME, pl))) { g_debug ("Failed to allocate pa_context"); goto fail; } pa_proplist_free (pl); pl = NULL; if (pa_context_connect (c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { g_debug ("pa_context_connect(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until the connection is established */ while (pa_context_get_state (c) != PA_CONTEXT_READY) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { g_debug ("pa_mainloop_iterate() failed"); goto fail; } } /* Enumerate all cached samples */ if (!(o = pa_context_get_sample_info_list (c, sample_info_cb, NULL))) { g_debug ("pa_context_get_sample_info_list(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until our operation is finished and there's nothing * more queued to send to the server */ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING || pa_context_is_pending (c)) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { g_debug ("pa_mainloop_iterate() failed"); goto fail; } } g_debug ("Sample cache flushed"); fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } if (c) { pa_context_disconnect (c); pa_context_unref (c); } if (pl) pa_proplist_free (pl); if (ml) pa_mainloop_free (ml); } static gboolean flush_cb (CsdSoundManager *manager) { flush_cache (); manager->priv->timeout = 0; return FALSE; } static void trigger_flush (CsdSoundManager *manager) { if (manager->priv->timeout) { g_source_remove (manager->priv->timeout); manager->priv->timeout = 0; } /* We delay the flushing a bit so that we can coalesce * multiple changes into a single cache flush */ manager->priv->timeout = g_timeout_add (500, (GSourceFunc) flush_cb, manager); } static void settings_changed_cb (GSettings *settings, const char *key, CsdSoundManager *manager) { trigger_flush (manager); } static void register_config_callback (CsdSoundManager *manager) { manager->priv->settings = g_settings_new ("org.cinnamon.desktop.sound"); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (settings_changed_cb), manager); } static void file_monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, CsdSoundManager *manager) { g_debug ("Theme dir changed"); trigger_flush (manager); } static gboolean register_directory_callback (CsdSoundManager *manager, const char *path, GError **error) { GFile *f; GFileMonitor *m; gboolean succ = FALSE; g_debug ("Registering directory monitor for %s", path); f = g_file_new_for_path (path); m = g_file_monitor_directory (f, 0, NULL, error); if (m != NULL) { g_signal_connect (m, "changed", G_CALLBACK (file_monitor_changed_cb), manager); manager->priv->monitors = g_list_prepend (manager->priv->monitors, m); succ = TRUE; } g_object_unref (f); return succ; } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdSoundManager *manager) { GDBusConnection *connection; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; g_dbus_connection_register_object (connection, SOUND_HANDLER_DBUS_PATH, manager->priv->idata->interfaces[0], &interface_vtable, manager, NULL, NULL); manager->priv->name_id = g_bus_own_name_on_connection (connection, SOUND_HANDLER_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); } gboolean csd_sound_manager_start (CsdSoundManager *manager, GError **error) { char *p, **ps, **k; const char *env, *dd; g_debug ("Starting sound manager"); cinnamon_settings_profile_start (NULL); /* We listen for change of the selected theme ... */ register_config_callback (manager); /* ... and we listen to changes of the theme base directories * in $HOME ...*/ if ((env = g_getenv ("XDG_DATA_HOME")) && *env == '/') p = g_build_filename (env, "sounds", NULL); else if (((env = g_getenv ("HOME")) && *env == '/') || (env = g_get_home_dir ())) p = g_build_filename (env, ".local", "share", "sounds", NULL); else p = NULL; if (p) { register_directory_callback (manager, p, NULL); g_free (p); } /* ... and globally. */ if (!(dd = g_getenv ("XDG_DATA_DIRS")) || *dd == 0) dd = "/usr/local/share:/usr/share"; ps = g_strsplit (dd, ":", 0); for (k = ps; *k; ++k) register_directory_callback (manager, *k, NULL); g_strfreev (ps); manager->priv->onetime_sounds = NULL; /* Sound events */ ca_context_create (&manager->priv->ca); ca_context_set_driver (manager->priv->ca, "pulse"); ca_context_change_props (manager->priv->ca, 0, CA_PROP_APPLICATION_ID, "org.Cinnamon.Sound", NULL); manager->priv->idata = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->idata != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_sound_manager_stop (CsdSoundManager *manager) { g_debug ("Stopping sound manager"); if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->timeout) { g_source_remove (manager->priv->timeout); manager->priv->timeout = 0; } if (manager->priv->bus_cancellable != NULL) { g_cancellable_cancel (manager->priv->bus_cancellable); g_object_unref (manager->priv->bus_cancellable); manager->priv->bus_cancellable = NULL; } if (manager->priv->idata) { g_dbus_node_info_unref (manager->priv->idata); manager->priv->idata = NULL; } if (manager->priv->ca) { ca_context_destroy (manager->priv->ca); manager->priv->ca = NULL; } if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->onetime_sounds != NULL) { g_list_free_full (manager->priv->onetime_sounds, g_free); manager->priv->onetime_sounds = NULL; } while (manager->priv->monitors) { g_file_monitor_cancel (G_FILE_MONITOR (manager->priv->monitors->data)); g_object_unref (manager->priv->monitors->data); manager->priv->monitors = g_list_delete_link (manager->priv->monitors, manager->priv->monitors); } } static void csd_sound_manager_dispose (GObject *object) { CsdSoundManager *manager; manager = CSD_SOUND_MANAGER (object); csd_sound_manager_stop (manager); G_OBJECT_CLASS (csd_sound_manager_parent_class)->dispose (object); } static void csd_sound_manager_class_init (CsdSoundManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = csd_sound_manager_dispose; object_class->finalize = csd_sound_manager_finalize; g_type_class_add_private (klass, sizeof (CsdSoundManagerPrivate)); } static void csd_sound_manager_init (CsdSoundManager *manager) { manager->priv = CSD_SOUND_MANAGER_GET_PRIVATE (manager); } static void csd_sound_manager_finalize (GObject *object) { CsdSoundManager *sound_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SOUND_MANAGER (object)); sound_manager = CSD_SOUND_MANAGER (object); g_return_if_fail (sound_manager->priv); if (sound_manager->priv->name_id != 0) g_bus_unown_name (sound_manager->priv->name_id); G_OBJECT_CLASS (csd_sound_manager_parent_class)->finalize (object); } CsdSoundManager * csd_sound_manager_new (void) { if (manager_object) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_SOUND_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_SOUND_MANAGER (manager_object); } cinnamon-settings-daemon-4.4.0/plugins/sound/csd-sound-manager.h000066400000000000000000000041231356401377300247220ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Lennart Poettering * * 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 __CSD_SOUND_MANAGER_H #define __CSD_SOUND_MANAGER_H #include #include G_BEGIN_DECLS #define CSD_TYPE_SOUND_MANAGER (csd_sound_manager_get_type ()) #define CSD_SOUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManager)) #define CSD_SOUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerClass)) #define CSD_IS_SOUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SOUND_MANAGER)) #define CSD_IS_SOUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SOUND_MANAGER)) #define CSD_SOUND_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerClass)) typedef struct CsdSoundManagerPrivate CsdSoundManagerPrivate; typedef struct { GObject parent; CsdSoundManagerPrivate *priv; } CsdSoundManager; typedef struct { GObjectClass parent_class; } CsdSoundManagerClass; GType csd_sound_manager_get_type (void) G_GNUC_CONST; CsdSoundManager *csd_sound_manager_new (void); gboolean csd_sound_manager_start (CsdSoundManager *manager, GError **error); void csd_sound_manager_stop (CsdSoundManager *manager); G_END_DECLS #endif /* __CSD_SOUND_MANAGER_H */ cinnamon-settings-daemon-4.4.0/plugins/sound/main.c000066400000000000000000000010051356401377300223260ustar00rootroot00000000000000#define NEW csd_sound_manager_new #define START csd_sound_manager_start #define STOP csd_sound_manager_stop #define MANAGER CsdSoundManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-sound-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-4.4.0/plugins/wacom/000077500000000000000000000000001356401377300212205ustar00rootroot00000000000000cinnamon-settings-daemon-4.4.0/plugins/wacom/Makefile.am000066400000000000000000000102041356401377300232510ustar00rootroot00000000000000plugin_name = wacom org.cinnamon.settings-daemon.plugins.wacom.policy.in: org.cinnamon.settings-daemon.plugins.wacom.policy.in.in Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ csd-wacom-resources.c: wacom.gresource.xml tablet-layout.css glib-compile-resources \ --target=$@ \ --sourcedir=$(srcdir) \ --generate-source \ --c-name csd_wacom \ $(srcdir)/wacom.gresource.xml @INTLTOOL_POLICY_RULE@ polkit_policydir = $(datadir)/polkit-1/actions polkit_policy_in_files = org.cinnamon.settings-daemon.plugins.wacom.policy.in polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy) # so it always gets included in the tarball csd_wacom_led_helper_SOURCES = csd-wacom-led-helper.c EXTRA_DIST = $(csd_wacom_led_helper_SOURCES) wacom.gresource.xml tablet-layout.css if HAVE_GUDEV libexec_PROGRAMS = csd-wacom-led-helper csd_wacom_led_helper_LDFLAGS = \ $(WARN_LDFLAGS) \ $(BACKLIGHT_HELPER_LIBS) \ -lm csd_wacom_led_helper_CFLAGS = \ $(WARN_CFLAGS) \ $(BACKLIGHT_HELPER_CFLAGS) else libexec_PROGRAMS = endif EXTRA_DIST += org.cinnamon.settings-daemon.plugins.wacom.policy.in.in libexec_PROGRAMS += csd-wacom csd-list-wacom csd-wacom-osd csd_wacom_SOURCES = \ main.c \ csd-wacom-manager.c \ csd-wacom-manager.h \ csd-wacom-osd-window.h \ csd-wacom-osd-window.c \ csd-wacom-device.c \ csd-wacom-device.h \ csd-wacom-resources.c csd_wacom_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_wacom_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) csd_wacom_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm csd_list_wacom_SOURCES = \ list-wacom.c \ csd-wacom-device.c \ csd-wacom-device.h csd_list_wacom_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_list_wacom_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) csd_list_wacom_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm csd_wacom_osd_SOURCES = \ test-osd-window.c \ csd-wacom-osd-window.h \ csd-wacom-osd-window.c \ csd-wacom-device.c \ csd-wacom-device.h \ csd-wacom-resources.c csd_wacom_osd_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_wacom_osd_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) csd_wacom_osd_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm desktopdir = $(sysconfdir)/xdg/autostart desktop_in_files = cinnamon-settings-daemon-wacom.desktop.in desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) cinnamon-settings-daemon-wacom.desktop: $(desktop_in_files) Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ EXTRA_DIST += README.config-storage $(desktop_in_files) CLEANFILES = \ $(desktop_DATA) \ csd-wacom-resources.c \ org.cinnamon.settings-daemon.plugins.wacom.policy \ org.cinnamon.settings-daemon.plugins.wacom.policy.in cinnamon-settings-daemon-4.4.0/plugins/wacom/README.config-storage000066400000000000000000000032621356401377300250110ustar00rootroot00000000000000Configuration storage for Wacom tablets and styli Tablets ------- Configuration is stored on a per-device model basis, meaning that it's possible to use the same device, with same configuration on 2 machines with a shared home directory, or replace a malfunctioning device with the same model and have the same configuration. It does not allow having 2 separate tablets of the same model to have different configurations, whether on a single machine, or using a shared home directory. The configuration scheme is: schema: org.cinnamon.settings-daemon.peripherals.wacom path: /org/cinnamon/settings-daemon/peripherals/wacom/-/ where is the D-Bus machine-id for the machine, and is a unique identifier for the tablet. Stylus ------ Styli use a similar configuration scheme. The identifier for each stylus is the tool ID, for professional ranges, and a generic identifier for the consumer ranges that do not support tool ID. schema: org.cinnamon.settings-daemon.peripherals.wacom.stylus or: org.cinnamon.settings-daemon.peripherals.wacom.eraser path: /org/cinnamon/settings-daemon/peripherals/wacom/// So each tool can be configured per tablet (so the compatible airbrush stylus will have different configurations on a Cintiq and an Intuos tablet) Buttons ------- schema: org.cinnamon.settings-daemon.peripherals.wacom.tablet-button path: /org/cinnamon/settings-daemon/peripherals/wacom//