Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:alefnode:branches:devel:ARM:Factory:Contrib:PinePhone
upower
upower-1.90.6.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File upower-1.90.6.obscpio of Package upower
07070100000000000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001200000000upower-1.90.6/.ci07070100000001000081ED00000000000000000000000166EA48140000033E000000000000000000000000000000000000002800000000upower-1.90.6/.ci/fail_skipped_tests.py#!/usr/bin/python3 from lxml import etree import sys def format_title(title): """Put title in a box""" box = { 'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║', } hline = box['h'] * (len(title) + 2) return '\n'.join([ f"{box['tl']}{hline}{box['tr']}", f"{box['v']} {title} {box['v']}", f"{box['bl']}{hline}{box['br']}", ]) # The log coloring causes the XML to be invalid, so set recover=True tree = etree.parse(sys.argv[1], etree.XMLParser(recover=True)) for suite in tree.xpath('/testsuites/testsuite'): skipped = suite.get('skipped') if int(skipped) != 0: print(format_title('Tests were skipped when they should not have been. All the tests must be run in the CI'), end='\n\n', flush=True) sys.exit(1) 07070100000002000081A400000000000000000000000166EA48140000011C000000000000000000000000000000000000001F00000000upower-1.90.6/.ci/upower.suppr[suppress_type] type_kind = enum changed_enumerators = UP_DEVICE_KIND_BLUETOOTH_GENERIC, UP_DEVICE_KIND_LAST [suppress_function] type_kind = function name_regexp = up_exported_kbd_backlight_* [suppress_function] type_kind = function symbol_name_regexp = up_exported_kbd_backlight_* 07070100000003000081A400000000000000000000000166EA481400001E0F000000000000000000000000000000000000001D00000000upower-1.90.6/.gitlab-ci.ymlinclude: - project: 'freedesktop/ci-templates' ref: master file: '/templates/fedora.yml' - project: 'freedesktop/ci-templates' ref: master file: '/templates/debian.yml' variables: FDO_DISTRIBUTION_TAG: latest FDO_DISTRIBUTION_VERSION: rawhide FDO_UPSTREAM_REPO: "upower/$CI_PROJECT_NAME" FEDORA_IMAGE: "$CI_REGISTRY/upower/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG" DEPENDENCIES: gtk-doc meson gettext-devel gcc redhat-rpm-config gcc-c++ glibc-devel systemd sqlite-devel gobject-introspection-devel libgudev-devel libimobiledevice-devel glib2-devel libplist-devel umockdev dbus-x11 polkit-devel python3-gobject python3-dbusmock python3-pip python3-packaging git clang LAST_ABI_BREAK: "9058d45685d1c7c08d52fb64c393fed9eeed542b" workflow: rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - if: $CI_PIPELINE_SOURCE == 'push' - if: $CI_PIPELINE_SOURCE == 'schedule' stages: - check-source - build - test - deploy image: $FEDORA_IMAGE test_nut_hwdb: stage: check-source except: variables: - $CI_PIPELINE_SOURCE == "schedule" allow_failure: true script: - curl https://raw.githubusercontent.com/networkupstools/nut/master/scripts/upower/95-upower-hid.hwdb >rules/95-upower-hid.hwdb - git diff - "! git status -s | grep -q ." build: stage: build before_script: - git clone https://gitlab.gnome.org/GNOME/libgudev.git - cd libgudev - dnf install -y glibc-langpack-fr umockdev-devel - meson _build -Dprefix=/usr - ninja -C _build install - cd .. script: - meson _build -Dintrospection=enabled -Dman=true -Dgtk-doc=true -Didevice=enabled - ninja -C _build except: variables: - $CI_PIPELINE_SOURCE == "schedule" # avoid recompiling in test stage artifacts: name: untracked paths: - "${CI_PROJECT_DIR}" expire_in: 3h30min build_debian: stage: build image: registry.freedesktop.org/upower/upower/debian/trixie:latest before_script: - apt update - apt install -y git - git -c http.sslVerify=false clone https://gitlab.gnome.org/GNOME/libgudev.git - cd libgudev - apt install -y umockdev libumockdev-dev libumockdev0 libsystemd-dev systemd - meson _debian_build -Dprefix=/usr - ninja -C _debian_build install - cd .. script: - meson _debian_build -Dintrospection=enabled -Dman=true -Dgtk-doc=true -Didevice=enabled - ninja -C _debian_build except: variables: - $CI_PIPELINE_SOURCE == "schedule" # avoid recompiling in test stage artifacts: name: untracked paths: - "${CI_PROJECT_DIR}" expire_in: 3h30min # Compile test the other backends (they don't have extra dependencies currently) .build_backend_template: &build_backend stage: build script: - CFLAGS=-DUPOWER_CI_DISABLE_PLATFORM_CODE=1 meson _build -Dos_backend=$backend - ninja -C _build except: variables: - $CI_PIPELINE_SOURCE == "schedule" build_dummy: variables: backend: dummy <<: *build_backend build_freebsd: variables: backend: freebsd <<: *build_backend build_openbsd: variables: backend: openbsd <<: *build_backend test: stage: test dependencies: - build before_script: - git clone https://github.com/zatrazz/glibc-tools.git - cd glibc-tools - ./configure - make install - cd .. script: - meson _build -Dintrospection=enabled -Dman=true -Dgtk-doc=true -Didevice=enabled - ninja -C _build - catchsegv meson test -C _build --print-errorlogs --no-stdsplit - .ci/fail_skipped_tests.py _build/meson-logs/testlog.junit.xml artifacts: when: always expire_in: 1 week paths: - "${CI_PROJECT_DIR}/_build/meson-logs/" except: variables: - $CI_PIPELINE_SOURCE == "schedule" test_debian: stage: test image: registry.freedesktop.org/upower/upower/debian/trixie:latest dependencies: - build_debian before_script: - git -c http.sslVerify=false clone https://github.com/zatrazz/glibc-tools.git - cd glibc-tools - ./configure - make install - cd .. - cd libgudev - apt update - apt install -y umockdev libumockdev-dev libumockdev0 libsystemd-dev systemd - ninja -C _debian_build install - cd .. script: - meson _debian_build -Dintrospection=enabled -Dman=true -Dgtk-doc=true -Didevice=enabled --wipe - ninja -C _debian_build - catchsegv meson test -C _debian_build --print-errorlogs --no-stdsplit - .ci/fail_skipped_tests.py _debian_build/meson-logs/testlog.junit.xml artifacts: when: always expire_in: 1 week paths: - "${CI_PROJECT_DIR}/_debian_build/meson-logs/" except: variables: - $CI_PIPELINE_SOURCE == "schedule" check_abi: stage: test before_script: - cd libgudev - dnf install -y glibc-langpack-fr umockdev-devel - meson _build -Dprefix=/usr - ninja -C _build install - cd .. script: - check-abi --suppr .ci/upower.suppr --parameters="-Dman=false -Dgtk-doc=false -Didevice=enabled" ${LAST_ABI_BREAK} $(git rev-parse HEAD) except: variables: - $CI_PIPELINE_SOURCE == "schedule" # Create docs artifact for the website. # Note that the last successful artifact build is always kept, so 1 day as # expiry is completely fine. docs: stage: deploy dependencies: - build script: - meson _build -Dintrospection=enabled -Dman=true -Dgtk-doc=true -Didevice=enabled - ninja -C _build/ UPower-doc artifacts: name: "docs" when: always expire_in: 1 day paths: - "_build/doc/html" only: - master except: variables: - $CI_PIPELINE_SOURCE == "schedule" # CONTAINERS creation stage container_fedora_build: extends: .fdo.container-build@fedora only: variables: - $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES" variables: GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image FDO_FORCE_REBUILD: 1 # a list of packages to install FDO_DISTRIBUTION_PACKAGES: $DEPENDENCIES FDO_DISTRIBUTION_EXEC: | curl https://gitlab.freedesktop.org/hadess/check-abi/-/raw/main/contrib/check-abi-fedora.sh | bash # CONTAINERS creation stage container_debian_build: extends: .fdo.container-build@debian only: variables: - $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES" variables: FDO_DISTRIBUTION_TAG: latest FDO_DISTRIBUTION_VERSION: trixie GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image FDO_FORCE_REBUILD: 1 # a list of packages to install FDO_DISTRIBUTION_PACKAGES: autoconf automake autopoint autotools-dev binutils binutils-common binutils-x86-64-linux-gnu bsdextrautils build-essential bzip2 cpp cpp-14 cpp-14-x86-64-linux-gnu cpp-x86-64-linux-gnu curl debhelper git g++ g++-14 g++-14-x86-64-linux-gnu g++-x86-64-linux-gnu gcc gcc-14 gcc-14-x86-64-linux-gnu gcc-x86-64-linux-gnu m4 make systemd-dev python3-dbus python3-packaging python3-dbusmock gir1.2-upowerglib-1.0 libpolkit-gobject-1-dev FDO_DISTRIBUTION_EXEC: >- echo "deb-src http://deb.debian.org/debian/ trixie main contrib non-free" >> /etc/apt/sources.list && apt update && apt build-dep -y upower && curl https://gitlab.freedesktop.org/hadess/check-abi/-/raw/main/contrib/check-abi-fedora.sh | bash07070100000004000081A400000000000000000000000166EA481400000048000000000000000000000000000000000000001600000000upower-1.90.6/AUTHORSDavid Zeuthen <davidz@redhat.com> Richard Hughes <richard@hughsie.com> 07070100000005000081A400000000000000000000000166EA4814000007FE000000000000000000000000000000000000001900000000upower-1.90.6/COMMITMENTCommon Cure Rights Commitment, version 1.0 Before filing or continuing to prosecute any legal proceeding or claim (other than a Defensive Action) arising from termination of a Covered License, we commit to extend to the person or entity ('you') accused of violating the Covered License the following provisions regarding cure and reinstatement, taken from GPL version 3. As used here, the term 'this License' refers to the specific Covered License being enforced. However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. We intend this Commitment to be irrevocable, and binding and enforceable against us and assignees of or successors to our copyrights. Definitions 'Covered License' means the GNU General Public License, version 2 (GPLv2), the GNU Lesser General Public License, version 2.1 (LGPLv2.1), or the GNU Library General Public License, version 2 (LGPLv2), all as published by the Free Software Foundation. 'Defensive Action' means a legal proceeding or claim that We bring against you in response to a prior proceeding or claim initiated by you or your affiliate. 'We' means each contributor to this repository as of the date of inclusion of this file, including subsidiaries of a corporate contributor. This work is available under a Creative Commons Attribution-ShareAlike 4.0 International license. 07070100000006000081A400000000000000000000000166EA4814000047B6000000000000000000000000000000000000001600000000upower-1.90.6/COPYINGCopyright (C) 2008 David Zeuthen <davidz@redhat.com> (C) 2008 Richard Hughes <richard@hughsie.com> All Rights Reserved. The UPower source code is licensed to you under the GNU General Public License. Either version 2 of the License, or (at your option) any later version. The license is included below. -- BEGIN GPLv2+ License --- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, 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. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. -- END GPLv2+ License --- 07070100000007000081A400000000000000000000000166EA481400000B5F000000000000000000000000000000000000001600000000upower-1.90.6/HACKINGSCM === - anonymous checkouts $ git clone git://git.freedesktop.org/git/upower.git - checkouts if you got an ssh account on fd.o (username@ is optional) $ git clone ssh://[username@]git.freedesktop.org/git/upower.git - commit to local repository $ git commit -a - push local repository to master repository at fd.o (remember most patches requires review at the mailing list) $ git push - pull changes from master repository at fd.o $ git pull - diff of working tree versus local repository $ git diff - diff of local repository vs. master repository at fd.o synchronize with upstream repo: $ git pull (possibly merge changes) generate the diff: $ git diff origin HEAD - influential environment variables (set these in e.g. .bash_profile) export GIT_AUTHOR_NAME='Your Full Name' export GIT_COMMITTER_NAME='Your Full Name' export GIT_COMMITTER_EMAIL=youremail@domain.net export GIT_AUTHOR_EMAIL=youremail@domain.net - see also http://www.kernel.org/pub/software/scm/git/docs/ Committing code === - Commit messages should be of the form (the five lines between the lines starting with ===) === begin example commit === short explanation of the commit Longer explanation explaining exactly what's changed, whether any external or private interfaces changed, what bugs were fixed (with bug tracker reference if applicable) and so forth. Be concise but not too brief. === end example commit === - Always add a brief description of the commit to the _first_ line of the commit and terminate by two newlines (it will work without the second newline, but that is not nice for the interfaces). - First line (the brief description) must only be one sentence and must not start with a capital letter. Don't use a trailing period either. - The main description (the body) is normal prose and should use normal punctuation and capital letters where appropriate. Normally, for patches sent to a mailing list it's copied from there. - When committing code on behalf of others use the --author option, e.g. git commit -a --author "Joe Coder <joe@coder.org>" Coding Style === - Please follow the coding style already used. - Write docs for all functions and structs and so on. We use gtkdoc format. - All external interfaces (network protocols, file formats, etc.) should have documented specifications sufficient to allow an alternative implementation to be written. Our implementation should be strict about specification compliance (should not for example heuristically parse a file and accept not-well-formed data). Avoiding heuristics is also important for security reasons; if it looks funny, ignore it (or exit, or disconnect). Testing === Under Linux, with the umockdev package installed, you can run "make check" in the root build directory to run an automated test suite. 07070100000008000081A400000000000000000000000166EA48140000B1E8000000000000000000000000000000000000001300000000upower-1.90.6/NEWSVersion 1.90.6 -------------- Released: 2024-09-18 - Fractional battery percentage (!226) - CI enhancement. (!236) - Tweak the default battery charging threshold to 75-80. (!234) - Fix g_object_weak_ref: assertion 'g_atomic_int_get (&object->ref_count) >= 1' failed (#281, !233) Version 1.90.5 -------------- Released: 2024-08-22 - Suspend and Ignore as the CriticalPowerActions (!218 and !218) - Support for battery charging threshold (!208) - Tweak the device priority to make sure the device kind joystick can be correctly shown. (#267) Version 1.90.4 -------------- Released: 2024-04-08 - Update the information for version 1.90.3. - Resolved high disk and CPU rate. (#256) - Update glib2 requirement to 2.66.0. - Stop guessing the unknown battery as a power supply. - Continue to support lid handling. - Fix org.freedesktop.UPower: EnergyRate is a positive value. (#252) - Fix uni-test python script. (!205) Version 1.90.3 -------------- Released: 2024-04-08 - Resolved high disk and CPU rate. (#256) - Update glib2 requirement to 2.66.0. - Stop guessing the unknown battery as a power supply. - Continue to support lid handling. - Fix org.freedesktop.UPower: EnergyRate is a positive value. (#252) - Fix uni-test python script. (!205) Version 1.90.2 -------------- Released: 2023-07-06 Note that this is the last release of UPower with lid handling. OS components that rely on the lid status should get it from logind instead. See: https://www.freedesktop.org/software/systemd/man/org.freedesktop.login1.html - Fix wireless devices not disappearing from Settings when disconnected - Require a newer libgudev to avoid bugs related to newline stripping when reading sysfs attributes - Add installed-tests files for use with gnome-desktop-testing - Fix integration test to work with system installed upower binary and under jhbuild Version 1.90.1 -------------- Released: 2023-07-04 - Detect headsets with kernel batteries such as Logitech and Steelseries headsets, and make them automatically disappear if the headset is turned off (if the kernel driver supports the wireless_status attribute) - Hide duplicate Logitech Bluetooth devices (Bolt-compatible devices connected through Bluetooth would show as 2 batteries) - Hide duplicate Logitech wireless devices when they get connected through USB as well - Fix Bluetooth device names not synchronising, and use user-chosen names when available - Handle the "present" sysfs attribute changing - Fix iDevices not appearing - Fix reading capacity_level with newer libgudev - Fix OpenBSD backend Version 1.90.0 -------------- Released: 2022-07-21 Note that the version number bump was made to allow bugfixes for older releases while also making new releases that contain with more in-depth code changes. The old (soft) API/ABI guarantees are currently unchanged. Changes: - Refactor internal battery handling into separate classes - Guess charging/discharging state based on energy rate (#196) Bug fixes: - Fix polling after resume (#198) - Fix battery state guessing (#146) - Reload history when battery ID changes - Test fixes Version 0.99.19 --------------- Released: 2022-06-08 Changes: - Move state guessing into DisplayDevice - Always use 90% threshold to consider a battery full - Various test improvements Bug fixes: - Fix mice showing up as keyboards (#189) - Allow unit test inspector to fail (#187) - Fix test cases when daemon shuts down too slowly (#188) Version 0.99.18 --------------- Released: 2022-05-17 Changes: - Remove broken wakeup DBus API - Tag UPS hid devices using hwdb and update list from upstream - Only permit Refresh method when in debug mode - Refactor device polling - Refactor udev device discovery and sibling detection - Improved testing and CI - Handle SIGTERM to trigger a clean shutdown Bug fixes: - Improve polling of batteries after line-power "online" status change - Multiple wacom tablet detection fixes - Fix updates after a BT hid power supply moves in sysfs - Fix enumeration of "Whats Up!" devices on startup - Accept USB power supplies without warning - Allow building without gtk-doc Version 0.99.17 --------------- Released: 2022-03-09 Bug fixes: - Fix FD handling issues that may cause lid to not be detected Version 0.99.16 --------------- Released: 2022-02-23 Bug fixes: - Silence unnecessary udev event warnings - Increase test timeout (#171) - Explicitly link with plist - Fix UpClient reference leak - Fix DisplayDevice state on battery hotplug - Fix critical action to work after it was cancelled (#172) Version 0.99.15 --------------- Released: 2022-02-09 Bug fixes: - Various build fixes - Update bluetooth device alias when it changes (#169) Version 0.99.14 --------------- Released: 2022-02-03 Changes: - Port build system to meson - New ChargeCycles D-Bus property (#152) - New async GLib APIs (#121) - lid related functions are now deprecated - Refresh API is now deprecated Bug fixes: - Plenty of test suite fixes - Fix leak of inhibitor lock (#160) - Recognize USB power supplies (#148) - Fix time compression of data points (#167) - Fix disk write amplification when battery is low (#150) Version 0.99.13 --------------- Released: 2021-08-17 Bug fixes: - Tweak default percentage levels to better match other operating systems - Support large energy rates seen in some modern laptops - Fix touchpads showing up as mice - Fix composite battery state when multiple batteries are used and one isn't drawing any power - Make the icon and warning properties respect the "low battery level" configuration option - Stop the device being suspended during the 20-second "shutdown" grace period Version 0.99.12 ~~~~~~~~~~~~~~~ Released: 2021-06-17 New Features: - Add a raft of new device types - Add support for iPhone XR, XS and newer models Bug fixes: - Work-around incorrect battery percentage reported by MacBooks - Identify keyboard/pointing device combos as keyboards - Fix small memory leak in Bluetooth backend - Fix warning in Bluetooth backend - Set update time in Bluetooth backend - Remove support for obsolete CSR devices Version 0.99.11 ~~~~~~~~~~~~~~~ Released: 2019-09-03 New Features: - Add code of conduct document - build: Migrate from intltool to gettext - rules: Split off HID++ udev rules - Harden systemd service - Let systemd create /var/lib/upower - Move D-Bus policy file to /usr/share/dbus-1/system.d/ Bug fixes: - Fix endless loop burning 100% CPU on keyboard plugout with external backlight - linux: Start polling for unknown device batteries too - linux: Retry to get a battery type if it's unknown - linux: Don't treat device batteries like laptop batteries - Replace use of G_TYPE_INSTANCE_GET_PRIVATE and g_type_class_add_private() Version 0.99.10 ~~~~~~~~~~~~~~~ Released: 2019-02-20 Bugfixes: - Set 'pending-charge' for DisplayDevice if at least one battery is in the 'pending-charge' state - Map pending-charge to fully-charged when charge is 100% Version 0.99.9 ~~~~~~~~~~~~~~ Released: 2018-10-25 Bugfixes: - Fix lack of update after AC status changes, and broken keyboard backlight, following the daemon lockdown added in 0.99.8 - Multiple API documentation fixes - Out-of-tree build fixes Version 0.99.8 ~~~~~~~~~~~~~~ Released: 2018-06-18 New Features: - Lock down systemd service file - Add support for "Unknown" capacity level, and clarify handling of devices with coarse battery levels - Add a new version of up_client_get_devices() which unrefs contents Bugfixes: - Fix warnings when D-Bus related properties change - Prevent crash after attaching an Apple TV, and support newer versions of iOS - Lower severity of "unhandled action" messages - Fix battery status on MacBooks after a plug or unplug event - Fix double-close on exit Version 0.99.7 ~~~~~~~~~~~~~~ Released: 2017-11-28 New Features: - Add support for Bluetooth LE device batteries (Bastien Nocera) - Allow to be replaced via --replace,-r (Christian Kellner) Bugfixes: - Fix critical action after resume from hibernate (Miroslav Sustek) - Fix compilation with libimobiledevice git (Bastien Nocera) Version 0.99.6 ~~~~~~~~~~~~~~ Released: 2017-09-11 New Features: - Add UP_DEVICE_KIND_GAMING_INPUT for gaming devices (Bastien Nocera) - Detect joysticks as gaming input devices (Bastien Nocera) Bugfixes: - Correctly close inhibitor FD (Benjamin Berg) - Fix crash when '@' is present in the device name (oleid, Bastien Nocera) - Fix lid detection on FreeBSD (Alberto Villa) - Grab the model name from device if unavailable from battery (Bastien Nocera) Version 0.99.5 ~~~~~~~~~~~~~~ Released: 2017-07-24 New Features: - Add a more complete self test for HID++ devices (Bastien Nocera) - Add BatteryLevel property for devices with a finite number of power levels (Bastien Nocera) - Add support for pausing and resuming of the daemon poll (Christian Kellner, Bastien Nocera) - Get a serial number for device batteries (Bastien Nocera) - Refresh devices after waking up from sleep (Christian Kellner) Bugfixes: - Add proper error and cancellable handling to UpClient constructor (Martin Pitt) - Do not spin in a loop when /proc/timer_stats cannot be written (Richard Hughes) - Exit early from up-tool when connecting to upower fails (Martin Pitt) - Expand the integration-tests to run in more environments (Bastien Nocera, Christian Kellner) - Fix reading and writing the keyboard brightness level (Hans de Goede, Marco Trevisan) - Fix -Wformat-y2k compilation errors (Bastien Nocera) - Lower initial power usage when iDevice isn't accessible (Bastien Nocera) - Simplify string checks in upower-glib (Bastien Nocera) Version 0.99.4 ~~~~~~~~~~~~~~ Released: 2016-02-16 New Features: - Add support for Logitech G700s/G700 Gaming Mouse (muzena) - Port to GDBus (Cosimo Cecchi) - Support g_autoptr() for all libupower-glib object types (Kalev Lember) Bugfixes: - Add critical action support for *BSD (Eric Koegel) - Change the default low battery policy to percentage (Bastien Nocera) - Fix deprecation warning in integration-test (Bastien Nocera) - Fix memory leak in up_client_get_devices() (Bastien Nocera) - Fix possible double-free (Bastien Nocera) - Update HID rules and fix build regression (Arnaud Quette) Version 0.99.3 ~~~~~~~~~~~~~~ Released: 2015-05-28 Bugfixes: - Bail out when iDevice state is malformed (Bastien Nocera) - Defer getting iDevice info until ready (Bastien Nocera) - Fix crash on uninitialized variant (Vlad Orlov) - Fix libimobiledevice msg in configure (Bastien Nocera) - More memory handling fixes in iDevice (Bastien Nocera) - Properly detect bluetooth mice and keyboards that are HID devices (Marc Deslauriers) - Support Logitech Unifying in Linux 3.19 (Peter Wu) - Work-around broken battery on the Onda v975w (Bastien Nocera) Version 0.99.2 ~~~~~~~~~~~~~~ Released: 2014-12-18 Bugfixes: - Avoid unaligned memory access in hidpp-device (Peter Wu) - Bump GLib min req to 2.34 (Eric Koegel) - Correct check to prevent the display of invalid ASCII codes (Eric Koegel) - Fencepost array access error (Eric Koegel) - Fix cleanup in up_device_idevice_coldplug/finalize (Nikolay Martynov) - Fix crash if there is no session D-BUS (Martin Pitt) - Fix error handling for Python 3.4 (Martin Pitt) - Fix various memory and reference leaks (Peter Wu) - Release resources at shutdown (Peter Wu) - Respect the CriticalPowerAction config option (Bastien Nocera) - Set update-time on the aggregate device (Bastien Nocera) - Split out updating on_battery and warning_level (Bastien Nocera) - Update aggregate device on battery removal (Evangelos Foutras) - Update display device when battery is removed (Bastien Nocera) - Use g_get_real_time() when possible (Bastien Nocera) Version 0.99.1 ~~~~~~~~~~~~~~ Released: 2014-08-18 New Features: - Expose "capacity" and "energy-full-design" properties on OpenBSD (Fabian Raetz) - Remove IsDocked property (Bastien Nocera) - Remove unused polkit dependency (Eric Koegel, Martin Pitt) Bugfixes: - Create the history directory at runtime (Cosimo Cecchi) - Do not log a critical warning when using _set_object_path_sync() (Richard Hughes) - Fix API doc for up_client_get_on_battery() (Bastien Nocera) - Fix possible UpHistoryItem leak on failure (Bastien Nocera) - Fix segfault on getting property when daemon is not running (Martin Pitt) - Fix shutdown on boot on some machines (Bastien Nocera) - Fix small memleak on startup with Logitech devices (Bastien Nocera) - Free the obtained device list array after use (Alexander Jesner) - Update lid status when updating AC status (Jasper Lievisse Adriaanse) Version 0.99.0 ~~~~~~~~~~~~~~ Released: 2013-10-29 Notes: - This version contains major API changes. Use the 0.9.* versions if you want to keep using the old API. New Features: - Add WarningLevel and IconName properties to all devices (Bastien Nocera) - Add DisplayDevice composite battery (Bastien Nocera) - Enforce critical battery policy on the daemon side (Bastien Nocera) Bugfixes: - Reduce client-side and daemon-side wake-ups (Bastien Nocera) - Emit PropertiesChanged signals (Bastien Nocera) - Register objects on the bus once they've been setup (Bastien Nocera) - Clamp percentage for overfull batteries (Martin Pitt) Feature Removals: - Remove battery recall support (Bastien Nocera) - Remove QoS support (Bastien Nocera) - Remove OnLowBattery property (use WarningLevel instead) (Bastien Nocera) - Remove DeviceChanged and Changed signals (PropertiesChanged signals are sent instead) (Bastien Nocera) Version 0.9.22 ~~~~~~~~~~~~~~ Released: 2013-10-08 New Features: - Add temperature property for batteries (Seth Forshee) Bugfixes: - Fix error handling in up_client_get_properties_sync() (Bastien Nocera, Martin Pitt) - Make GetHistory() array order consistent (Martin Pitt) - Fix crash with bluetooth input devices (Martin Pitt) - Lots of fixes/rework for Logitech wireless input devices (Peter Wu) - Allow valid UTF-8 encoded properties (Shih-Yuan Lee (FourDollars)) - Detect the battery of bluetooth input devices (Shih-Yuan Lee (FourDollars)) - Only one warning if no valid voltage found (Timothée Ravier) - openbsd: Do not call g_thread_init() (Richard Hughes) Version 0.9.21 ~~~~~~~~~~~~~~ Released: 2013-07-26 New Features: - Add support for Logitech Wireless (NonUnifying) devices (Arkadiusz Miśkiewicz) - Use PIE to better secure installed tools and also use full RELRO in the daemon (Richard Hughes) Bugfixes: - Allow clients to call org.freedesktop.DBus.Peer (Richard Hughes) - Detect udev rules dir (Tom Gundersen) - Drop --enable-systemd and linking to libsystemd-daemon (Martin Pitt) - Find hidraw devices correctly with systemd udev >= v196 (Arkadiusz Miśkiewicz) - Fix test for logind availability (Martin Pitt) - Update the upower man page with all the current options (Richard Hughes) Version 0.9.20 ~~~~~~~~~~~~~~ Released: 2013-03-18 New Features: - Add a --enable-deprecated configure argument to remove pm-utils support (Richard Hughes) - Deprecate running the powersave scripts (Richard Hughes) - Factor out the Logitech Unifying support to support other devices (Richard Hughes) - Require applications to define UPOWER_ENABLE_DEPRECATED to use deprecated functionality (Richard Hughes) Bugfixes: - Bump maximum accepted "time to empty" to 10 days (Martin Pitt) - Don't use the deprecated INCLUDES in Makefile.am (Richard Hughes) - Fix batteries which report current energy but full charge (Alex Hornung) - Fix K750 features name, use 1 second interval (Julien Danjou) - Fix memory leak in up_polkit_get_subject (Charles Kerr) - Fix two memory leaks (Colin Watson) - integration-test: Always run on a fake system bus (Martin Pitt) - integration-test: Move to using umockdev (Martin Pitt) - Never use -WError when building (Richard Hughes) - Raise the hard PolicyKit dep to 0.97 (Richard Hughes) Version 0.9.19 ~~~~~~~~~~~~~~ Released: 2013-01-02 New Features: - Add a Documentation tag to the service file (Matthias Clasen) - Add luminosity property (Julien Danjou) - Add support for Logitech Unifying devices (Julien Danjou) Bugfixes: - Always return 0 from notify-upower.sh (Richard Hughes) - Do not continue to poll if /proc/timer_stats is not readable (Richard Hughes) - Fix "can-hibernate" formatting in upower --dump (Martin Pitt) - Fix device matching for recent kernels (Peter Hurley) - Fix srcdir != builddir (Colin Walters) - Send resume signal when built with systemd and using pm-utils suspend (Jan Alexander Steffens) Version 0.9.18 ~~~~~~~~~~~~~~ Released: 2012-08-08 New Features: - Use systemd if possible for suspend and hibernate (Matthias Clasen) Bugfixes: - openbsd: Properly initialize update-time when creating devices (Landry Breuil) Version 0.9.17 ~~~~~~~~~~~~~~ Released: 2012-06-25 New Features: - Fail on CRITICALs in the integration-test (Martin Pitt) Bugfixes: - Drop 'type' parameter from CancelRequest() signature (Sascha Silbe) - Fix the LatencyChanged signal (Sascha Silbe) - Fix use-after-free of qos item (Sascha Silbe) - Fix wrong PowerSupply property for devices without a scope sysfs attribute (Martin Pitt) - linux: Don't allow non-power-supply devices to set the OnBattery property (Daniel Nicoletti) - linux: Remove obsolete check for magicmouse_ and duplicated wacom_ checks (Daniel Nicoletti) - linux: Treat the battery state 'not charging' as PENDING_CHARGE (Richard Hughes) - Selectively disable warnings for deprecated GValueArray (Martin Pitt) Version 0.9.16 ~~~~~~~~~~~~~~ Released: 2012-04-30 Translations: New Features: - Add boolean RunPowersaveCommand to UPower.conf (Landry Breuil) - Install a systemd service file if systemd is used (Benedikt Morbach) Bugfixes: - Clamp the UPS percentage from 0 to 100 to fix syslog spam (Richard Hughes) - Correct the cap on the energy rate (Gary Ching-Pang Lin) - Do not print error message for missing /etc/crypttab (Kelly Anderson) - Fix crash in up_device_csr_finalize (Martin Pitt) - Never detect HID devices with batteries as power supplies (Richard Hughes) - Re-coldplug dock status when resuming from sleep (Evan Broder) - Return all history records for a timespan of zero (Richard Hughes) - libupower-glib: fix small memory leak (Pavel Vasin) - libupower-glib: srcdir != builddir fix (Ryan Lortie) - openbsd: Fix history by not trying to refresh if /dev/apm wasn't opened yet (Landry Breuil) - openbsd: Handle case where minutes_left might be negative (Landry Breuil) - openbsd: Set powersave command to apm -C/-A (Landry Breuil) - openbsd: Use a singleton pattern to access /dev/apm (Landry Breuil) Version 0.9.15 ~~~~~~~~~~~~~~ Released: 2011-12-05 New Features: - Add --with-historydir to specify where we want the history files to be stored (Landry Breuil) - Use linear regression to get better predicted battery times (Leonardo Robol) Bugfixes: - Don't assert when the power_supply device type is usb (Richard Hughes) - Don't spam the log when we're saving history when on low power (Richard Hughes) - Fail the tests gracefully if GI is not available (Martin Pitt) - Fix crash in up_device_csr_finalize() (Martin Pitt) - Fix invocation of src/linux/integration-test (Martin Pitt) - Handle Linux power supplies not exporting a present property (Heiko Stübner) - If a power-supply device doesn't report charge or energy, try to read the percentage (Richard Hughes) - Move the wacom hack to allow us to support other types of USB device (Richard Hughes) - Port the tests to Python 3 (Martin Pitt) Version 0.9.14 ~~~~~~~~~~~~~~ Released: 2011-10-03 New Features: - Filter the debugging details unless --verbose is specified (Richard Hughes) Bugfixes: - Fix linux up_backend_supports_sleep_state() return code (Christian Seiler) - Fix the kFreeBSD detection (Pino Toscano) Version 0.9.13 ~~~~~~~~~~~~~~ Released: 2011-09-05 New Features: - Modernize autotools config (Javier Jardón) - Use git.mk and remove the manual .gitignore files (Richard Hughes) - Use upstream gettext instead the glib one (Javier Jardón) Bugfixes: - Avoid warnings about missing annotations (Javier Jardón) - Don't rely on files' presence to define the default backend (Diego Elio Pettenò) - Fully port the test suite to use GObject Introspection (Martin Pitt) - Hardcode wacom battery devices as not power-supply devices (Richard Hughes) - Use autoreconf instead custom script (Javier Jardón) - Use g_unix_signal_add_full() which has been renamed in GLib (Denis Washington) Version 0.9.12 ~~~~~~~~~~~~~~ Released: 2011-07-04 Bugfixes: - Add AC_PROG_LIBTOOL as advised by autotools (Landry Breuil) - Add openbsd missing includes for close and strcmp (Landry Breuil) - Fix how we estimate the device rate for batteries that do not provide this data (Richard Hughes) - Silence some openbsd warnings about unused vars and bad return values (Landry Breuil) - Switch to using .xz tarballs (Richard Hughes) Version 0.9.11 ~~~~~~~~~~~~~~ Released: 2011-05-25 New Features: - Add new NotifySleep() and NotifyResume() signals that include the sleep type (Richard Hughes) Bugfixes: - Ensure up-apm-native.h gets shipped in the tarball for OpenBSD (Richard Hughes) - Check energy vs. charge in the Linux integration tests (Martin Pitt) - Only include glib-unix.h if the GLib version is >= 2.29.4 (Richard Hughes) - Respect $PYTHON for running the test suite (Martin Pitt) - Run subset of tests when system D-BUS is not available (Martin Pitt) Version 0.9.10 ~~~~~~~~~~~~~~ Released: 2011-05-03 New Features: - Add a config option 'IgnoreLid' for users with broken lid switches (Richard Hughes) - Add integration test suite for Linux (Martin Pitt) - Add option to run daemon on the session bus for testing (Martin Pitt) - Add OpenBSD backend which uses the APM_IOC_GETPOWER ioctl() (Landry Breuil) - Support virtual UPS devices for testing (Martin Pitt) Bugfixes: - Consider a discharging UPS as "on battery" (Martin Pitt) - Do not overwrite aclocal flags in autogen, fixes b.fd.o #35261 (Tobias Mueller) - Fix "unknown" battery status guessing to not be recursive (Martin Pitt) - Respect $UPOWER_CONF_FILE_NAME in up_config_init (Martin Pitt) - Support batteries that report both energy and charge (Benson Leung) - upower needs -pthread (Landry Breuil) - Use the new threadsafe signal handling support in GLib (Richard Hughes) - Wuninitialized needs -O (Landry Breuil) Version 0.9.9 ~~~~~~~~~~~~~ Released: 2011-03-21 New Features: - Add a config option to disable the Watts Up Pro device (Richard Hughes) - Add a LidForceSleep property to ensure that we don't melt any laptops (Richard Hughes) - Add an option for polling dock devices in UPower.conf, defaulting to false (Richard Hughes) Bugfixes: - Depend on stable GUdev API (Michael Biebl) - Drop devkit and devkit-power-daemon symlinks (Michael Biebl) - Fix bitmap check in the input code (Arnaud Patard) - Honour ACLOCAL_FLAGS in Makefile.am (Richard Hughes) Version 0.9.8 ~~~~~~~~~~~~~ Released: 2011-01-07 New Features: - Add an IsDocked binary property to the main interface (Richard Hughes) - Use the number of active DRM devices to determine the system docked status (Richard Hughes) Bugfixes: - Add method to set history dir (Martin Pitt) - Check for and link against libplist (Martin Pitt) - Drop check for polkit-backend again (Martin Pitt) - Fix compilation error against Linux 2.6.36 (Martin Pitt) - Fix links to git repository in HACKING (Zygmunt Krynicki) - Fix self check to work as non-root (Martin Pitt) - Re-add AM_MAINTAINER_MODE (but enable it by default) (Michael Biebl) - Reduce race condition in history purging self check (Martin Pitt) - Support the power_now sysfs attribute to get time remaining on new kernels (Richard Hughes) - Update the list of HID UPS devices (Arnaud Quette) Version 0.9.7 ~~~~~~~~~~~~~ Released: 2010-11-01 Translations: - Add French translation (Christoph Thompson) New Features: - Add support for controlling leds keyboard backlights (Alex Murray) - Port from EggDebug to the GLib built-in logging framework (Richard Hughes) Bugfixes: - Fix building with gobject-introspection 0.9.10 (Edward Sheldrake) - Fix up all the warnings when building with new versions of gobject-introspection (Richard Hughes) - Keyboard backlight of zero is not an error (Alex Murray) - libupower-glib: Reject invalid object paths to avoid asserting libdbus (Richard Hughes) - Remove the UP_DEVICE_SUPPLY_CHARGED_THRESHOLD heuristic (Michal Schmidt) Version 0.9.6 ~~~~~~~~~~~ Released: 2010-10-04 New Features: - Remove devkit-power-gobject (Richard Hughes) Bugfixes: - Allow explicitly disabling libimobiledevice support (Brett Witherspoon) - Free GErrors after returning them (Matthias Clasen) - Add missing D-Bus return in up_qos_cancel_request() (Matthias Clasen) - Fix double D-BUS return in up_daemon_*_allowed (Matthias Clasen) - Fix up_polkit_get_subject() D-BUS error return (Matthias Clasen) - Ensure the new device types get valid descriptions in upower --dump (Richard Hughes) - Fix compile with the latest PolicyKit release (Richard Hughes) - Only save by default 7 days data to stop the log files becoming huge. Fixes rh#634228 (Richard Hughes) - Do not continue to poll the serial port if there is no Watts Up Pro adaptor (Richard Hughes) - Fix the build with new versions of gobject-introspection (Richard Hughes) Version 0.9.5 ~~~~~~~~~~~ Released: 2010-07-12 New Features: - Add battery query support for iDevices (Bastien Nocera) - Assign names to our idle sources when using new versions of glib2 (Richard Hughes) - Dynamic testing for enough hibernate swap (Martin Pitt) - Port UPower to libusb1 to avoid unfixable crashes (Richard Hughes) - Port to GTest (Richard Hughes) - Get the powersave command from the backend rather than hardcoding Linux specifics (Richard Hughes) Bugfixes: - Update the list of supported TrippLite HID Power Devices (Joseph Stockman) - Fix a potential daemon crash. Fixes fd#27902 (Mariusz Ceier) - Increase UP_DAEMON_SWAP_WATERLINE (Martin Pitt) - Fix up a potential crasher in the CSR device code (Richard Hughes) - When calculating used swap space, only use anonymous pages (Steven Walter) - Use pm-is-supported to test if various sleep modes are supported (Victor Lowther) IMPORTANT NOTE: - This is the last release with the deprecated devkit-power-gobject library included. Users should have ported to libupower-glib months ago... Version 0.9.4 ~~~~~~~~~~~ Released: 2010-05-12 New Features: - Detect when the kernel changes the reported charge units. Fixes rh#587112 (Kyle McMartin) Bugfixes: - Only emit ::Sleeping() after we've checked AboutToSleep (Richard Hughes) - Ensure we send ::Sleeping() if clients do not call AboutToSleep (Richard Hughes) - Ensure we sent ::notify signals when UpDaemon properties change (Richard Hughes) Version 0.9.3 ~~~~~~~~~~~ Released: 2010-05-06 New Features: - Add a config file with SleepTimeout and AllowHibernateEncryptedSwap entries (Richard Hughes) Bugfixes: - Fix c&p typo in documentation (Michael Biebl) - The gettext package should match the tarball name (Richard Hughes) - Provide UpDaemon with C setters rather than relying on GObject properties (Richard Hughes) - Sanity check the device is not already in the list before adding (Richard Hughes) - Fix recognition of lithium iron phosphate (LiFePO4) batteries (Sascha Silbe) Version 0.9.2 ~~~~~~~~~~~~~ Released: 2010-04-06 New Features: - Add a missing accessor: up_client_get_lid_is_present() (Richard Hughes) - Change the tarball name to be all lower case to match udisks and udev (Richard Hughes) - Convert the daemon to using objects from libupower-glib, not devkit-power-gobject (Richard Hughes) - Do not allow client programs to enumerate the device list more than once (Richard Hughes) - Get the encrypted swap status from the backend, rather than hardcoding Linux specifics (Richard Hughes) - Get the kernel sleep capabilities from the backend, rather than hardcoding Linux specifics (Richard Hughes) - Get the suspend and hibernate commands from the backend, rather than hardcoding Linux specifics (Richard Hughes) - Get the swap size from the backend, rather than hardcoding Linux specifics (Richard Hughes) - Show in ./configure summary if unit tests have been enabled or not (Michael Biebl) Bugfixes: - Do not warn what we are correcting energy-full when there is no data to copy (Richard Hughes) - Ensure we enumerate devices before we start monitoring them (Richard Hughes) - Fixes to the autogen.sh script (Michael Biebl) - Make dummy backend usable for architectures without a native backend (Michael Biebl) - Remove libdevkit-power-gobject dependency from backends (Michael Biebl) - Simplify udev subdirectory handling (Michael Biebl) Version 0.9.1 ~~~~~~~~~~~~~ Released: 2010-03-03 New Features: - Add a new method and two new signals to inform userspace of the pending suspend and the resume event (Richard Hughes) - Add {Suspend,Hibernate}Allowed D-Bus methods (Martin Pitt) - Add up_polkit_is_allowed() function (Martin Pitt) - Check PolicyKit in client's can_{suspend,hibernate} properties (Martin Pitt) - Don't ship an introspection file for devkit-power-gobject, it's soon to be obsolete (Richard Hughes) - Install the introspection data to the correct location (Richard Hughes) - Make the upower client tool use libupower-glib, rather than devit-power-gobject (Richard Hughes) - Use GCancellable in libupower-glib so we can eventually get to GIO async methods (Richard Hughes) Bugfixes: - Ensure we return all lines of the UpDevice when we call up_device_to_string() (Richard Hughes) - Fix libupower-glib include dir and pkgconfig (Martin Pitt) - Fix up autogen.sh after the configure.ac modernisation (Michael Biebl) - Fix up the FreeBSD backend compile (Michael Biebl) - Fix up the include directory in the pkgconfig file (Richard Hughes) - Make sure the tests link against all necessary libraries (Michael Biebl) - Move the history files to /var/lib/upower (Michael Biebl) - Update help and g_option_context_new to upower (Michael Biebl) - Use the new project name in g_option_context_new (Michael Biebl) Version 0.9.0 ~~~~~~~~~~~ Released: 2010-02-01 NOTES: - The DBus service and interfaces have been renamed - The devkit-power-gobject library is still API and ABI stable - The libupower library co-installs with devkit-power-gobject for now - The version has changed to 0.9.0 from 015. You'll need to use an epoch in your distro package if you're not renaming the package from DeviceKit-power to UPower. See the sample Fedora spec if you need a template. Translations: - Add Swedish translation (Daniel Nylander) - Added Italian translation (Luca Ferretti) - Add Polish translation (Piotr Drąg) New Features: - Add initial GObject introspection support (Richard Hughes) Bugfixes: - Use a fallback for the capability bit when checking the lid status. Fixes #25041 (Richard Hughes) - Rename the DBus service from org.freedesktop.DeviceKit.Power to org.freedesktop.UPower (Richard Hughes) - Rename the PolicyKit rules from org.freedesktop.devicekit.power to org.freedesktop.upower (Richard Hughes) - Make the client tool be called upower, but maintain a symlink to devkit-power (Richard Hughes) - Rename the man pages and rename the main daemon binary name (Richard Hughes) - Change the version number to 0.9.0 and tarball name to UPower (Richard Hughes) - Version-lock the devkit-power-gobject version to 015, not 0.9.0 (Richard Hughes) - Make DkpClient a singleton to avoid some weird race conditions (Richard Hughes) - Add libupower so applications can switch away from devkit-power-gobject (Richard Hughes) - Update the Free Software Foundation address (Richard Hughes) Version 014 ~~~~~~~~~~~ Released: 2010-01-08 New Features: - Import the FreeBSD backend (Joe Marcus Clarke) Bugfixes: - Check if swap exists before determining how much is free (Debbie Beliveau) - Comment out some problematic compiler warnings (Joe Marcus Clarke) - Prevent segfault if connection to system dbus fails (Martin Koegler) - Fix segfault in the history code. Fixes fd#25632 (Richard Hughes) Version 013 ~~~~~~~~~~~ Released: 2009-12-07 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - This will probably be the last release of DeviceKit-power as the project has been renamed to upower. New Features: - When using devkit-power --monitor, print a timestamp before each message for debugging. Fixes fd#24666 (Richard Hughes) Bugfixes: - Update the list of HID UPS (Arnaud Quette) - Use a gdouble for percentage to fix on-battery reporting (Byron Clark) - Bug 24262 – incorrect battery recall warning for Lenovo T61 (Martin Pitt) - Fix the toshiba battery recal notices by matching up the double quotes (Richard Hughes) - Avoid going from discharging to pending-discharge when the expansion battery is very low (Richard Hughes) - Some vendors fill the NVRAM full of junk. Don't crash the daemon if the battery is broken. Fixes rh#533654 (Richard Hughes) - When the internal battery is in the unknown state, we can't make a decision whether the system is on battery power (Richard Hughes) - Some batteries give out massive rate values when nearly empty (Richard Hughes) Version 012 ~~~~~~~~~~~ Released: 2009-10-19 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. New Features: - Detect encrypted swap and prevent hibernate in this case. Fixes fd#23196 (Richard Hughes) - Add g_object_notify() calls for properties on DkpClient (Richard Hughes) Bugfixes: - Ensure we only reset the update-time property when we have done the refresh, not before (Richard Hughes) - Don't emit changed events from the DkpBackend layer, instead push then through DkpDevice (Richard Hughes) - When we do a delayed refresh, actually do 5 x 1 second apart rather than 1 x 3 seconds (Richard Hughes) Version 011 ~~~~~~~~~~~ Released: 2009-10-06 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - The DBus interface has changed to use FirstLetterCaps property names so Qt projects can use the DBus interface without resorting to ugly hacks. New Features: - Return meaningful errors if the user tries to suspend or hibernate without kernel support or swap set up (Richard Hughes) - Use the sysfs file 'type' to work out the battery type before using a fallback (Enrico Zini, Richard Hughes) Bugfixes: - Update list of HID UPS devices (Arnaud Quette) - Add backend code to make DeviceKit-power compile without GUdev for non-Linux platforms (Richard Hughes) - Only disable the polling if the kernel tells us we're fully charged, not if we guessed it (Richard Hughes) - Make the remove logic much cleaner to try to fix bugs where removing the mouse kills the session (Richard Hughes) - Fix up some small memory leaks (Richard Hughes) - Freeze and thaw the device during initial coldplug (Richard Hughes) - Fix up a few potential problems spotted by clang (Richard Hughes) - Fix a tiny memory leak when we collect the properties from the interface multiple times (Richard Hughes) - Use voltage_now as a fallback to the design voltage (Enrico Zini, Richard Hughes) Version 010 ~~~~~~~~~~~ Released: 2009-07-22 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - This project now depends on GUdev and PolicyKit1 New Features: - Port to GUdev (Richard Hughes) - Port to PolicyKit1 (Richard Hughes) Bugfixes: - Add a notify flag to set_lid_is_closed to fix the initial state (Loïc Minier) - Correct a description string from one of the new enums (Richard Hughes) - Only guess the battery status if we have > 1 battery in the system (Richard Hughes) - Use the global battery state as a metric for single battery machines (Richard Hughes) - Query the kernel to decide if we have hibernate and suspend support (Richard Hughes) - If we don't have enough swap available, don't advertise hibernate. Fixes rh#513015 (Richard Hughes) - Force a refresh all battery devices when the ac-adaptor changes. Fixes rh#512995 (Richard Hughes) Version 009 ~~~~~~~~~~~ Released: 2009-07-06 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - The experimental devkit-power-gobject library has no API or ABI guarantees. - This is the first version of DeviceKit-power where multiple laptop batteries are officially supported. New Features: - Interface with pm-powersave as external vendors are using this (Richard Hughes) - Enable pretty compiler output with new automake versions (Richard Hughes) - udev rules files now live in /lib/udev/rules.d, not /etc/udev/rules.d (Richard Hughes) - Add battery recall data rules (Richard Hughes) - Export the recall-notice, recall-vendor and recall-url properties on power devices (Richard Hughes) - Protect the non-GObject accessors with DKP_DISABLE_DEPRECATED (Richard Hughes) - Add two new state enums, pending-discharge and pending-charge (Richard Hughes) - Use the global state to fix the unknown battery status (Richard Hughes) Bugfixes: - Suppress lid change event on startup (Martin Pitt) - Fix two issues with the pm-powersave code (Roland Dreier) - Mark batteries as empty if they have unknown state and a very low energy (Richard Hughes) - For power_supply, unknown is a valid state from the kernel (Richard Hughes) - Don't assume all batteries have positive energy_full values (Richard Hughes) - Add one more variation of lithium-poly (Richard Hughes) - Don't show empty vendor, model or serials in the debug outputs (Richard Hughes) - Fix a small memory leak on supply coldplugging (Richard Hughes) - Hardcode pm-powersave like we do pm-suspend and pm-hibernate (Richard Hughes) - Initial refresh after coldplug is not fatal if it fails (Richard Hughes) - Set the GObject properties correctly in the DkpDeviceHid class (Richard Hughes) - The UPS can't expose empty or fully-charged, so fixup these states (Richard Hughes) - Fix detecting the USB UPS devices (Richard Hughes) - Add a lid-is-present property (Richard Hughes) - Be less asserty when enum values are added in newer versions of the spec (Richard Hughes) - Add a DKP_CHECK_VERSION macro which we can use in client tools (Richard Hughes) - Move the udev rules to their own directory (Richard Hughes) - Move a small rule about the fully charged level from g-p-m (Richard Hughes) Version 008 ~~~~~~~~~~~ Released: 2009-06-01 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - The experimental devkit-power-gobject library has no API or ABI guarantees. New Features: - Allow the daemon to get the global online state for all devices (Matthew Garrett) - Add a has-capability to the org.freedesktop.DeviceKit.Power.Wakeups interface (Richard Hughes) - Add a property lid-is-closed for g-p-m and x-p-m to use (Richard Hughes) Bugfixes: - Fix up some issues in DkpClient, and expose GObject properties (Ali Abdallah) - Remove the 0x prefix from some rule matches (Ronald) - Allow all DBus properties to be read with the new DBus (Richard Hughes) - Only reset the update-time if the read was successful (Richard Hughes) - Optimise the udev rules to skip non-usb devices (Richard Hughes) - Ensure we get properties on devices correctly that have not yet been changed (Richard Hughes) - Make the suspend and hibernate scripts execute synchronously. Fixes rh#497563 (Richard Hughes) - Ignore method timeouts when we suspend and hibernate (Richard Hughes) - Add two missing files to the last commit (Richard Hughes) - Don't overwrite energy-full-design with zero after coldplug (Richard Hughes) - Only get the device state for the poll after the refresh (Richard Hughes) - Continue to poll when power supply device is marked unknown. Fixes rh#495493 (Richard Hughes) - Correct a debugging statement (Richard Hughes) - Never overwrite ID_PRODUCT or ID_VENDOR (Richard Hughes) - Don't return history data relative to the earliest point (Richard Hughes) - Setup different polls based on the battery state (Matthew Garrett) - Don't poll on unknown forever. Based on a patch from Matthew Garrett (Richard Hughes) - Fix up the return statuses from coldplug and refresh (Richard Hughes) - Only attempt to print history if the device is capable (Richard Hughes) - Allow properties in DkpDevice (client) to be set (Richard Hughes) Version 007 ~~~~~~~~~~~ Released: 2009-03-30 Note: - The DBus interface of DeviceKit-power may be subject to change in future versions of this daemon. - The experimental devkit-power-gobject library has no API or ABI guarantees. New Features: - Get rid of internal Object and instead use the GObject property system (Richard Hughes) - Move the library directory from libdevkit-power to devkit-power-gobject (Richard Hughes) - Ship a shared library. There are now three external projects using copies of this, which is rediculous (Richard Hughes) - Require I_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE (Richard Hughes) Bugfixes: - Fix up DBus interface for CVE-2008-4311 (Stanislav Brabec) - Fix g-p-m and DeviceKit-power when running with a permissive dbus. Fixes fd#20882 (Frederic Crozat) - Remove use of EggObjList, and make the library more sane (Richard Hughes) - Fix compile error in dkp-power. Fixes #20749 (Richard Hughes) Version 006 ~~~~~~~~~~~ Released: 2009-02-10 Bugfixes: - Fix compile failure with gcc-4.4.0 and old versions of glib2 (Richard Hughes) - Only enable the wakeups polling if a client requires the data (Richard Hughes) - Correctly set the power-supply property (David Zeuthen) - Don't crash when we limit the resolution of a small dataset (Richard Hughes) - Don't sync to disk every 5 seconds, do it every 10 minutes (Richard Hughes) - Fix the QoS interface with the proper signature (Richard Hughes) Version 005 ~~~~~~~~~~~ Released: 2009-02-02 New Features: - Add a wakeups interface so we can get data from the system over DBus (Richard Hughes) - Allow showing the wakeup data in the devkit-power command line tool (Richard Hughes) Version 004 ~~~~~~~~~~~ Released: 2009-01-23 Bugfixes: - Fix the battery capacity calculation. Fixes fd#19165 (Richard Hughes) - Special case machines where the kernel does not convert charge to power (Richard Hughes) - Check all the power supply fields for valid data (Richard Hughes) Version 003 ~~~~~~~~~~~ Released: 2008-12-09 New Features: - Implement the .QoS interface -- still proof of concept (Richard Hughes) Bugfixes: - Enable the low power saving code in DkpHistory (Richard Hughes) - Don't keep putting off the profile saving in DkpHistory (Richard Hughes) - Allow DeviceKit-power to run with the 'fixed' DBus (Richard Hughes) Version 002 ~~~~~~~~~~~ Released: 2008-11-13 New Features: - add in CanSuspend and CanHibernate into API (Richard Hughes) - add two new properties, has-history and has-statistics (Richard Hughes) - add voltage property of a power device (Richard Hughes) - all logging for all the other device types too (Richard Hughes) - Move object paths so things are rooted under /org/freedesktop/DeviceKit/Power (David Zeuthen) - Add functionality to monitor a Watts Up Pro device (Richard Hughes) - Turn some methods into properties (David Zeuthen) Bugfixes: - Also rename configure.in to configure.ac in autogen.sh (David Zeuthen) - Fix up deps and build system (David Zeuthen) - We're a fd.o project (David Zeuthen) - Update my email address (David Zeuthen) - Update mailing list reference in man pages (David Zeuthen) - Update bug report URL to point to our mailing list (David Zeuthen) - Nuke devkit-power-on-battery for now (David Zeuthen) - Don't report negative rate when charging (Richard Hughes) - Remove the battery- and line-power- prefix from the device properties (Richard Hughes) - Add DkpStatsObj convenience helpers (Richard Hughes) - Save the time to full and time to empty too (Richard Hughes) - Don't clear the list when we print it (Richard Hughes) - Support getting stats from DkpSupply devices (Richard Hughes) - Poll every 10 seconds to get better stats results (Richard Hughes) - Work out the statistics by binning them into percentage sized holes (Richard Hughes) - Add two remove functions to the generic object list (Richard Hughes) - Don't unconditionally set the energy_full to energy_full_design if larger (Richard Hughes) - Add a first approximation of a time resolution limiter (Richard Hughes) - Expand the client helper library to cover all the base API for gnome-power-manager (Richard Hughes) - Use 0 for unknown, not -1 as some values like rate and voltage are valid when negative (Richard Hughes) - Use a better resolution limiting function for getting the history to reduce CPU load (Richard Hughes) - Match the WUP device on the tty device, not the USB device (Richard Hughes) - Fix the include headers for DeviceKit 002 (Richard Hughes) - Document how to access the D-Bus service with examples (David Zeuthen) Version 001 ~~~~~~~~~~~ Released: 2008-09-02 - Initial proof of concept version 07070100000009000081A400000000000000000000000166EA481400000721000000000000000000000000000000000000001500000000upower-1.90.6/README=============== UPower =============== Requirements: glib-2.0 >= 2.66.0 gio-2.0 >= 2.16.1 gudev-1.0 >= 235 (Linux) libimobiledevice-1.0 >= 0.9.7 (optional) polkit-gobject-1 >= 124 UPower is an abstraction for enumerating power devices, listening to device events and querying history and statistics. Any application or service on the system can access the org.freedesktop.UPower service via the system message bus. Debugging --------- When doing bug reports, the following information can be useful: * `grep . /sys/class/power_supply/*/*`: This includes the current kernel view of all power supplies in the system. It is always a good idea to include this information. * `udevadm info -e`: This shows the hardware configuration and is relevant when e.g. the type of an external device is misdetected. * `upower -d`: Shows upower's view of the state * `upower --monitor-detail`: Dumps device information every time that a change happens. This helps with debugging dynamic issues. * `udevadm monitor`: Dumps the udev/kernel reported hardware changes (and addition/removal). This is helpful when debugging dynamic issues, in particular if it is not clear whether the issue is coming from the kernel or upower. In addition, it can also be useful to run upower in debug mode and post the logs. There are two ways of doing so: * Run upower daemon manually, you can do so using: `sudo /usr/libexec/upowerd -rd` * Modify the systemd service and restart. This is best done by: 1. `sudo systemctl edit upower.service` 2. Adding the two lines: ``` [Service] Environment=G_MESSAGES_DEBUG=all ``` 3. `sudo systemctl restart upower.service` 4. Grab logs using `journalctl -u upower.service` or similar 0707010000000A000081A400000000000000000000000166EA481400000281000000000000000000000000000000000000001600000000upower-1.90.6/RELEASEUPower Release Notes 1. Write NEWS entries for UPower in the same format as usual. git shortlog v0.99.14.. | grep -i -v trivial | grep -v Merge > NEWS.new Version 0.99.8 -------------- Released: 2017-xx-xx New Features: Bugfixes: 2. Commit changes to git (bump version in meson.build if needed): git branch -b <user>/v0.99.14 git commit -a -m "Release 0.99.14" 3. Run tests and try building a tarball meson dist 4. Create an MR and merge it 5. Tag the release git fetch origin git check master git evtag sign v0.99.14 git push --tags 4. Paste the release notes into the tag information 5. Optional: Do a post-release version bump0707010000000B000081A400000000000000000000000166EA4814000000A0000000000000000000000000000000000000002100000000upower-1.90.6/code-of-conduct.mdThis project and its community follow the [Freedesktop.org code of conduct] [Freedesktop.org code of conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/ 0707010000000C000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001300000000upower-1.90.6/dbus0707010000000D000081A400000000000000000000000166EA48140000045E000000000000000000000000000000000000001F00000000upower-1.90.6/dbus/meson.build upowerd_dbus_interfaces = [ [ 'daemon', 'org.freedesktop.UPower', 'Daemon' ], [ 'device', 'org.freedesktop.UPower.Device', 'Device' ], [ 'kbd-backlight', 'org.freedesktop.UPower.KbdBacklight', 'KbdBacklight' ], ] upowerd_dbus_headers = [] upowerd_dbus_sources = [] foreach interface: upowerd_dbus_interfaces xml = interface[1] + '.xml' t = gnome.gdbus_codegen('up-' + interface[0] + '-generated', sources: xml, autocleanup: 'all', annotations:[ [ interface[1], 'org.gtk.GDBus.C.Name', 'Exported' + interface[2] ] ], namespace: 'Up', object_manager: false, ) upowerd_dbus_sources += t[0] upowerd_dbus_headers += t[1] install_data(xml, install_dir: dbusdir / 'interfaces', ) endforeach upowerd_dbus = static_library('libupower-dbus', sources: upowerd_dbus_sources + upowerd_dbus_headers, dependencies: [ gobject_dep, gio_dep, gio_unix_dep ], ) upowerd_dbus_dep = declare_dependency( link_with: upowerd_dbus, include_directories: [ '.' ], sources: upowerd_dbus_headers, dependencies: [ gio_unix_dep ] ) 0707010000000E000081A400000000000000000000000166EA481400007EAB000000000000000000000000000000000000003500000000upower-1.90.6/dbus/org.freedesktop.UPower.Device.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ <!ENTITY ERROR_GENERAL "org.freedesktop.UPower.Device.GeneralError"> ]> <node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.freedesktop.UPower.Device"> <doc:doc> <doc:description> <doc:para> Objects implementing this interface are usually discovered through the <doc:tt>org.freedesktop.UPower</doc:tt> interface on the <doc:tt>/org/freedesktop/UPower</doc:tt> object on the D-Bus system bus service with the well-known name <doc:tt>org.freedesktop.UPower</doc:tt> using the <doc:ref type="method" to="Power.EnumerateDevices">EnumerateDevices</doc:ref> method. </doc:para> <doc:para> <doc:example language="shell" title="simple example"> <doc:code> $ dbus-send --print-reply \ --system \ --dest=org.freedesktop.UPower \ /org/freedesktop/UPower/devices/battery_BAT0 \ org.freedesktop.DBus.Properties.GetAll \ string:org.freedesktop.UPower.Device method return sender=:1.386 -> dest=:1.477 reply_serial=2 array [ dict entry( string "native-path" variant string "/sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0" ) dict entry( string "vendor" variant string "SONY" ) dict entry( string "model" variant string "42T4568" ) dict entry( string "serial" variant string "4179" ) dict entry( string "update-time" variant uint64 1226417875 ) dict entry( string "type" variant uint 2 ) dict entry( string "power-supply" variant boolean true ) dict entry( string "has-history" variant boolean true ) dict entry( string "has-statistics" variant boolean true ) dict entry( string "online" variant boolean false ) dict entry( string "energy" variant double 72.85 ) dict entry( string "energy-empty" variant double 0 ) dict entry( string "energy-full" variant double 74.55 ) dict entry( string "energy-full-design" variant double 74.88 ) dict entry( string "energy-rate" variant double 0 ) dict entry( string "voltage" variant double 16.415 ) dict entry( string "time-to-empty" variant int64 0 ) dict entry( string "time-to-full" variant int64 0 ) dict entry( string "percentage" variant double 97.7197 ) dict entry( string "is-present" variant boolean true ) dict entry( string "state" variant uint 3 ) dict entry( string "is-rechargeable" variant boolean true ) dict entry( string "capacity" variant double 100 ) dict entry( string "technology" variant uint 1 ) ] </doc:code> </doc:example> </doc:para> <doc:para> Unless otherwise noted, an empty string or the value 0 in a property on this interface means not set. </doc:para> </doc:description> </doc:doc> <!-- ************************************************************ --> <method name="Refresh"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <doc:doc> <doc:description> <doc:para> Refreshes the data collected from the power source. </doc:para> </doc:description> <doc:permission>Callers will need to make sure that the daemon was started in debug mode</doc:permission> <doc:errors> <doc:error name="&ERROR_GENERAL;">if an error occured while refreshing</doc:error> </doc:errors> </doc:doc> </method> <!-- ************************************************************ --> <method name="GetHistory"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg name="type" direction="in" type="s"> <doc:doc><doc:summary>The type of history. Valid types are <doc:tt>rate</doc:tt> or <doc:tt>charge</doc:tt>.</doc:summary></doc:doc> </arg> <arg name="timespan" direction="in" type="u"> <doc:doc><doc:summary>The amount of data to return in seconds, or 0 for all.</doc:summary></doc:doc> </arg> <arg name="resolution" direction="in" type="u"> <doc:doc> <doc:summary> The approximate number of points to return. A higher resolution is more accurate, at the expense of plotting speed. </doc:summary> </doc:doc> </arg> <arg name="data" direction="out" type="a(udu)"> <doc:doc><doc:summary> The history data for the power device, if the device supports history. Data is ordered from the earliest in time, to the newest data point. Each element contains the following members: <doc:list> <doc:item> <doc:term>time</doc:term> <doc:definition> The time value in seconds from the <doc:tt>gettimeofday()</doc:tt> method. </doc:definition> </doc:item> <doc:item> <doc:term>value</doc:term> <doc:definition> The data value, for instance the rate in W or the charge in %. </doc:definition> </doc:item> <doc:item> <doc:term>state</doc:term> <doc:definition> The state of the device, for instance <doc:tt>charging</doc:tt> or <doc:tt>discharging</doc:tt>. </doc:definition> </doc:item> </doc:list> </doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Gets history for the power device that is persistent across reboots. </doc:para> </doc:description> </doc:doc> </method> <!-- ************************************************************ --> <method name="GetStatistics"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg name="type" direction="in" type="s"> <doc:doc><doc:summary>The mode for the statistics. Valid types are <doc:tt>charging</doc:tt> or <doc:tt>discharging</doc:tt>.</doc:summary></doc:doc> </arg> <arg name="data" direction="out" type="a(dd)"> <doc:doc><doc:summary> The statistics data for the power device. Each element contains the following members: <doc:list> <doc:item> <doc:term>value</doc:term> <doc:definition> The value of the percentage point, usually in seconds </doc:definition> </doc:item> <doc:item> <doc:term>accuracy</doc:term> <doc:definition> The accuracy of the prediction in percent. </doc:definition> </doc:item> </doc:list> </doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Gets statistics for the power device that may be interesting to show on a graph in the session. </doc:para> </doc:description> </doc:doc> </method> <!-- ************************************************************ --> <method name="EnableChargeThreshold"> <arg name="chargeThreshold" direction="in" type="b"> <doc:doc> <doc:summary> If it is true, the battery charge will be limited to ChargeEndThreshold and start to charge when the battery is lower than ChargeStartThreshold. Moreovere, if ChargeEndThreshold and/or ChargeStartThreshold are not supported, charge limit functionality on the whole may still be supported but the firmware will choose its own thresholds. If it is false, the battery will always be fully charged. </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Limiting the battery charge to the configured thresholds ChargeStartThreshold and ChargeEndThreshold. </doc:para> </doc:description> <doc:errors> <doc:error name="&ERROR_GENERAL;">if an error occured while setting the battery charge limits</doc:error> </doc:errors> </doc:doc> </method> <!-- ************************************************************ --> <property name="NativePath" type="s" access="read"> <doc:doc> <doc:description> <doc:para> OS specific native path of the power source. On Linux this is the sysfs path, for example <doc:tt>/sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0</doc:tt>. Is blank if the device is being driven by a user space driver. </doc:para> </doc:description> </doc:doc> </property> <property name="Vendor" type="s" access="read"> <doc:doc> <doc:description> <doc:para> Name of the vendor of the battery. </doc:para> </doc:description> </doc:doc> </property> <property name="Model" type="s" access="read"> <doc:doc> <doc:description> <doc:para> Name of the model of this battery. </doc:para> </doc:description> </doc:doc> </property> <property name="Serial" type="s" access="read"> <doc:doc> <doc:description> <doc:para> Unique serial number of the battery. </doc:para> </doc:description> </doc:doc> </property> <property name="UpdateTime" type="t" access="read"> <doc:doc> <doc:description> <doc:para> The point in time (seconds since the Epoch Jan 1, 1970 0:00 UTC) that data was read from the power source. </doc:para> </doc:description> </doc:doc> </property> <property name="Type" type="u" access="read"> <doc:doc> <doc:description> <doc:para> Type of power source. </doc:para> <doc:list> <doc:item> <doc:term>0</doc:term><doc:definition>Unknown</doc:definition> </doc:item> <doc:item> <doc:term>1</doc:term><doc:definition>Line Power</doc:definition> </doc:item> <doc:item> <doc:term>2</doc:term><doc:definition>Battery</doc:definition> </doc:item> <doc:item> <doc:term>3</doc:term><doc:definition>Ups</doc:definition> </doc:item> <doc:item> <doc:term>4</doc:term><doc:definition>Monitor</doc:definition> </doc:item> <doc:item> <doc:term>5</doc:term><doc:definition>Mouse</doc:definition> </doc:item> <doc:item> <doc:term>6</doc:term><doc:definition>Keyboard</doc:definition> </doc:item> <doc:item> <doc:term>7</doc:term><doc:definition>Pda</doc:definition> </doc:item> <doc:item> <doc:term>8</doc:term><doc:definition>Phone</doc:definition> </doc:item> <doc:item> <doc:term>9</doc:term><doc:definition>Media Player</doc:definition> </doc:item> <doc:item> <doc:term>10</doc:term><doc:definition>Tablet</doc:definition> </doc:item> <doc:item> <doc:term>11</doc:term><doc:definition>Computer</doc:definition> </doc:item> <doc:item> <doc:term>12</doc:term><doc:definition>Gaming Input</doc:definition> </doc:item> <doc:item> <doc:term>13</doc:term><doc:definition>Pen</doc:definition> </doc:item> <doc:item> <doc:term>14</doc:term><doc:definition>Touchpad</doc:definition> </doc:item> <doc:item> <doc:term>15</doc:term><doc:definition>Modem</doc:definition> </doc:item> <doc:item> <doc:term>16</doc:term><doc:definition>Network</doc:definition> </doc:item> <doc:item> <doc:term>17</doc:term><doc:definition>Headset</doc:definition> </doc:item> <doc:item> <doc:term>18</doc:term><doc:definition>Speakers</doc:definition> </doc:item> <doc:item> <doc:term>19</doc:term><doc:definition>Headphones</doc:definition> </doc:item> <doc:item> <doc:term>20</doc:term><doc:definition>Video</doc:definition> </doc:item> <doc:item> <doc:term>21</doc:term><doc:definition>Other Audio</doc:definition> </doc:item> <doc:item> <doc:term>22</doc:term><doc:definition>Remote Control</doc:definition> </doc:item> <doc:item> <doc:term>23</doc:term><doc:definition>Printer</doc:definition> </doc:item> <doc:item> <doc:term>24</doc:term><doc:definition>Scanner</doc:definition> </doc:item> <doc:item> <doc:term>25</doc:term><doc:definition>Camera</doc:definition> </doc:item> <doc:item> <doc:term>26</doc:term><doc:definition>Wearable</doc:definition> </doc:item> <doc:item> <doc:term>27</doc:term><doc:definition>Toy</doc:definition> </doc:item> <doc:item> <doc:term>28</doc:term><doc:definition>Bluetooth Genreic</doc:definition> </doc:item> </doc:list> <doc:para> If the value is set to "Battery", you will need to verify that the property <doc:ref type="property" to="Source:PowerSupply">power-supply</doc:ref> has the value "true" before considering it as a laptop battery. Otherwise it will likely be the battery for a device of an unknown type. </doc:para> </doc:description> </doc:doc> </property> <property name="PowerSupply" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the power device is used to supply the system. This would be set TRUE for laptop batteries and UPS devices, but set FALSE for wireless mice or PDAs. </doc:para> </doc:description> </doc:doc> </property> <property name="HasHistory" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the power device has history. </doc:para> </doc:description> </doc:doc> </property> <property name="HasStatistics" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the power device has statistics. </doc:para> </doc:description> </doc:doc> </property> <property name="Online" type="b" access="read"> <doc:doc> <doc:description> <doc:para> Whether power is currently being provided through line power. This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "line-power". </doc:para> </doc:description> </doc:doc> </property> <property name="Energy" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Amount of energy (measured in Wh) currently available in the power source. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="EnergyEmpty" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Amount of energy (measured in Wh) in the power source when it's considered to be empty. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="EnergyFull" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Amount of energy (measured in Wh) in the power source when it's considered full. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="EnergyFullDesign" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Amount of energy (measured in Wh) the power source is designed to hold when it's considered full. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="EnergyRate" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Amount of energy being drained from the source, measured in W. If positive, the source is being discharged, if negative it's being charged. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="Voltage" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Voltage in the Cell or being recorded by the meter. </doc:para> </doc:description> </doc:doc> </property> <property name="ChargeCycles" type="i" access="read"> <doc:doc> <doc:description> <doc:para> The number of charge cycles as defined by the TCO certification, or -1 if that value is unknown or not applicable. </doc:para> </doc:description> </doc:doc> </property> <property name="Luminosity" type="d" access="read"> <doc:doc> <doc:description> <doc:para> Luminosity being recorded by the meter. </doc:para> </doc:description> </doc:doc> </property> <property name="TimeToEmpty" type="x" access="read"> <doc:doc> <doc:description> <doc:para> Number of seconds until the power source is considered empty. Is set to 0 if unknown. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="TimeToFull" type="x" access="read"> <doc:doc> <doc:description> <doc:para> Number of seconds until the power source is considered full. Is set to 0 if unknown. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="Percentage" type="d" access="read"> <doc:doc> <doc:description> <doc:para> The amount of energy left in the power source expressed as a percentage between 0 and 100. Typically this is the same as (<doc:ref type="property" to="Source:Energy">energy</doc:ref> - <doc:ref type="property" to="Source:EnergyEmpty">energy-empty</doc:ref>) / (<doc:ref type="property" to="Source:EnergyFull">energy-full</doc:ref> - <doc:ref type="property" to="Source:EnergyEmpty">energy-empty</doc:ref>). However, some primitive power sources are capable of only reporting percentages and in this case the energy-* properties will be unset while this property is set. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> <doc:para> The percentage will be an approximation if the <doc:ref type="property" to="BatteryLevel">battery level</doc:ref> is set to something other than None. The percentage is kept for compatibility reasons. </doc:para> </doc:description> </doc:doc> </property> <property name="Temperature" type="d" access="read"> <doc:doc> <doc:description> <doc:para> The temperature of the device in degrees Celsius. This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="IsPresent" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the power source is present in the bay. This field is required as some batteries are hot-removable, for example expensive UPS and most laptop batteries. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="State" type="u" access="read"> <doc:doc> <doc:description> <doc:para> The battery power state. </doc:para> <doc:list> <doc:item> <doc:term>0</doc:term><doc:definition>Unknown</doc:definition> </doc:item> <doc:item> <doc:term>1</doc:term><doc:definition>Charging</doc:definition> </doc:item> <doc:item> <doc:term>2</doc:term><doc:definition>Discharging</doc:definition> </doc:item> <doc:item> <doc:term>3</doc:term><doc:definition>Empty</doc:definition> </doc:item> <doc:item> <doc:term>4</doc:term><doc:definition>Fully charged</doc:definition> </doc:item> <doc:item> <doc:term>5</doc:term><doc:definition>Pending charge</doc:definition> </doc:item> <doc:item> <doc:term>6</doc:term><doc:definition>Pending discharge</doc:definition> </doc:item> </doc:list> <doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="IsRechargeable" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the power source is rechargeable. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="Capacity" type="d" access="read"> <doc:doc> <doc:description> <doc:para> The capacity of the power source expressed as a percentage between 0 and 100. The capacity of the battery will reduce with age. A capacity value less than 75% is usually a sign that you should renew your battery. Typically this value is the same as (<doc:ref type="property" to="Source:FullDesign">full-design</doc:ref> / <doc:ref type="property" to="Source:Full">full</doc:ref>) * 100. However, some primitive power sources are not capable reporting capacity and in this case the capacity property will be unset. </doc:para><doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="Technology" type="u" access="read"> <doc:doc> <doc:description> <doc:para> Technology used in the battery: </doc:para> <doc:list> <doc:item> <doc:term>0</doc:term><doc:definition>Unknown</doc:definition> </doc:item> <doc:item> <doc:term>1</doc:term><doc:definition>Lithium ion</doc:definition> </doc:item> <doc:item> <doc:term>2</doc:term><doc:definition>Lithium polymer</doc:definition> </doc:item> <doc:item> <doc:term>3</doc:term><doc:definition>Lithium iron phosphate</doc:definition> </doc:item> <doc:item> <doc:term>4</doc:term><doc:definition>Lead acid</doc:definition> </doc:item> <doc:item> <doc:term>5</doc:term><doc:definition>Nickel cadmium</doc:definition> </doc:item> <doc:item> <doc:term>6</doc:term><doc:definition>Nickel metal hydride</doc:definition> </doc:item> </doc:list> <doc:para> This property is only valid if the property <doc:ref type="property" to="Source:Type">type</doc:ref> has the value "battery". </doc:para> </doc:description> </doc:doc> </property> <property name="WarningLevel" type="u" access="read"> <doc:doc> <doc:description> <doc:para> Warning level of the battery: </doc:para> <doc:list> <doc:item> <doc:term>0</doc:term><doc:definition>Unknown</doc:definition> </doc:item> <doc:item> <doc:term>1</doc:term><doc:definition>None</doc:definition> </doc:item> <doc:item> <doc:term>2</doc:term><doc:definition>Discharging (only for UPSes)</doc:definition> </doc:item> <doc:item> <doc:term>3</doc:term><doc:definition>Low</doc:definition> </doc:item> <doc:item> <doc:term>4</doc:term><doc:definition>Critical</doc:definition> </doc:item> <doc:item> <doc:term>5</doc:term><doc:definition>Action</doc:definition> </doc:item> </doc:list> </doc:description> </doc:doc> </property> <property name="BatteryLevel" type="u" access="read"> <doc:doc> <doc:description> <doc:para> The level of the battery for devices which do not report a percentage but rather a coarse battery level. If the value is None, then the device does not support coarse battery reporting, and the percentage should be used instead. </doc:para> <doc:list> <doc:item> <doc:term>0</doc:term><doc:definition>Unknown</doc:definition> </doc:item> <doc:item> <doc:term>1</doc:term><doc:definition>None (the battery does not use a coarse level of battery reporting)</doc:definition> </doc:item> <doc:item> <doc:term>3</doc:term><doc:definition>Low</doc:definition> </doc:item> <doc:item> <doc:term>4</doc:term><doc:definition>Critical</doc:definition> </doc:item> <doc:item> <doc:term>6</doc:term><doc:definition>Normal</doc:definition> </doc:item> <doc:item> <doc:term>7</doc:term><doc:definition>High</doc:definition> </doc:item> <doc:item> <doc:term>8</doc:term><doc:definition>Full</doc:definition> </doc:item> </doc:list> </doc:description> </doc:doc> </property> <property name="IconName" type="s" access="read"> <doc:doc> <doc:description> <doc:para> <p>An icon name, following the <a href="http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html">Icon Naming Specification</a></p> <p>Note that the icons might not match end-user expectations in terms of presentation relative to the amount of battery left or perceived to be left. It is recommended that front-ends use the BatteryLevel property first, if available, followed by the Percentage, to present a more realistic battery level to the user.</p> </doc:para> </doc:description> </doc:doc> </property> <property name="ChargeStartThreshold" type="u" access="read"> <doc:doc> <doc:description> <doc:para> <p>When a start charge threshold is set the battery won't get charged until the charge drops under this threshold.</p> <p>In general case, ChargeStartThreshold is between 0 and 100. If it is G_MAXUINT, upower will skip to set charge_control_start_threshold.</p> </doc:para> </doc:description> </doc:doc> </property> <property name="ChargeEndThreshold" type="u" access="read"> <doc:doc> <doc:description> <doc:para> <p>The end charge threshold stops the battery from getting charged after the set threshold</p> <p>In general case, ChargeEndThreshold is between 0 and 100. If it is G_MAXUINT, upower will skip to set charge_control_end_threshold.</p> </doc:para> </doc:description> </doc:doc> </property> <property name="ChargeThresholdEnabled" type="b" access="read"> <doc:doc> <doc:description> <doc:para> <p>If battery charge start and end limits are applied.</p> </doc:para> </doc:description> </doc:doc> </property> <property name="ChargeThresholdSupported" type="b" access="read"> <doc:doc> <doc:description> <doc:para> <p>If setting battery charge limits is supported.</p> </doc:para> </doc:description> </doc:doc> </property> </interface> </node> 0707010000000F000081A400000000000000000000000166EA481400001056000000000000000000000000000000000000003B00000000upower-1.90.6/dbus/org.freedesktop.UPower.KbdBacklight.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ <!ENTITY ERROR_GENERAL "org.freedesktop.UPower.GeneralError"> ]> <node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.freedesktop.UPower.KbdBacklight"> <doc:doc> <doc:description> <doc:para> org.freedesktop.UPower.KbdBacklight is a DBus interface implemented by UPower. It allows the keyboard backlight (if present) to be controlled. </doc:para> </doc:description> </doc:doc> <!-- ************************************************************ --> <method name="GetMaxBrightness"> <arg name="value" direction="out" type="i"> <doc:doc> <doc:summary> The maximum value of the keyboard backlight brightness. </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Get the maximum brightness level for the keyboard backlight. </doc:para> </doc:description> <doc:errors> <doc:error name="&ERROR_GENERAL;">if an error occured while getting the maximum brightness</doc:error> </doc:errors> </doc:doc> </method> <!-- ************************************************************ --> <method name="GetBrightness"> <arg name="value" direction="out" type="i"> <doc:doc> <doc:summary> The current value of the keyboard backlight brightness. </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Get the brightness level of the keyboard backlight. </doc:para> </doc:description> <doc:errors> <doc:error name="&ERROR_GENERAL;">if an error occured while getting the brightness</doc:error> </doc:errors> </doc:doc> </method> <!-- ************************************************************ --> <method name="SetBrightness"> <arg name="value" direction="in" type="i"> <doc:doc> <doc:summary> The value to set the KbdBacklight brightness. </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Set the brightness level of the keyboard backlight. </doc:para> </doc:description> <doc:errors> <doc:error name="&ERROR_GENERAL;">if an error occured while setting the brightness</doc:error> </doc:errors> </doc:doc> </method> <!-- ************************************************************ --> <signal name="BrightnessChanged"> <arg name="value" direction="out" type="i"> <doc:doc> <doc:summary> The new brightness value of the keyboard backlight. </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> The keyboard backlight brightness level has changed. </doc:para> </doc:description> </doc:doc> </signal> <signal name="BrightnessChangedWithSource"> <arg name="value" direction="out" type="i"> <doc:doc> <doc:summary> The new brightness value of the keyboard backlight. </doc:summary> </doc:doc> </arg> <arg name="source" direction="out" type="s"> <doc:doc> <doc:summary> Source of the keyboard backlight brightness change, either "external" if SetBrightness was called, or "internal" if the hardware changed the keyboard brightness itself (automatically or through a firmware-handled hotkey being pressed). </doc:summary> </doc:doc> </arg> <doc:doc> <doc:description> <doc:para> The keyboard backlight brightness level has changed including information about the source of the change. </doc:para> </doc:description> </doc:doc> </signal> </interface> </node> 07070100000010000081A400000000000000000000000166EA481400001EFF000000000000000000000000000000000000002E00000000upower-1.90.6/dbus/org.freedesktop.UPower.xml<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.freedesktop.UPower"> <doc:doc> <doc:description> <doc:para> The UPower service is available via the system message bus. To access the service, use the <doc:tt>org.freedesktop.UPower</doc:tt> interface on the <doc:tt>/org/freedesktop/UPower</doc:tt> object on the D-Bus system bus service with the well-known name <doc:tt>org.freedesktop.UPower</doc:tt>. </doc:para> <doc:para> <doc:example language="shell" title="simple example"> <doc:code> $ dbus-send --print-reply \ --system \ --dest=org.freedesktop.UPower \ /org/freedesktop/UPower \ org.freedesktop.UPower.EnumerateDevices method return sender=:1.386 -> dest=:1.451 reply_serial=2 array [ object path "/org/freedesktop/UPower/devices/line_power_AC" object path "/org/freedesktop/UPower/devices/battery_BAT0" ] </doc:code> </doc:example> </doc:para> </doc:description> </doc:doc> <!-- ************************************************************ --> <method name="EnumerateDevices"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg name="devices" direction="out" type="ao"> <doc:doc><doc:summary>An array of object paths for devices.</doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Enumerate all power objects on the system. </doc:para> </doc:description> </doc:doc> </method> <method name="GetDisplayDevice"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg name="device" direction="out" type="o"> <doc:doc><doc:summary>An object path for the "display device.</doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Get the object to the "display device", a composite device that represents the status icon to show in desktop environments. You can also access the object directly as its path is guaranteed to be /org/freedesktop/UPower/devices/DisplayDevice. The following standard org.freedesktop.UPower.Device properties will be defined (only <doc:ref type="property" to="Source:IsPresent">IsPresent</doc:ref> takes a special meaning): <doc:list> <doc:item> <doc:term>Type</doc:term><doc:definition>the type of the display device, UPS or Battery. Note that this value can change, as opposed to real devices.</doc:definition> </doc:item> <doc:item> <doc:term>State</doc:term><doc:definition>the power state of the display device, such as Charging or Discharging.</doc:definition> </doc:item> <doc:item> <doc:term>Percentage</doc:term><doc:definition>the amount of energy left on the device.</doc:definition> </doc:item> <doc:item> <doc:term>Energy</doc:term><doc:definition>Amount of energy (measured in Wh) currently available in the power source.</doc:definition> </doc:item> <doc:item> <doc:term>EnergyFull</doc:term><doc:definition>Amount of energy (measured in Wh) in the power source when it's considered full.</doc:definition> </doc:item> <doc:item> <doc:term>EnergyRate</doc:term><doc:definition>Discharging/charging rate of the source, measured in Watt.</doc:definition> </doc:item> <doc:item> <doc:term>TimeToEmpty</doc:term><doc:definition>Number of seconds until the power source is considered empty.</doc:definition> </doc:item> <doc:item> <doc:term>TimeToFull</doc:term><doc:definition>Number of seconds until the power source is considered full.</doc:definition> </doc:item> <doc:item> <doc:term>IsPresent</doc:term><doc:definition>Whether a status icon using this information should be presented.</doc:definition> </doc:item> <doc:item> <doc:term>IconName</doc:term><doc:definition>An icon name representing the device state.</doc:definition> </doc:item> <doc:item> <doc:term>WarningLevel</doc:term><doc:definition>The same as the overall <doc:ref type="property" to="Source:WarningLevel">WarningLevel</doc:ref></doc:definition> </doc:item> </doc:list> </doc:para> </doc:description> </doc:doc> </method> <method name="GetCriticalAction"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg name="action" direction="out" type="s"> <doc:doc><doc:summary>A string representing the critical action configured and available.</doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> When the system's power supply is critical (critically low batteries or UPS), the system will take this action. Possible values are: <doc:list> <doc:item> <doc:term>HybridSleep</doc:term> </doc:item> <doc:item> <doc:term>Hibernate</doc:term> </doc:item> <doc:item> <doc:term>PowerOff</doc:term> </doc:item> </doc:list> </doc:para> </doc:description> </doc:doc> </method> <!-- ************************************************************ --> <signal name="DeviceAdded"> <arg name="device" type="o"> <doc:doc><doc:summary>Object path of device that was added.</doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Emitted when a device is added. </doc:para> </doc:description> </doc:doc> </signal> <!-- ************************************************************ --> <signal name="DeviceRemoved"> <arg name="device" type="o"> <doc:doc><doc:summary>Object path of device that was removed.</doc:summary></doc:doc> </arg> <doc:doc> <doc:description> <doc:para> Emitted when a device is removed. </doc:para> </doc:description> </doc:doc> </signal> <!-- ************************************************************ --> <property name="DaemonVersion" type="s" access="read"> <doc:doc><doc:description><doc:para> Version of the running daemon, e.g. <doc:tt>002</doc:tt>. </doc:para></doc:description></doc:doc> </property> <property name="OnBattery" type="b" access="read"> <doc:doc><doc:description><doc:para> Indicates whether the system is running on battery power. This property is provided for convenience. </doc:para></doc:description></doc:doc> </property> <property name="LidIsClosed" type="b" access="read"> <doc:doc> <doc:description> <doc:para> Indicates if the laptop lid is closed where the display cannot be seen. </doc:para> </doc:description> </doc:doc> </property> <property name="LidIsPresent" type="b" access="read"> <doc:doc> <doc:description> <doc:para> If the system has a lid device. </doc:para> </doc:description> </doc:doc> </property> </interface> </node> 07070100000011000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001200000000upower-1.90.6/doc07070100000012000081A400000000000000000000000166EA48140000045F000000000000000000000000000000000000002B00000000upower-1.90.6/doc/dbus-introspect-docs.dtd<!-- DTD for D-Bus Introspection Documentation --> <!ELEMENT doc (summary?,description?,errors?,permission?,since?,deprecated,seealso?)> <!ELEMENT summary (#PCDATA|ref)*> <!ELEMENT description (#PCDATA|para|example)*> <!ELEMENT errors (error)*> <!ELEMENT permission (#PCDATA|ref|para)*> <!ELEMENT since EMPTY> <!ATTLIST since version CDATA #REQUIRED> <!ELEMENT deprecated (#PCDATA|ref)> <!ATTLIST deprecated version CDATA #REQUIRED> <!ATTLIST deprecated instead CDATA #REQUIRED> <!ELEMENT seealso (ref+)> <!ELEMENT error (#PCDATA|para)*> <!ATTLIST error name CDATA #REQUIRED> <!ELEMENT para (#PCDATA|example|code|list|ref)*> <!ELEMENT example (#PCDATA|para|code|ref)*> <!ATTLIST language (c|glib|python|shell) #REQUIRED> <!ATTLIST title CDATA #IMPLIED> <!ELEMENT list (item*)> <!ATTLIST list type (bullet|number) #REQUIRED> <!ELEMENT item (term|definition)*> <!ELEMENT term (#PCDATA|ref)*> <!ELEMENT definition (#PCDATA|para)*> <!ELEMENT code (#PCDATA)> <!ATTLIST code lang CDATA #IMPLIED> <!ELEMENT ref CDATA> <!ATTLIST ref type (parameter|arg|signal|method|interface) #REQUIRED> <!ATTLIST ref to CDATA #REQUIRED> 07070100000013000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001600000000upower-1.90.6/doc/man07070100000014000081A400000000000000000000000166EA4814000006A6000000000000000000000000000000000000002100000000upower-1.90.6/doc/man/UPower.xml<refentry id="UPower.7"> <refentryinfo> <title>UPower</title> <date>March 2008</date> <productname>UPower</productname> </refentryinfo> <refmeta> <refentrytitle>UPower</refentrytitle> <manvolnum>7</manvolnum> <refmiscinfo class="version"></refmiscinfo> </refmeta> <refnamediv> <refname>UPower</refname> <refpurpose>System-wide Power Management</refpurpose> </refnamediv> <refsect1><title>DESCRIPTION</title> <para> UPower provides an interface to enumerate power sources on the system and control system-wide power management. Any application can access the <emphasis>org.freedesktop.UPower</emphasis> service on the system message bus. </para> </refsect1> <refsect1><title>AUTHOR</title> <para> Written by David Zeuthen <email>davidz@redhat.com</email>, Richard Hughes <email>richard@hughsie.com</email> and with a lot of help from many others. </para> </refsect1> <refsect1> <title>BUGS</title> <para> Please send bug reports to either the distribution or the DeviceKit mailing list, see <ulink url="http://lists.freedesktop.org/mailman/listinfo/devkit-devel"/> on how to subscribe. </para> </refsect1> <refsect1> <title>SEE ALSO</title> <para> <citerefentry> <refentrytitle>PolicyKit</refentrytitle><manvolnum>8</manvolnum> </citerefentry>, <citerefentry> <refentrytitle>upowerd</refentrytitle><manvolnum>8</manvolnum> </citerefentry>, <citerefentry> <refentrytitle>upower</refentrytitle><manvolnum>1</manvolnum> </citerefentry> </para> </refsect1> </refentry> 07070100000015000081A400000000000000000000000166EA48140000025E000000000000000000000000000000000000002200000000upower-1.90.6/doc/man/meson.build man_pages = [ [ 'upower', 1 ], [ 'upowerd', 8 ], [ 'UPower', 7 ], ] foreach man: man_pages custom_target( '@0@.@1@'.format(man[0], man[1]), input: files(join_paths(man[0] + '.xml')), output: '@0@.@1@'.format(man[0], man[1]), command: [xsltproc, '--output', '@OUTPUT@', '-nonet', 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl', '@INPUT@'], build_by_default: get_option('man'), install: get_option('man'), install_dir: get_option('prefix') / get_option('mandir') / 'man@0@'.format(man[1]), ) endforeach 07070100000016000081A400000000000000000000000166EA481400000B07000000000000000000000000000000000000002100000000upower-1.90.6/doc/man/upower.xml<refentry id="upower.1"> <refentryinfo> <title>upower</title> <date>April 2008</date> <productname>upower</productname> </refentryinfo> <refmeta> <refentrytitle>upower</refentrytitle> <manvolnum>1</manvolnum> <refmiscinfo class="version"></refmiscinfo> </refmeta> <refnamediv> <refname>upower</refname> <refpurpose>UPower command line tool</refpurpose> </refnamediv> <refsynopsisdiv> <cmdsynopsis> <command>upower</command> <arg><option>--dump</option></arg> <arg><option>--enumerate</option></arg> <arg><option>--monitor-detail</option></arg> <arg><option>--monitor</option></arg> <arg><option>--show-info</option></arg> <arg><option>--version</option></arg> <arg><option>--help</option></arg> </cmdsynopsis> </refsynopsisdiv> <refsect1><title>DESCRIPTION</title> <para> <emphasis><refentrytitle>upower</refentrytitle></emphasis> is a simple command line client for the <citerefentry><refentrytitle>UPower</refentrytitle><manvolnum>7</manvolnum></citerefentry> daemon. TODO: not fully documented. </para> </refsect1> <refsect1> <title>OPTIONS</title> <variablelist> <varlistentry> <term><option>--monitor</option></term> <listitem> <para> Connect to the UPower daemon and print a line every time a power source is added, removed or changed. </para> </listitem> </varlistentry> <varlistentry> <term><option>--monitor-detail</option></term> <listitem> <para> Like <option>--monitor</option> but prints the full details of the power source whenever an event happens. </para> </listitem> </varlistentry> <varlistentry> <term><option>--help</option></term> <listitem> <para> Show help options. </para> </listitem> </varlistentry> </variablelist> </refsect1> <refsect1><title>AUTHOR</title> <para> Written by David Zeuthen <email>davidz@redhat.com</email> with a lot of help from many others. </para> </refsect1> <refsect1> <title>BUGS</title> <para> Please send bug reports to either the distribution or the DeviceKit mailing list, see <ulink url="http://lists.freedesktop.org/mailman/listinfo/devkit-devel"/> on how to subscribe. </para> </refsect1> <refsect1> <title>SEE ALSO</title> <para> <citerefentry> <refentrytitle>upowerd</refentrytitle><manvolnum>8</manvolnum> </citerefentry>, <citerefentry> <refentrytitle>UPower</refentrytitle><manvolnum>7</manvolnum> </citerefentry>, </para> </refsect1> </refentry> 07070100000017000081A400000000000000000000000166EA481400000900000000000000000000000000000000000000002200000000upower-1.90.6/doc/man/upowerd.xml<refentry id="upowerd.8"> <refentryinfo> <title>upowerd</title> <date>April 2008</date> <productname>upowerd</productname> </refentryinfo> <refmeta> <refentrytitle>upowerd</refentrytitle> <manvolnum>8</manvolnum> <refmiscinfo class="version"></refmiscinfo> </refmeta> <refnamediv> <refname>upowerd</refname> <refpurpose>UPower Daemon</refpurpose> </refnamediv> <refsynopsisdiv> <cmdsynopsis> <command>upowerd</command> <arg><option>--help</option></arg> </cmdsynopsis> </refsynopsisdiv> <refsect1><title>DESCRIPTION</title> <para> <emphasis><refentrytitle>upowerd</refentrytitle></emphasis> provides the <emphasis>org.freedesktop.UPower</emphasis> service on the system message bus. Users or administrators should never need to start this daemon as it will be automatically started by <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry> whenever an application calls into the <emphasis>org.freedesktop.UPower</emphasis> service. </para> </refsect1> <refsect1> <title>OPTIONS</title> <variablelist> <varlistentry> <term><option>--help</option></term> <listitem> <para> Show help options. </para> </listitem> </varlistentry> </variablelist> </refsect1> <refsect1><title>AUTHOR</title> <para> Written by David Zeuthen <email>davidz@redhat.com</email> with a lot of help from many others. </para> </refsect1> <refsect1> <title>BUGS</title> <para> Please send bug reports to either the distribution or the DeviceKit mailing list, see <ulink url="http://lists.freedesktop.org/mailman/listinfo/devkit-devel"/> on how to subscribe. </para> </refsect1> <refsect1> <title>SEE ALSO</title> <para> <citerefentry> <refentrytitle>UPower</refentrytitle><manvolnum>7</manvolnum> </citerefentry>, <citerefentry> <refentrytitle>upower</refentrytitle><manvolnum>1</manvolnum> </citerefentry>, <citerefentry> <refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum> </citerefentry>, </para> </refsect1> </refentry> 07070100000018000081A400000000000000000000000166EA481400000515000000000000000000000000000000000000001E00000000upower-1.90.6/doc/meson.buildsubdir('man') ifaces_refs = [] dbus_dir = join_paths(meson.project_source_root(), 'dbus') spec_to_docbook = files('spec-to-docbook.xsl') foreach iface: upowerd_dbus_interfaces iface = iface[1] iface_ref = iface + '.ref.xml' ifaces_refs += custom_target( iface_ref, input: files(dbus_dir / iface + '.xml'), output: iface_ref, command: [xsltproc, '--output', '@OUTPUT@', spec_to_docbook, '@INPUT@'], # gnome.gtkdoc dependencies don't work properly # https://github.com/mesonbuild/meson/pull/9960 build_by_default: get_option('gtk-doc'), ) endforeach cdata = configuration_data() cdata.set('VERSION', meson.project_version()) version_xml = configure_file( output: 'version.xml', input: 'version.xml.in', configuration: cdata) if get_option('gtk-doc') gnome.gtkdoc('UPower', main_xml: 'upower-docs.xml', src_dir: meson.project_source_root() / 'libupower-glib', dependencies: [ libupower_glib_dep ], scan_args: ['--rebuild-types', '--rebuild-sections'], content_files: [ version_xml, ifaces_refs, 'man/UPower.xml', 'man/upowerd.xml', 'man/upower.xml', '../COPYING', ], ignore_headers: [ 'config.h', ], install: true ) endif 07070100000019000081A400000000000000000000000166EA481400004CEF000000000000000000000000000000000000002600000000upower-1.90.6/doc/spec-to-docbook.xsl<?xml version='1.0'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd" exclude-result-prefixes="doc"> <!-- Convert D-Bus Glib xml into DocBook refentries Copyright (C) 2007 William Jon McCann License: GPL --> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:template match="/"> <xsl:variable name="interface" select="//interface/@name"/> <xsl:variable name="basename"> <xsl:call-template name="interface-basename"> <xsl:with-param name="str" select="$interface"/> </xsl:call-template> </xsl:variable> <refentry><xsl:attribute name="id"><xsl:value-of select="$basename"/></xsl:attribute> <refmeta> <refentrytitle role="top_of_page"><xsl:value-of select="//interface/@name"/></refentrytitle> </refmeta> <refnamediv> <refname><xsl:value-of select="//interface/@name"/></refname> <refpurpose><xsl:value-of select="$basename"/> interface</refpurpose> </refnamediv> <refsynopsisdiv role="synopsis"> <title role="synopsis.title">Methods</title> <synopsis> <xsl:call-template name="methods-synopsis"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </synopsis> </refsynopsisdiv> <xsl:choose> <xsl:when test="count(///signal) > 0"> <refsect1 role="signal_proto"> <title role="signal_proto.title">Signals</title> <synopsis> <xsl:call-template name="signals-synopsis"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </synopsis> </refsect1> </xsl:when> </xsl:choose> <refsect1 role="impl_interfaces"> <title role="impl_interfaces.title">Implemented Interfaces</title> <para> Objects implementing <xsl:value-of select="$interface"/> also implements org.freedesktop.DBus.Introspectable, org.freedesktop.DBus.Properties </para> </refsect1> <xsl:choose> <xsl:when test="count(///property) > 0"> <refsect1 role="properties"> <title role="properties.title">Properties</title> <synopsis> <xsl:call-template name="properties-synopsis"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </synopsis> </refsect1> </xsl:when> </xsl:choose> <refsect1 role="desc"> <title role="desc.title">Description</title> <para> <xsl:apply-templates select="//interface/doc:doc"/> </para> </refsect1> <refsect1 role="details"> <title role="details.title">Details</title> <xsl:call-template name="method-details"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </refsect1> <xsl:choose> <xsl:when test="count(///signal) > 0"> <refsect1 role="signals"> <title role="signals.title">Signal Details</title> <xsl:call-template name="signal-details"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </refsect1> </xsl:when> </xsl:choose> <xsl:choose> <xsl:when test="count(///property) > 0"> <refsect1 role="property_details"> <title role="property_details.title">Property Details</title> <xsl:call-template name="property-details"> <xsl:with-param name="basename" select="$basename"/> </xsl:call-template> </refsect1> </xsl:when> </xsl:choose> </refentry> </xsl:template> <xsl:template name="property-doc"> <xsl:apply-templates select="doc:doc/doc:description"/> <variablelist role="params"> <xsl:for-each select="arg"> <varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> <listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> </varlistentry> </xsl:for-each> </variablelist> <xsl:apply-templates select="doc:doc/doc:since"/> <xsl:apply-templates select="doc:doc/doc:deprecated"/> <xsl:apply-templates select="doc:doc/doc:permission"/> <xsl:apply-templates select="doc:doc/doc:seealso"/> </xsl:template> <xsl:template name="property-details"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///property"> <refsect2> <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property</title> <indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> <programlisting>'<xsl:value-of select="@name"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="2"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/></xsl:call-template></programlisting> </refsect2> <xsl:call-template name="property-doc"/> </xsl:for-each> </xsl:template> <xsl:template name="signal-doc"> <xsl:apply-templates select="doc:doc/doc:description"/> <variablelist role="params"> <xsl:for-each select="arg"> <varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> <listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> </varlistentry> </xsl:for-each> </variablelist> <xsl:apply-templates select="doc:doc/doc:since"/> <xsl:apply-templates select="doc:doc/doc:deprecated"/> <xsl:apply-templates select="doc:doc/doc:permission"/> <xsl:apply-templates select="doc:doc/doc:seealso"/> </xsl:template> <xsl:template name="signal-details"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///signal"> <refsect2> <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal</title> <indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> <programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> </refsect2> <xsl:call-template name="signal-doc"/> </xsl:for-each> </xsl:template> <xsl:template match="doc:code"> <programlisting> <xsl:apply-templates /> </programlisting> </xsl:template> <xsl:template match="doc:tt"> <literal> <xsl:apply-templates /> </literal> </xsl:template> <xsl:template match="doc:i"> <emphasis> <xsl:apply-templates /> </emphasis> </xsl:template> <xsl:template match="doc:b"> <emphasis role="bold"> <xsl:apply-templates /> </emphasis> </xsl:template> <xsl:template match="doc:ulink"> <ulink> <xsl:attribute name="url"><xsl:value-of select="@url"/></xsl:attribute> <xsl:value-of select="."/> </ulink> </xsl:template> <xsl:template match="doc:summary"> <xsl:apply-templates /> </xsl:template> <xsl:template match="doc:example"> <informalexample> <xsl:apply-templates /> </informalexample> </xsl:template> <xsl:template name="listitems-do-term"> <xsl:param name="str"/> <xsl:choose> <xsl:when test="string-length($str) > 0"> <emphasis role="bold"><xsl:value-of select="$str"/>: </emphasis> </xsl:when> </xsl:choose> </xsl:template> <xsl:template name="do-listitems"> <xsl:for-each select="doc:item"> <listitem> <xsl:call-template name="listitems-do-term"><xsl:with-param name="str" select="doc:term"/></xsl:call-template> <xsl:apply-templates select="doc:definition"/> </listitem> </xsl:for-each> </xsl:template> <xsl:template match="doc:list"> <para> <xsl:choose> <xsl:when test="contains(@type,'number')"> <orderedlist> <xsl:call-template name="do-listitems"/> </orderedlist> </xsl:when> <xsl:otherwise> <itemizedlist> <xsl:call-template name="do-listitems"/> </itemizedlist> </xsl:otherwise> </xsl:choose> </para> </xsl:template> <xsl:template match="doc:para"> <para> <xsl:apply-templates /> </para> </xsl:template> <xsl:template match="doc:description"> <xsl:apply-templates /> </xsl:template> <xsl:template match="doc:since"> <para role="since">Since <xsl:value-of select="@version"/> </para> </xsl:template> <xsl:template match="doc:deprecated"> <xsl:variable name="name" select="../../@name"/> <xsl:variable name="parent"> <xsl:call-template name="interface-basename"> <xsl:with-param name="str" select="../../../@name"/>/> </xsl:call-template> </xsl:variable> <xsl:variable name="type" select="name(../..)"/> <para role="deprecated"> <warning><para><literal><xsl:value-of select="$name"/></literal> is deprecated since version <xsl:value-of select="@version"/> and should not be used in newly-written code. Use <xsl:variable name="to"> <xsl:choose> <xsl:when test="contains($type,'property')"> <xsl:value-of select="$parent"/>:<xsl:value-of select="@instead"/> </xsl:when> <xsl:when test="contains($type,'signal')"> <xsl:value-of select="$parent"/>::<xsl:value-of select="@instead"/> </xsl:when> <xsl:when test="contains($type,'method')"> <xsl:value-of select="$parent"/>.<xsl:value-of select="@instead"/> </xsl:when> <xsl:when test="contains($type,'interface')"> <xsl:value-of select="@instead"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="@instead"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:call-template name="create-link"> <xsl:with-param name="type" select="$type"/> <xsl:with-param name="to" select="$to"/> <xsl:with-param name="val" select="@instead"/> </xsl:call-template> instead.</para></warning> </para> </xsl:template> <xsl:template match="doc:permission"> <para role="permission"> <xsl:apply-templates /> </para> </xsl:template> <xsl:template match="doc:errors"> <para role="errors"> <xsl:apply-templates /> </para> </xsl:template> <xsl:template match="doc:seealso"> <para> See also: <xsl:apply-templates /> </para> </xsl:template> <xsl:template name="create-link"> <xsl:param name="type"/> <xsl:param name="to"/> <xsl:param name="val"/> <xsl:choose> <xsl:when test="contains($type,'property')"> <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> </xsl:when> <xsl:when test="contains($type,'signal')"> <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> </xsl:when> <xsl:when test="contains($type,'method')"> <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><function><xsl:value-of select="$val"/></function></link> </xsl:when> <xsl:when test="contains($type,'interface')"> <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link> </xsl:when> </xsl:choose> </xsl:template> <xsl:template match="doc:ref"> <xsl:call-template name="create-link"> <xsl:with-param name="type" select="@type"/> <xsl:with-param name="to" select="@to"/> <xsl:with-param name="val" select="."/> </xsl:call-template> </xsl:template> <xsl:template name="method-doc"> <xsl:apply-templates select="doc:doc/doc:description"/> <variablelist role="params"> <xsl:for-each select="arg"> <varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> <listitem><simpara><xsl:apply-templates select="doc:doc/doc:summary"/></simpara></listitem> </varlistentry> </xsl:for-each> </variablelist> <xsl:apply-templates select="doc:doc/doc:since"/> <xsl:apply-templates select="doc:doc/doc:deprecated"/> <xsl:choose> <xsl:when test="count(doc:doc/doc:errors) > 0"> <refsect3> <title>Errors</title> <variablelist role="errors"> <xsl:for-each select="doc:doc/doc:errors/doc:error"> <varlistentry> <term><parameter><xsl:value-of select="@name"/></parameter>:</term> <listitem><simpara><xsl:apply-templates select="."/></simpara></listitem> </varlistentry> </xsl:for-each> </variablelist> </refsect3> </xsl:when> </xsl:choose> <xsl:choose> <xsl:when test="count(doc:doc/doc:permission) > 0"> <refsect3> <title>Permissions</title> <xsl:apply-templates select="doc:doc/doc:permission"/> </refsect3> </xsl:when> </xsl:choose> <xsl:apply-templates select="doc:doc/doc:seealso"/> </xsl:template> <xsl:template name="method-details"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///method"> <refsect2> <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> ()</title> <indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> <programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="method-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> </refsect2> <xsl:call-template name="method-doc"/> </xsl:for-each> </xsl:template> <xsl:template name="properties-synopsis"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="///property/@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///property"> <link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute>'<xsl:value-of select="@name"/>'</link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="$longest + 2"/></xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name="signals-synopsis"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="///signal/@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///signal"> <link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///signal"/></xsl:call-template>) </xsl:for-each> </xsl:template> <xsl:template name="methods-synopsis"> <xsl:param name="basename"/> <xsl:variable name="longest"> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="///method/@name"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="///method"> <link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="method-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///method"/></xsl:call-template>) </xsl:for-each> </xsl:template> <xsl:template name="method-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg"><xsl:value-of select="@direction"/> <xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="4 - string-length(@direction)"/></xsl:call-template>'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> <xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, <xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> </xsl:for-each> </xsl:template> <xsl:template name="signal-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg">'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> <xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, <xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> </xsl:for-each> </xsl:template> <xsl:template name="property-args"><xsl:param name="indent"/> <xsl:value-of select="@access"/><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="9 - string-length(@access) + 1"/></xsl:call-template>'<xsl:value-of select="@type"/>' </xsl:template> <xsl:template name="pad-spaces"> <xsl:param name="width"/> <xsl:variable name="spaces" xml:space="preserve"> </xsl:variable> <xsl:value-of select="substring($spaces,1,$width)"/> </xsl:template> <xsl:template name="find-longest"> <xsl:param name="set"/> <xsl:param name="index" select="1"/> <xsl:param name="longest" select="0"/> <xsl:choose> <xsl:when test="$index > count($set)"> <!--finished looking--> <xsl:value-of select="$longest"/> </xsl:when> <xsl:when test="string-length($set[$index])>$longest"> <!--found new longest--> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="$set"/> <xsl:with-param name="index" select="$index + 1"/> <xsl:with-param name="longest" select="string-length($set[$index])"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <!--this isn't any longer--> <xsl:call-template name="find-longest"> <xsl:with-param name="set" select="$set"/> <xsl:with-param name="index" select="$index + 1"/> <xsl:with-param name="longest" select="$longest"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="interface-basename"> <xsl:param name="str"/> <xsl:choose> <xsl:when test="contains($str,'.')"> <xsl:call-template name="interface-basename"> <xsl:with-param name="str" select="substring-after($str,'.')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$str"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> 0707010000001A000081A400000000000000000000000166EA481400000E8E000000000000000000000000000000000000002200000000upower-1.90.6/doc/upower-docs.xml<?xml version="1.0"?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ <!ENTITY version SYSTEM "version.xml"> ]> <book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> <bookinfo> <title>UPower Reference Manual</title> <releaseinfo>Version &version;</releaseinfo> <authorgroup> <author> <firstname>Richard</firstname> <surname>Hughes</surname> <affiliation> <address> <email>richard@hughsie.com</email> </address> </affiliation> </author> </authorgroup> <copyright> <year>2010</year> <holder>The UPower Authors</holder> </copyright> <legalnotice> <para> Permission is granted to copy, distribute and/or modify this document under the terms of the <citetitle>GNU Free Documentation License</citetitle>, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the <citetitle>GNU Free Documentation License</citetitle> from the Free Software Foundation by visiting <ulink type="http" url="http://www.fsf.org">their Web site</ulink> or by writing to: <address> The Free Software Foundation, Inc., <street>59 Temple Place</street> - Suite 330, <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>, <country>USA</country> </address> </para> <para> Many of the names used by companies to distinguish their products and services are claimed as trademarks. Where those names appear in any freedesktop.org documentation, and those trademarks are made aware to the members of the freedesktop.org Project, the names have been printed in caps or initial caps. </para> </legalnotice> </bookinfo> <reference id="ref-dbus"> <title>D-Bus API Reference</title> <partintro> <para> This part documents the D-Bus interface used to access the UPower daemon. </para> </partintro> <xi:include href="org.freedesktop.UPower.ref.xml"/> <xi:include href="org.freedesktop.UPower.Device.ref.xml"/> <xi:include href="org.freedesktop.UPower.KbdBacklight.ref.xml"/> </reference> <reference id="libupower-glib"> <title>libupower-glib GObjects</title> <partintro> <para> This part documents GObjects used in libupower-glib. </para> </partintro> <xi:include href="xml/up-client.xml"/> <xi:include href="xml/up-device.xml"/> <xi:include href="xml/up-history-item.xml"/> <xi:include href="xml/up-stats-item.xml"/> </reference> <reference id="libupower-glib-helpers"> <title>libupower-glib helpers</title> <partintro> <para> This part documents helper funtions in libupower-glib. </para> </partintro> <xi:include href="xml/up-types.xml"/> </reference> <reference id="tools-fileformats"> <title>Manual Pages</title> <partintro> <para> This part contains the manual pages distributed with UPower. </para> </partintro> <xi:include href="man/UPower.xml"/> <xi:include href="man/upowerd.xml"/> <xi:include href="man/upower.xml"/> </reference> <index> <title>Index</title> </index> <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include> <!-- License --> <appendix id="license"> <title>License</title> <para> <programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../COPYING" parse="text"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting> </para> </appendix> </book> 0707010000001B000081A400000000000000000000000166EA48140000000A000000000000000000000000000000000000002100000000upower-1.90.6/doc/version.xml.in@VERSION@ 0707010000001C000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001200000000upower-1.90.6/etc0707010000001D000081A400000000000000000000000166EA481400000D36000000000000000000000000000000000000001E00000000upower-1.90.6/etc/UPower.conf# Only the system vendor should modify this file, ordinary users # should not have to change anything. [UPower] # Enable the Watts Up Pro device. # # The Watts Up Pro contains a generic FTDI USB device without a specific # vendor and product ID. When we probe for WUP devices, we can cause # the user to get a perplexing "Device or resource busy" error when # attempting to use their non-WUP device. # # The generic FTDI device is known to also be used on: # # - Sparkfun FT232 breakout board # - Parallax Propeller # # default=false EnableWattsUpPro=false # Don't poll the kernel for battery level changes. # # Some hardware will send us battery level changes through # events, rather than us having to poll for it. This option # allows disabling polling for hardware that sends out events. # # default=false NoPollBatteries=false # Do we ignore the lid state # # Some laptops are broken. The lid state is either inverted, or stuck # on or off. We can't do much to fix these problems, but this is a way # for users to make the laptop panel vanish, a state that might be used # by a couple of user-space daemons. On Linux systems, see also # logind.conf(5). # # default=false IgnoreLid=false # Policy for warnings and action based on battery levels # # Whether battery percentage based policy should be used. The default # is to use the time left, change to true to use the percentage, which # should work around broken firmwares. It is also more reliable than # the time left (frantically saving all your files is going to use more # battery than letting it rest for example). # default=true UsePercentageForPolicy=true # When UsePercentageForPolicy is true, the levels at which UPower will # consider the battery low, critical, or take action for the critical # battery level. # # This will also be used for batteries which don't have time information # such as that of peripherals. # # If any value is invalid, or not in descending order, the defaults # will be used. # # Defaults: # PercentageLow=20.0 # PercentageCritical=5.0 # PercentageAction=2.0 PercentageLow=20.0 PercentageCritical=5.0 PercentageAction=2.0 # When UsePercentageForPolicy is false, the time remaining in seconds at # which UPower will consider the battery low, critical, or take action for # the critical battery level. # # If any value is invalid, or not in descending order, the defaults # will be used. # # Defaults: # TimeLow=1200 # TimeCritical=300 # TimeAction=120 TimeLow=1200 TimeCritical=300 TimeAction=120 # Enable the risky CriticalPowerAction-Suspend # This option is not recommended, but it is here for users who # want to enable the riscky CriticalPowerAction, such as "Suspend" # to fulfil their needs. # Default is false AllowRiskyCriticalPowerAction=false # The action to take when "TimeAction" or "PercentageAction" above has been # reached for the batteries (UPS or laptop batteries) supplying the computer # # Possible values are: # PowerOff # Hibernate # HybridSleep # Suspend (AllowRiskyCriticalPowerAction should be true to use this option but risky) # Ignore (AllowRiskyCriticalPowerAction should be true to use this option but risky) # # If Suspend isn't available or AllowRiskyCriticalPowerAction=false, HybridSleep will be used # If HybridSleep isn't available, Hibernate will be used # If Hibernate isn't available, PowerOff will be used CriticalPowerAction=HybridSleep 0707010000001E000081A400000000000000000000000166EA48140000004E000000000000000000000000000000000000001E00000000upower-1.90.6/etc/meson.buildinstall_data('UPower.conf', install_dir: get_option('sysconfdir') / 'UPower') 0707010000001F000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001D00000000upower-1.90.6/libupower-glib07070100000020000081A400000000000000000000000166EA48140000087D000000000000000000000000000000000000002900000000upower-1.90.6/libupower-glib/meson.buildversion_arr = meson.project_version().split('.') major_version = version_arr[0].to_int() minor_version = version_arr[1].to_int() micro_version = version_arr[2].to_int() cdata = configuration_data() cdata.set('UP_MAJOR_VERSION', major_version) cdata.set('UP_MINOR_VERSION', minor_version) cdata.set('UP_MICRO_VERSION', micro_version) up_version_h = configure_file( output: 'up-version.h', input: 'up-version.h.in', configuration: cdata, ) libupower_glib_headers = [ 'upower.h', 'up-autocleanups.h', 'up-types.h', 'up-device.h', 'up-stats-item.h', 'up-history-item.h', 'up-client.h', up_version_h, ] libupower_glib_sources = [ 'up-types.c', 'up-client.c', 'up-stats-item.c', 'up-history-item.c', 'up-device.c', ] install_headers(libupower_glib_headers, subdir: 'libupower-glib' ) libupower_glib = shared_library('upower-glib', sources: libupower_glib_headers + libupower_glib_sources, dependencies: [ gobject_dep, gio_dep, upowerd_dbus_dep ], include_directories: [ '..' ], c_args: [ '-DUP_COMPILATION', '-DG_LOG_DOMAIN="libupower-glib"', ], soversion: soversion, version: libversion, install: true, ) libupower_glib_dep = declare_dependency( sources: libupower_glib_headers, link_with: libupower_glib, # FIXME: The libupower-glib prefix is used inconsistently when including include_directories: [ '.', '..' ], dependencies: [ gobject_dep, gio_dep ], ) if gobject_introspection.found() gir = gnome.generate_gir(libupower_glib, sources : libupower_glib_headers + libupower_glib_sources, namespace : 'UPowerGlib', symbol_prefix : 'up_', identifier_prefix : 'Up', extra_args : [ '--c-include=upower.h', ], link_with : libupower_glib, nsversion: '1.0', dependencies : [ gobject_dep, gio_dep, declare_dependency(compile_args: [ '-DUP_COMPILATION' ]), ], includes : [ 'GObject-2.0', 'Gio-2.0', ], install : true) libupower_glib_typelib = gir[1] endif 07070100000021000081A400000000000000000000000166EA481400000583000000000000000000000000000000000000002F00000000upower-1.90.6/libupower-glib/up-autocleanups.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Kalev Lember <klember@redhat.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_AUTOCLEANUPS_H #define __UP_AUTOCLEANUPS_H #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC(UpClient, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(UpDevice, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(UpHistoryItem, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(UpStatsItem, g_object_unref) #endif #endif /* __UP_AUTOCLEANUPS_H */ 07070100000022000081A400000000000000000000000166EA481400004849000000000000000000000000000000000000002900000000upower-1.90.6/libupower-glib/up-client.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008-2010 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-client * @short_description: Main client object for accessing the UPower daemon * @see_also: #UpDevice * * A helper GObject to use for accessing UPower information, and to be notified * when it is changed. */ #include "config.h" #include <stdlib.h> #include <stdio.h> #include <glib-object.h> #include "upower.h" #include "up-daemon-generated.h" static void up_client_class_init (UpClientClass *klass); static void up_client_initable_iface_init (GInitableIface *iface); static void up_client_async_initable_iface_init (GAsyncInitableIface *async_initable_iface); static void up_client_init (UpClient *client); static void up_client_finalize (GObject *object); /** * UpClientPrivate: * * Private #UpClient data **/ struct _UpClientPrivate { UpExportedDaemon *proxy; }; enum { UP_CLIENT_DEVICE_ADDED, UP_CLIENT_DEVICE_REMOVED, UP_CLIENT_LAST_SIGNAL }; enum { PROP_0, PROP_DAEMON_VERSION, PROP_ON_BATTERY, PROP_LID_IS_CLOSED, PROP_LID_IS_PRESENT, PROP_LAST }; static guint signals [UP_CLIENT_LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE (UpClient, up_client, G_TYPE_OBJECT, G_ADD_PRIVATE(UpClient) G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, up_client_initable_iface_init) G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, up_client_async_initable_iface_init)) /** * up_client_get_devices: * @client: a #UpClient instance. * * Get a copy of the device objects. This function does not set the free * function for the #GPtrArray so you need use g_object_unref on all * elements when you are finished with the array. * * Return value: (element-type UpDevice) (transfer full): an array of #UpDevice objects or %NULL on error, free with g_ptr_array_unref() * * Since: 0.9.0 * Deprecated: 0.99.8 **/ GPtrArray * up_client_get_devices (UpClient *client) { GPtrArray *array = up_client_get_devices2 (client); if (array) g_ptr_array_set_free_func (array, NULL); return array; } static GPtrArray * up_client_get_devices_full (UpClient *client, GCancellable *cancellable, GError **error) { g_auto(GStrv) devices = NULL; GPtrArray *array; guint i; g_return_val_if_fail (UP_IS_CLIENT (client), NULL); if (up_exported_daemon_call_enumerate_devices_sync (client->priv->proxy, &devices, cancellable, error) == FALSE) { return NULL; } array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (i = 0; devices[i] != NULL; i++) { g_autoptr(UpDevice) device = NULL; const char *object_path = devices[i]; gboolean ret; device = up_device_new (); ret = up_device_set_object_path_sync (device, object_path, cancellable, NULL); if (!ret) continue; g_ptr_array_add (array, g_steal_pointer (&device)); } return array; } /** * up_client_get_devices2: * @client: a #UpClient instance. * * Get a copy of the device objects. * * Return value: (element-type UpDevice) (transfer full): an array of #UpDevice objects or %NULL on error, free with g_ptr_array_unref() * * Since: 0.99.8 **/ GPtrArray * up_client_get_devices2 (UpClient *client) { g_autoptr(GError) error = NULL; GPtrArray *ret = NULL; ret = up_client_get_devices_full (client, NULL, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("up_client_get_devices failed: %s", error->message); return NULL; } return ret; } static void get_devices_async_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { GError *error = NULL; GPtrArray *array; array = up_client_get_devices_full (UP_CLIENT (source_object), cancellable, &error); if (!array) g_task_return_error (task, error); else g_task_return_pointer (task, array, (GDestroyNotify) g_ptr_array_unref); } /** * up_client_get_devices_async: * @client: a #UpClient instance. * @cancellable: (nullable): a #GCancellable or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: the data to pass to @callback * * Asynchronously fetches the list of #UpDevice objects. * * Since: 0.99.14 **/ void up_client_get_devices_async (UpClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(GTask) task = NULL; task = g_task_new (client, cancellable, callback, user_data); g_task_set_source_tag (task, (gpointer) G_STRFUNC); g_task_run_in_thread (task, get_devices_async_thread); } /** * up_client_get_devices_finish: * @client: a #UpClient instance. * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed * to up_client_get_devices_async() * * Finishes an operation started with up_client_get_devices_async(). * * Return value: (element-type UpDevice) (transfer full): an array of * #UpDevice objects or %NULL on error. **/ GPtrArray * up_client_get_devices_finish (UpClient *client, GAsyncResult *res, GError **error) { g_return_val_if_fail (UP_IS_CLIENT (client), NULL); g_return_val_if_fail (g_task_is_valid (res, client), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); return g_task_propagate_pointer (G_TASK (res), error); } /** * up_client_get_display_device: * @client: a #UpClient instance. * * Get the composite display device. * Return value: (transfer full): a #UpDevice object, or %NULL on error. * * Since: 1.0 **/ UpDevice * up_client_get_display_device (UpClient *client) { gboolean ret; UpDevice *device; device = up_device_new (); ret = up_device_set_object_path_sync (device, "/org/freedesktop/UPower/devices/DisplayDevice", NULL, NULL); if (!ret) { g_object_unref (G_OBJECT (device)); return NULL; } return device; } /** * up_client_get_critical_action: * @client: a #UpClient instance. * * Gets a string representing the configured critical action, * depending on availability. * * Return value: the action name, or %NULL on error. * * Since: 1.0 **/ char * up_client_get_critical_action (UpClient *client) { char *action; g_return_val_if_fail (UP_IS_CLIENT (client), NULL); if (!up_exported_daemon_call_get_critical_action_sync (client->priv->proxy, &action, NULL, NULL)) { return NULL; } return action; } /** * up_client_get_daemon_version: * @client: a #UpClient instance. * * Get UPower daemon version. * * Return value: string containing the daemon version, e.g. 008 * * Since: 0.9.0 **/ const gchar * up_client_get_daemon_version (UpClient *client) { g_return_val_if_fail (UP_IS_CLIENT (client), NULL); return up_exported_daemon_get_daemon_version (client->priv->proxy); } /** * up_client_get_lid_is_closed: * @client: a #UpClient instance. * * Get whether the laptop lid is closed. * * Return value: %TRUE if lid is closed or %FALSE otherwise. * * Since: 0.9.0 */ gboolean up_client_get_lid_is_closed (UpClient *client) { g_return_val_if_fail (UP_IS_CLIENT (client), FALSE); return up_exported_daemon_get_lid_is_closed (client->priv->proxy); } /** * up_client_get_lid_is_present: * @client: a #UpClient instance. * * Get whether a laptop lid is present on this machine. * * Return value: %TRUE if the machine has a laptop lid * * Since: 0.9.2 */ gboolean up_client_get_lid_is_present (UpClient *client) { g_return_val_if_fail (UP_IS_CLIENT (client), FALSE); return up_exported_daemon_get_lid_is_present (client->priv->proxy); } /** * up_client_get_on_battery: * @client: a #UpClient instance. * * Get whether the system is running on battery power. * * Return value: %TRUE if the system is currently running on battery, %FALSE otherwise. * * Since: 0.9.0 **/ gboolean up_client_get_on_battery (UpClient *client) { g_return_val_if_fail (UP_IS_CLIENT (client), FALSE); return up_exported_daemon_get_on_battery (client->priv->proxy); } /* * up_client_add: */ static void up_client_add (UpClient *client, const gchar *object_path) { UpDevice *device = NULL; gboolean ret; /* create new device */ device = up_device_new (); ret = up_device_set_object_path_sync (device, object_path, NULL, NULL); if (!ret) goto out; /* add to array */ g_signal_emit (client, signals [UP_CLIENT_DEVICE_ADDED], 0, device); out: g_clear_object (&device); } /* * up_client_notify_cb: */ static void up_client_notify_cb (GObject *gobject, GParamSpec *pspec, UpClient *client) { /* Proxy the notification from the D-Bus glue object * to the real one, but only if the property exists * for UpClient */ if (!g_object_class_find_property (G_OBJECT_GET_CLASS (client), pspec->name)) return; g_object_notify (G_OBJECT (client), pspec->name); } /* * up_client_added_cb: */ static void up_device_added_cb (UpExportedDaemon *proxy, const gchar *object_path, UpClient *client) { up_client_add (client, object_path); } /* * up_client_removed_cb: */ static void up_device_removed_cb (UpExportedDaemon *proxy, const gchar *object_path, UpClient *client) { g_signal_emit (client, signals [UP_CLIENT_DEVICE_REMOVED], 0, object_path); } static void up_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UpClient *client; client = UP_CLIENT (object); if (client->priv->proxy == NULL) return; switch (prop_id) { case PROP_DAEMON_VERSION: g_value_set_string (value, up_exported_daemon_get_daemon_version (client->priv->proxy)); break; case PROP_ON_BATTERY: g_value_set_boolean (value, up_exported_daemon_get_on_battery (client->priv->proxy)); break; case PROP_LID_IS_CLOSED: g_value_set_boolean (value, up_exported_daemon_get_lid_is_closed (client->priv->proxy)); break; case PROP_LID_IS_PRESENT: g_value_set_boolean (value, up_exported_daemon_get_lid_is_present (client->priv->proxy)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /* * up_client_class_init: * @klass: The UpClientClass */ static void up_client_class_init (UpClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = up_client_get_property; object_class->finalize = up_client_finalize; /** * UpClient:daemon-version: * * The daemon version. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_DAEMON_VERSION, g_param_spec_string ("daemon-version", "Daemon version", NULL, NULL, G_PARAM_READABLE)); /** * UpClient:on-battery: * * If the computer is on battery power. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_ON_BATTERY, g_param_spec_boolean ("on-battery", "If the computer is on battery power", NULL, FALSE, G_PARAM_READABLE)); /** * UpClient:lid-is-closed: * * If the laptop lid is closed. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_LID_IS_CLOSED, g_param_spec_boolean ("lid-is-closed", "If the laptop lid is closed", NULL, FALSE, G_PARAM_READABLE | G_PARAM_DEPRECATED)); /** * UpClient:lid-is-present: * * If a laptop lid is present. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_LID_IS_PRESENT, g_param_spec_boolean ("lid-is-present", "If a laptop lid is present", NULL, FALSE, G_PARAM_READABLE | G_PARAM_DEPRECATED)); /** * UpClient::device-added: * @client: the #UpClient instance that emitted the signal * @device: the #UpDevice that was added. * * The ::device-added signal is emitted when a power device is added. * * Since: 0.9.0 **/ signals [UP_CLIENT_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpClientClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, UP_TYPE_DEVICE); /** * UpClient::device-removed: * @client: the #UpClient instance that emitted the signal * @object_path: the object path of the #UpDevice that was removed. * * The ::device-removed signal is emitted when a power device is removed. * * Since: 1.0 **/ signals [UP_CLIENT_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpClientClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } /* * up_client_init: * @client: This class instance */ static gboolean up_client_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { UpClient *client = UP_CLIENT (initable); client->priv = up_client_get_instance_private (client); /* connect to main interface */ client->priv->proxy = up_exported_daemon_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, "org.freedesktop.UPower", "/org/freedesktop/UPower", cancellable, error); if (client->priv->proxy == NULL) return FALSE; /* all callbacks */ g_signal_connect (client->priv->proxy, "device-added", G_CALLBACK (up_device_added_cb), client); g_signal_connect (client->priv->proxy, "device-removed", G_CALLBACK (up_device_removed_cb), client); g_signal_connect (client->priv->proxy, "notify", G_CALLBACK (up_client_notify_cb), client); return TRUE; } static void up_client_initable_iface_init (GInitableIface *iface) { iface->init = up_client_initable_init; } /* * up_client_init: * @client: This class instance */ static void up_client_init (UpClient *client) { } /* * up_client_finalize: */ static void up_client_finalize (GObject *object) { UpClient *client; g_return_if_fail (UP_IS_CLIENT (object)); client = UP_CLIENT (object); g_clear_object (&client->priv->proxy); G_OBJECT_CLASS (up_client_parent_class)->finalize (object); } /** * up_client_new_full: * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for error or %NULL. * * Creates a new #UpClient object. If connecting to upowerd on D-Bus fails, * this returns %NULL and sets @error. * * Return value: a new UpClient object, or %NULL on failure. * * Since: 0.99.5 **/ UpClient * up_client_new_full (GCancellable *cancellable, GError **error) { return g_initable_new (UP_TYPE_CLIENT, cancellable, error, NULL); } /** * up_client_new: * * Creates a new #UpClient object. If connecting to upowerd on D-Bus fails, * this returns %NULL and prints out a warning with the error message. * Consider using up_client_new_full() instead which allows you to handle errors * and cancelling long operations yourself. * * Return value: a new UpClient object, or %NULL on failure. * * Since: 0.9.0 **/ UpClient * up_client_new (void) { GError *error = NULL; UpClient *client; client = up_client_new_full (NULL, &error); if (client == NULL) { g_warning ("Couldn't connect to proxy: %s", error->message); g_error_free (error); } return client; } static void up_client_async_initable_iface_init (GAsyncInitableIface *async_initable_iface) { /* Use default */ } static void up_client_new_async_initable_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GTask *task = user_data; GError *error = NULL; if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object), res, &error)) { g_assert (error != NULL); g_task_return_error (task, error); g_object_unref (source_object); } else { g_task_return_pointer (task, source_object, g_object_unref); } g_object_unref (task); } /** * up_client_new_async: * @cancellable: (nullable): a #GCancellable or %NULL * @callback: a #GAsyncReadyCallback to call when the request is satisfied * @user_data: the data to pass to @callback * * Asynchronously creates a new #UpClient object. * * This is an asynchronous failable function. * * Since: 0.99.14 **/ void up_client_new_async (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { UpClient *client; GTask *task; task = g_task_new (NULL, cancellable, callback, user_data); g_task_set_source_tag (task, (gpointer) G_STRFUNC); client = g_object_new (UP_TYPE_CLIENT, NULL); g_async_initable_init_async (G_ASYNC_INITABLE (client), G_PRIORITY_DEFAULT, cancellable, up_client_new_async_initable_cb, task); } /** * up_client_new_finish: * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed * to up_client_new_async() * @error: return location for error or %NULL * * Finishes an operation started with up_client_new_async(). * * Returns: (transfer full): a #UpClient or %NULL if @error is set. * Free with g_object_unref(). * * Since: 0.99.14 **/ UpClient * up_client_new_finish (GAsyncResult *res, GError **error) { g_return_val_if_fail (g_task_is_valid (res, NULL), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); return g_task_propagate_pointer (G_TASK (res), error); } 07070100000023000081A400000000000000000000000166EA481400000EED000000000000000000000000000000000000002900000000upower-1.90.6/libupower-glib/up-client.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008-2010 Richard Hughes <richard@hughsie.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_CLIENT_H #define __UP_CLIENT_H #include <glib-object.h> #include <gio/gio.h> #include <libupower-glib/up-device.h> G_BEGIN_DECLS #define UP_TYPE_CLIENT (up_client_get_type ()) #define UP_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_CLIENT, UpClient)) #define UP_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_CLIENT, UpClientClass)) #define UP_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_CLIENT)) #define UP_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_CLIENT)) #define UP_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_CLIENT, UpClientClass)) #define UP_CLIENT_ERROR (up_client_error_quark ()) #define UP_CLIENT_TYPE_ERROR (up_client_error_get_type ()) typedef struct _UpClientPrivate UpClientPrivate; typedef struct { GObject parent; UpClientPrivate *priv; } UpClient; typedef struct { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (*device_added) (UpClient *client, UpDevice *device); void (*device_removed) (UpClient *client, const gchar *object_path); /*< private >*/ /* Padding for future expansion */ void (*_up_client_reserved1) (void); void (*_up_client_reserved2) (void); void (*_up_client_reserved3) (void); void (*_up_client_reserved4) (void); void (*_up_client_reserved5) (void); void (*_up_client_reserved6) (void); void (*_up_client_reserved7) (void); void (*_up_client_reserved8) (void); } UpClientClass; /* general */ GType up_client_get_type (void); UpClient *up_client_new (void); UpClient *up_client_new_full (GCancellable *cancellable, GError **error); void up_client_new_async (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); UpClient *up_client_new_finish (GAsyncResult *res, GError **error); /* sync versions */ UpDevice * up_client_get_display_device (UpClient *client); char * up_client_get_critical_action (UpClient *client); /* accessors */ GPtrArray *up_client_get_devices (UpClient *client) G_DEPRECATED_FOR(up_client_get_devices2); GPtrArray *up_client_get_devices2 (UpClient *client); void up_client_get_devices_async (UpClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); GPtrArray *up_client_get_devices_finish (UpClient *client, GAsyncResult *res, GError **error); const gchar *up_client_get_daemon_version (UpClient *client); G_DEPRECATED gboolean up_client_get_lid_is_closed (UpClient *client); G_DEPRECATED gboolean up_client_get_lid_is_present (UpClient *client); gboolean up_client_get_on_battery (UpClient *client); G_END_DECLS #endif /* __UP_CLIENT_H */ 07070100000024000081A400000000000000000000000166EA48140000A792000000000000000000000000000000000000002900000000upower-1.90.6/libupower-glib/up-device.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-device * @short_description: Client object for accessing information about UPower devices * @see_also: #UpClient * * A helper GObject to use for accessing UPower devices, and to be notified * when it is changed. */ #include "config.h" #include <stdlib.h> #include <stdio.h> #include <glib-object.h> #include <string.h> #include "up-device.h" #include "up-device-generated.h" #include "up-stats-item.h" #include "up-history-item.h" static void up_device_class_init (UpDeviceClass *klass); static void up_device_init (UpDevice *device); static void up_device_finalize (GObject *object); /** * UpDevicePrivate: * * Private #PkDevice data **/ struct _UpDevicePrivate { UpExportedDevice *proxy_device; /* For use when a UpDevice isn't backed by a D-Bus object * by the UPower daemon */ GHashTable *offline_props; }; enum { PROP_0, PROP_UPDATE_TIME, PROP_VENDOR, PROP_MODEL, PROP_SERIAL, PROP_NATIVE_PATH, PROP_POWER_SUPPLY, PROP_ONLINE, PROP_IS_PRESENT, PROP_IS_RECHARGEABLE, PROP_HAS_HISTORY, PROP_HAS_STATISTICS, PROP_KIND, PROP_STATE, PROP_TECHNOLOGY, PROP_CAPACITY, PROP_ENERGY, PROP_ENERGY_EMPTY, PROP_ENERGY_FULL, PROP_ENERGY_FULL_DESIGN, PROP_ENERGY_RATE, PROP_VOLTAGE, PROP_LUMINOSITY, PROP_TIME_TO_EMPTY, PROP_TIME_TO_FULL, PROP_PERCENTAGE, PROP_TEMPERATURE, PROP_WARNING_LEVEL, PROP_BATTERY_LEVEL, PROP_ICON_NAME, PROP_CHARGE_CYCLES, PROP_CHARGE_START_THRESHOLD, PROP_CHARGE_END_THRESHOLD, PROP_CHARGE_THRESHOLD_ENABLED, PROP_CHARGE_THRESHOLD_SUPPORTED, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (UpDevice, up_device, G_TYPE_OBJECT) /* * up_device_changed_cb: */ static void up_device_changed_cb (UpExportedDevice *proxy, GParamSpec *pspec, UpDevice *device) { /* Proxy the notification from the D-Bus glue object * to the real one, but only if the property exists * for UpClient */ if (!g_object_class_find_property (G_OBJECT_GET_CLASS (device), pspec->name) && !g_str_equal (pspec->name, "type")) return; if (g_strcmp0 (pspec->name, "type") == 0) g_object_notify (G_OBJECT (device), "kind"); else g_object_notify (G_OBJECT (device), pspec->name); } /** * up_device_set_object_path_sync: * @device: a #UpDevice instance. * @object_path: The UPower object path. * @cancellable: a #GCancellable or %NULL * @error: a #GError, or %NULL. * * Sets the object path of the object and fills up initial properties. * * Return value: #TRUE for success, else #FALSE and @error is used * * Since: 0.9.0 **/ gboolean up_device_set_object_path_sync (UpDevice *device, const gchar *object_path, GCancellable *cancellable, GError **error) { UpExportedDevice *proxy_device; gboolean ret = TRUE; g_return_val_if_fail (UP_IS_DEVICE (device), FALSE); g_return_val_if_fail (object_path != NULL, FALSE); if (device->priv->proxy_device != NULL) return FALSE; /* check valid */ if (!g_variant_is_object_path (object_path)) { ret = FALSE; g_set_error (error, 1, 0, "Object path invalid: %s", object_path); goto out; } g_clear_pointer (&device->priv->offline_props, g_hash_table_unref); /* connect to the correct path for all the other methods */ proxy_device = up_exported_device_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, "org.freedesktop.UPower", object_path, cancellable, error); if (proxy_device == NULL) return FALSE; /* listen to Changed */ g_signal_connect (proxy_device, "notify", G_CALLBACK (up_device_changed_cb), device); /* yay */ device->priv->proxy_device = proxy_device; out: return ret; } /** * up_device_get_object_path: * @device: a #UpDevice instance. * * Gets the object path for the device. * * Return value: the object path, or %NULL * * Since: 0.9.0 **/ const gchar * up_device_get_object_path (UpDevice *device) { g_return_val_if_fail (UP_IS_DEVICE (device), NULL); return g_dbus_proxy_get_object_path (G_DBUS_PROXY (device->priv->proxy_device)); } /* * up_device_to_text_history: */ static void up_device_to_text_history (UpDevice *device, GString *string, const gchar *type) { guint i; GPtrArray *array; UpHistoryItem *item; /* get a fair chunk of data */ array = up_device_get_history_sync (device, type, 120, 10, NULL, NULL); if (array == NULL) return; /* pretty print */ g_string_append_printf (string, " History (%s):\n", type); for (i=0; i<array->len; i++) { item = (UpHistoryItem *) g_ptr_array_index (array, i); g_string_append_printf (string, " %i\t%.3f\t%s\n", up_history_item_get_time (item), up_history_item_get_value (item), up_device_state_to_string (up_history_item_get_state (item))); } g_ptr_array_unref (array); } /* * up_device_bool_to_string: */ static const gchar * up_device_bool_to_string (gboolean ret) { return ret ? "yes" : "no"; } /* * up_device_to_text_time_to_string: */ static gchar * up_device_to_text_time_to_string (gint seconds) { gfloat value = seconds; if (value < 0) return g_strdup ("unknown"); if (value < 60) return g_strdup_printf ("%.0f seconds", value); value /= 60.0; if (value < 60) return g_strdup_printf ("%.1f minutes", value); value /= 60.0; if (value < 60) return g_strdup_printf ("%.1f hours", value); value /= 24.0; return g_strdup_printf ("%.1f days", value); } /** * up_device_to_text: * @device: a #UpDevice instance. * * Converts the device to a string description. * * Return value: text representation of #UpDevice * * Since: 0.9.0 **/ gchar * up_device_to_text (UpDevice *device) { struct tm *time_tm; time_t t; gchar time_buf[256]; gchar *time_str; GString *string; UpDevicePrivate *priv; const gchar *vendor; const gchar *model; const gchar *serial; UpDeviceKind kind; gboolean is_display; UpDeviceLevel battery_level; g_return_val_if_fail (UP_IS_DEVICE (device), NULL); g_return_val_if_fail (device->priv->proxy_device != NULL, NULL); priv = device->priv; is_display = (g_strcmp0 ("/org/freedesktop/UPower/devices/DisplayDevice", up_device_get_object_path (device)) == 0); /* get a human readable time */ t = (time_t) up_exported_device_get_update_time (priv->proxy_device); time_tm = localtime (&t); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-y2k" strftime (time_buf, sizeof time_buf, "%c", time_tm); #pragma GCC diagnostic pop string = g_string_new (""); if (!is_display) g_string_append_printf (string, " native-path: %s\n", up_exported_device_get_native_path (priv->proxy_device)); vendor = up_exported_device_get_vendor (priv->proxy_device); if (vendor != NULL && vendor[0] != '\0') g_string_append_printf (string, " vendor: %s\n", vendor); model = up_exported_device_get_model (priv->proxy_device); if (model != NULL && model[0] != '\0') g_string_append_printf (string, " model: %s\n", model); serial = up_exported_device_get_serial (priv->proxy_device); if (serial != NULL && serial[0] != '\0') g_string_append_printf (string, " serial: %s\n", serial); g_string_append_printf (string, " power supply: %s\n", up_device_bool_to_string (up_exported_device_get_power_supply (priv->proxy_device))); g_string_append_printf (string, " updated: %s (%d seconds ago)\n", time_buf, (int) (time (NULL) - up_exported_device_get_update_time (priv->proxy_device))); g_string_append_printf (string, " has history: %s\n", up_device_bool_to_string (up_exported_device_get_has_history (priv->proxy_device))); g_string_append_printf (string, " has statistics: %s\n", up_device_bool_to_string (up_exported_device_get_has_statistics (priv->proxy_device))); kind = up_exported_device_get_type_ (priv->proxy_device); g_string_append_printf (string, " %s\n", up_device_kind_to_string (kind)); if (kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_UPS || kind == UP_DEVICE_KIND_TOUCHPAD) g_string_append_printf (string, " present: %s\n", up_device_bool_to_string (up_exported_device_get_is_present (priv->proxy_device))); if ((kind == UP_DEVICE_KIND_PHONE || kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_GAMING_INPUT || kind == UP_DEVICE_KIND_PEN || kind == UP_DEVICE_KIND_TOUCHPAD) && !is_display) g_string_append_printf (string, " rechargeable: %s\n", up_device_bool_to_string (up_exported_device_get_is_rechargeable (priv->proxy_device))); if (kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_UPS || kind == UP_DEVICE_KIND_TOUCHPAD) g_string_append_printf (string, " state: %s\n", up_device_state_to_string (up_exported_device_get_state (priv->proxy_device))); g_string_append_printf (string, " warning-level: %s\n", up_device_level_to_string (up_exported_device_get_warning_level (priv->proxy_device))); battery_level = up_exported_device_get_battery_level (priv->proxy_device); if (battery_level != UP_DEVICE_LEVEL_NONE) g_string_append_printf (string, " battery-level: %s\n", up_device_level_to_string (battery_level)); if (kind == UP_DEVICE_KIND_BATTERY) { g_string_append_printf (string, " energy: %g Wh\n", up_exported_device_get_energy (priv->proxy_device)); if (!is_display) g_string_append_printf (string, " energy-empty: %g Wh\n", up_exported_device_get_energy_empty (priv->proxy_device)); g_string_append_printf (string, " energy-full: %g Wh\n", up_exported_device_get_energy_full (priv->proxy_device)); if (!is_display) g_string_append_printf (string, " energy-full-design: %g Wh\n", up_exported_device_get_energy_full_design (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_MONITOR) g_string_append_printf (string, " energy-rate: %g W\n", up_exported_device_get_energy_rate (priv->proxy_device)); if (kind == UP_DEVICE_KIND_UPS || kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_MONITOR) { if (up_exported_device_get_voltage (priv->proxy_device) > 0) g_string_append_printf (string, " voltage: %g V\n", up_exported_device_get_voltage (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_BATTERY) { if (up_exported_device_get_charge_cycles (priv->proxy_device) > 0) g_string_append_printf (string, " charge-cycles: %d\n", up_exported_device_get_charge_cycles (priv->proxy_device)); else g_string_append_printf (string, " charge-cycles: %s\n", "N/A"); } if (kind == UP_DEVICE_KIND_KEYBOARD) { if (up_exported_device_get_luminosity (priv->proxy_device) > 0) g_string_append_printf (string, " luminosity: %g lx\n", up_exported_device_get_luminosity (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_BATTERY || kind == UP_DEVICE_KIND_UPS) { if (up_exported_device_get_time_to_full (priv->proxy_device) > 0) { time_str = up_device_to_text_time_to_string (up_exported_device_get_time_to_full (priv->proxy_device)); g_string_append_printf (string, " time to full: %s\n", time_str); g_free (time_str); } if (up_exported_device_get_time_to_empty (priv->proxy_device) > 0) { time_str = up_device_to_text_time_to_string (up_exported_device_get_time_to_empty (priv->proxy_device)); g_string_append_printf (string, " time to empty: %s\n", time_str); g_free (time_str); } } if (kind != UP_DEVICE_KIND_LINE_POWER || kind >= UP_DEVICE_KIND_LAST) { if (battery_level == UP_DEVICE_LEVEL_NONE) g_string_append_printf (string, " percentage: %g%%\n", up_exported_device_get_percentage (priv->proxy_device)); else g_string_append_printf (string, " percentage: %g%% (should be ignored)\n", up_exported_device_get_percentage (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_BATTERY) { if (up_exported_device_get_temperature (priv->proxy_device) > 0) g_string_append_printf (string, " temperature: %g degrees C\n", up_exported_device_get_temperature (priv->proxy_device)); if (up_exported_device_get_capacity (priv->proxy_device) > 0) g_string_append_printf (string, " capacity: %g%%\n", up_exported_device_get_capacity (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_BATTERY) { if (up_exported_device_get_technology (priv->proxy_device) != UP_DEVICE_TECHNOLOGY_UNKNOWN) g_string_append_printf (string, " technology: %s\n", up_device_technology_to_string (up_exported_device_get_technology (priv->proxy_device))); if (up_exported_device_get_charge_start_threshold (priv->proxy_device) > 0) g_string_append_printf (string, " charge-start-threshold: %d%%\n", up_exported_device_get_charge_start_threshold (priv->proxy_device)); if (up_exported_device_get_charge_end_threshold (priv->proxy_device) > 0) g_string_append_printf (string, " charge-end-threshold: %d%%\n", up_exported_device_get_charge_end_threshold (priv->proxy_device)); if (up_exported_device_get_charge_threshold_enabled (priv->proxy_device)) g_string_append_printf (string, " charge-threshold-enabled: %d\n", up_exported_device_get_charge_threshold_enabled (priv->proxy_device)); if (up_exported_device_get_charge_threshold_supported (priv->proxy_device)) g_string_append_printf (string, " charge-threshold-supported: %d\n", up_exported_device_get_charge_threshold_supported (priv->proxy_device)); } if (kind == UP_DEVICE_KIND_LINE_POWER) g_string_append_printf (string, " online: %s\n", up_device_bool_to_string (up_exported_device_get_online (priv->proxy_device))); g_string_append_printf (string, " icon-name: '%s'\n", up_exported_device_get_icon_name (priv->proxy_device)); /* if we can, get history */ if (up_exported_device_get_has_history (priv->proxy_device)) { up_device_to_text_history (device, string, "charge"); up_device_to_text_history (device, string, "rate"); } return g_string_free (string, FALSE); } /** * up_device_refresh_sync: * @device: a #UpDevice instance. * @cancellable: a #GCancellable or %NULL * @error: a #GError, or %NULL. * * Refreshes properties on the device. * This function is normally not required and will only return without * an error if the daemon was started in debug mode. * * Return value: #TRUE for success, else #FALSE and @error is used * * Since: 0.9.0 **/ gboolean up_device_refresh_sync (UpDevice *device, GCancellable *cancellable, GError **error) { g_return_val_if_fail (UP_IS_DEVICE (device), FALSE); g_return_val_if_fail (device->priv->proxy_device != NULL, FALSE); return up_exported_device_call_refresh_sync (device->priv->proxy_device, cancellable, error); } /** * up_device_get_history_sync: * @device: a #UpDevice instance. * @type: The type of history, known values are "rate" and "charge". * @timespec: the amount of time to look back into time. * @resolution: the resolution of data. * @cancellable: a #GCancellable or %NULL * @error: a #GError, or %NULL. * * Gets the device history. * * Return value: (element-type UpHistoryItem) (transfer full): an array of #UpHistoryItem's, with the most * recent one being first; %NULL if @error is set or @device is * invalid * * Since: 0.9.0 **/ GPtrArray * up_device_get_history_sync (UpDevice *device, const gchar *type, guint timespec, guint resolution, GCancellable *cancellable, GError **error) { GError *error_local = NULL; GVariant *gva = NULL; guint i; GPtrArray *array = NULL; gboolean ret; gsize len; GVariantIter *iter; g_return_val_if_fail (UP_IS_DEVICE (device), NULL); g_return_val_if_fail (device->priv->proxy_device != NULL, NULL); /* get compound data */ ret = up_exported_device_call_get_history_sync (device->priv->proxy_device, type, timespec, resolution, &gva, NULL, &error_local); if (!ret) { g_set_error (error, 1, 0, "GetHistory(%s,%i) on %s failed: %s", type, timespec, up_device_get_object_path (device), error_local->message); g_error_free (error_local); goto out; } iter = g_variant_iter_new (gva); len = g_variant_iter_n_children (iter); /* no data */ if (len == 0) { g_set_error_literal (error, 1, 0, "no data"); g_variant_iter_free (iter); goto out; } /* convert */ array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (i = 0; i < len; i++) { UpHistoryItem *obj; GVariant *v; gdouble value; guint32 time, state; v = g_variant_iter_next_value (iter); g_variant_get (v, "(udu)", &time, &value, &state); g_variant_unref (v); obj = up_history_item_new (); up_history_item_set_time (obj, time); up_history_item_set_value (obj, value); up_history_item_set_state (obj, state); g_ptr_array_add (array, obj); } g_variant_iter_free (iter); out: g_clear_pointer (&gva, g_variant_unref); return array; } /** * up_device_get_statistics_sync: * @device: a #UpDevice instance. * @type: the type of statistics. * @cancellable: a #GCancellable or %NULL * @error: a #GError, or %NULL. * * Gets the device current statistics. * * Return value: (element-type UpStatsItem) (transfer full): an array of #UpStatsItem's, else #NULL and @error is used * * Since: 0.9.0 **/ GPtrArray * up_device_get_statistics_sync (UpDevice *device, const gchar *type, GCancellable *cancellable, GError **error) { GError *error_local = NULL; GVariant *gva = NULL; guint i; GPtrArray *array = NULL; gboolean ret; gsize len; GVariantIter *iter; g_return_val_if_fail (UP_IS_DEVICE (device), NULL); g_return_val_if_fail (device->priv->proxy_device != NULL, NULL); /* get compound data */ ret = up_exported_device_call_get_statistics_sync (device->priv->proxy_device, type, &gva, NULL, &error_local); if (!ret) { g_set_error (error, 1, 0, "GetStatistics(%s) on %s failed: %s", type, up_device_get_object_path (device), error_local->message); g_error_free (error_local); goto out; } iter = g_variant_iter_new (gva); len = g_variant_iter_n_children (iter); /* no data */ if (len == 0) { g_set_error_literal (error, 1, 0, "no data"); g_variant_iter_free (iter); goto out; } /* convert */ array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); for (i = 0; i < len; i++) { UpStatsItem *obj; GVariant *v; gdouble value, accuracy; v = g_variant_iter_next_value (iter); g_variant_get (v, "(dd)", &value, &accuracy); g_variant_unref (v); obj = up_stats_item_new (); up_stats_item_set_value (obj, value); up_stats_item_set_accuracy (obj, accuracy); g_ptr_array_add (array, obj); } g_variant_iter_free (iter); out: g_clear_pointer (&gva, g_variant_unref); return array; } /* * up_device_set_property: */ static void up_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UpDevice *device = UP_DEVICE (object); if (device->priv->proxy_device == NULL) { GValue *v; v = g_slice_new0 (GValue); g_value_init (v, G_VALUE_TYPE (value)); g_value_copy (value, v); g_hash_table_insert (device->priv->offline_props, GUINT_TO_POINTER (prop_id), v); return; } switch (prop_id) { case PROP_NATIVE_PATH: up_exported_device_set_native_path (device->priv->proxy_device, g_value_get_string (value)); break; case PROP_VENDOR: up_exported_device_set_vendor (device->priv->proxy_device, g_value_get_string (value)); break; case PROP_MODEL: up_exported_device_set_model (device->priv->proxy_device, g_value_get_string (value)); break; case PROP_SERIAL: up_exported_device_set_serial (device->priv->proxy_device, g_value_get_string (value)); break; case PROP_UPDATE_TIME: up_exported_device_set_update_time (device->priv->proxy_device, g_value_get_uint64 (value)); break; case PROP_KIND: up_exported_device_set_type_ (device->priv->proxy_device, g_value_get_uint (value)); break; case PROP_POWER_SUPPLY: up_exported_device_set_power_supply (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_ONLINE: up_exported_device_set_online (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_IS_PRESENT: up_exported_device_set_is_present (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_IS_RECHARGEABLE: up_exported_device_set_is_rechargeable (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_HAS_HISTORY: up_exported_device_set_has_history (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_HAS_STATISTICS: up_exported_device_set_has_statistics (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_STATE: up_exported_device_set_state (device->priv->proxy_device, g_value_get_uint (value)); break; case PROP_CAPACITY: up_exported_device_set_capacity (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_ENERGY: up_exported_device_set_energy (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_ENERGY_EMPTY: up_exported_device_set_energy_empty (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_ENERGY_FULL: up_exported_device_set_energy_full (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_ENERGY_FULL_DESIGN: up_exported_device_set_energy_full_design (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_ENERGY_RATE: up_exported_device_set_energy_rate (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_VOLTAGE: up_exported_device_set_voltage (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_LUMINOSITY: up_exported_device_set_luminosity (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_TIME_TO_EMPTY: up_exported_device_set_time_to_empty (device->priv->proxy_device, g_value_get_int64 (value)); break; case PROP_TIME_TO_FULL: up_exported_device_set_time_to_full (device->priv->proxy_device, g_value_get_int64 (value)); break; case PROP_PERCENTAGE: up_exported_device_set_percentage (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_TEMPERATURE: up_exported_device_set_temperature (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_TECHNOLOGY: up_exported_device_set_technology (device->priv->proxy_device, g_value_get_uint (value)); break; case PROP_WARNING_LEVEL: up_exported_device_set_warning_level (device->priv->proxy_device, g_value_get_uint (value)); break; case PROP_BATTERY_LEVEL: up_exported_device_set_battery_level (device->priv->proxy_device, g_value_get_uint (value)); break; case PROP_ICON_NAME: up_exported_device_set_icon_name (device->priv->proxy_device, g_value_get_string (value)); break; case PROP_CHARGE_CYCLES: up_exported_device_set_charge_cycles (device->priv->proxy_device, g_value_get_int (value)); break; case PROP_CHARGE_START_THRESHOLD: up_exported_device_set_charge_start_threshold (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_CHARGE_END_THRESHOLD: up_exported_device_set_charge_end_threshold (device->priv->proxy_device, g_value_get_double (value)); break; case PROP_CHARGE_THRESHOLD_ENABLED: up_exported_device_set_charge_threshold_enabled (device->priv->proxy_device, g_value_get_boolean (value)); break; case PROP_CHARGE_THRESHOLD_SUPPORTED: up_exported_device_set_charge_threshold_supported (device->priv->proxy_device, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /* * up_device_get_property: */ static void up_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UpDevice *device = UP_DEVICE (object); if (device->priv->proxy_device == NULL) { GValue *v; v = g_hash_table_lookup (device->priv->offline_props, GUINT_TO_POINTER(prop_id)); if (v) g_value_copy (v, value); else g_warning ("Property ID '%s' (%d) was never set", pspec->name, prop_id); return; } switch (prop_id) { case PROP_UPDATE_TIME: g_value_set_uint64 (value, up_exported_device_get_update_time (device->priv->proxy_device)); break; case PROP_VENDOR: g_value_set_string (value, up_exported_device_get_vendor (device->priv->proxy_device)); break; case PROP_MODEL: g_value_set_string (value, up_exported_device_get_model (device->priv->proxy_device)); break; case PROP_SERIAL: g_value_set_string (value, up_exported_device_get_serial (device->priv->proxy_device)); break; case PROP_NATIVE_PATH: g_value_set_string (value, up_exported_device_get_native_path (device->priv->proxy_device)); break; case PROP_POWER_SUPPLY: g_value_set_boolean (value, up_exported_device_get_power_supply (device->priv->proxy_device)); break; case PROP_ONLINE: g_value_set_boolean (value, up_exported_device_get_online (device->priv->proxy_device)); break; case PROP_IS_PRESENT: g_value_set_boolean (value, up_exported_device_get_is_present (device->priv->proxy_device)); break; case PROP_IS_RECHARGEABLE: g_value_set_boolean (value, up_exported_device_get_is_rechargeable (device->priv->proxy_device)); break; case PROP_HAS_HISTORY: g_value_set_boolean (value, up_exported_device_get_has_history (device->priv->proxy_device)); break; case PROP_HAS_STATISTICS: g_value_set_boolean (value, up_exported_device_get_has_statistics (device->priv->proxy_device)); break; case PROP_KIND: g_value_set_uint (value, up_exported_device_get_type_ (device->priv->proxy_device)); break; case PROP_STATE: g_value_set_uint (value, up_exported_device_get_state (device->priv->proxy_device)); break; case PROP_TECHNOLOGY: g_value_set_uint (value, up_exported_device_get_technology (device->priv->proxy_device)); break; case PROP_CAPACITY: g_value_set_double (value, up_exported_device_get_capacity (device->priv->proxy_device)); break; case PROP_ENERGY: g_value_set_double (value, up_exported_device_get_energy (device->priv->proxy_device)); break; case PROP_ENERGY_EMPTY: g_value_set_double (value, up_exported_device_get_energy_empty (device->priv->proxy_device)); break; case PROP_ENERGY_FULL: g_value_set_double (value, up_exported_device_get_energy_full (device->priv->proxy_device)); break; case PROP_ENERGY_FULL_DESIGN: g_value_set_double (value, up_exported_device_get_energy_full_design (device->priv->proxy_device)); break; case PROP_ENERGY_RATE: g_value_set_double (value, up_exported_device_get_energy_rate (device->priv->proxy_device)); break; case PROP_VOLTAGE: g_value_set_double (value, up_exported_device_get_voltage (device->priv->proxy_device)); break; case PROP_LUMINOSITY: g_value_set_double (value, up_exported_device_get_luminosity (device->priv->proxy_device)); break; case PROP_TIME_TO_EMPTY: g_value_set_int64 (value, up_exported_device_get_time_to_empty (device->priv->proxy_device)); break; case PROP_TIME_TO_FULL: g_value_set_int64 (value, up_exported_device_get_time_to_full (device->priv->proxy_device)); break; case PROP_PERCENTAGE: g_value_set_double (value, up_exported_device_get_percentage (device->priv->proxy_device)); break; case PROP_TEMPERATURE: g_value_set_double (value, up_exported_device_get_temperature (device->priv->proxy_device)); break; case PROP_WARNING_LEVEL: g_value_set_uint (value, up_exported_device_get_warning_level (device->priv->proxy_device)); break; case PROP_BATTERY_LEVEL: g_value_set_uint (value, up_exported_device_get_battery_level (device->priv->proxy_device)); break; case PROP_ICON_NAME: g_value_set_string (value, up_exported_device_get_icon_name (device->priv->proxy_device)); break; case PROP_CHARGE_CYCLES: g_value_set_int (value, up_exported_device_get_charge_cycles (device->priv->proxy_device)); break; case PROP_CHARGE_START_THRESHOLD: g_value_set_uint (value, up_exported_device_get_charge_start_threshold (device->priv->proxy_device)); break; case PROP_CHARGE_END_THRESHOLD: g_value_set_uint (value, up_exported_device_get_charge_end_threshold (device->priv->proxy_device)); break; case PROP_CHARGE_THRESHOLD_ENABLED: g_value_set_boolean (value, up_exported_device_get_charge_threshold_enabled (device->priv->proxy_device)); break; case PROP_CHARGE_THRESHOLD_SUPPORTED: g_value_set_boolean (value, up_exported_device_get_charge_threshold_supported (device->priv->proxy_device)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /* * up_device_class_init: */ static void up_device_class_init (UpDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_device_finalize; object_class->set_property = up_device_set_property; object_class->get_property = up_device_get_property; /** * UpDevice:update-time: * * The last time the device was updated. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_UPDATE_TIME, g_param_spec_uint64 ("update-time", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READWRITE)); /** * UpDevice:vendor: * * The vendor of the device. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_VENDOR, g_param_spec_string ("vendor", NULL, NULL, NULL, G_PARAM_READWRITE)); /** * UpDevice:model: * * The model of the device. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_MODEL, g_param_spec_string ("model", NULL, NULL, NULL, G_PARAM_READWRITE)); /** * UpDevice:serial: * * The serial number of the device. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_SERIAL, g_param_spec_string ("serial", NULL, NULL, NULL, G_PARAM_READWRITE)); /** * UpDevice:native-path: * * The native path of the device, useful for direct device access. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_NATIVE_PATH, g_param_spec_string ("native-path", NULL, NULL, NULL, G_PARAM_READWRITE)); /** * UpDevice:power-supply: * * If the device is powering the system. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_POWER_SUPPLY, g_param_spec_boolean ("power-supply", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:online: * * If the device is online, i.e. connected. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ONLINE, g_param_spec_boolean ("online", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:is-present: * * If the device is present, as some devices like laptop batteries * can be removed, leaving an empty bay that is still technically a * device. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_IS_PRESENT, g_param_spec_boolean ("is-present", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:is-rechargeable: * * If the device has a rechargable battery. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_IS_RECHARGEABLE, g_param_spec_boolean ("is-rechargeable", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:has-history: * * If the device has history data that might be useful. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_HAS_HISTORY, g_param_spec_boolean ("has-history", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:has-statistics: * * If the device has statistics data that might be useful. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_HAS_STATISTICS, g_param_spec_boolean ("has-statistics", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:kind: * * The device kind, e.g. %UP_DEVICE_KIND_KEYBOARD. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_KIND, g_param_spec_uint ("kind", NULL, NULL, UP_DEVICE_KIND_UNKNOWN, UP_DEVICE_KIND_LAST, UP_DEVICE_KIND_UNKNOWN, G_PARAM_READWRITE)); /** * UpDevice:state: * * The state the device is in at this time, e.g. %UP_DEVICE_STATE_EMPTY. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_STATE, g_param_spec_uint ("state", NULL, NULL, UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_LAST, UP_DEVICE_STATE_UNKNOWN, G_PARAM_READWRITE)); /** * UpDevice:technology: * * The battery technology e.g. %UP_DEVICE_TECHNOLOGY_LITHIUM_ION. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_TECHNOLOGY, g_param_spec_uint ("technology", NULL, NULL, UP_DEVICE_TECHNOLOGY_UNKNOWN, UP_DEVICE_TECHNOLOGY_LAST, UP_DEVICE_TECHNOLOGY_UNKNOWN, G_PARAM_READWRITE)); /** * UpDevice:capacity: * * The percentage capacity of the device where 100% means the device has * the same charge potential as when it was manufactured. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_CAPACITY, g_param_spec_double ("capacity", NULL, NULL, 0.0, 100.f, 100.0, G_PARAM_READWRITE)); /** * UpDevice:energy: * * The energy left in the device. Measured in mWh. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ENERGY, g_param_spec_double ("energy", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:energy-empty: * * The energy the device will have when it is empty. This is usually zero. * Measured in mWh. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ENERGY_EMPTY, g_param_spec_double ("energy-empty", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:energy-full: * * The amount of energy when the device is fully charged. Measured in mWh. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ENERGY_FULL, g_param_spec_double ("energy-full", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:energy-full-design: * * The amount of energy when the device was brand new. Measured in mWh. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ENERGY_FULL_DESIGN, g_param_spec_double ("energy-full-design", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:energy-rate: * * The rate of discharge or charge. Measured in mW. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ENERGY_RATE, g_param_spec_double ("energy-rate", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:voltage: * * The current voltage of the device. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_VOLTAGE, g_param_spec_double ("voltage", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:luminosity: * * The current luminosity of the device. * * Since: 0.9.19 **/ g_object_class_install_property (object_class, PROP_LUMINOSITY, g_param_spec_double ("luminosity", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:time-to-empty: * * The amount of time until the device is empty. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_TIME_TO_EMPTY, g_param_spec_int64 ("time-to-empty", NULL, NULL, 0, G_MAXINT64, 0, G_PARAM_READWRITE)); /** * UpDevice:time-to-full: * * The amount of time until the device is fully charged. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_TIME_TO_FULL, g_param_spec_int64 ("time-to-full", NULL, NULL, 0, G_MAXINT64, 0, G_PARAM_READWRITE)); /** * UpDevice:percentage: * * The percentage charge of the device. Note that if the battery level property * is something other than %UP_DEVICE_LEVEL_NONE, then this percentage is an * approximation, and should not be used a number to display to the user. * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_PERCENTAGE, g_param_spec_double ("percentage", NULL, NULL, 0.0, 100.f, 100.0, G_PARAM_READWRITE)); /** * UpDevice:temperature: * * The temperature of the device in degrees Celsius. * * Since: 0.9.22 **/ g_object_class_install_property (object_class, PROP_TEMPERATURE, g_param_spec_double ("temperature", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpDevice:warning-level: * * The warning level e.g. %UP_DEVICE_LEVEL_CRITICAL. * * Since: 1.0 **/ g_object_class_install_property (object_class, PROP_WARNING_LEVEL, g_param_spec_uint ("warning-level", NULL, NULL, UP_DEVICE_LEVEL_UNKNOWN, UP_DEVICE_LEVEL_LAST, UP_DEVICE_LEVEL_UNKNOWN, G_PARAM_READWRITE)); /** * UpDevice:battery-level: * * The battery level, e.g. %UP_DEVICE_LEVEL_CRITICAL. If this is something * other than %UP_DEVICE_LEVEL_NONE, then User Interfaces should use this * approximate level instead of percentages. * * Since: 1.0 **/ g_object_class_install_property (object_class, PROP_BATTERY_LEVEL, g_param_spec_uint ("battery-level", NULL, NULL, UP_DEVICE_LEVEL_UNKNOWN, UP_DEVICE_LEVEL_LAST, UP_DEVICE_LEVEL_NONE, G_PARAM_READWRITE)); /** * UpDevice:icon-name: * * The icon name, following the Icon Naming Speficiation * * Since: 1.0 **/ g_object_class_install_property (object_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", NULL, NULL, NULL, G_PARAM_READWRITE)); /** * UpDevice:charge-cycles: * * The number of charge cycles for the battery, or -1 if unknown * or non-applicable. * * Since: 1.0 **/ g_object_class_install_property (object_class, PROP_CHARGE_CYCLES, g_param_spec_int ("charge-cycles", NULL, NULL, -1, G_MAXINT, -1, G_PARAM_READWRITE)); /** * UpDevice:charge-start-threshold: * * The charge start threshold of a battery. * * Since: 1.90.5 **/ g_object_class_install_property (object_class, PROP_CHARGE_START_THRESHOLD, g_param_spec_uint ("charge-start-threshold", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE)); /** * UpDevice:charge-end-threshold: * * The charge end threshold of a battery. * * Since: 1.90.5 **/ g_object_class_install_property (object_class, PROP_CHARGE_END_THRESHOLD, g_param_spec_uint ("charge-end-threshold", NULL, NULL, 0, 100, 100, G_PARAM_READWRITE)); /** * UpDevice:charge-threshold-enabled: * * The charge threshold of a battery is enabled, or false if unknown * or non-applicable. * * Since: 1.90.5 **/ g_object_class_install_property (object_class, PROP_CHARGE_THRESHOLD_ENABLED, g_param_spec_boolean ("charge-threshold-enabled", NULL, NULL, FALSE, G_PARAM_READWRITE)); /** * UpDevice:charge-threshold-supported: * * The charge threshold of a battery is supported, or false if unknown * or non-applicable. * * Since: 1.90.5 **/ g_object_class_install_property (object_class, PROP_CHARGE_THRESHOLD_SUPPORTED, g_param_spec_boolean ("charge-threshold-supported", NULL, NULL, FALSE, G_PARAM_READWRITE)); } static void value_free (GValue *value) { g_value_unset (value); g_slice_free (GValue, value); } /* * up_device_init: */ static void up_device_init (UpDevice *device) { device->priv = up_device_get_instance_private (device); device->priv->offline_props = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) value_free); } /* * up_device_finalize: */ static void up_device_finalize (GObject *object) { UpDevice *device; g_return_if_fail (UP_IS_DEVICE (object)); device = UP_DEVICE (object); if (device->priv->proxy_device != NULL) { g_signal_handlers_disconnect_by_func (device->priv->proxy_device, up_device_changed_cb, device); } g_clear_object (&device->priv->proxy_device); g_clear_pointer (&device->priv->offline_props, g_hash_table_unref); G_OBJECT_CLASS (up_device_parent_class)->finalize (object); } /** * up_device_new: * * Creates a new #UpDevice object. * * Return value: a new UpDevice object. * * Since: 0.9.0 **/ UpDevice * up_device_new (void) { return UP_DEVICE (g_object_new (UP_TYPE_DEVICE, NULL)); } 07070100000025000081A400000000000000000000000166EA481400000CAD000000000000000000000000000000000000002900000000upower-1.90.6/libupower-glib/up-device.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_DEVICE_H #define __UP_DEVICE_H #include <glib-object.h> #include <gio/gio.h> #include <libupower-glib/up-types.h> G_BEGIN_DECLS #define UP_TYPE_DEVICE (up_device_get_type ()) #define UP_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE, UpDevice)) #define UP_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE, UpDeviceClass)) #define UP_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE)) #define UP_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE)) #define UP_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE, UpDeviceClass)) #define UP_DEVICE_ERROR (up_device_error_quark ()) #define UP_DEVICE_TYPE_ERROR (up_device_error_get_type ()) typedef struct _UpDevicePrivate UpDevicePrivate; typedef struct { GObject parent; UpDevicePrivate *priv; } UpDevice; typedef struct { /*< private >*/ GObjectClass parent_class; /* Padding for future expansion */ void (*_up_device_reserved1) (void); void (*_up_device_reserved2) (void); void (*_up_device_reserved3) (void); void (*_up_device_reserved4) (void); void (*_up_device_reserved5) (void); void (*_up_device_reserved6) (void); void (*_up_device_reserved7) (void); void (*_up_device_reserved8) (void); } UpDeviceClass; /* general */ GType up_device_get_type (void); UpDevice *up_device_new (void); gchar *up_device_to_text (UpDevice *device); /* sync versions */ G_DEPRECATED gboolean up_device_refresh_sync (UpDevice *device, GCancellable *cancellable, GError **error); gboolean up_device_set_object_path_sync (UpDevice *device, const gchar *object_path, GCancellable *cancellable, GError **error); GPtrArray *up_device_get_history_sync (UpDevice *device, const gchar *type, guint timespec, guint resolution, GCancellable *cancellable, GError **error); GPtrArray *up_device_get_statistics_sync (UpDevice *device, const gchar *type, GCancellable *cancellable, GError **error); /* accessors */ const gchar *up_device_get_object_path (UpDevice *device); G_END_DECLS #endif /* __UP_DEVICE_H */ 07070100000026000081A400000000000000000000000166EA48140000203B000000000000000000000000000000000000002F00000000upower-1.90.6/libupower-glib/up-history-item.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-history-item * @short_description: Helper object representing one item of historical data. * @see_also: #UpDevice, #UpClient * * This object represents one item of data which may be returned from the * daemon in response to a query. */ #include "config.h" #include <glib.h> #include <stdlib.h> #include "up-history-item.h" static void up_history_item_class_init (UpHistoryItemClass *klass); static void up_history_item_init (UpHistoryItem *history_item); static void up_history_item_finalize (GObject *object); struct UpHistoryItemPrivate { gdouble value; guint time; UpDeviceState state; }; enum { PROP_0, PROP_VALUE, PROP_TIME, PROP_STATE, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (UpHistoryItem, up_history_item, G_TYPE_OBJECT) /** * up_history_item_set_value: * @history_item: #UpHistoryItem * @value: the new value * * Sets the item value. * * Since: 0.9.0 **/ void up_history_item_set_value (UpHistoryItem *history_item, gdouble value) { g_return_if_fail (UP_IS_HISTORY_ITEM (history_item)); history_item->priv->value = value; g_object_notify (G_OBJECT(history_item), "value"); } /** * up_history_item_get_value: * @history_item: #UpHistoryItem * * Gets the item value. * * Since: 0.9.0 **/ gdouble up_history_item_get_value (UpHistoryItem *history_item) { g_return_val_if_fail (UP_IS_HISTORY_ITEM (history_item), G_MAXDOUBLE); return history_item->priv->value; } /** * up_history_item_set_time: * @history_item: #UpHistoryItem * @time: the new value * * Sets the item time. * * Since: 0.9.0 **/ void up_history_item_set_time (UpHistoryItem *history_item, guint time) { g_return_if_fail (UP_IS_HISTORY_ITEM (history_item)); history_item->priv->time = time; g_object_notify (G_OBJECT(history_item), "time"); } /** * up_history_item_set_time_to_present: * @history_item: #UpHistoryItem * * Sets the item time to the present value. * * Since: 0.9.1 **/ void up_history_item_set_time_to_present (UpHistoryItem *history_item) { guint64 time_now; g_return_if_fail (UP_IS_HISTORY_ITEM (history_item)); time_now = g_get_real_time (); history_item->priv->time = time_now / 1000000; g_object_notify (G_OBJECT(history_item), "time"); } /** * up_history_item_get_time: * @history_item: #UpHistoryItem * * Gets the item time. * * Since: 0.9.0 **/ guint up_history_item_get_time (UpHistoryItem *history_item) { g_return_val_if_fail (UP_IS_HISTORY_ITEM (history_item), G_MAXUINT); return history_item->priv->time; } /** * up_history_item_set_state: * @history_item: #UpHistoryItem * @state: the new value * * Sets the item state. * * Since: 0.9.0 **/ void up_history_item_set_state (UpHistoryItem *history_item, UpDeviceState state) { g_return_if_fail (UP_IS_HISTORY_ITEM (history_item)); history_item->priv->state = state; g_object_notify (G_OBJECT(history_item), "state"); } /** * up_history_item_get_state: * @history_item: #UpHistoryItem * * Gets the item state. * * Since: 0.9.0 **/ UpDeviceState up_history_item_get_state (UpHistoryItem *history_item) { g_return_val_if_fail (UP_IS_HISTORY_ITEM (history_item), G_MAXUINT); return history_item->priv->state; } /** * up_history_item_to_string: * @history_item: #UpHistoryItem * * Converts the history item to a string representation. * * Since: 0.9.1 **/ gchar * up_history_item_to_string (UpHistoryItem *history_item) { g_return_val_if_fail (UP_IS_HISTORY_ITEM (history_item), NULL); return g_strdup_printf ("%i\t%.3f\t%s", history_item->priv->time, history_item->priv->value, up_device_state_to_string (history_item->priv->state)); } /** * up_history_item_set_from_string: * @history_item: #UpHistoryItem * * Converts the history item to a string representation. * * Since: 0.9.1 **/ gboolean up_history_item_set_from_string (UpHistoryItem *history_item, const gchar *text) { gchar **parts = NULL; guint length; gboolean ret = FALSE; g_return_val_if_fail (UP_IS_HISTORY_ITEM (history_item), FALSE); g_return_val_if_fail (text != NULL, FALSE); /* split by tab */ parts = g_strsplit (text, "\t", 0); length = g_strv_length (parts); if (length != 3) { g_warning ("invalid string: '%s'", text); goto out; } /* parse */ up_history_item_set_time (history_item, atoi (parts[0])); up_history_item_set_value (history_item, atof (parts[1])); up_history_item_set_state (history_item, up_device_state_from_string (parts[2])); /* success */ ret = TRUE; out: g_strfreev (parts); return ret; } /** * up_history_item_set_property: **/ static void up_history_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UpHistoryItem *history_item = UP_HISTORY_ITEM (object); switch (prop_id) { case PROP_VALUE: history_item->priv->value = g_value_get_double (value); break; case PROP_TIME: history_item->priv->time = g_value_get_uint (value); break; case PROP_STATE: history_item->priv->state = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * up_history_item_get_property: **/ static void up_history_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UpHistoryItem *history_item = UP_HISTORY_ITEM (object); switch (prop_id) { case PROP_VALUE: g_value_set_double (value, history_item->priv->value); break; case PROP_TIME: g_value_set_uint (value, history_item->priv->time); break; case PROP_STATE: g_value_set_uint (value, history_item->priv->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * up_history_item_class_init: **/ static void up_history_item_class_init (UpHistoryItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_history_item_finalize; object_class->set_property = up_history_item_set_property; object_class->get_property = up_history_item_get_property; /** * UpHistoryItem:value: * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_VALUE, g_param_spec_double ("value", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpHistoryItem:time: * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_TIME, g_param_spec_uint ("time", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE)); /** * UpHistoryItem:state: * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_STATE, g_param_spec_uint ("state", NULL, NULL, 0, G_MAXUINT, UP_DEVICE_STATE_UNKNOWN, G_PARAM_READWRITE)); } /** * up_history_item_init: **/ static void up_history_item_init (UpHistoryItem *history_item) { history_item->priv = up_history_item_get_instance_private (history_item); } /** * up_history_item_finalize: **/ static void up_history_item_finalize (GObject *object) { g_return_if_fail (UP_IS_HISTORY_ITEM (object)); G_OBJECT_CLASS (up_history_item_parent_class)->finalize (object); } /** * up_history_item_new: * * Return value: a new UpHistoryItem object. * * Since: 0.9.0 **/ UpHistoryItem * up_history_item_new (void) { return UP_HISTORY_ITEM (g_object_new (UP_TYPE_HISTORY_ITEM, NULL)); } 07070100000027000081A400000000000000000000000166EA481400000B03000000000000000000000000000000000000002F00000000upower-1.90.6/libupower-glib/up-history-item.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_HISTORY_ITEM_H #define __UP_HISTORY_ITEM_H #include <glib-object.h> #include <libupower-glib/up-types.h> G_BEGIN_DECLS #define UP_TYPE_HISTORY_ITEM (up_history_item_get_type ()) #define UP_HISTORY_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_HISTORY_ITEM, UpHistoryItem)) #define UP_HISTORY_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_HISTORY_ITEM, UpHistoryItemClass)) #define UP_IS_HISTORY_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_HISTORY_ITEM)) #define UP_IS_HISTORY_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_HISTORY_ITEM)) #define UP_HISTORY_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_HISTORY_ITEM, UpHistoryItemClass)) typedef struct UpHistoryItemPrivate UpHistoryItemPrivate; typedef struct { GObject parent; UpHistoryItemPrivate *priv; } UpHistoryItem; typedef struct { GObjectClass parent_class; } UpHistoryItemClass; GType up_history_item_get_type (void); UpHistoryItem *up_history_item_new (void); gdouble up_history_item_get_value (UpHistoryItem *history_item); void up_history_item_set_value (UpHistoryItem *history_item, gdouble value); guint up_history_item_get_time (UpHistoryItem *history_item); void up_history_item_set_time (UpHistoryItem *history_item, guint time); void up_history_item_set_time_to_present (UpHistoryItem *history_item); UpDeviceState up_history_item_get_state (UpHistoryItem *history_item); void up_history_item_set_state (UpHistoryItem *history_item, UpDeviceState state); gchar *up_history_item_to_string (UpHistoryItem *history_item); gboolean up_history_item_set_from_string (UpHistoryItem *history_item, const gchar *text); G_END_DECLS #endif /* __UP_HISTORY_ITEM_H */ 07070100000028000081A400000000000000000000000166EA4814000014C1000000000000000000000000000000000000002D00000000upower-1.90.6/libupower-glib/up-stats-item.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-stats-item * @short_description: Helper object representing one item of statistics data. * @see_also: #UpDevice, #UpClient * * This object represents one item of data which may be returned from the * daemon in response to a query. */ #include "config.h" #include <glib.h> #include "up-stats-item.h" static void up_stats_item_class_init (UpStatsItemClass *klass); static void up_stats_item_init (UpStatsItem *stats_item); static void up_stats_item_finalize (GObject *object); struct UpStatsItemPrivate { gdouble value; gdouble accuracy; }; enum { PROP_0, PROP_VALUE, PROP_ACCURACY, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (UpStatsItem, up_stats_item, G_TYPE_OBJECT) /** * up_stats_item_set_value: * * Sets the item value. * * Since: 0.9.0 **/ void up_stats_item_set_value (UpStatsItem *stats_item, gdouble value) { g_return_if_fail (UP_IS_STATS_ITEM (stats_item)); stats_item->priv->value = value; g_object_notify (G_OBJECT(stats_item), "value"); } /** * up_stats_item_get_value: * * Gets the item value. * * Since: 0.9.0 **/ gdouble up_stats_item_get_value (UpStatsItem *stats_item) { g_return_val_if_fail (UP_IS_STATS_ITEM (stats_item), G_MAXDOUBLE); return stats_item->priv->value; } /** * up_stats_item_set_accuracy: * * Sets the item accuracy. * * Since: 0.9.0 **/ void up_stats_item_set_accuracy (UpStatsItem *stats_item, gdouble accuracy) { g_return_if_fail (UP_IS_STATS_ITEM (stats_item)); /* constrain */ if (accuracy < 0.0f) accuracy = 0.0f; else if (accuracy > 100.0f) accuracy = 100.0f; stats_item->priv->accuracy = accuracy; g_object_notify (G_OBJECT(stats_item), "accuracy"); } /** * up_stats_item_get_accuracy: * * Gets the item accuracy. * * Since: 0.9.0 **/ gdouble up_stats_item_get_accuracy (UpStatsItem *stats_item) { g_return_val_if_fail (UP_IS_STATS_ITEM (stats_item), G_MAXDOUBLE); return stats_item->priv->accuracy; } /** * up_stats_item_set_property: **/ static void up_stats_item_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UpStatsItem *stats_item = UP_STATS_ITEM (object); switch (prop_id) { case PROP_VALUE: stats_item->priv->value = g_value_get_double (value); break; case PROP_ACCURACY: stats_item->priv->accuracy = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * up_stats_item_get_property: **/ static void up_stats_item_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UpStatsItem *stats_item = UP_STATS_ITEM (object); switch (prop_id) { case PROP_VALUE: g_value_set_double (value, stats_item->priv->value); break; case PROP_ACCURACY: g_value_set_double (value, stats_item->priv->accuracy); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * up_stats_item_class_init: * @klass: The UpStatsItemClass **/ static void up_stats_item_class_init (UpStatsItemClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_stats_item_finalize; object_class->set_property = up_stats_item_set_property; object_class->get_property = up_stats_item_get_property; /** * UpStatsItem:value: * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_VALUE, g_param_spec_double ("value", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /** * UpStatsItem:accuracy: * * Since: 0.9.0 **/ g_object_class_install_property (object_class, PROP_ACCURACY, g_param_spec_double ("accuracy", NULL, NULL, 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); } /** * up_stats_item_init: * @stats_item: This class instance **/ static void up_stats_item_init (UpStatsItem *stats_item) { stats_item->priv = up_stats_item_get_instance_private (stats_item); } /** * up_stats_item_finalize: * @object: The object to finalize **/ static void up_stats_item_finalize (GObject *object) { g_return_if_fail (UP_IS_STATS_ITEM (object)); G_OBJECT_CLASS (up_stats_item_parent_class)->finalize (object); } /** * up_stats_item_new: * * Return value: a new UpStatsItem object. * * Since: 0.9.0 **/ UpStatsItem * up_stats_item_new (void) { return UP_STATS_ITEM (g_object_new (UP_TYPE_STATS_ITEM, NULL)); } 07070100000029000081A400000000000000000000000166EA481400000902000000000000000000000000000000000000002D00000000upower-1.90.6/libupower-glib/up-stats-item.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_STATS_ITEM_H #define __UP_STATS_ITEM_H #include <glib-object.h> G_BEGIN_DECLS #define UP_TYPE_STATS_ITEM (up_stats_item_get_type ()) #define UP_STATS_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_STATS_ITEM, UpStatsItem)) #define UP_STATS_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_STATS_ITEM, UpStatsItemClass)) #define UP_IS_STATS_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_STATS_ITEM)) #define UP_IS_STATS_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_STATS_ITEM)) #define UP_STATS_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_STATS_ITEM, UpStatsItemClass)) typedef struct UpStatsItemPrivate UpStatsItemPrivate; typedef struct { GObject parent; UpStatsItemPrivate *priv; } UpStatsItem; typedef struct { GObjectClass parent_class; } UpStatsItemClass; GType up_stats_item_get_type (void); UpStatsItem *up_stats_item_new (void); gdouble up_stats_item_get_value (UpStatsItem *stats_item); void up_stats_item_set_value (UpStatsItem *stats_item, gdouble value); gdouble up_stats_item_get_accuracy (UpStatsItem *stats_item); void up_stats_item_set_accuracy (UpStatsItem *stats_item, gdouble accuracy); G_END_DECLS #endif /* __UP_STATS_ITEM_H */ 0707010000002A000081A400000000000000000000000166EA48140000268D000000000000000000000000000000000000002800000000upower-1.90.6/libupower-glib/up-types.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-types * @short_description: Types used by UPower and libupower-glib * @see_also: #UpClient, #UpDevice * * These helper functions provide a way to marshal enumerated values to * text and back again. */ #include "config.h" #include <glib.h> #include "up-types.h" /** * up_device_kind_to_string: * * Converts a #UpDeviceKind to a string. * * Return value: identifier string * * Since: 0.9.0 **/ const gchar * up_device_kind_to_string (UpDeviceKind type_enum) { switch (type_enum) { case UP_DEVICE_KIND_LINE_POWER: return "line-power"; case UP_DEVICE_KIND_BATTERY: return "battery"; case UP_DEVICE_KIND_UPS: return "ups"; case UP_DEVICE_KIND_MONITOR: return "monitor"; case UP_DEVICE_KIND_MOUSE: return "mouse"; case UP_DEVICE_KIND_KEYBOARD: return "keyboard"; case UP_DEVICE_KIND_PDA: return "pda"; case UP_DEVICE_KIND_PHONE: return "phone"; case UP_DEVICE_KIND_MEDIA_PLAYER: return "media-player"; case UP_DEVICE_KIND_TABLET: return "tablet"; case UP_DEVICE_KIND_COMPUTER: return "computer"; case UP_DEVICE_KIND_GAMING_INPUT: return "gaming-input"; case UP_DEVICE_KIND_PEN: return "pen"; case UP_DEVICE_KIND_TOUCHPAD: return "touchpad"; case UP_DEVICE_KIND_MODEM: return "modem"; case UP_DEVICE_KIND_NETWORK: return "network"; case UP_DEVICE_KIND_HEADSET: return "headset"; case UP_DEVICE_KIND_SPEAKERS: return "speakers"; case UP_DEVICE_KIND_HEADPHONES: return "headphones"; case UP_DEVICE_KIND_VIDEO: return "video"; case UP_DEVICE_KIND_OTHER_AUDIO: return "audio-device"; case UP_DEVICE_KIND_REMOTE_CONTROL: return "remote-control"; case UP_DEVICE_KIND_PRINTER: return "printer"; case UP_DEVICE_KIND_SCANNER: return "scanner"; case UP_DEVICE_KIND_CAMERA: return "camera"; case UP_DEVICE_KIND_WEARABLE: return "wearable"; case UP_DEVICE_KIND_TOY: return "toy"; case UP_DEVICE_KIND_BLUETOOTH_GENERIC: return "bluetooth-generic"; default: return "unknown"; } g_assert_not_reached (); } /** * up_device_kind_from_string: * * Converts a string to a #UpDeviceKind. * * Return value: enumerated value * * Since: 0.9.0 **/ UpDeviceKind up_device_kind_from_string (const gchar *type) { if (type == NULL) return UP_DEVICE_KIND_UNKNOWN; if (g_str_equal (type, "line-power")) return UP_DEVICE_KIND_LINE_POWER; if (g_str_equal (type, "battery")) return UP_DEVICE_KIND_BATTERY; if (g_str_equal (type, "ups")) return UP_DEVICE_KIND_UPS; if (g_str_equal (type, "monitor")) return UP_DEVICE_KIND_MONITOR; if (g_str_equal (type, "mouse")) return UP_DEVICE_KIND_MOUSE; if (g_str_equal (type, "keyboard")) return UP_DEVICE_KIND_KEYBOARD; if (g_str_equal (type, "pda")) return UP_DEVICE_KIND_PDA; if (g_str_equal (type, "phone")) return UP_DEVICE_KIND_PHONE; if (g_str_equal (type, "media-player")) return UP_DEVICE_KIND_MEDIA_PLAYER; if (g_str_equal (type, "tablet")) return UP_DEVICE_KIND_TABLET; if (g_str_equal (type, "gaming-input")) return UP_DEVICE_KIND_GAMING_INPUT; if (g_str_equal (type, "pen")) return UP_DEVICE_KIND_PEN; if (g_str_equal (type, "touchpad")) return UP_DEVICE_KIND_TOUCHPAD; if (g_str_equal (type, "modem")) return UP_DEVICE_KIND_MODEM; if (g_str_equal (type, "network")) return UP_DEVICE_KIND_NETWORK; if (g_str_equal (type, "headset")) return UP_DEVICE_KIND_HEADSET; if (g_str_equal (type, "speakers")) return UP_DEVICE_KIND_SPEAKERS; if (g_str_equal (type, "headphones")) return UP_DEVICE_KIND_HEADPHONES; if (g_str_equal (type, "video")) return UP_DEVICE_KIND_VIDEO; if (g_str_equal (type, "audio-device")) return UP_DEVICE_KIND_OTHER_AUDIO; if (g_str_equal (type, "remote-control")) return UP_DEVICE_KIND_REMOTE_CONTROL; if (g_str_equal (type, "printer")) return UP_DEVICE_KIND_PRINTER; if (g_str_equal (type, "scanner")) return UP_DEVICE_KIND_SCANNER; if (g_str_equal (type, "camera")) return UP_DEVICE_KIND_CAMERA; if (g_str_equal (type, "wearable")) return UP_DEVICE_KIND_WEARABLE; if (g_str_equal (type, "toy")) return UP_DEVICE_KIND_TOY; if (g_str_equal (type, "bluetooth-generic")) return UP_DEVICE_KIND_BLUETOOTH_GENERIC; return UP_DEVICE_KIND_UNKNOWN; } /** * up_device_state_to_string: * * Converts a #UpDeviceState to a string. * * Return value: identifier string * * Since: 0.9.0 **/ const gchar * up_device_state_to_string (UpDeviceState state_enum) { switch (state_enum) { case UP_DEVICE_STATE_CHARGING: return "charging"; case UP_DEVICE_STATE_DISCHARGING: return "discharging"; case UP_DEVICE_STATE_EMPTY: return "empty"; case UP_DEVICE_STATE_FULLY_CHARGED: return "fully-charged"; case UP_DEVICE_STATE_PENDING_CHARGE: return "pending-charge"; case UP_DEVICE_STATE_PENDING_DISCHARGE: return "pending-discharge"; default: return "unknown"; } g_assert_not_reached (); } /** * up_device_state_from_string: * * Converts a string to a #UpDeviceState. * * Return value: enumerated value * * Since: 0.9.0 **/ UpDeviceState up_device_state_from_string (const gchar *state) { if (state == NULL) return UP_DEVICE_STATE_UNKNOWN; if (g_str_equal (state, "charging")) return UP_DEVICE_STATE_CHARGING; if (g_str_equal (state, "discharging")) return UP_DEVICE_STATE_DISCHARGING; if (g_str_equal (state, "empty")) return UP_DEVICE_STATE_EMPTY; if (g_str_equal (state, "fully-charged")) return UP_DEVICE_STATE_FULLY_CHARGED; if (g_str_equal (state, "pending-charge")) return UP_DEVICE_STATE_PENDING_CHARGE; if (g_str_equal (state, "pending-discharge")) return UP_DEVICE_STATE_PENDING_DISCHARGE; return UP_DEVICE_STATE_UNKNOWN; } /** * up_device_technology_to_string: * * Converts a #UpDeviceTechnology to a string. * * Return value: identifier string * * Since: 0.9.0 **/ const gchar * up_device_technology_to_string (UpDeviceTechnology technology_enum) { switch (technology_enum) { case UP_DEVICE_TECHNOLOGY_LITHIUM_ION: return "lithium-ion"; case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER: return "lithium-polymer"; case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE: return "lithium-iron-phosphate"; case UP_DEVICE_TECHNOLOGY_LEAD_ACID: return "lead-acid"; case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM: return "nickel-cadmium"; case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE: return "nickel-metal-hydride"; default: return "unknown"; } g_assert_not_reached (); } /** * up_device_technology_from_string: * * Converts a string to a #UpDeviceTechnology. * * Return value: enumerated value * * Since: 0.9.0 **/ UpDeviceTechnology up_device_technology_from_string (const gchar *technology) { if (technology == NULL) return UP_DEVICE_TECHNOLOGY_UNKNOWN; if (g_str_equal (technology, "lithium-ion")) return UP_DEVICE_TECHNOLOGY_LITHIUM_ION; if (g_str_equal (technology, "lithium-polymer")) return UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER; if (g_str_equal (technology, "lithium-iron-phosphate")) return UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE; if (g_str_equal (technology, "lead-acid")) return UP_DEVICE_TECHNOLOGY_LEAD_ACID; if (g_str_equal (technology, "nickel-cadmium")) return UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM; if (g_str_equal (technology, "nickel-metal-hydride")) return UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE; return UP_DEVICE_TECHNOLOGY_UNKNOWN; } /** * up_device_level_to_string: * * Converts a #UpDeviceLevel to a string. * * Return value: identifier string * * Since: 1.0 **/ const gchar * up_device_level_to_string (UpDeviceLevel level_enum) { switch (level_enum) { case UP_DEVICE_LEVEL_UNKNOWN: return "unknown"; case UP_DEVICE_LEVEL_NONE: return "none"; case UP_DEVICE_LEVEL_DISCHARGING: return "discharging"; case UP_DEVICE_LEVEL_LOW: return "low"; case UP_DEVICE_LEVEL_CRITICAL: return "critical"; case UP_DEVICE_LEVEL_ACTION: return "action"; case UP_DEVICE_LEVEL_NORMAL: return "normal"; case UP_DEVICE_LEVEL_HIGH: return "high"; case UP_DEVICE_LEVEL_FULL: return "full"; default: return "unknown"; } g_assert_not_reached (); } /** * up_device_level_from_string: * * Converts a string to a #UpDeviceLevel. * * Return value: enumerated value * * Since: 1.0 **/ UpDeviceLevel up_device_level_from_string (const gchar *level) { if (level == NULL) return UP_DEVICE_LEVEL_UNKNOWN; if (g_str_equal (level, "unknown")) return UP_DEVICE_LEVEL_UNKNOWN; if (g_str_equal (level, "none")) return UP_DEVICE_LEVEL_NONE; if (g_str_equal (level, "discharging")) return UP_DEVICE_LEVEL_DISCHARGING; if (g_str_equal (level, "low")) return UP_DEVICE_LEVEL_LOW; if (g_str_equal (level, "critical")) return UP_DEVICE_LEVEL_CRITICAL; if (g_str_equal (level, "action")) return UP_DEVICE_LEVEL_ACTION; if (g_str_equal (level, "normal")) return UP_DEVICE_LEVEL_NORMAL; if (g_str_equal (level, "high")) return UP_DEVICE_LEVEL_HIGH; if (g_str_equal (level, "full")) return UP_DEVICE_LEVEL_FULL; return UP_DEVICE_LEVEL_UNKNOWN; } 0707010000002B000081A400000000000000000000000166EA481400000F82000000000000000000000000000000000000002800000000upower-1.90.6/libupower-glib/up-types.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_TYPES_H #define __UP_TYPES_H #include <glib-object.h> G_BEGIN_DECLS /** * UpDeviceKind: * * The device type. **/ typedef enum { UP_DEVICE_KIND_UNKNOWN, UP_DEVICE_KIND_LINE_POWER, UP_DEVICE_KIND_BATTERY, UP_DEVICE_KIND_UPS, UP_DEVICE_KIND_MONITOR, UP_DEVICE_KIND_MOUSE, UP_DEVICE_KIND_KEYBOARD, UP_DEVICE_KIND_PDA, UP_DEVICE_KIND_PHONE, UP_DEVICE_KIND_MEDIA_PLAYER, UP_DEVICE_KIND_TABLET, UP_DEVICE_KIND_COMPUTER, UP_DEVICE_KIND_GAMING_INPUT, UP_DEVICE_KIND_PEN, UP_DEVICE_KIND_TOUCHPAD, UP_DEVICE_KIND_MODEM, UP_DEVICE_KIND_NETWORK, UP_DEVICE_KIND_HEADSET, UP_DEVICE_KIND_SPEAKERS, UP_DEVICE_KIND_HEADPHONES, UP_DEVICE_KIND_VIDEO, UP_DEVICE_KIND_OTHER_AUDIO, UP_DEVICE_KIND_REMOTE_CONTROL, UP_DEVICE_KIND_PRINTER, UP_DEVICE_KIND_SCANNER, UP_DEVICE_KIND_CAMERA, UP_DEVICE_KIND_WEARABLE, UP_DEVICE_KIND_TOY, UP_DEVICE_KIND_BLUETOOTH_GENERIC, UP_DEVICE_KIND_LAST } UpDeviceKind; /** * UpDeviceState: * * The device state. **/ typedef enum { UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_CHARGING, UP_DEVICE_STATE_DISCHARGING, UP_DEVICE_STATE_EMPTY, UP_DEVICE_STATE_FULLY_CHARGED, UP_DEVICE_STATE_PENDING_CHARGE, UP_DEVICE_STATE_PENDING_DISCHARGE, UP_DEVICE_STATE_LAST } UpDeviceState; /** * UpDeviceTechnology: * * The device technology. **/ typedef enum { UP_DEVICE_TECHNOLOGY_UNKNOWN, UP_DEVICE_TECHNOLOGY_LITHIUM_ION, UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER, UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE, UP_DEVICE_TECHNOLOGY_LEAD_ACID, UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM, UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE, UP_DEVICE_TECHNOLOGY_LAST } UpDeviceTechnology; /** * UpDeviceLevel: * * The level of a battery. Only values up to, and including * %UP_DEVICE_LEVEL_ACTION are relevant for the #WarningLevel. * The #BatteryLevel only uses the following values: * - %UP_DEVICE_LEVEL_UNKNOWN * - %UP_DEVICE_LEVEL_NONE * - %UP_DEVICE_LEVEL_LOW * - %UP_DEVICE_LEVEL_CRITICAL * - %UP_DEVICE_LEVEL_NORMAL * - %UP_DEVICE_LEVEL_HIGH * - %UP_DEVICE_LEVEL_FULL **/ typedef enum { UP_DEVICE_LEVEL_UNKNOWN, UP_DEVICE_LEVEL_NONE, UP_DEVICE_LEVEL_DISCHARGING, UP_DEVICE_LEVEL_LOW, UP_DEVICE_LEVEL_CRITICAL, UP_DEVICE_LEVEL_ACTION, UP_DEVICE_LEVEL_NORMAL, UP_DEVICE_LEVEL_HIGH, UP_DEVICE_LEVEL_FULL, UP_DEVICE_LEVEL_LAST } UpDeviceLevel; const gchar *up_device_kind_to_string (UpDeviceKind type_enum); const gchar *up_device_state_to_string (UpDeviceState state_enum); const gchar *up_device_technology_to_string (UpDeviceTechnology technology_enum); const gchar *up_device_level_to_string (UpDeviceLevel level_enum); UpDeviceKind up_device_kind_from_string (const gchar *type); UpDeviceState up_device_state_from_string (const gchar *state); UpDeviceTechnology up_device_technology_from_string (const gchar *technology); UpDeviceLevel up_device_level_from_string (const gchar *level); G_END_DECLS #endif /* __UP_TYPES_H */ 0707010000002C000081A400000000000000000000000166EA481400000828000000000000000000000000000000000000002D00000000upower-1.90.6/libupower-glib/up-version.h.in/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2010 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:up-version * @short_description: Obtains the version for the installed UPower * @see_also: #UpClient, #UpDevice * * These compile time macros allow the user to enable parts of client code * depending on the version of libupower-glib installed. */ #if !defined (__UPOWER_H_INSIDE__) && !defined (UP_COMPILATION) #error "Only <upower.h> can be included directly." #endif #ifndef __UP_VERSION_H #define __UP_VERSION_H /** * UP_CHECK_VERSION: * * The compile-time major version */ #define UP_MAJOR_VERSION (@UP_MAJOR_VERSION@) /** * UP_CHECK_MINOR: * * The compile-time minor version */ #define UP_MINOR_VERSION (@UP_MINOR_VERSION@) /** * UP_MICRO_VERSION: * * The compile-time micro version */ #define UP_MICRO_VERSION (@UP_MICRO_VERSION@) /* check whether a UPower version equal to or greater than * major.minor.micro. */ #define UP_CHECK_VERSION(major,minor,micro) \ (UP_MAJOR_VERSION > (major) || \ (UP_MAJOR_VERSION == (major) && UP_MINOR_VERSION > (minor)) || \ (UP_MAJOR_VERSION == (major) && UP_MINOR_VERSION == (minor) && \ UP_MICRO_VERSION >= (micro))) #endif /* __UP_VERSION_H */ 0707010000002D000081A400000000000000000000000166EA481400000631000000000000000000000000000000000000002600000000upower-1.90.6/libupower-glib/upower.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008-2010 Richard Hughes <richard@hughsie.com> * * 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. */ /** * SECTION:upower * @short_description: Client objects for accessing UPower * @see_also: #UpClient, #UpDevice * * These objects allow client programs to trivially get details about the power * state, and about devices on the system. */ #ifndef __UPOWER_H__ #define __UPOWER_H__ #define __UPOWER_H_INSIDE__ #include <libupower-glib/up-version.h> #include <libupower-glib/up-types.h> #include <libupower-glib/up-client.h> #include <libupower-glib/up-device.h> #include <libupower-glib/up-history-item.h> #include <libupower-glib/up-stats-item.h> #include <libupower-glib/up-autocleanups.h> #undef __UPOWER_H_INSIDE__ #endif /* __UPOWER_H__ */ 0707010000002E000081A400000000000000000000000166EA4814000016BD000000000000000000000000000000000000001A00000000upower-1.90.6/meson.buildproject('upower', 'c', version: '1.90.6', license: 'GPLv2+', default_options: [ 'buildtype=debugoptimized', 'warning_level=1', 'c_std=gnu99', ], meson_version: '>= 0.60.0') soversion = 3 current = 1 revision = 0 libversion = '@0@.@1@.@2@'.format(soversion, current, revision) gnome = import('gnome') i18n = import('i18n') cc = meson.get_compiler('c') # TODO: Get rid of these by including config.h where needed add_project_arguments([ '-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), '-DPACKAGE_VERSION="@0@"'.format(meson.project_version()), ], language: 'c') cdata = configuration_data() cdata.set_quoted('GETTEXT_PACKAGE', meson.project_name()) cdata.set_quoted('PACKAGE_VERSION', meson.project_version()) cdata.set_quoted('VERSION', meson.project_version()) cdata.set_quoted('PACKAGE_SYSCONF_DIR', get_option('sysconfdir')) glib_min_version = '2.66' glib_version_def = 'GLIB_VERSION_@0@_@1@'.format( glib_min_version.split('.')[0], glib_min_version.split('.')[1]) common_cflags = cc.get_supported_arguments([ '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, ]) add_project_arguments(common_cflags, language: 'c') glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version) gio_dep = dependency('gio-2.0', version: '>=' + glib_min_version) gio_unix_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) m_dep = cc.find_library('m', required: true) polkit = dependency('polkit-gobject-1', version: '>= 0.103', required: get_option('polkit').disable_auto_if(host_machine.system() != 'linux')) if polkit.found() cdata.set('HAVE_POLKIT', '1') if polkit.version().version_compare('>= 0.114') cdata.set('HAVE_POLKIT_0_114', '1') endif cdata.set_quoted ('POLKIT_ACTIONDIR', polkit.get_variable(pkgconfig: 'actiondir')) endif xsltproc = find_program('xsltproc', disabler: true, required: get_option('gtk-doc') or get_option('man')) # Resolve OS backend os_backend = get_option('os_backend') if os_backend == 'auto' # Likely needs to be updated when options are added if host_machine.system() in ['linux', 'freebsd', 'openbsd'] os_backend = host_machine.system() else os_backend = 'dummy' endif endif cdata.set_quoted('BACKEND', os_backend) # Backend specific dependencies gudev_dep = dependency('', required: false) idevice_dep = dependency('', required: false) plist_dep = dependency('', required: false) gobject_introspection = dependency('gobject-introspection-1.0', required: get_option('introspection')) if os_backend == 'linux' gudev_dep = dependency('gudev-1.0', version: '>= 238') idevice_dep = dependency('libimobiledevice-1.0', version : '>= 0.9.7', required : get_option('idevice')) if idevice_dep.found() plist_dep = dependency('libplist-2.0', required: false) if not plist_dep.found() plist_dep = dependency('libplist', required: true) endif cdata.set10('HAVE_IDEVICE', true) endif udevrulesdir = get_option('udevrulesdir') if udevrulesdir == 'auto' udev_dep = dependency('udev', required: true) udevrulesdir = udev_dep.get_variable(pkgconfig: 'udev_dir') / 'rules.d' endif udevhwdbdir = get_option('udevhwdbdir') if udevhwdbdir == 'auto' udev_dep = dependency('udev', required: true) udevhwdbdir = udev_dep.get_variable(pkgconfig: 'udev_dir') / 'hwdb.d' endif endif historydir = get_option('historydir') if historydir == '' historydir = get_option('prefix') / get_option('localstatedir') / 'lib' / 'upower' endif statedir = get_option('statedir') if statedir == '' statedir = get_option('prefix') / get_option('localstatedir') / 'lib' / 'upower' endif dbusdir = get_option('datadir') / 'dbus-1' systemdsystemunitdir = get_option('systemdsystemunitdir') if systemdsystemunitdir == '' systemd_dep = dependency('systemd') systemdsystemunitdir = systemd_dep.get_variable(pkgconfig: 'systemdsystemunitdir') endif datadir = get_option('datadir') if datadir == '' datadir = join_paths(prefix, get_option('datadir')) endif # Generate configuration file config_h = configure_file(output: 'config.h', configuration: cdata) subdir('etc') subdir('rules') subdir('po') subdir('dbus') subdir('libupower-glib') subdir('src') subdir('tools') subdir('doc') subdir('policy') pkgconfig = import('pkgconfig') pkgconfig.generate( name: 'upower-glib', description: 'UPower is a system daemon for managing power devices', version: meson.project_version(), libraries: libupower_glib, requires: [glib_dep, gobject_dep, polkit], subdirs: 'libupower-glib', ) output = [] output += 'UPower ' + meson.project_version() output += 'System Paths' output += ' prefix: ' + get_option('prefix') output += ' libdir: ' + get_option('libdir') output += ' libexecdir: ' + get_option('prefix') / get_option('libexecdir') output += ' bindir: ' + get_option('prefix') / get_option('bindir') output += ' sbindir: ' + get_option('prefix') / get_option('sbindir') output += ' datadir: ' + get_option('prefix') / get_option('datadir') output += ' sysconfdir: ' + get_option('sysconfdir') output += ' localstatedir: ' + get_option('prefix') / get_option('localstatedir') output += ' historydir: ' + historydir output += '\nFeatures' output += ' Backend: ' + os_backend output += ' libimobiledevice support: ' + idevice_dep.found().to_string() output += ' Building api docs: ' + get_option('gtk-doc').to_string() output += ' Building man pages: ' + get_option('man').to_string() message('\n'+'\n'.join(output)+'\n') 0707010000002F000081A400000000000000000000000166EA481400000560000000000000000000000000000000000000002000000000upower-1.90.6/meson_options.txtoption('man', type : 'boolean', value : 'true', description : 'Build manpages') option('gtk-doc', type : 'boolean', value : 'true', description : 'Build developer documentation') option('introspection', type : 'feature', value : 'auto', description : 'Build GObject Introspection data') option('udevrulesdir', type : 'string', value: 'auto', description : 'Directory for udev rules') option('udevhwdbdir', type : 'string', value: 'auto', description : 'Directory for udev hwdb') option('historydir', type : 'string', description : 'Directory for upower history files will be stored') option('statedir', type : 'string', description : 'Directory for upower status files will be stored') option('systemdsystemunitdir', type : 'string', description : 'Directory for systemd service files ("no" to disable)') option('os_backend', type : 'combo', choices : [ 'auto', 'linux', 'freebsd', 'openbsd', 'dummy'], value : 'auto', description : 'Directory for systemd service files') option('idevice', type : 'feature', value : 'auto', description : 'Build with libimobiledevice') option('polkit', type: 'feature', value: 'auto', description: 'PolKit support in daemon') 07070100000030000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001100000000upower-1.90.6/po07070100000031000081A400000000000000000000000166EA48140000003D000000000000000000000000000000000000001900000000upower-1.90.6/po/LINGUAS# please keep this list sorted alphabetically # fr it sv pl 07070100000032000081A400000000000000000000000166EA481400000085000000000000000000000000000000000000001D00000000upower-1.90.6/po/POTFILES.in# List of source files containing translatable strings. # Please keep this file sorted alphabetically. src/up-main.c tools/up-tool.c 07070100000033000081A400000000000000000000000166EA481400000001000000000000000000000000000000000000001F00000000upower-1.90.6/po/POTFILES.skip 07070100000034000081A400000000000000000000000166EA481400000F6E000000000000000000000000000000000000001700000000upower-1.90.6/po/fr.po# French translation for upower # Copyright (C) 2010 The Free Software Foundation, Inc # This file is distributed under the same license as the polkit package. # Christoph J. Thompson <cjsthompson@gmail.com>, 2010. # msgid "" msgstr "" "Project-Id-Version: upower 0.9.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-17 10:52+0200\n" "PO-Revision-Date: 2010-11-01 08:21+0100\n" "Last-Translator: Christoph J. Thompson <cjsthompson@gmail.com>\n" "Language-Team: French <fr@li.org>\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. TRANSLATORS: exit after we've started up, used for user profiling #: src/up-main.c:190 msgid "Exit after a small delay" msgstr "Terminer le processus après un court delai" #. TRANSLATORS: exit straight away, used for automatic profiling #: src/up-main.c:193 msgid "Exit after the engine has loaded" msgstr "Terminer le processus après le chargement du moteur" #: src/up-main.c:195 msgid "Replace the old daemon" msgstr "" #: src/up-main.c:197 #, fuzzy msgid "Show extra debugging information" msgstr "Afficher les options de débogage" #: src/up-main.c:199 msgid "Enable debugging (implies --verbose)" msgstr "" #: tools/up-tool.c:206 msgid "Enumerate objects paths for devices" msgstr "Enumérer les chemins des objets des périphériques" #: tools/up-tool.c:207 msgid "Dump all parameters for all objects" msgstr "Capturer tous les paramètres de tous les objets" #: tools/up-tool.c:208 msgid "Monitor activity from the power daemon" msgstr "Contrôller l'activité du démon de l'alimentation" #: tools/up-tool.c:209 msgid "Monitor with detail" msgstr "Contrôller dans les détails" #: tools/up-tool.c:210 msgid "Show information about object path" msgstr "Afficher les informations sur le chemin de l'objet" #~ msgid "Authentication is required to hibernate the system" #~ msgstr "Vous devez vous identifier pour mettre le système en hibernation" #~ msgid "Authentication is required to suspend the system" #~ msgstr "Vous devez vous identifier pour mettre le système en veille" #~ msgid "Hibernate the system" #~ msgstr "Mettre le système en hibernation" #~ msgid "Suspend the system" #~ msgstr "Mettre le système en veille" #~ msgid "Authentication is required to cancel a latency request" #~ msgstr "Vous devez vous identifier pour annuler une demande de latence" #~ msgid "Authentication is required to set a persistent latency setting" #~ msgstr "Vous devez vous identifier pour définir de latence persistante" #~ msgid "" #~ "Authentication is required to set administrator settings for latency " #~ "control" #~ msgstr "" #~ "Vous devez vous identifier pour définir les paramètres administrateur de " #~ "contrôle de latence" #~ msgid "" #~ "Authentication is required to set the required latency of an application" #~ msgstr "" #~ "Vous devez vous identifier pour définir la latence requise d'une " #~ "application" #~ msgid "Cancel a latency request" #~ msgstr "Annuler une demande de latence" #~ msgid "Set a persistent latency setting" #~ msgstr "Définir une latence persistante" #~ msgid "Set administrator settings for latency control" #~ msgstr "" #~ "Définir les paramètres administrateur pour le contrôle de la latence" #~ msgid "Set the required latency of an application" #~ msgstr "Définir la latence requise d'une application" #~ msgid "Get the wakeup data" #~ msgstr "Obtenir les données de réveil" #~ msgid "Show debugging information for all files" #~ msgstr "Afficher les informations de débogage pour tous les fichiers" #~ msgid "Debug these specific modules" #~ msgstr "Déboguer les modules suivants" #~ msgid "Debug these specific functions" #~ msgstr "Déboguer les fonctions suivantes" #~ msgid "Log debugging data to a file" #~ msgstr "Consigner les données de débogage dans un fichier" #~ msgid "Debugging Options" #~ msgstr "Options de Débogage" 07070100000035000081A400000000000000000000000166EA481400000DEF000000000000000000000000000000000000001700000000upower-1.90.6/po/it.po# Italian translation for UPower # Copyright (C) 2009 The Free Software Foundation, Inc # This file is distributed under the same license as the PolicyKit package. # Luca Ferretti <elle.uca@libero.it>, 2009. # # Milo Casagrande <milo@ubuntu.com>, 2009. msgid "" msgstr "" "Project-Id-Version: UPower 011\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-17 10:52+0200\n" "PO-Revision-Date: 2009-08-26 21:05+0200\n" "Last-Translator: Milo Casagrande <milo@ubuntu.com>\n" "Language-Team: Italian <tp@lists.linux.it>\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. TRANSLATORS: exit after we've started up, used for user profiling #: src/up-main.c:190 msgid "Exit after a small delay" msgstr "" #. TRANSLATORS: exit straight away, used for automatic profiling #: src/up-main.c:193 msgid "Exit after the engine has loaded" msgstr "" #: src/up-main.c:195 msgid "Replace the old daemon" msgstr "" #: src/up-main.c:197 msgid "Show extra debugging information" msgstr "Mostra informazioni di debug aggiuntive" #: src/up-main.c:199 msgid "Enable debugging (implies --verbose)" msgstr "" #: tools/up-tool.c:206 msgid "Enumerate objects paths for devices" msgstr "Enumera i percorsi di oggetti per i dispositivi" #: tools/up-tool.c:207 msgid "Dump all parameters for all objects" msgstr "Riversa tutti i parametri per tutti gli oggetti" # credo sia del #: tools/up-tool.c:208 msgid "Monitor activity from the power daemon" msgstr "Monitoraggio dell'attività del demone di alimentazione" #: tools/up-tool.c:209 msgid "Monitor with detail" msgstr "Monitoraggio con dettagli" #: tools/up-tool.c:210 msgid "Show information about object path" msgstr "Mostra informazioni sul percorso dell'oggetto" # message #~ msgid "Authentication is required to hibernate the system" #~ msgstr "È richiesto autenticarsi per ibernare il sistema" # message #~ msgid "Authentication is required to suspend the system" #~ msgstr "È richiesto autenticarsi per sospendere il sistema" # description #~ msgid "Hibernate the system" #~ msgstr "Iberna il sistema" # description #~ msgid "Suspend the system" #~ msgstr "Sospende il sistema" # message #~ msgid "Authentication is required to cancel a latency request" #~ msgstr "È richiesto autenticarsi per annullare una richiesta di latenza" # message #~ msgid "Authentication is required to set a persistent latency setting" #~ msgstr "" #~ "È richiesto autenticarsi per impostare una impostazione di latenza " #~ "duratura" # message #~ msgid "" #~ "Authentication is required to set administrator settings for latency " #~ "control" #~ msgstr "" #~ "È richiesto autenticarsi per impostare le impostazioni di amministrazione " #~ "per il controllo della latenza" # message #~ msgid "" #~ "Authentication is required to set the required latency of an application" #~ msgstr "" #~ "È richiesto autenticarsi per impostare la latenza richiesta di " #~ "un'applicazione" # description #~ msgid "Cancel a latency request" #~ msgstr "Annulla una richiesta di latenza" # description #~ msgid "Set a persistent latency setting" #~ msgstr "Imposta una impostazione di latenza duratura" # description #~ msgid "Set administrator settings for latency control" #~ msgstr "" #~ "Imposta le impostazioni di amministrazione per il controllo della latenza" # description #~ msgid "Set the required latency of an application" #~ msgstr "Imposta la latenza richiesta di un'applicazione" #~ msgid "Get the wakeup data" #~ msgstr "Ottiene i dati di risveglio" 07070100000036000081A400000000000000000000000166EA48140000109E000000000000000000000000000000000000001700000000upower-1.90.6/po/ka.po# Georgian translation for devicekit-power. # Copyright (C) 2022 Free Software Foundation, Inc. # This file is distributed under the same license as the devicekit-power package. # Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022 # msgid "" msgstr "" "Project-Id-Version: devicekit-power\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-17 10:52+0200\n" "PO-Revision-Date: 2022-07-17 08:03+0200\n" "Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n" "Language-Team: Georgian <(nothing)>.\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.1.1\n" #. TRANSLATORS: exit after we've started up, used for user profiling #: src/up-main.c:190 msgid "Exit after a small delay" msgstr "გამოსვლამდე მცირე დაყოვნება" #. TRANSLATORS: exit straight away, used for automatic profiling #: src/up-main.c:193 msgid "Exit after the engine has loaded" msgstr "გამოსვლა ძრავის ჩატვირთვის შემდეგ" #: src/up-main.c:195 msgid "Replace the old daemon" msgstr "ძველი დემონის შეცვლა" #: src/up-main.c:197 msgid "Show extra debugging information" msgstr "გამართვის დამატებითი ინფორმაციის ჩვენება" #: src/up-main.c:199 msgid "Enable debugging (implies --verbose)" msgstr "დამატებითი შეტყობინებების ჩართვა(ასევე შეიცავს --verbose)" #: tools/up-tool.c:206 msgid "Enumerate objects paths for devices" msgstr "ობიექტების ბილიკების ჩამონათვალი მოწყობილობებისთვის" #: tools/up-tool.c:207 msgid "Dump all parameters for all objects" msgstr "ყველა ობიექტის ყველა პარამეტრის გამოტანა" #: tools/up-tool.c:208 msgid "Monitor activity from the power daemon" msgstr "აქტივობის მონიტორინგი კვების მართვის დემონიდიდან" #: tools/up-tool.c:209 msgid "Monitor with detail" msgstr "მონიტორინგი დეტალებით" #: tools/up-tool.c:210 msgid "Show information about object path" msgstr "ობიექტის ბილიკის ინფორმაციის ჩვენება" #~ msgid "Authentication is required to hibernate the system" #~ msgstr "Autentisering krävs för att försätta systemet i viloläge" #~ msgid "Authentication is required to suspend the system" #~ msgstr "Autentisering krävs för att försätta systemet i vänteläge" #~ msgid "Hibernate the system" #~ msgstr "Försätt systemet i viloläge" #~ msgid "Suspend the system" #~ msgstr "Försätt systemet i vänteläge" #~ msgid "Authentication is required to cancel a latency request" #~ msgstr "Autentisering krävs för att avbryta en fördröjningsbegäran" #~ msgid "Authentication is required to set a persistent latency setting" #~ msgstr "Autentisering krävs för att ställa in en bestående fördröjningsinställning" #~ msgid "Authentication is required to set administrator settings for latency control" #~ msgstr "Autentisering krävs för att ställa in administratörsinställningar för fördröjningskontroll" #~ msgid "Authentication is required to set the required latency of an application" #~ msgstr "Autentisering krävs för att ställa in nödvändig fördröjning för ett program" #~ msgid "Cancel a latency request" #~ msgstr "Avbryt en fördröjningsbegäran" #~ msgid "Set a persistent latency setting" #~ msgstr "Ställ in en bestående fördröjningsinställning" #~ msgid "Set administrator settings for latency control" #~ msgstr "Ställ in administratörsinställningar för fördröjningskontroll" #~ msgid "Set the required latency of an application" #~ msgstr "Ställ in nödvändig fördröjning för ett program" #~ msgid "Get the wakeup data" #~ msgstr "Hämta uppvakningsdata" 07070100000037000081A400000000000000000000000166EA481400000033000000000000000000000000000000000000001D00000000upower-1.90.6/po/meson.buildi18n.gettext(meson.project_name(), preset: 'glib') 07070100000038000081A400000000000000000000000166EA481400000E76000000000000000000000000000000000000001700000000upower-1.90.6/po/pl.po# translation of pl.po to Polish # Piotr Drąg <piotrdrag@gmail.com>, 2010. # msgid "" msgstr "" "Project-Id-Version: pl\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-17 10:52+0200\n" "PO-Revision-Date: 2010-01-22 22:14+0100\n" "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n" "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. TRANSLATORS: exit after we've started up, used for user profiling #: src/up-main.c:190 msgid "Exit after a small delay" msgstr "Kończy działanie po małym opóźnieniu" #. TRANSLATORS: exit straight away, used for automatic profiling #: src/up-main.c:193 msgid "Exit after the engine has loaded" msgstr "Kończy działanie po wczytaniu mechanizmu" #: src/up-main.c:195 msgid "Replace the old daemon" msgstr "" #: src/up-main.c:197 #, fuzzy msgid "Show extra debugging information" msgstr "Wyświetla opcje debugowania" #: src/up-main.c:199 msgid "Enable debugging (implies --verbose)" msgstr "" #: tools/up-tool.c:206 msgid "Enumerate objects paths for devices" msgstr "Wylicza ścieżki obiektów dla urządzeń" #: tools/up-tool.c:207 msgid "Dump all parameters for all objects" msgstr "Zrzuca wszystkie parametry dla wszystkich obiektów" #: tools/up-tool.c:208 msgid "Monitor activity from the power daemon" msgstr "Monitoruje aktywność usługi zasilania" #: tools/up-tool.c:209 msgid "Monitor with detail" msgstr "Monitoruje więcej szczegółów" #: tools/up-tool.c:210 msgid "Show information about object path" msgstr "Wyświetla informacje o ścieżce obiektu" #~ msgid "Authentication is required to hibernate the system" #~ msgstr "Wymagane jest uwierzytelnienie, aby zahibernować system" #~ msgid "Authentication is required to suspend the system" #~ msgstr "Wymagane jest uwierzytelnienie, aby wstrzymać system" #~ msgid "Hibernate the system" #~ msgstr "Hibernacja systemu" #~ msgid "Suspend the system" #~ msgstr "Wstrzymanie systemu" #~ msgid "Authentication is required to cancel a latency request" #~ msgstr "Wymagane jest uwierzytelnienie, aby anulować żądanie opóźnienia" #~ msgid "Authentication is required to set a persistent latency setting" #~ msgstr "" #~ "Wymagane jest uwierzytelnienie, aby ustanowić trwałe ustawienie opóźnienia" #~ msgid "" #~ "Authentication is required to set administrator settings for latency " #~ "control" #~ msgstr "" #~ "Wymagane jest uwierzytelnienie, aby ustanowić ustawienia administratora " #~ "do kontroli opóźnienia" #~ msgid "" #~ "Authentication is required to set the required latency of an application" #~ msgstr "" #~ "Wymagane jest uwierzytelnienie, aby ustawić wymagane opóźnienie programu" #~ msgid "Cancel a latency request" #~ msgstr "Anulowanie żądania opóźnienia" #~ msgid "Set a persistent latency setting" #~ msgstr "Ustanowienie ustawienia trwałego opóźnienia" #~ msgid "Set administrator settings for latency control" #~ msgstr "Ustanowienie ustawień administratora do kontroli opóźnienia" #~ msgid "Set the required latency of an application" #~ msgstr "Ustawienie wymaganego opóźnienia programu" #~ msgid "Get the wakeup data" #~ msgstr "Uzyskuje dane wybudzeń" #~ msgid "Show debugging information for all files" #~ msgstr "Wyświetla informacje debugowania dla wszystkich plików" #~ msgid "Debug these specific modules" #~ msgstr "Debuguje podane moduły" #~ msgid "Debug these specific functions" #~ msgstr "Debuguje podane funkcje" #~ msgid "Log debugging data to a file" #~ msgstr "Zapisuje dane debugowania do pliku" #~ msgid "Debugging Options" #~ msgstr "Opcje debugowania" 07070100000039000081A400000000000000000000000166EA481400000D33000000000000000000000000000000000000001700000000upower-1.90.6/po/sv.po# Swedish translation for devicekit-power. # Copyright (C) 2009 Free Software Foundation, Inc. # This file is distributed under the same license as the devicekit-power package. # Daniel Nylander <po@danielnylander.se>, 2009. # msgid "" msgstr "" "Project-Id-Version: devicekit-power\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-17 10:52+0200\n" "PO-Revision-Date: 2009-09-06 10:13+0100\n" "Last-Translator: Daniel Nylander <po@danielnylander.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #. TRANSLATORS: exit after we've started up, used for user profiling #: src/up-main.c:190 msgid "Exit after a small delay" msgstr "" #. TRANSLATORS: exit straight away, used for automatic profiling #: src/up-main.c:193 msgid "Exit after the engine has loaded" msgstr "" #: src/up-main.c:195 msgid "Replace the old daemon" msgstr "" #: src/up-main.c:197 msgid "Show extra debugging information" msgstr "Visa extra felsökningsinformation" #: src/up-main.c:199 msgid "Enable debugging (implies --verbose)" msgstr "" #: tools/up-tool.c:206 msgid "Enumerate objects paths for devices" msgstr "Räkna upp objektsökvägar för enheter" #: tools/up-tool.c:207 msgid "Dump all parameters for all objects" msgstr "Dumpa alla parametrar för alla objekt" #: tools/up-tool.c:208 msgid "Monitor activity from the power daemon" msgstr "Övervaka aktivitet från strömdemonen" #: tools/up-tool.c:209 msgid "Monitor with detail" msgstr "Övervaka i detalj" #: tools/up-tool.c:210 msgid "Show information about object path" msgstr "Visa information om objektsökväg" #~ msgid "Authentication is required to hibernate the system" #~ msgstr "Autentisering krävs för att försätta systemet i viloläge" #~ msgid "Authentication is required to suspend the system" #~ msgstr "Autentisering krävs för att försätta systemet i vänteläge" #~ msgid "Hibernate the system" #~ msgstr "Försätt systemet i viloläge" #~ msgid "Suspend the system" #~ msgstr "Försätt systemet i vänteläge" #~ msgid "Authentication is required to cancel a latency request" #~ msgstr "Autentisering krävs för att avbryta en fördröjningsbegäran" #~ msgid "Authentication is required to set a persistent latency setting" #~ msgstr "" #~ "Autentisering krävs för att ställa in en bestående fördröjningsinställning" #~ msgid "" #~ "Authentication is required to set administrator settings for latency " #~ "control" #~ msgstr "" #~ "Autentisering krävs för att ställa in administratörsinställningar för " #~ "fördröjningskontroll" #~ msgid "" #~ "Authentication is required to set the required latency of an application" #~ msgstr "" #~ "Autentisering krävs för att ställa in nödvändig fördröjning för ett " #~ "program" #~ msgid "Cancel a latency request" #~ msgstr "Avbryt en fördröjningsbegäran" #~ msgid "Set a persistent latency setting" #~ msgstr "Ställ in en bestående fördröjningsinställning" #~ msgid "Set administrator settings for latency control" #~ msgstr "Ställ in administratörsinställningar för fördröjningskontroll" #~ msgid "Set the required latency of an application" #~ msgstr "Ställ in nödvändig fördröjning för ett program" #~ msgid "Get the wakeup data" #~ msgstr "Hämta uppvakningsdata" 0707010000003A000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001500000000upower-1.90.6/policy0707010000003B000081A400000000000000000000000166EA481400000336000000000000000000000000000000000000002100000000upower-1.90.6/policy/meson.buildif polkit.found() #newer polkit has the ITS rules included if polkit.version().version_compare('>0.113') i18n.merge_file( input: 'org.freedesktop.upower.policy.in', output: 'org.freedesktop.upower.policy', install: true, install_dir: join_paths(datadir, 'polkit-1', 'actions') , type: 'xml', po_dir: join_paths(meson.project_source_root(), 'po') ) #older polkit is missing ITS rules and will fail else i18n.merge_file( input: 'org.freedesktop.upower.policy.in', output: 'org.freedesktop.upower.policy', install: true, install_dir: join_paths(datadir, 'polkit-1', 'actions') , type: 'xml', data_dirs: join_paths(meson.project_source_root(), 'policy'), po_dir: join_paths(meson.project_source_root(), 'po') ) endif endif0707010000003C000081A400000000000000000000000166EA48140000040F000000000000000000000000000000000000003600000000upower-1.90.6/policy/org.freedesktop.upower.policy.in<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd"> <!-- Policy definitions for UPower Copyright (c) 2008 David Zeuthen <david@fubar.dk> Copyright (c) 2008-2010 Richard Hughes <richard@hughsie.com> NOTE: If you make changes to this file, make sure to validate the file using the polkit-policy-file-validate(1) tool. Changes made to this file are instantly applied. --> <policyconfig> <vendor>The UPower Project</vendor> <vendor_url>http://upower.freedesktop.org/</vendor_url> <icon_name>system-suspend</icon_name> <action id="org.freedesktop.UPower.enable-charging-limit"> <_description>Enable battery charging limit</_description> <_message>Authentication is required to set battery charging start and end limit.</_message> <defaults> <allow_inactive>no</allow_inactive> <allow_active>yes</allow_active> </defaults> </action> </policyconfig> 0707010000003D000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001400000000upower-1.90.6/rules0707010000003E000081A400000000000000000000000166EA481400000587000000000000000000000000000000000000002B00000000upower-1.90.6/rules/60-upower-battery.hwdb# This file is part of upower. # # The lookup keys are composed in: # 60-upower-battery.rules # # Match string format: # battery:<kernel>:<model_name>:dmi:<dmi pattern> # # The kernel is the name of battery in /sys/class/power_supply for # differentiating between multiple batteries. # # The model_name is battery model name in for example # /sys/class/power_supply/BAT0/model_name. # # The full DMI string of the running machine can be read from # /sys/class/dmi/id/modalias # That requires a kernel built with CONFIG_DMIID set, which is common. # The full DMI string is not needed here and the meaning of individual parts # can be seen in the source of the DMIID kernel module # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/dmi-id.c # # To add local overrides, create a new file # /etc/udev/hwdb.d/61-battery-local.hwdb # and add your rules there. To load the new rules execute (as root): # systemd-hwdb update # udevadm trigger -v -p /sys/class/power_supply/BAT # where BAT is the battery in question. # # CHARGE_LIMIT is in tuple format and each of the variables can be disabled by "_" character. # For example: # CHARGE_LIMIT=60,80 (charge_control_start_threshold is 60 and charge_control_end_threshold is 80.) # CHARGE_LIMIT=_,80 (charge_control_start_threshold will be skipped and charge_control_end_threshold is 80.) battery:*:*:dmi:* CHARGE_LIMIT=75,80 0707010000003F000081A400000000000000000000000166EA4814000000ED000000000000000000000000000000000000002C00000000upower-1.90.6/rules/60-upower-battery.rulesACTION=="remove", GOTO="battery_end" SUBSYSTEM=="power_supply",ATTR{charge_control_start_threshold}!="" \ IMPORT{builtin}="hwdb 'battery:$kernel:$attr{model_name}:$attr{[dmi/id]modalias}'", \ GOTO="battery_end" LABEL="battery_end" 07070100000040000081A400000000000000000000000166EA481400000E13000000000000000000000000000000000000002700000000upower-1.90.6/rules/95-upower-hid.hwdb############################################################################################################## # Uninterruptible Power Supplies with USB HID interfaces # # This file was automatically generated by NUT: # https://github.com/networkupstools/nut/ # # To keep up to date, monitor upstream NUT # https://github.com/networkupstools/nut/commits/master/scripts/upower/95-upower-hid.hwdb # or checkout the NUT repository and call 'tools/nut-usbinfo.pl' # Hewlett Packard usb:v03F0p0001* usb:v03F0p1F06* usb:v03F0p1F08* usb:v03F0p1F09* usb:v03F0p1F0A* usb:v03F0p1FE0* usb:v03F0p1FE1* usb:v03F0p1FE2* usb:v03F0p1FE3* usb:v03F0p1FE5* usb:v03F0p1FE6* usb:v03F0p1FE7* usb:v03F0p1FE8* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Hewlett Packard # Eaton usb:v0463p0001* usb:v0463pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Eaton # Dell usb:v047CpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Dell # ST Microelectronics usb:v0483pA113* usb:v0483pA430* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=ST Microelectronics # IBM usb:v04B3p0001* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=IBM # Minibox usb:v04D8pD004* usb:v04D8pD005* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Minibox # Belkin usb:v050Dp0375* usb:v050Dp0551* usb:v050Dp0750* usb:v050Dp0751* usb:v050Dp0900* usb:v050Dp0910* usb:v050Dp0912* usb:v050Dp0980* usb:v050Dp0F51* usb:v050Dp1100* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Belkin # APC usb:v051Dp0000* usb:v051Dp0002* usb:v051Dp0003* usb:v051Dp0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=APC # Powerware usb:v0592p0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powerware # Delta UPS usb:v05DDp041B* usb:v05DDpA011* usb:v05DDpA0A0* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Delta UPS # Phoenixtec Power Co., Ltd usb:v06DApFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Phoenixtec Power Co., Ltd # iDowell usb:v075Dp0300* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=iDowell # Cyber Power Systems usb:v0764p0005* usb:v0764p0501* usb:v0764p0601* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Cyber Power Systems # TrippLite usb:v09AEp1003* usb:v09AEp1007* usb:v09AEp1008* usb:v09AEp1009* usb:v09AEp1010* usb:v09AEp1330* usb:v09AEp2005* usb:v09AEp2007* usb:v09AEp2008* usb:v09AEp2009* usb:v09AEp2010* usb:v09AEp2011* usb:v09AEp2012* usb:v09AEp2013* usb:v09AEp2014* usb:v09AEp3008* usb:v09AEp3009* usb:v09AEp3010* usb:v09AEp3011* usb:v09AEp3012* usb:v09AEp3013* usb:v09AEp3014* usb:v09AEp3015* usb:v09AEp3016* usb:v09AEp3024* usb:v09AEp4001* usb:v09AEp4002* usb:v09AEp4003* usb:v09AEp4004* usb:v09AEp4005* usb:v09AEp4006* usb:v09AEp4007* usb:v09AEp4008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=TrippLite # PowerCOM usb:v0D9Fp0001* usb:v0D9Fp0004* usb:v0D9Fp00A2* usb:v0D9Fp00A3* usb:v0D9Fp00A4* usb:v0D9Fp00A5* usb:v0D9Fp00A6* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=PowerCOM # Liebert usb:v10AFp0000* usb:v10AFp0001* usb:v10AFp0002* usb:v10AFp0004* usb:v10AFp0008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Liebert # Legrand usb:v1CB0p0032* usb:v1CB0p0038* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Legrand # Arduino usb:v2341p0036* usb:v2341p8036* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # Arduino usb:v2A03p0036* usb:v2A03p0040* usb:v2A03p8036* usb:v2A03p8040* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # AEG usb:v2B2DpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=AEG # Ever usb:v2E51p0000* usb:v2E51pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Ever # Salicru usb:v2E66p0101* usb:v2E66p0201* usb:v2E66p0202* usb:v2E66p0203* usb:v2E66p0300* usb:v2E66p0302* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Salicru # Powervar usb:v4234p0002* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powervar 07070100000041000081A400000000000000000000000166EA4814000000CF000000000000000000000000000000000000002800000000upower-1.90.6/rules/95-upower-hid.rules# Copy some attributes from the USB device to the hiddev device SUBSYSTEM=="usbmisc", SUBSYSTEMS=="usb", KERNEL=="hiddev*", IMPORT{parent}="UPOWER_*", IMPORT{parent}="ID_VENDOR", IMPORT{parent}="ID_PRODUCT" 07070100000042000081A400000000000000000000000166EA481400000162000000000000000000000000000000000000002800000000upower-1.90.6/rules/95-upower-wup.rules############################################################################################################## # Watts Up? Pro Devices # SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A80?????", ENV{UPOWER_VENDOR}="Watts Up, Inc.", ENV{UPOWER_PRODUCT}="Watts Up? Pro", ENV{UP_MONITOR_TYPE}="wup" 07070100000043000081A400000000000000000000000166EA481400000158000000000000000000000000000000000000002000000000upower-1.90.6/rules/meson.buildrules = [ '60-upower-battery.rules', '95-upower-wup.rules', '95-upower-hid.rules', ] hwdb = [ '95-upower-hid.hwdb', '60-upower-battery.hwdb', ] if os_backend == 'linux' install_data( rules, install_dir: udevrulesdir, ) install_data( hwdb, install_dir: udevhwdbdir, ) endif 07070100000044000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001200000000upower-1.90.6/src07070100000045000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001600000000upower-1.90.6/src/bsd07070100000046000081A400000000000000000000000166EA481400000187000000000000000000000000000000000000002200000000upower-1.90.6/src/bsd/meson.buildupshared_common = static_library('upshared-common', sources: [ 'up-backend-common.c', ], c_args: [ '-DG_LOG_DOMAIN="UPower-Unix"' ], dependencies: [ gudev_dep, upowerd_deps ], build_by_default: false, ) upshared_common_dep = declare_dependency( link_with: [ upshared_common ], # TODO: Move up-backend-bsd-private.h here and add it as include directory ) 07070100000047000081A400000000000000000000000166EA481400000EF1000000000000000000000000000000000000002A00000000upower-1.90.6/src/bsd/up-backend-common.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Eric Koegel <eric.koegel@gmail.com> * * 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 "up-backend-bsd-private.h" static gboolean check_action_result (GVariant *result) { if (result) { const char *s; g_variant_get (result, "(s)", &s); if (g_strcmp0 (s, "yes") == 0) return TRUE; } return FALSE; } /** * functions called by upower daemon **/ /** * up_backend_get_critical_action: * @backend: The %UpBackend class instance * * Which action will be taken when %UP_DEVICE_LEVEL_ACTION * warning-level occurs. **/ const char * up_backend_get_critical_action (UpBackend *backend) { struct { const gchar *method; const gchar *can_method; } actions[] = { { "HybridSleep", "CanHybridSleep" }, { "Hibernate", "CanHibernate" }, { "PowerOff", NULL }, }; guint i = 0; char *action; GDBusProxy *seat_manager_proxy = up_backend_get_seat_manager_proxy (backend); UpConfig *config = up_backend_get_config (backend); g_return_val_if_fail (seat_manager_proxy != NULL, NULL); g_return_val_if_fail (config != NULL, NULL); /* Find the configured action first */ action = up_config_get_string (config, "CriticalPowerAction"); if (action != NULL) { for (i = 0; i < G_N_ELEMENTS (actions); i++) if (g_str_equal (actions[i].method, action)) break; if (i >= G_N_ELEMENTS (actions)) i = 0; g_free (action); } for (; i < G_N_ELEMENTS (actions); i++) { GVariant *result; if (actions[i].can_method) { gboolean action_available; /* Check whether we can use the method */ result = g_dbus_proxy_call_sync (seat_manager_proxy, actions[i].can_method, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); action_available = check_action_result (result); g_variant_unref (result); if (!action_available) continue; } return actions[i].method; } g_assert_not_reached (); } /** * up_backend_take_action: * @backend: The %UpBackend class instance * * Act upon the %UP_DEVICE_LEVEL_ACTION warning-level. **/ void up_backend_take_action (UpBackend *backend) { const char *method; GDBusProxy *seat_manager_proxy = up_backend_get_seat_manager_proxy (backend); method = up_backend_get_critical_action (backend); g_assert (method != NULL); /* Take action */ g_debug ("About to call ConsoleKit2 method %s", method); g_dbus_proxy_call (seat_manager_proxy, method, g_variant_new ("(b)", FALSE), G_DBUS_CALL_FLAGS_NONE, G_MAXINT, NULL, NULL, NULL); } /** * up_backend_inhibitor_lock_take: * @backend: The %UpBackend class instance * @reason: Why the inhibitor lock is taken * @mode: The mode of the lock ('delay' or 'block') * * BSD does not support inhibitor locks so they are simply ignored. */ int up_backend_inhibitor_lock_take (UpBackend *backend, const char *reason, const char *mode) { g_debug ("Taking inhibitor locks are not supported in BSD"); return -1; } 07070100000048000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001800000000upower-1.90.6/src/dummy07070100000049000081A400000000000000000000000166EA4814000000F7000000000000000000000000000000000000002400000000upower-1.90.6/src/dummy/meson.buildupshared += { 'dummy': static_library('upshared', sources: [ 'up-backend.c', 'up-native.c', ], c_args: [ '-DG_LOG_DOMAIN="UPower-Dummy"' ], dependencies: [ gudev_dep, upowerd_deps ], build_by_default: false, )} 0707010000004A000081A400000000000000000000000166EA481400001B85000000000000000000000000000000000000002500000000upower-1.90.6/src/dummy/up-backend.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 <stdlib.h> #include <stdio.h> #include <math.h> #include <glib/gi18n.h> #include <gio/gio.h> #include "up-backend.h" #include "up-daemon.h" #include "up-device.h" static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); struct UpBackendPrivate { UpDaemon *daemon; #ifdef EGG_TEST UpDevice *device; #endif UpDeviceList *device_list; /* unused */ #ifdef EGG_TEST GObject *native; #endif }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (UpBackend, up_backend, G_TYPE_OBJECT) #ifdef EGG_TEST /** * up_backend_changed_time_cb: **/ static gboolean up_backend_changed_time_cb (UpBackend *backend) { UpDevice *device; //FIXME! device = NULL; /* reset time */ g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); return TRUE; } /** * up_backend_add_cb: **/ static gboolean up_backend_add_cb (UpBackend *backend) { gboolean ret; guint timer_id; /* coldplug */ ret = g_initable_init (G_INITABLE (backend->priv->device), NULL, NULL); if (!ret) { g_warning ("failed to coldplug"); goto out; } /* emit */ g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, backend->priv->device); /* setup poll */ timer_id = g_timeout_add_seconds (2, (GSourceFunc) up_backend_changed_time_cb, backend); g_source_set_name_by_id (timer_id, "[upower] up_backend_changed_time_cb (dummy)"); out: return FALSE; } #endif /** * up_backend_coldplug: * @backend: The %UpBackend class instance * @daemon: The %UpDaemon controlling instance * * Finds all the devices already plugged in, and emits device-add signals for * each of them. * * Return value: %TRUE for success **/ gboolean up_backend_coldplug (UpBackend *backend, UpDaemon *daemon) { backend->priv->daemon = g_object_ref (daemon); backend->priv->device_list = up_daemon_get_device_list (daemon); #ifdef EGG_TEST /* small delay until first device is added */ g_timeout_add_seconds (1, (GSourceFunc) up_backend_add_cb, backend); #endif return TRUE; } /** * up_backend_unplug: * @backend: The %UpBackend class instance * * Forget about all learned devices, effectively undoing up_backend_coldplug. * Resources are released without emitting signals. */ void up_backend_unplug (UpBackend *backend) { if (backend->priv->device_list != NULL) { g_object_unref (backend->priv->device_list); backend->priv->device_list = NULL; } if (backend->priv->daemon != NULL) { g_object_unref (backend->priv->daemon); backend->priv->daemon = NULL; } } /** * up_backend_get_critical_action: * @backend: The %UpBackend class instance * * Which action will be taken when %UP_DEVICE_LEVEL_ACTION * warning-level occurs. **/ const char * up_backend_get_critical_action (UpBackend *backend) { return "PowerOff"; } /** * up_backend_take_action: * @backend: The %UpBackend class instance * * Act upon the %UP_DEVICE_LEVEL_ACTION warning-level. **/ void up_backend_take_action (UpBackend *backend) { g_debug ("Not taking any action, dummy backend is used"); } /** * up_backend_inhibitor_lock_take: * @backend: The %UpBackend class instance * @reason: Why the inhibitor lock is taken * @mode: The mode of the lock ('delay' or 'block') * * Dummy does not support inhibitor locks so they are simply ignored. */ int up_backend_inhibitor_lock_take (UpBackend *backend, const char *reason, const char *mode) { g_debug ("Not taking inhibitor, dummy backend is used"); return -ENOTSUP; } /** * up_backend_class_init: * @klass: The UpBackendClass **/ static void up_backend_class_init (UpBackendClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_backend_finalize; signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); } /** * up_backend_init: **/ static void up_backend_init (UpBackend *backend) { backend->priv = up_backend_get_instance_private (backend); backend->priv->daemon = NULL; backend->priv->device_list = NULL; #ifdef EGG_TEST backend->priv->native = g_object_new (UP_TYPE_DEVICE, NULL); backend->priv->device = up_device_new (); /* setup dummy */ g_object_set (backend->priv->device, "native-path", "/hal/blows/goats", "vendor", "hughsie", "model", "BAT1", "serial", "0001", "type", UP_DEVICE_KIND_BATTERY, "online", FALSE, "power-supply", TRUE, "is-present", TRUE, "is-rechargeable", TRUE, "has-history", FALSE, "has-statistics", FALSE, "state", UP_DEVICE_STATE_DISCHARGING, "energy", 0.0f, "energy-empty", 0.0f, "energy-full", 10.0f, "energy-full-design", 10.0f, "energy-rate", 5.0f, "percentage", 50.0f, NULL); #endif } /** * up_backend_finalize: **/ static void up_backend_finalize (GObject *object) { UpBackend *backend; g_return_if_fail (UP_IS_BACKEND (object)); backend = UP_BACKEND (object); if (backend->priv->daemon != NULL) g_object_unref (backend->priv->daemon); if (backend->priv->device_list != NULL) g_object_unref (backend->priv->device_list); #ifdef EGG_TEST g_object_unref (backend->priv->native); g_object_unref (backend->priv->device); #endif G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } /** * up_backend_new: * * Return value: a new %UpBackend object. **/ UpBackend * up_backend_new (void) { return g_object_new (UP_TYPE_BACKEND, NULL); } 0707010000004B000081A400000000000000000000000166EA481400000545000000000000000000000000000000000000002400000000upower-1.90.6/src/dummy/up-native.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <glib.h> #include "up-native.h" /** * up_native_get_native_path: * @object: the native tracking object * * This converts a GObject used as the device data into a native path. * This would be implemented on a Linux system using: * g_udev_device_get_sysfs_path (G_UDEV_DEVICE (object)) * * Return value: The native path for the device which is unique, e.g. "/sys/class/power/BAT1" **/ const gchar * up_native_get_native_path (GObject *object) { return "/sys/dummy"; } 0707010000004C000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001A00000000upower-1.90.6/src/freebsd0707010000004D000081A400000000000000000000000166EA4814000001F5000000000000000000000000000000000000002600000000upower-1.90.6/src/freebsd/meson.buildupshared += { 'freebsd': static_library('upshared', sources: [ 'up-acpi-native.c', 'up-acpi-native.h', 'up-backend-acpi.h', 'up-backend.c', 'up-devd.c', 'up-devd.h', 'up-device-supply.c', 'up-device-supply.h', 'up-native.c', 'up-util.c', 'up-util.h', ], c_args: [ '-DG_LOG_DOMAIN="UPower-Freebsd"' ], dependencies: [ gudev_dep, upowerd_deps, upshared_common_dep ], build_by_default: false, )} 0707010000004E000081A400000000000000000000000166EA481400002026000000000000000000000000000000000000002B00000000upower-1.90.6/src/freebsd/up-acpi-native.c/* up-acpi-native.c generated by valac, the Vala compiler * generated from up-acpi-native.vala, do not modify */ #include <glib.h> #include <glib-object.h> #include <stdlib.h> #include <string.h> #define TYPE_UP_ACPI_NATIVE (up_acpi_native_get_type ()) #define UP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_UP_ACPI_NATIVE, UpAcpiNative)) #define UP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_UP_ACPI_NATIVE, UpAcpiNativeClass)) #define IS_UP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_UP_ACPI_NATIVE)) #define IS_UP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_UP_ACPI_NATIVE)) #define UP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_UP_ACPI_NATIVE, UpAcpiNativeClass)) typedef struct _UpAcpiNative UpAcpiNative; typedef struct _UpAcpiNativeClass UpAcpiNativeClass; typedef struct _UpAcpiNativePrivate UpAcpiNativePrivate; #define _g_free0(var) (var = (g_free (var), NULL)) #define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL))) #define _g_match_info_free0(var) ((var == NULL) ? NULL : (var = (g_match_info_free (var), NULL))) #define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL))) struct _UpAcpiNative { GObject parent_instance; UpAcpiNativePrivate * priv; }; struct _UpAcpiNativeClass { GObjectClass parent_class; }; struct _UpAcpiNativePrivate { gchar *_driver; gint _unit; gchar *_path; }; static gpointer up_acpi_native_parent_class = NULL; GType up_acpi_native_get_type (void); #define UP_ACPI_NATIVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_UP_ACPI_NATIVE, UpAcpiNativePrivate)) enum { UP_ACPI_NATIVE_DUMMY_PROPERTY, UP_ACPI_NATIVE_DRIVER, UP_ACPI_NATIVE_UNIT, UP_ACPI_NATIVE_PATH }; UpAcpiNative* up_acpi_native_new (const char* path); UpAcpiNative* up_acpi_native_construct (GType object_type, const char* path); UpAcpiNative* up_acpi_native_new_driver_unit (const char* driver, gint unit); UpAcpiNative* up_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit); const char* up_acpi_native_get_driver (UpAcpiNative* self); gint up_acpi_native_get_unit (UpAcpiNative* self); const char* up_acpi_native_get_path (UpAcpiNative* self); static void up_acpi_native_finalize (GObject* obj); static void up_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec); UpAcpiNative* up_acpi_native_construct (GType object_type, const char* path) { GError * _inner_error_; UpAcpiNative * self; GRegex* r; GMatchInfo* mi; gboolean ret = FALSE; char* _tmp9_; g_return_val_if_fail (path != NULL, NULL); _inner_error_ = NULL; self = (UpAcpiNative*) g_object_new (object_type, NULL); r = NULL; mi = NULL; { GRegex* _tmp0_; GRegex* _tmp1_; GMatchInfo* _tmp4_; gboolean _tmp3_; GMatchInfo* _tmp2_ = NULL; _tmp0_ = g_regex_new ("dev\\.([^\\.])\\.(\\d+)", 0, 0, &_inner_error_); if (_inner_error_ != NULL) { if (_inner_error_->domain == G_REGEX_ERROR) { goto __catch0_g_regex_error; } goto __finally0; } r = (_tmp1_ = _tmp0_, _g_regex_unref0 (r), _tmp1_); ret = (_tmp3_ = g_regex_match (r, path, 0, &_tmp2_), mi = (_tmp4_ = _tmp2_, _g_match_info_free0 (mi), _tmp4_), _tmp3_); if (ret) { char* _tmp5_; char* _tmp6_; self->priv->_driver = (_tmp5_ = g_match_info_fetch (mi, 1), _g_free0 (self->priv->_driver), _tmp5_); self->priv->_unit = atoi (_tmp6_ = g_match_info_fetch (mi, 2)); _g_free0 (_tmp6_); } else { char* _tmp7_; self->priv->_driver = (_tmp7_ = NULL, _g_free0 (self->priv->_driver), _tmp7_); self->priv->_unit = -1; } } goto __finally0; __catch0_g_regex_error: { GError * re; re = _inner_error_; _inner_error_ = NULL; { char* _tmp8_; self->priv->_driver = (_tmp8_ = NULL, _g_free0 (self->priv->_driver), _tmp8_); self->priv->_unit = -1; _g_error_free0 (re); } } __finally0: if (_inner_error_ != NULL) { _g_regex_unref0 (r); _g_match_info_free0 (mi); g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code); g_clear_error (&_inner_error_); return NULL; } self->priv->_path = (_tmp9_ = g_strdup (path), _g_free0 (self->priv->_path), _tmp9_); _g_regex_unref0 (r); _g_match_info_free0 (mi); return self; } UpAcpiNative* up_acpi_native_new (const char* path) { return up_acpi_native_construct (TYPE_UP_ACPI_NATIVE, path); } UpAcpiNative* up_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit) { UpAcpiNative * self; char* _tmp0_; char* _tmp1_; g_return_val_if_fail (driver != NULL, NULL); self = (UpAcpiNative*) g_object_new (object_type, NULL); self->priv->_driver = (_tmp0_ = g_strdup (driver), _g_free0 (self->priv->_driver), _tmp0_); self->priv->_unit = unit; self->priv->_path = (_tmp1_ = g_strdup_printf ("dev.%s.%i", self->priv->_driver, self->priv->_unit), _g_free0 (self->priv->_path), _tmp1_); return self; } UpAcpiNative* up_acpi_native_new_driver_unit (const char* driver, gint unit) { return up_acpi_native_construct_driver_unit (TYPE_UP_ACPI_NATIVE, driver, unit); } const char* up_acpi_native_get_driver (UpAcpiNative* self) { const char* result; g_return_val_if_fail (self != NULL, NULL); result = self->priv->_driver; return result; } gint up_acpi_native_get_unit (UpAcpiNative* self) { gint result; g_return_val_if_fail (self != NULL, 0); result = self->priv->_unit; return result; } const char* up_acpi_native_get_path (UpAcpiNative* self) { const char* result; g_return_val_if_fail (self != NULL, NULL); result = self->priv->_path; return result; } static void up_acpi_native_class_init (UpAcpiNativeClass * klass) { up_acpi_native_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (klass, sizeof (UpAcpiNativePrivate)); G_OBJECT_CLASS (klass)->get_property = up_acpi_native_get_property; G_OBJECT_CLASS (klass)->finalize = up_acpi_native_finalize; g_object_class_install_property (G_OBJECT_CLASS (klass), UP_ACPI_NATIVE_DRIVER, g_param_spec_string ("driver", "driver", "driver", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (klass), UP_ACPI_NATIVE_UNIT, g_param_spec_int ("unit", "unit", "unit", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (klass), UP_ACPI_NATIVE_PATH, g_param_spec_string ("path", "path", "path", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE)); } static void up_acpi_native_instance_init (UpAcpiNative * self) { self->priv = UP_ACPI_NATIVE_GET_PRIVATE (self); } static void up_acpi_native_finalize (GObject* obj) { UpAcpiNative * self; self = UP_ACPI_NATIVE (obj); _g_free0 (self->priv->_driver); _g_free0 (self->priv->_path); G_OBJECT_CLASS (up_acpi_native_parent_class)->finalize (obj); } GType up_acpi_native_get_type (void) { static GType up_acpi_native_type_id = 0; if (up_acpi_native_type_id == 0) { static const GTypeInfo g_define_type_info = { sizeof (UpAcpiNativeClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) up_acpi_native_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (UpAcpiNative), 0, (GInstanceInitFunc) up_acpi_native_instance_init, NULL }; up_acpi_native_type_id = g_type_register_static (G_TYPE_OBJECT, "UpAcpiNative", &g_define_type_info, 0); } return up_acpi_native_type_id; } static void up_acpi_native_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { UpAcpiNative * self; self = UP_ACPI_NATIVE (object); switch (property_id) { case UP_ACPI_NATIVE_DRIVER: g_value_set_string (value, up_acpi_native_get_driver (self)); break; case UP_ACPI_NATIVE_UNIT: g_value_set_int (value, up_acpi_native_get_unit (self)); break; case UP_ACPI_NATIVE_PATH: g_value_set_string (value, up_acpi_native_get_path (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } 0707010000004F000081A400000000000000000000000166EA48140000066C000000000000000000000000000000000000002B00000000upower-1.90.6/src/freebsd/up-acpi-native.h/* up-acpi-native.h generated by valac, the Vala compiler, do not modify */ #ifndef __UP_ACPI_NATIVE_H__ #define __UP_ACPI_NATIVE_H__ #include <glib.h> #include <glib-object.h> #include <stdlib.h> #include <string.h> G_BEGIN_DECLS #define TYPE_UP_ACPI_NATIVE (up_acpi_native_get_type ()) #define UP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_UP_ACPI_NATIVE, UpAcpiNative)) #define UP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_UP_ACPI_NATIVE, UpAcpiNativeClass)) #define IS_UP_ACPI_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_UP_ACPI_NATIVE)) #define IS_UP_ACPI_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_UP_ACPI_NATIVE)) #define UP_ACPI_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_UP_ACPI_NATIVE, UpAcpiNativeClass)) typedef struct _UpAcpiNative UpAcpiNative; typedef struct _UpAcpiNativeClass UpAcpiNativeClass; typedef struct _UpAcpiNativePrivate UpAcpiNativePrivate; struct _UpAcpiNative { GObject parent_instance; UpAcpiNativePrivate * priv; }; struct _UpAcpiNativeClass { GObjectClass parent_class; }; GType up_acpi_native_get_type (void); UpAcpiNative* up_acpi_native_new (const char* path); UpAcpiNative* up_acpi_native_construct (GType object_type, const char* path); UpAcpiNative* up_acpi_native_new_driver_unit (const char* driver, gint unit); UpAcpiNative* up_acpi_native_construct_driver_unit (GType object_type, const char* driver, gint unit); const char* up_acpi_native_get_driver (UpAcpiNative* self); gint up_acpi_native_get_unit (UpAcpiNative* self); const char* up_acpi_native_get_path (UpAcpiNative* self); G_END_DECLS #endif 07070100000050000081A400000000000000000000000166EA48140000034F000000000000000000000000000000000000002E00000000upower-1.90.6/src/freebsd/up-acpi-native.valapublic class UpAcpiNative : Object { private string? _driver; private int _unit; private string _path; public string driver { get { return _driver; } } public int unit { get { return _unit; } } public string path { get { return _path; } } public UpAcpiNative (string path) { Regex r; MatchInfo mi; bool ret; try { r = new Regex("dev\\.([^\\.])\\.(\\d+)"); ret = r.match(path, 0, out mi); if (ret) { _driver = mi.fetch(1); _unit = mi.fetch(2).to_int(); } else { _driver = null; _unit = -1; } } catch (RegexError re) { _driver = null; _unit = -1; } _path = path; } public UpAcpiNative.driver_unit (string driver, int unit) { _driver = driver; _unit = unit; _path = "dev.%s.%i".printf (_driver, _unit); } } 07070100000051000081A400000000000000000000000166EA48140000049D000000000000000000000000000000000000002C00000000upower-1.90.6/src/freebsd/up-backend-acpi.h/*************************************************************************** * * up-backend-acpi.h : define some backend objects * * Copyright (C) 2006, 2009 Joe Marcus Clarke <marcus@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * **************************************************************************/ #ifndef _UP_BACKEND_ACPI_H #define _UP_BACKEND_ACPI_H #include "config.h" #include "up-devd.h" extern UpDevdHandler up_backend_acpi_devd_handler; #endif /* _UP_BACKEND_ACPI_H */ 07070100000052000081A400000000000000000000000166EA481400002857000000000000000000000000000000000000002700000000upower-1.90.6/src/freebsd/up-backend.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Joe Marcus Clarke <marcus@FreeBSD.org> * * 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 <math.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <unistd.h> #include <sys/types.h> #include <glib/gi18n.h> #include <gio/gio.h> #include "up-acpi-native.h" #include "up-backend-acpi.h" #include "up-devd.h" #include "up-device-supply.h" #include "up-util.h" #include "up-backend.h" #include "up-daemon.h" #include "up-device.h" #include "up-backend-bsd-private.h" #define UP_BACKEND_REFRESH_TIMEOUT 30 /* seconds */ static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); static gboolean up_backend_acpi_devd_notify (UpBackend *backend, const gchar *system, const gchar *subsystem, const gchar *type, const gchar *data); static void up_backend_create_new_device (UpBackend *backend, UpAcpiNative *native); static void up_backend_lid_coldplug (UpBackend *backend); struct UpBackendPrivate { UpDaemon *daemon; UpDeviceList *device_list; GHashTable *handle_map; UpConfig *config; GDBusProxy *seat_manager_proxy; }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (UpBackend, up_backend, G_TYPE_OBJECT) static const gchar *handlers[] = { "battery", }; UpDevdHandler up_backend_acpi_devd_handler = { .notify = up_backend_acpi_devd_notify }; /** * up_backend_acpi_devd_notify: **/ static gboolean up_backend_acpi_devd_notify (UpBackend *backend, const gchar *system, const gchar *subsystem, const gchar *type, const gchar *data) { GObject *object = NULL; UpAcpiNative *native = NULL; if (strcmp (system, "ACPI")) return FALSE; if (!strcmp (subsystem, "ACAD")) { native = up_acpi_native_new ("hw.acpi.acline"); object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native)); } else if (!strcmp (subsystem, "CMBAT")) { gchar *ptr; int unit; ptr = strstr (type, ".BAT"); if (ptr != NULL && sscanf (ptr, ".BAT%i", &unit)) { native = up_acpi_native_new_driver_unit ("battery", unit); object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native)); if (object == NULL) { gpointer hptr; hptr = g_hash_table_lookup (backend->priv->handle_map, type); if (hptr != NULL) { object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (hptr)); } } } } else if (!strcmp (subsystem, "Lid")) { gboolean is_present; gboolean is_closed; g_object_get (backend->priv->daemon, "lid-is-present", &is_present, NULL); if (!is_present) { g_warning ("received lid event without a configured lid; cold-plugging one"); up_backend_lid_coldplug (backend); /* FALLTHROUGH */ } is_closed = (data != NULL && !strcmp (data, "notify=0x00")) ? TRUE : FALSE; up_daemon_set_lid_is_closed (backend->priv->daemon, is_closed); goto out; } if (native == NULL) goto out; if (object == NULL) { g_warning ("did not find existing %s device; cold-plugging a new one", subsystem); up_backend_create_new_device (backend, native); goto out; } up_device_refresh_internal (UP_DEVICE (object), UP_REFRESH_EVENT); if (object != NULL) g_object_unref (object); out: if (native != NULL) g_object_unref (native); return TRUE; } /** * up_backend_create_new_device: **/ static void up_backend_create_new_device (UpBackend *backend, UpAcpiNative *native) { g_autoptr(UpDevice) device = NULL; device = g_initable_new (UP_TYPE_DEVICE_SUPPLY, NULL, NULL, "daemon", backend->priv->daemon, "native", G_OBJECT (native), "poll-timeout", UP_BACKEND_REFRESH_TIMEOUT, NULL); if (device) { if (!strncmp (up_acpi_native_get_path (native), "dev.", strlen ("dev."))) { const gchar *path; path = up_acpi_native_get_path (native); if (up_has_sysctl ("%s.%%location", path)) { gchar *location; location = up_get_string_sysctl (NULL, "%s.%%location", path); if (location != NULL && strstr (location, "handle=") != NULL) { gchar *handle; handle = strstr (location, "handle="); handle += strlen ("handle="); g_hash_table_insert (backend->priv->handle_map, g_strdup (handle), g_object_ref (native)); } g_free (location); } } g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, device); } } /** * up_backend_lid_coldplug: **/ static void up_backend_lid_coldplug (UpBackend *backend) { gchar *lid_state; lid_state = up_get_string_sysctl (NULL, "hw.acpi.lid_switch_state"); if (lid_state) { up_daemon_set_lid_is_present (backend->priv->daemon, TRUE); } g_free (lid_state); } /** * up_backend_coldplug: * @backend: The %UpBackend class instance * @daemon: The %UpDaemon controlling instance * * Finds all the devices already plugged in, and emits device-add signals for * each of them. * * Return value: %TRUE for success **/ gboolean up_backend_coldplug (UpBackend *backend, UpDaemon *daemon) { UpAcpiNative *acnative; int i; backend->priv->daemon = g_object_ref (daemon); backend->priv->device_list = up_daemon_get_device_list (daemon); for (i = 0; i < (int) G_N_ELEMENTS (handlers); i++) { int j; for (j = 0; up_has_sysctl ("dev.%s.%i.%%driver", handlers[i], j); j++) { UpAcpiNative *native; UpDevice *device; GObject *object; native = up_acpi_native_new_driver_unit (handlers[i], j); object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native)); if (object != NULL) { device = UP_DEVICE (object); g_warning ("treating add event as change event on %s", up_device_get_object_path (device)); up_device_refresh_internal (device, UP_REFRESH_EVENT); } else { up_backend_create_new_device (backend, native); } if (object != NULL) { g_object_unref (object); } if (native != NULL) { g_object_unref (native); } } } up_backend_lid_coldplug (backend); acnative = up_acpi_native_new ("hw.acpi.acline"); up_backend_create_new_device (backend, acnative); g_object_unref (acnative); up_devd_init (backend); return TRUE; } /** * up_backend_unplug: * @backend: The %UpBackend class instance * * Forget about all learned devices, effectively undoing up_backend_coldplug. * Resources are released without emitting signals. */ void up_backend_unplug (UpBackend *backend) { if (backend->priv->device_list != NULL) { g_object_unref (backend->priv->device_list); backend->priv->device_list = NULL; } if (backend->priv->daemon != NULL) { g_object_unref (backend->priv->daemon); backend->priv->daemon = NULL; } } /** * up_backend_get_seat_manager_proxy: * @backend: The %UpBackend class instance * * Returns the seat manager object or NULL on error. [transfer none] */ GDBusProxy * up_backend_get_seat_manager_proxy (UpBackend *backend) { g_return_val_if_fail (UP_IS_BACKEND (backend), NULL); return backend->priv->seat_manager_proxy; } /** * up_backend_get_config: * @backend: The %UpBackend class instance * * Returns the UpConfig object or NULL on error. [transfer none] */ UpConfig * up_backend_get_config (UpBackend *backend) { g_return_val_if_fail (UP_IS_BACKEND (backend), NULL); return backend->priv->config; } /** * up_backend_class_init: * @klass: The UpBackendClass **/ static void up_backend_class_init (UpBackendClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_backend_finalize; signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); } /** * up_backend_init: **/ static void up_backend_init (UpBackend *backend) { backend->priv = up_backend_get_instance_private (backend); backend->priv->handle_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); backend->priv->config = up_config_new (); backend->priv->seat_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, CONSOLEKIT2_DBUS_NAME, CONSOLEKIT2_DBUS_PATH, CONSOLEKIT2_DBUS_INTERFACE, NULL, NULL); } /** * up_backend_finalize: **/ static void up_backend_finalize (GObject *object) { UpBackend *backend; g_return_if_fail (UP_IS_BACKEND (object)); backend = UP_BACKEND (object); g_object_unref (backend->priv->config); if (backend->priv->daemon != NULL) g_object_unref (backend->priv->daemon); if (backend->priv->device_list != NULL) g_object_unref (backend->priv->device_list); if (backend->priv->handle_map != NULL) g_hash_table_unref (backend->priv->handle_map); g_clear_object (&backend->priv->seat_manager_proxy); G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } /** * up_backend_new: * * Return value: a new %UpBackend object. **/ UpBackend * up_backend_new (void) { return g_object_new (UP_TYPE_BACKEND, NULL); } 07070100000053000081A400000000000000000000000166EA4814000016B6000000000000000000000000000000000000002400000000upower-1.90.6/src/freebsd/up-devd.c/*************************************************************************** * * up-devd.c : process devd events * * Copyright (C) 2006, 2007 Joe Marcus Clarke <marcus@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * **************************************************************************/ #include "config.h" #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/param.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include "up-backend.h" #include "up-backend-acpi.h" #include "up-devd.h" #define UP_DEVD_SOCK_PATH "/var/run/devd.pipe" #define UP_DEVD_EVENT_NOTIFY '!' #define UP_DEVD_EVENT_ADD '+' #define UP_DEVD_EVENT_REMOVE '-' #define UP_DEVD_EVENT_NOMATCH '?' static UpDevdHandler *handlers[] = { &up_backend_acpi_devd_handler, }; static gboolean up_devd_inited = FALSE; #if 0 static GHashTable * up_devd_parse_params (const gchar *str) { GHashTable *params; gchar **pairs; gint i; g_return_val_if_fail (str != NULL, FALSE); params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); pairs = g_strsplit(str, " ", 0); for (i = 0; pairs[i]; i++) { gchar *equal; equal = strchr (pairs[i], '='); g_hash_table_insert (params, equal ? g_strndup(pairs[i], equal - pairs[i]) : g_strdup(pairs[i]), equal ? g_strdup(equal + 1) : NULL); } g_strfreev (pairs); return params; } #endif static gboolean up_devd_parse_notify (const gchar *event, gchar **system, gchar **subsystem, gchar **type, gchar **data) { gchar **items; gboolean status = FALSE; /* !system=IFNET subsystem=bge0 type=LINK_DOWN */ g_return_val_if_fail(event != NULL, FALSE); g_return_val_if_fail(system != NULL, FALSE); g_return_val_if_fail(subsystem != NULL, FALSE); g_return_val_if_fail(type != NULL, FALSE); g_return_val_if_fail(data != NULL, FALSE); items = g_strsplit(event, " ", 0); if (g_strv_length(items) < 3) goto end; if (! g_str_has_prefix(items[0], "system=") || ! g_str_has_prefix(items[1], "subsystem=") || ! g_str_has_prefix(items[2], "type=")) goto end; *system = g_strdup(items[0] + 7); *subsystem = g_strdup(items[1] + 10); *type = g_strdup(items[2] + 5); *data = g_strdup(items[3]); /* may be NULL */ status = TRUE; end: g_strfreev(items); return status; } static void up_devd_process_notify_event (UpBackend *backend, const gchar *system, const gchar *subsystem, const gchar *type, const gchar *data) { gint i; g_return_if_fail(backend != NULL); g_return_if_fail(system != NULL); g_return_if_fail(subsystem != NULL); g_return_if_fail(type != NULL); g_return_if_fail(data != NULL); for (i = 0; i < (int) G_N_ELEMENTS(handlers); i++) if (handlers[i]->notify && handlers[i]->notify (backend, system, subsystem, type, data)) return; /* no default action */ } static void up_devd_process_event (const gchar *event, gpointer user_data) { UpBackend *backend; g_return_if_fail(event != NULL); backend = UP_BACKEND(user_data); g_debug("received devd event: '%s'", event); switch (event[0]) { case UP_DEVD_EVENT_ADD: case UP_DEVD_EVENT_REMOVE: /* Do nothing as we don't currently hotplug ACPI devices. */ return; case UP_DEVD_EVENT_NOTIFY: { gchar *system; gchar *subsystem; gchar *type; gchar *data; if (!up_devd_parse_notify (event + 1, &system, &subsystem, &type, &data)) goto malformed; up_devd_process_notify_event (backend, system, subsystem, type, data); g_free (system); g_free (subsystem); g_free (type); g_free (data); } return; case UP_DEVD_EVENT_NOMATCH: /* Do nothing. */ return; } malformed: g_warning("malformed devd event: %s", event); } static gboolean up_devd_event_cb (GIOChannel *source, GIOCondition condition, gpointer user_data) { gchar *event; gsize terminator; GIOStatus status; status = g_io_channel_read_line(source, &event, NULL, &terminator, NULL); if (status == G_IO_STATUS_NORMAL) { event[terminator] = 0; up_devd_process_event(event, user_data); g_free(event); } else if (status == G_IO_STATUS_AGAIN) { up_devd_init (UP_BACKEND(user_data)); if (up_devd_inited) { int fd; fd = g_io_channel_unix_get_fd (source); g_io_channel_shutdown (source, FALSE, NULL); close (fd); return FALSE; } } return TRUE; } void up_devd_init (UpBackend *backend) { int event_fd; struct sockaddr_un addr; event_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (event_fd < 0) { g_warning("failed to create event socket: '%s'", g_strerror(errno)); up_devd_inited = FALSE; return; } addr.sun_family = AF_UNIX; strncpy (addr.sun_path, UP_DEVD_SOCK_PATH, sizeof(addr.sun_path)); if (connect (event_fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { GIOChannel *channel; channel = g_io_channel_unix_new (event_fd); g_io_add_watch (channel, G_IO_IN, up_devd_event_cb, backend); g_io_channel_unref (channel); up_devd_inited = TRUE; } else { g_warning ("failed to connect to %s: '%s'", UP_DEVD_SOCK_PATH, g_strerror(errno)); close (event_fd); up_devd_inited = FALSE; } } 07070100000054000081A400000000000000000000000166EA48140000057F000000000000000000000000000000000000002400000000upower-1.90.6/src/freebsd/up-devd.h/*************************************************************************** * * up-devd.h : process devd events * * Copyright (C) 2006, 2009 Joe Marcus Clarke <marcus@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * **************************************************************************/ #ifndef _UP_DEVD_H #define _UP_DEVD_H #include "config.h" #include "up-backend.h" #include <glib.h> typedef struct { /* return TRUE to consume the event and stop processing */ gboolean (*notify) (UpBackend *backend, const char *system, const char *subsystem, const char *type, const char *data); /* may be NULL */ } UpDevdHandler; void up_devd_init (UpBackend *backend); #endif /* _UP_DEVD_H */ 07070100000055000081A400000000000000000000000166EA481400002D87000000000000000000000000000000000000002D00000000upower-1.90.6/src/freebsd/up-device-supply.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Joe Marcus Clarke <marcus@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <limits.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE #include <dev/acpica/acpiio.h> #endif #include <glib.h> #include <glib/gstdio.h> #include <glib/gprintf.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include "up-common.h" #include "up-acpi-native.h" #include "up-util.h" #include "up-common.h" #include "up-device-supply.h" #define UP_ACPIDEV "/dev/acpi" G_DEFINE_TYPE (UpDeviceSupply, up_device_supply, UP_TYPE_DEVICE) static gboolean up_device_supply_refresh (UpDevice *device, UpRefreshReason reason); static gboolean up_device_supply_acline_coldplug (UpDevice *device); static gboolean up_device_supply_battery_coldplug (UpDevice *device, UpAcpiNative *native); static gboolean up_device_supply_acline_set_properties (UpDevice *device); static gboolean up_device_supply_battery_set_properties (UpDevice *device, UpAcpiNative *native); static gboolean up_device_supply_get_on_battery (UpDevice *device, gboolean *on_battery); static gboolean up_device_supply_get_online (UpDevice *device, gboolean *online); /** * up_device_supply_reset_values: **/ static void up_device_supply_reset_values (UpDevice *device) { /* reset to default */ g_object_set (device, "vendor", NULL, "model", NULL, "serial", NULL, "update-time", (guint64) 0, "power-supply", FALSE, "online", FALSE, "energy", (gdouble) 0.0, "is-present", FALSE, "is-rechargeable", FALSE, "has-history", FALSE, "has-statistics", FALSE, "state", UP_DEVICE_STATE_UNKNOWN, "capacity", (gdouble) 0.0, "energy-empty", (gdouble) 0.0, "energy-full", (gdouble) 0.0, "energy-full-design", (gdouble) 0.0, "energy-rate", (gdouble) 0.0, "voltage", (gdouble) 0.0, "time-to-empty", (gint64) 0, "time-to-full", (gint64) 0, "percentage", (gdouble) 0.0, "technology", UP_DEVICE_TECHNOLOGY_UNKNOWN, NULL); } /** * up_device_supply_acline_coldplug: **/ static gboolean up_device_supply_acline_coldplug (UpDevice *device) { gboolean ret; g_object_set (device, "online", FALSE, "power-supply", TRUE, "type", UP_DEVICE_KIND_LINE_POWER, NULL); ret = up_device_supply_acline_set_properties (device); return ret; } /** * up_device_supply_battery_coldplug: **/ static gboolean up_device_supply_battery_coldplug (UpDevice *device, UpAcpiNative *native) { gboolean ret; g_object_set (device, "type", UP_DEVICE_KIND_BATTERY, NULL); ret = up_device_supply_battery_set_properties (device, native); return ret; } /** * up_device_supply_battery_set_properties: **/ static gboolean up_device_supply_battery_set_properties (UpDevice *device, UpAcpiNative *native) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE gint fd; gdouble volt, dvolt, rate, lastfull, cap, dcap, lcap, capacity; gboolean is_present; gboolean ret = FALSE; gint64 time_to_empty, time_to_full; gchar *vendor, *model, *serial; UpDeviceTechnology technology; UpDeviceState state; union acpi_battery_ioctl_arg battif, battst, battinfo; if (!up_has_sysctl ("hw.acpi.battery.units")) return FALSE; battif.unit = battst.unit = battinfo.unit = up_acpi_native_get_unit (native); fd = open (UP_ACPIDEV, O_RDONLY); if (fd < 0) { g_warning ("unable to open %s: '%s'", UP_ACPIDEV, g_strerror (errno)); return FALSE; } if (ioctl (fd, ACPIIO_BATT_GET_BIF, &battif) == -1) { g_warning ("ioctl ACPIIO_BATT_GET_BIF failed for battery %d: '%s'", battif.unit, g_strerror (errno)); goto end; } if (ioctl (fd, ACPIIO_BATT_GET_BST, &battst) == -1) { g_warning ("ioctl ACPIIO_BATT_GET_BST failed for battery %d: '%s'", battst.unit, g_strerror (errno)); goto end; } if (ioctl (fd, ACPIIO_BATT_GET_BATTINFO, &battinfo) == -1) { g_warning ("ioctl ACPIIO_BATT_GET_BATTINFO failed for battery %d: '%s'", battinfo.unit, g_strerror (errno)); goto end; } ret = TRUE; is_present = (battst.bst.state == ACPI_BATT_STAT_NOT_PRESENT) ? FALSE : TRUE; g_object_set (device, "is-present", is_present, NULL); if (!is_present) { up_device_supply_reset_values (device); goto end; } vendor = up_make_safe_string (g_strdup (battif.bif.oeminfo)); model = up_make_safe_string (g_strdup (battif.bif.model)); serial = up_make_safe_string (g_strdup (battif.bif.serial)); technology = up_convert_device_technology (battif.bif.type); g_object_set (device, "vendor", vendor, "model", model, "serial", serial, "power-supply", TRUE, "technology", technology, "has-history", TRUE, "has-statistics", TRUE, NULL); g_free (vendor); g_free (model); g_free (serial); g_object_set (device, "is-rechargeable", battif.bif.btech == 0 ? FALSE : TRUE, NULL); volt = (gdouble) battst.bst.volt; dvolt = (gdouble) battif.bif.dvol; lastfull = (gdouble) battif.bif.lfcap; dcap = (gdouble) battif.bif.dcap; rate = (gdouble) battst.bst.rate; cap = (gdouble) battst.bst.cap; lcap = (gdouble) battif.bif.lcap; if (rate == 0xffff) rate = 0.0f; if (rate > 100.0f * 1000.0f) rate = 0.0f; dvolt /= 1000.0f; volt /= 1000.0f; if (battif.bif.units == ACPI_BIF_UNITS_MA) { if (dvolt <= 0.0f) dvolt = 1.0f; if (volt <= 0.0f || volt > dvolt) volt = dvolt; dcap *= volt; lastfull *= volt; rate *= volt; cap *= volt; lcap *= volt; } dcap /= 1000.0f; lastfull /= 1000.0f; rate /= 1000.0f; cap /= 1000.0f; lcap /= 1000.0f; if (cap == 0.0f) rate = 0.0f; capacity = 0.0f; if (lastfull > 0 && dcap > 0) { capacity = (lastfull / dcap) * 100.0f; if (capacity < 0) capacity = 0.0f; if (capacity > 100.0) capacity = 100.0f; } g_object_set (device, "percentage", (gdouble) battinfo.battinfo.cap, "energy", cap, "energy-full", lastfull, "energy-full-design", dcap, "energy-rate", rate, "energy-empty", lcap, "voltage", volt, "capacity", capacity, NULL); time_to_empty = 0; time_to_full = 0; if (battinfo.battinfo.state & ACPI_BATT_STAT_DISCHARG) { state = UP_DEVICE_STATE_DISCHARGING; if (battinfo.battinfo.min > 0) time_to_empty = battinfo.battinfo.min * 60; else if (rate > 0) { time_to_empty = 3600 * (cap / rate); if (time_to_empty > (20 * 60 * 60)) time_to_empty = 0; } } else if (battinfo.battinfo.state & ACPI_BATT_STAT_CHARGING) { state = UP_DEVICE_STATE_CHARGING; if (battinfo.battinfo.min > 0) time_to_full = battinfo.battinfo.min * 60; else if (rate > 0) { time_to_full = 3600 * ((lastfull - cap) / rate); if (time_to_full > (20 * 60 * 60)) time_to_full = 0; } } else if (battinfo.battinfo.state & ACPI_BATT_STAT_CRITICAL) { state = UP_DEVICE_STATE_EMPTY; } else if (battinfo.battinfo.state == 0) { state = UP_DEVICE_STATE_FULLY_CHARGED; } else { state = UP_DEVICE_STATE_UNKNOWN; } g_object_set (device, "state", state, "time-to-empty", time_to_empty, "time-to-full", time_to_full, NULL); end: close (fd); return ret; #else return FALSE; #endif } /** * up_device_supply_acline_set_properties: **/ static gboolean up_device_supply_acline_set_properties (UpDevice *device) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE int acstate; if (up_get_int_sysctl (&acstate, NULL, "hw.acpi.acline")) { g_object_set (device, "online", acstate ? TRUE : FALSE, NULL); return TRUE; } #endif return FALSE; } /** * up_device_supply_coldplug: * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_supply_coldplug (UpDevice *device) { UpAcpiNative *native; const gchar *native_path; const gchar *driver; gboolean ret = FALSE; up_device_supply_reset_values (device); native = UP_ACPI_NATIVE (up_device_get_native (device)); native_path = up_acpi_native_get_path (native); driver = up_acpi_native_get_driver (native); if (native_path == NULL) { g_warning ("could not get native path for %p", device); goto out; } if (!strcmp (native_path, "hw.acpi.acline")) { ret = up_device_supply_acline_coldplug (device); goto out; } if (!g_strcmp0 (driver, "battery")) { ret = up_device_supply_battery_coldplug (device, native); goto out; } g_warning ("invalid device %s with driver %s", native_path, driver); out: return ret; } /** * up_device_supply_refresh: * * Return %TRUE on success, %FALSE if we failed to refresh or no data **/ static gboolean up_device_supply_refresh (UpDevice *device, UpRefreshReason reason) { GObject *object; UpDeviceKind type; gboolean ret; g_object_get (device, "type", &type, NULL); switch (type) { case UP_DEVICE_KIND_LINE_POWER: ret = up_device_supply_acline_set_properties (device); break; case UP_DEVICE_KIND_BATTERY: object = up_device_get_native (device); ret = up_device_supply_battery_set_properties (device, UP_ACPI_NATIVE (object)); break; default: g_assert_not_reached (); break; } if (ret) g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); return ret; } /** * up_device_supply_get_on_battery: **/ static gboolean up_device_supply_get_on_battery (UpDevice *device, gboolean *on_battery) { UpDeviceKind type; UpDeviceState state; gboolean is_present; g_return_val_if_fail (on_battery != NULL, FALSE); g_object_get (device, "type", &type, "state", &state, "is-present", &is_present, NULL); if (type != UP_DEVICE_KIND_BATTERY) return FALSE; if (state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (!is_present) return FALSE; *on_battery = (state == UP_DEVICE_STATE_DISCHARGING); return TRUE; } /** * up_device_supply_get_online: **/ static gboolean up_device_supply_get_online (UpDevice *device, gboolean *online) { UpDeviceKind type; gboolean online_tmp; g_return_val_if_fail (online != NULL, FALSE); g_object_get (device, "type", &type, "online", &online_tmp, NULL); if (type != UP_DEVICE_KIND_LINE_POWER) return FALSE; *online = online_tmp; return TRUE; } /** * up_device_supply_init: **/ static void up_device_supply_init (UpDeviceSupply *supply) { } /** * up_device_supply_class_init: **/ static void up_device_supply_class_init (UpDeviceSupplyClass *klass) { UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); device_class->get_on_battery = up_device_supply_get_on_battery; device_class->get_online = up_device_supply_get_online; device_class->coldplug = up_device_supply_coldplug; device_class->refresh = up_device_supply_refresh; } 07070100000056000081A400000000000000000000000166EA48140000078C000000000000000000000000000000000000002D00000000upower-1.90.6/src/freebsd/up-device-supply.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_SUPPLY_H__ #define __UP_DEVICE_SUPPLY_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_SUPPLY (up_device_supply_get_type ()) #define UP_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupply)) #define UP_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupplyClass)) #define UP_IS_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_SUPPLY)) #define UP_IS_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_SUPPLY)) #define UP_DEVICE_SUPPLY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupplyClass)) typedef struct UpDeviceSupplyPrivate UpDeviceSupplyPrivate; typedef struct { UpDevice parent; UpDeviceSupplyPrivate *priv; } UpDeviceSupply; typedef struct { UpDeviceClass parent_class; } UpDeviceSupplyClass; GType up_device_supply_get_type (void); G_END_DECLS #endif /* __UP_DEVICE_SUPPLY_H__ */ 07070100000057000081A400000000000000000000000166EA481400000515000000000000000000000000000000000000002600000000upower-1.90.6/src/freebsd/up-native.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <glib.h> #include "up-acpi-native.h" #include "up-native.h" /** * up_native_get_native_path: * @object: the native tracking object * * This converts a GObject used as the device data into a native path. * * Return value: The native path for the device which is unique, e.g. "/sys/class/power/BAT1" **/ const gchar * up_native_get_native_path (GObject *object) { return up_acpi_native_get_path (UP_ACPI_NATIVE (object)); } 07070100000058000081A400000000000000000000000166EA481400000B27000000000000000000000000000000000000002400000000upower-1.90.6/src/freebsd/up-util.c/*************************************************************************** * * up-util.c : utilities * * Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * **************************************************************************/ #include "config.h" #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/types.h> #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE #include <sys/sysctl.h> #endif #include <glib.h> #include "up-util.h" gboolean up_has_sysctl (const gchar *format, ...) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE va_list args; gchar *name; size_t value_len; gboolean status; g_return_val_if_fail (format != NULL, FALSE); va_start (args, format); name = g_strdup_vprintf (format, args); va_end (args); status = sysctlbyname (name, NULL, &value_len, NULL, 0) == 0; g_free (name); return status; #else return FALSE; #endif } gboolean up_get_int_sysctl (int *value, GError **err, const gchar *format, ...) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE va_list args; gchar *name; size_t value_len = sizeof(int); gboolean status; g_return_val_if_fail (value != NULL, FALSE); g_return_val_if_fail (format != NULL, FALSE); va_start (args, format); name = g_strdup_vprintf (format, args); va_end (args); status = sysctlbyname (name, value, &value_len, NULL, 0) == 0; if (!status) g_set_error(err, 0, 0, "%s", g_strerror (errno)); g_free (name); return status; #else return FALSE; #endif } gchar * up_get_string_sysctl (GError **err, const gchar *format, ...) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE va_list args; gchar *name; size_t value_len; gchar *str = NULL; g_return_val_if_fail(format != NULL, FALSE); va_start (args, format); name = g_strdup_vprintf (format, args); va_end (args); if (sysctlbyname (name, NULL, &value_len, NULL, 0) == 0) { str = g_new (char, value_len + 1); if (sysctlbyname (name, str, &value_len, NULL, 0) == 0) str[value_len] = 0; else { g_free (str); str = NULL; } } if (!str) g_set_error (err, 0, 0, "%s", g_strerror(errno)); g_free(name); return str; #else return g_strdup ("asdf"); #endif } 07070100000059000081A400000000000000000000000166EA481400000625000000000000000000000000000000000000002400000000upower-1.90.6/src/freebsd/up-util.h/*************************************************************************** * * up-util.h : utilities * * Copyright (C) 2006, 2007 Jean-Yves Lefort <jylefort@FreeBSD.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * **************************************************************************/ #ifndef _UP_UTIL_H #define _UP_UTIL_H #include "config.h" #include <stdarg.h> #include <glib.h> #define UP_BOOL_TO_STRING(val) ((val) ? "true" : "false") #define UP_LIST_FOREACH(var, head) \ for ((var) = (head); \ (var); \ (var) = (var)->next) gboolean up_has_sysctl (const gchar *format, ...) G_GNUC_PRINTF(1, 2); gboolean up_get_int_sysctl (int *value, GError **err, const gchar *format, ...) G_GNUC_PRINTF(3, 4); gchar *up_get_string_sysctl (GError **err, const gchar *format, ...) G_GNUC_PRINTF(2, 3); #endif /* _UP_UTIL_H */ 0707010000005A000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001800000000upower-1.90.6/src/linux0707010000005B000081A400000000000000000000000166EA481400000116000000000000000000000000000000000000002900000000upower-1.90.6/src/linux/README.debugging=============== Debugging =============== When filing new bugs, please include information about the output of "upower -d", "/usr/libexec/upowerd -v -r", and: find /sys/class/power_supply/hidpp_battery_1/ -type f -exec echo {} \; -exec cat {} \; -exec echo \; as appropriate. 0707010000005C000081ED00000000000000000000000166EA4814000236B3000000000000000000000000000000000000002C00000000upower-1.90.6/src/linux/integration-test.py#!/usr/bin/python3 -u # upower integration test suite # # Run in built tree to test local built binaries, or from anywhere else to test # system installed binaries. # # Copyright: (C) 2011 Martin Pitt <martin.pitt@ubuntu.com> # # 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. import os import sys import dbus import tempfile import shutil import subprocess import unittest import time import re from output_checker import OutputChecker from packaging.version import parse as parse_version edir = os.path.dirname(sys.argv[0]) try: import dbusmock except ImportError: sys.stderr.write('Skipping tests, python-dbusmock not available (http://pypi.python.org/pypi/python-dbusmock).\n') sys.exit(77) UP = 'org.freedesktop.UPower' UP_DEVICE = 'org.freedesktop.UPower.Device' UP_DISPLAY_OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice' UP_DAEMON_ACTION_DELAY = 20 UP_HISTORY_SAVE_INTERVAL = (10*60) UP_HISTORY_SAVE_INTERVAL_LOW_POWER = 5 DEVICE_IFACE = 'org.bluez.Device1' BATTERY_IFACE = 'org.bluez.Battery1' (UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_CHARGING, UP_DEVICE_STATE_DISCHARGING, UP_DEVICE_STATE_EMPTY, UP_DEVICE_STATE_FULLY_CHARGED, UP_DEVICE_STATE_PENDING_CHARGE, UP_DEVICE_STATE_PENDING_DISCHARGE) = range(7) (UP_DEVICE_LEVEL_UNKNOWN, UP_DEVICE_LEVEL_NONE, UP_DEVICE_LEVEL_DISCHARGING, UP_DEVICE_LEVEL_LOW, UP_DEVICE_LEVEL_CRITICAL, UP_DEVICE_LEVEL_ACTION, UP_DEVICE_LEVEL_NORMAL, UP_DEVICE_LEVEL_HIGH, UP_DEVICE_LEVEL_FULL) = range(9) (UP_DEVICE_KIND_UNKNOWN, UP_DEVICE_KIND_LINE_POWER, UP_DEVICE_KIND_BATTERY, UP_DEVICE_KIND_UPS, UP_DEVICE_KIND_MONITOR, UP_DEVICE_KIND_MOUSE, UP_DEVICE_KIND_KEYBOARD, UP_DEVICE_KIND_PDA, UP_DEVICE_KIND_PHONE, UP_DEVICE_KIND_MEDIA_PLAYER, UP_DEVICE_KIND_TABLET, UP_DEVICE_KIND_COMPUTER, UP_DEVICE_KIND_GAMING_INPUT, UP_DEVICE_KIND_PEN, UP_DEVICE_KIND_TOUCHPAD, UP_DEVICE_KIND_MODEM, UP_DEVICE_KIND_NETWORK, UP_DEVICE_KIND_HEADSET, UP_DEVICE_KIND_SPEAKERS, UP_DEVICE_KIND_HEADPHONES, UP_DEVICE_KIND_VIDEO, UP_DEVICE_KIND_OTHER_AUDIO, UP_DEVICE_KIND_REMOTE_CONTROL, UP_DEVICE_KIND_PRINTER, UP_DEVICE_KIND_SCANNER, UP_DEVICE_KIND_CAMERA, UP_DEVICE_KIND_WEARABLE, UP_DEVICE_KIND_TOY, UP_DEVICE_KIND_BLUETOOTH_GENERIC) = range(29) class Tests(dbusmock.DBusTestCase): @classmethod def setUpClass(cls): # run from local build tree if we are in one, otherwise use system instance builddir = os.getenv('top_builddir', '.') if os.access(os.path.join(builddir, 'src', 'upowerd'), os.X_OK): cls.daemon_path = os.path.join(builddir, 'src', 'upowerd') cls.upower_path = os.path.join(builddir, 'tools', 'upower') print('Testing binaries from local build tree') cls.local_daemon = True elif os.environ.get('UNDER_JHBUILD', False): jhbuild_prefix = os.environ['JHBUILD_PREFIX'] cls.daemon_path = os.path.join(jhbuild_prefix, 'libexec', 'upowerd') cls.upower_path = os.path.join(jhbuild_prefix, 'bin', 'upower') print('Testing binaries from JHBuild') cls.local_daemon = False else: print('Testing installed system binaries') cls.daemon_path = None cls.upower_path = shutil.which('upower') with open('/usr/share/dbus-1/system-services/org.freedesktop.UPower.service') as f: for line in f: if line.startswith('Exec='): cls.daemon_path = line.split('=', 1)[1].strip() break assert cls.daemon_path, 'could not determine daemon path from D-BUS .service file' assert cls.upower_path, 'could not determine upower path' cls.local_daemon = False # fail on CRITICALs on client side GLib.log_set_always_fatal(GLib.LogLevelFlags.LEVEL_WARNING | GLib.LogLevelFlags.LEVEL_ERROR | GLib.LogLevelFlags.LEVEL_CRITICAL) # set up a fake system D-BUS cls.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE) cls.test_bus.up() try: del os.environ['DBUS_SESSION_BUS_ADDRESS'] except KeyError: pass os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = cls.test_bus.get_bus_address() cls.dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) cls.dbus_con = cls.get_dbus(True) @classmethod def tearDownClass(cls): cls.test_bus.down() dbusmock.DBusTestCase.tearDownClass() def setUp(self): '''Set up a local umockdev testbed. The testbed is initially empty. ''' self.testbed = UMockdev.Testbed.new() self.proxy = None self.daemon = None self.bluez = None self.start_logind({'CanHybridSleep' : 'yes'}) self.start_polkitd({}) @classmethod def stop_process(cls, proc, timeout=1): proc.terminate() try: proc.wait(timeout) except: print("Killing %d (%s) after timeout of %f seconds" % (proc.pid, proc.args[0], timeout)) proc.kill() proc.wait() def tearDown(self): del self.testbed self.stop_daemon() # # Daemon control and D-BUS I/O # def start_daemon(self, cfgfile=None, warns=False, history_dir_override=None): '''Start daemon and create DBus proxy. Do this after adding the devices you want to test with. At the moment this only works with coldplugging, as we do not currently have a way to inject simulated uevents. When done, this sets self.proxy as the Gio.DBusProxy for upowerd. ''' env = os.environ.copy() if not cfgfile: _, cfgfile = tempfile.mkstemp(prefix='upower-cfg-') self.addCleanup(os.unlink, cfgfile) env['UPOWER_CONF_FILE_NAME'] = cfgfile if history_dir_override is not None: self.upower_history_dir = env['UPOWER_HISTORY_DIR'] = history_dir_override env['UPOWER_STATE_DIR'] = history_dir_override else: self.upower_history_dir = env['UPOWER_HISTORY_DIR'] = tempfile.mkdtemp(prefix='upower-history-') env['UPOWER_STATE_DIR'] = self.upower_history_dir self.addCleanup(shutil.rmtree, env['UPOWER_HISTORY_DIR']) env['G_DEBUG'] = 'fatal-criticals' if warns else 'fatal-warnings' # note: Python doesn't propagate the setenv from Testbed.new(), so we # have to do that ourselves env['UMOCKDEV_DIR'] = self.testbed.get_root_dir() # Hotfix for https://github.com/systemd/systemd/issues/23499 env['SYSTEMD_DEVICE_VERIFY_SYSFS'] = '0' self.daemon_log = OutputChecker() if os.getenv('VALGRIND') is not None: daemon_path = ['valgrind', self.daemon_path, '-v', '-r'] else: daemon_path = [self.daemon_path, '-v', '-r'] self.daemon = subprocess.Popen(daemon_path, env=env, stdout=self.daemon_log.fd, stderr=subprocess.STDOUT) self.daemon_log.writer_attached() # wait until the daemon gets online timeout = 100 while timeout > 0: time.sleep(0.1) timeout -= 1 try: self.get_dbus_property('DaemonVersion') break except GLib.GError: pass else: self.fail('daemon did not start in 10 seconds') self.proxy = Gio.DBusProxy.new_sync( self.dbus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, UP, '/org/freedesktop/UPower', UP, None) self.assertEqual(self.daemon.poll(), None, 'daemon crashed') def stop_daemon(self): '''Stop the daemon if it is running.''' if self.daemon: try: self.daemon.terminate() except OSError: pass try: self.assertEqual(self.daemon.wait(timeout=5.0), 0) except subprocess.TimeoutExpired: try: self.daemon.kill() except OSError: pass self.assertEqual(self.daemon.wait(), 0) self.daemon_log.assert_closed() self.daemon = None self.proxy = None def get_dbus_property(self, name): '''Get property value from daemon D-Bus interface.''' return self.dbus.call_sync(UP, '/org/freedesktop/UPower', 'org.freedesktop.DBus.Properties', 'Get', GLib.Variant('(ss)', (UP, name)), None, Gio.DBusCallFlags.NO_AUTO_START, -1, None).unpack()[0] def get_dbus_display_property(self, name): '''Get property value from display device D-Bus interface.''' return self.dbus.call_sync(UP, UP_DISPLAY_OBJECT_PATH, 'org.freedesktop.DBus.Properties', 'Get', GLib.Variant('(ss)', (UP_DEVICE, name)), None, Gio.DBusCallFlags.NO_AUTO_START, -1, None).unpack()[0] def get_dbus_dev_property(self, device, name): '''Get property value from an upower device D-Bus path.''' return self.dbus.call_sync(UP, device, 'org.freedesktop.DBus.Properties', 'Get', GLib.Variant('(ss)', (UP_DEVICE, name)), None, Gio.DBusCallFlags.NO_AUTO_START, -1, None).unpack()[0] def get_dbus_dev_properties(self, device): '''Get property values from an upower device D-Bus path.''' return self.dbus.call_sync(UP, device, 'org.freedesktop.DBus.Properties', 'GetAll', GLib.Variant('(s)', (UP_DEVICE,)), None, Gio.DBusCallFlags.NO_AUTO_START, -1, None).unpack()[0] def enable_charge_limits(self, device, enable): self.dbus.call_sync(UP, device, 'org.freedesktop.UPower.Device', 'EnableChargeThreshold', GLib.Variant('(b)', (enable,)), None, Gio.DBusCallFlags.NO_AUTO_START, -1, None) def assertDevs(self, expected): devs = self.proxy.EnumerateDevices() names = sorted(n.split('/')[-1] for n in devs) self.assertEqual(names, sorted(expected.keys())) for n in names: props = self.get_dbus_dev_properties('/org/freedesktop/UPower/devices/' + n) for k, v in expected[n].items(): self.assertEqual(props[k], v, msg=f'Property "{k}" of "{n}" should be {v} but is {props[k]}') def start_logind(self, parameters=None): self.logind, self.logind_obj = self.spawn_server_template('logind', parameters or {}) self.addCleanup(self.stop_process, self.logind) def start_bluez(self, parameters=None): self.bluez, self.bluez_obj = self.spawn_server_template('bluez5', parameters or {}) self.addCleanup(self.stop_process, self.bluez) def start_polkitd(self, parameters=None): self.polkit, self.polkit_obj = self.spawn_server_template('polkitd', parameters or {}) self.addCleanup(self.stop_process, self.polkit) def assertEventually(self, condition, message=None, timeout=50, value=True): '''Assert that condition function eventually returns True. Timeout is in deciseconds, defaulting to 50 (5 seconds). message is printed on failure. ''' while timeout >= 0: context = GLib.MainContext.default() while context.iteration(False): pass if condition() == value: break timeout -= 1 time.sleep(0.1) else: self.fail(message or 'timed out waiting for ' + str(condition)) def wait_for_mainloop(self): ml = GLib.MainLoop() GLib.timeout_add(100, ml.quit) ml.run() # # Actual test cases # def test_daemon_version(self): '''DaemonVersion property''' self.start_daemon() self.assertEqual(self.proxy.EnumerateDevices(), []) self.assertRegex(self.get_dbus_property('DaemonVersion'), '^[0-9.]+$') # without any devices we should assume AC self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_no_devices(self): '''no devices''' # without any devices we should assume AC self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_props_online_ac(self): '''properties with online AC''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '1'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) ac_up = devs[0] self.assertTrue('line_power_AC' in ac_up) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(ac_up, 'PowerSupply'), True) self.assertEqual(self.get_dbus_dev_property(ac_up, 'Type'), UP_DEVICE_KIND_LINE_POWER) self.assertEqual(self.get_dbus_dev_property(ac_up, 'Online'), True) self.assertEqual(self.get_dbus_dev_property(ac_up, 'NativePath'), 'AC') self.stop_daemon() def test_props_offline_ac(self): '''properties with offline AC''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) # we don't have any known online power device now, but still no battery self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(devs[0], 'Online'), False) self.stop_daemon() def test_macbook_capacity(self): '''MacBooks have incorrect sysfs capacity''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'capacity', '60', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.testbed.add_device('virtual', 'virtual/dmi', None, ['id/product_name', 'MacBookAir7,2'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) if 'BAT' in devs[0] == ac_up: (bat0_up, ac_up) = devs else: (ac_up, bat0_up) = devs self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 80) def test_macbook_uevent(self): '''MacBooks sent uevent 5 seconds before battery updates''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.testbed.add_device('virtual', 'virtual/dmi', None, ['id/product_name', 'MacBookAir7,2'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) if 'BAT' in devs[0] == ac_up: (bat0_up, ac_up) = devs else: (ac_up, bat0_up) = devs self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.testbed.set_attribute(ac, 'online', '1') self.testbed.uevent(ac, 'change') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) time.sleep(3) self.testbed.set_attribute(bat0, 'status', 'Charging') time.sleep(1) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_CHARGING) # We stopped polling now, so this update will *not* be read, even if # we send a new uevent, as the 'online' state does not change. self.testbed.uevent(ac, 'change') time.sleep(2) self.testbed.set_attribute(bat0, 'status', 'Discharging') time.sleep(1) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_CHARGING) def test_battery_ac(self): '''properties with dynamic battery/AC''' # offline AC + discharging battery ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) if 'BAT' in devs[0] == ac_up: (bat0_up, ac_up) = devs else: (ac_up, bat0_up) = devs # we don't have any known online power device now, but still no battery self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 80.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 48.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 60.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 80.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'NativePath'), 'BAT0') self.stop_daemon() # offline AC + discharging low battery self.testbed.set_attribute(bat0, 'energy_now', '1500000') self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_CRITICAL) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 2.5) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_BATTERY) self.stop_daemon() # now connect AC again self.testbed.set_attribute(ac, 'online', '1') self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) # we don't have any known online power device now, but still no battery self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(ac_up, 'Online'), True) self.stop_daemon() def test_multiple_batteries(self): '''Multiple batteries''' # one well charged, one low bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.testbed.add_device('power_supply', 'BAT1', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) # as we have one which is well-charged, the summary state is "not low # battery" self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() # now set both to low self.testbed.set_attribute(bat0, 'energy_now', '1500000') self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_CRITICAL) self.stop_daemon() def test_unknown_battery_status_no_ac(self): '''Unknown battery charge status, no AC''' for i in range(2): self.testbed.add_device('power_supply', f'BAT{i}', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) # with no other power sources, the OnBattery value here is really # arbitrary, so don't test it. The only thing we know for sure is that # we aren't on low battery self.start_daemon() time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_DISCHARGING) self.stop_daemon() def test_unknown_battery_status_with_ac(self): '''Unknown battery charge status, with AC''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) for i in range(2): self.testbed.add_device('power_supply', f'BAT{i}', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.testbed.set_attribute(ac, 'online', '0') self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_DISCHARGING) self.stop_daemon() self.testbed.set_attribute(ac, 'online', '1') self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_CHARGING) self.stop_daemon() def test_battery_state_guessing(self): energy_now = 48000000 ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', str(energy_now), 'voltage_now', '12000000'], []) self.start_daemon() self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_UNKNOWN }, 'line_power_AC' : {} }) # Discharge for 20s: for i in range(25): time.sleep(1) # 1W usage over 1 second energy_now -= 1.0 * 1000000 / 3600 self.testbed.set_attribute(bat0, 'energy_now', str(int(energy_now))) self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_DISCHARGING }, 'line_power_AC' : {} }) # History is discarded, we have an unknown state # (the "online" state does not actually matter for the test) self.testbed.set_attribute(bat0, 'online', '1') self.testbed.uevent(ac, 'change') time.sleep(1) # FIXME: this does not get reset # https://gitlab.freedesktop.org/upower/upower/-/issues/230 # self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_UNKNOWN }, 'line_power_AC' : {} }) # Charge for a while for i in range(40): time.sleep(1) # 1W charge over 1 second energy_now += 1.0 * 1000000 / 3600 self.testbed.set_attribute(bat0, 'energy_now', str(int(energy_now))) self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_CHARGING }, 'line_power_AC' : {} }) self.stop_daemon() def test_display_pending_charge_one_battery(self): '''One battery pending-charge''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Not charging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '40', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_PENDING_CHARGE) self.stop_daemon() def test_empty_guessing(self): '''One empty batter not reporting a state''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Unknown', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '0', 'voltage_now', '12000000'], []) self.start_daemon() self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_EMPTY } }) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_EMPTY) self.stop_daemon() def test_full_guessing(self): '''One full batter not reporting a state''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Unknown', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '99', 'voltage_now', '12000000'], []) self.start_daemon() self.assertDevs({ 'battery_BAT0': { 'State' : UP_DEVICE_STATE_FULLY_CHARGED } }) self.assertEqual(self.get_dbus_display_property('State'), UP_DEVICE_STATE_FULLY_CHARGED) self.stop_daemon() def test_display_state_aggregation(self): bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Not charging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '40', 'voltage_now', '12000000'], []) bat1 = self.testbed.add_device('power_supply', 'BAT1', None, ['type', 'Battery', 'present', '1', 'status', 'Not charging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '40', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') # The unknown poll can cause issues for test synchronization config.write("[UPower]\n") config.write("NoPollBatteries=true\n") config.close() self.addCleanup(os.unlink, config.name) self.start_daemon(config.name, warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) ANY = -1 TBD = -2 CONFLICT = -3 UNKNOWN = UP_DEVICE_STATE_UNKNOWN CHARGING = UP_DEVICE_STATE_CHARGING DISCHARGING = UP_DEVICE_STATE_DISCHARGING EMPTY = UP_DEVICE_STATE_EMPTY FULL = UP_DEVICE_STATE_FULLY_CHARGED P_CHARGE = UP_DEVICE_STATE_PENDING_CHARGE P_DISCHARGE = UP_DEVICE_STATE_PENDING_DISCHARGE states = [ 'Unknown', 'Charging', 'Discharging', 'Empty', 'Full', 'Not Charging' ] #, 'Pending Discharge' ] # pending discharge does not exist on Linux. List it, but it is not tested display_device_state = [ # UNKNOWN , CHARGING , DISCHARGING, EMPTY , FULL , P_CHARGE , P_DISCHARGE (ANY , CHARGING , DISCHARGING, ANY , ANY , TBD , ANY), (CHARGING , CHARGING , CONFLICT , CHARGING , CHARGING , CHARGING , CHARGING), (DISCHARGING, CONFLICT , DISCHARGING, DISCHARGING, DISCHARGING, DISCHARGING, DISCHARGING), (ANY , CHARGING , DISCHARGING, EMPTY , ANY , TBD , ANY), (ANY , CHARGING , DISCHARGING, ANY , ANY , TBD , ANY), (TBD , CHARGING , DISCHARGING, TBD , TBD , P_CHARGE , ANY), (ANY , CHARGING , DISCHARGING, ANY , ANY , ANY , ANY), ] self.daemon_log.clear() for i in range(len(states)): for j in range(len(states)): # The table should be mirrored assert display_device_state[i][j] == display_device_state[j][i] print(f'Test states are {states[i]} and {states[j]} expected state is {states[display_device_state[i][j]]}') self.testbed.set_attribute(bat0, 'status', states[i]) self.testbed.set_attribute(bat1, 'status', states[j]) self.testbed.uevent(bat0, 'change') # We can't guarantee that both uevents are processed without # the idle handler running. So, lets wait for the idle handler # to calculate the composite battery state. self.daemon_log.check_line('Calculating percentage', timeout=2.0) self.testbed.uevent(bat1, 'change') # TODO: Make this more elegant somehow lines = self.daemon_log.check_line('Calculating percentage', timeout=2.0) for l in lines: found = bool(re.match(b".*Conflicting.*state.*", l)) if found: break if display_device_state[i][j] == CONFLICT: self.assertTrue(found) else: self.assertFalse(found) if display_device_state[i][j] >= 0: self.assertEqual(self.get_dbus_display_property('State'), display_device_state[i][j], msg=f"Unexpected aggregate state for states {states[i]} and {states[j]}") else: self.assertIn(self.get_dbus_display_property('State'), ( UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_CHARGING, UP_DEVICE_STATE_DISCHARGING, UP_DEVICE_STATE_EMPTY, UP_DEVICE_STATE_FULLY_CHARGED, UP_DEVICE_STATE_PENDING_CHARGE, UP_DEVICE_STATE_PENDING_DISCHARGE), msg=f"Invalid aggregate state for states {states[i]} and {states[j]}" ) self.stop_daemon() def test_map_pending_charge_to_fully_charged(self): '''Map pending-charge to fully-charged''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Not charging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '100', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_FULLY_CHARGED) self.stop_daemon() # and make sure we still return pending-charge below the threshold self.testbed.set_attribute(bat0, 'capacity', '89') self.start_daemon() self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_PENDING_CHARGE) self.stop_daemon() def test_battery_charge(self): '''battery which reports charge instead of energy energy_* is in uWh, while charge_* is in uAh. ''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'charge_now', '7875000', 'current_now', '787000', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 75.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 94.5) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 126.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 132.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Temperature'), 0.0) self.stop_daemon() def test_battery_energy_charge_mixed(self): '''battery which reports both current charge and energy''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'charge_now', '4200000', 'energy_now', '9999999', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertAlmostEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 50.4) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 126.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 132.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 40.0) self.stop_daemon() def test_battery_capacity_and_charge(self): '''battery which reports capacity and charge_full''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'charge_full', '10500000', 'charge_full_design', '11000000', 'capacity', '40', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 40.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 50.4) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 126.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 132.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_BATTERY) self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_battery_overfull(self): '''battery which reports a > 100% percentage for a full battery''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Full', 'capacity_level', 'Normal\n', 'current_now', '1000', 'charge_now', '11000000', 'charge_full', '10000000', 'charge_full_design', '11000000', 'capacity', '110', 'voltage_now', '12000000'], []) self.start_daemon(warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # should clamp percentage self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 100.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'State'), UP_DEVICE_STATE_FULLY_CHARGED) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 132.0) # should adjust EnergyFull to reality, not what the battery claims self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFull'), 132.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyFullDesign'), 132.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Voltage'), 12.0) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_BATTERY) # capacity_level is unused because a 'capacity' attribute is present and used instead self.assertEqual(self.get_dbus_dev_property(bat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_battery_temperature(self): '''battery which reports temperature''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'temp', '254', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Temperature'), 25.4) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 2.5) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 1.5) self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_CRITICAL) self.stop_daemon() def test_battery_broken_name(self): '''Battery with funky kernel name''' self.testbed.add_device('power_supply', 'bq24735@5-0009', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.start_daemon() self.assertEqual(self.get_dbus_display_property('IsPresent'), True) self.stop_daemon() def test_battery_charge_limit_multiple_batteries(self): '''Battery with charge limits with multiple batteries''' if not self.polkit: self.start_polkitd({}) self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') self.testbed.add_device('power_supply', 'BAT1', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT1", 'CHARGE_LIMIT', '70,80') self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) bat0_up = devs[0] bat1_up = devs[0] for bat in [bat0_up, bat1_up]: self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), False) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeStartThreshold'), 70) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeEndThreshold'), 80) self.enable_charge_limits(bat0_up, True) self.enable_charge_limits(bat1_up, True) for bat in [bat0_up, bat1_up]: self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), True) battery_name = bat.split('_')[-1] with open(f'/sys/class/power_supply/{battery_name}/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '70') with open(f'/sys/class/power_supply/{battery_name}/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '80') def test_battery_charge_limit_multiple_batteries_polkit_not_allowed(self): '''Battery with charge limits with multiple batteries, but polkit isn't allowed''' if not self.polkit: self.start_polkitd({}) self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') self.testbed.add_device('power_supply', 'BAT1', None, ['type', 'Battery', 'present', '1', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT1", 'CHARGE_LIMIT', '70,80') self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 2) bat0_up = devs[0] bat1_up = devs[0] for bat in [bat0_up, bat1_up]: self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), False) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeStartThreshold'), 70) self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeEndThreshold'), 80) with self.assertRaises(Exception) as cm: self.enable_charge_limits(bat0_up, True) ex = cm.exception self.assertIn("Operation is not allowed", str(ex)) with self.assertRaises(Exception) as cm: self.enable_charge_limits(bat1_up, True) ex = cm.exception self.assertIn("Operation is not allowed", str(ex)) for bat in [bat0_up, bat1_up]: self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), False) battery_name = bat.split('_')[-1] with open(f'/sys/class/power_supply/{battery_name}/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '0') with open(f'/sys/class/power_supply/{battery_name}/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') def test_battery_charge_limit_supported(self): '''Battery with charge_control_start/end_threshold supported''' if not self.polkit: self.start_polkitd({}) self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'model_name', 'test', 'serial_number', '12', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') def start_daemon(charge_threshold_value=None): upower_history_dir_override = tempfile.mkdtemp(prefix='upower-history-') if charge_threshold_value is not None: with open(os.path.join(upower_history_dir_override, "charging-threshold-status") , 'w') as fp: fp.write(charge_threshold_value) self.start_daemon(history_dir_override=upower_history_dir_override) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) return devs[0] bat0_up = start_daemon() self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 70) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 80) self.enable_charge_limits(bat0_up, True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), True) # charge limits enabled? with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '70') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '80') self.enable_charge_limits(bat0_up, False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '0') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') # TODO: Test changing CHARGE_LIMIT # self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '20,30') # self.testbed.uevent("/sys/class/power_supply/BAT0", 'change') # devs = self.proxy.EnumerateDevices() # bat0_up = devs[0] # self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 20) # self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 30) self.stop_daemon() # On startup with threshold set self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '90,100') bat0_up = start_daemon(charge_threshold_value='1') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 90) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 100) with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '90') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') def test_battery_charge_limit_supported_polkit_not_allowed(self): '''Battery with charge_control_start/end_threshold supported''' if not self.polkit: self.start_polkitd({}) self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'model_name', 'test', 'serial_number', '12', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '0', 'charge_control_end_threshold', '100', ], []) self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') def start_daemon(charge_threshold_value=None): upower_history_dir_override = tempfile.mkdtemp(prefix='upower-history-') if charge_threshold_value is not None: with open(os.path.join(upower_history_dir_override, "charging-threshold-status") , 'w') as fp: fp.write(charge_threshold_value) self.start_daemon(history_dir_override=upower_history_dir_override) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) return devs[0] bat0_up = start_daemon() self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 70) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 80) with self.assertRaises(Exception) as cm: self.enable_charge_limits(bat0_up, True) ex = cm.exception self.assertIn("Operation is not allowed", str(ex)) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) # charge limits enabled? with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '0') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') with self.assertRaises(Exception) as cm: self.enable_charge_limits(bat0_up, False) ex = cm.exception self.assertIn("Operation is not allowed", str(ex)) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '0') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') self.stop_daemon() # On startup with threshold set self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '90,100') bat0_up = start_daemon(charge_threshold_value='1') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), True) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 90) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 100) with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: self.assertEqual(fp.read(), '90') with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: self.assertEqual(fp.read(), '100') def test_battery_charge_threshold_unsupported(self): '''Battery with only start_threshold supported''' if not self.polkit: self.start_polkitd({}) self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'model_name', 'test', 'serial_number', '12', 'status', 'unknown', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000', 'charge_control_start_threshold', '80', ], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) with self.assertRaises(Exception) as cm: self.enable_charge_limits(bat0_up, True) ex = cm.exception self.assertIn("setting battery charge thresholds", str(ex)) self.stop_daemon() def test_battery_zero_power_draw(self): '''Battery with zero power draw, e.g. in a dual-battery system''' self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Full', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '60000000', 'voltage_now', '12000000', 'power_now', '0', 'current_now', '787000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'EnergyRate'), 0.0) self.stop_daemon() def test_ups_no_ac(self): '''UPS properties without AC''' # add a charging UPS ups0 = self.testbed.add_device('usbmisc', 'hiddev0', None, [], ['DEVNAME', 'null', 'UPOWER_VENDOR', 'APC', 'UPOWER_BATTERY_TYPE', 'ups', 'UPOWER_FAKE_DEVICE', '1', 'UPOWER_FAKE_HID_CHARGING', '1', 'UPOWER_FAKE_HID_PERCENTAGE', '70']) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) ups0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Vendor'), 'APC') self.assertEqual(self.get_dbus_dev_property(ups0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Percentage'), 70.0) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'State'), UP_DEVICE_STATE_CHARGING) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'PowerSupply'), True) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Type'), UP_DEVICE_KIND_UPS) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() # now switch to discharging UPS self.testbed.set_property(ups0, 'UPOWER_FAKE_HID_CHARGING', '0') self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) self.assertEqual(devs[0], ups0_up) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'IsPresent'), True) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Percentage'), 70.0) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_DISCHARGING) self.stop_daemon() # low UPS charge self.testbed.set_property(ups0, 'UPOWER_FAKE_HID_PERCENTAGE', '2') self.start_daemon() self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Percentage'), 2.0) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.stop_daemon() def test_ups_offline_ac(self): '''UPS properties with offline AC''' # add low charge UPS ups0 = self.testbed.add_device('usbmisc', 'hiddev0', None, [], ['DEVNAME', 'null', 'UPOWER_VENDOR', 'APC', 'UPOWER_BATTERY_TYPE', 'ups', 'UPOWER_FAKE_DEVICE', '1', 'UPOWER_FAKE_HID_CHARGING', '0', 'UPOWER_FAKE_HID_PERCENTAGE', '2']) # add an offline AC, should still be on battery ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '0'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() if 'AC' in devs[0]: ups0_up = devs[1] else: ups0_up = devs[0] self.assertEqual(len(devs), 2) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'Percentage'), 2.0) self.assertEqual(self.get_dbus_dev_property(ups0_up, 'State'), UP_DEVICE_STATE_DISCHARGING) self.assertEqual(self.get_dbus_property('OnBattery'), True) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.stop_daemon() # now plug in the AC, should switch to OnBattery=False self.testbed.set_attribute(ac, 'online', '1') self.start_daemon() self.assertEqual(self.get_dbus_property('OnBattery'), False) # FIXME this is completely wrong # The AC status doesn't change anything, the AC is what powers the UPS # and the UPS powers the desktop # # A plugged in UPS is always the one supplying the computer self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.stop_daemon() def test_refresh_after_sleep(self): '''sleep/wake cycle to check we properly refresh the batteries''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.start_daemon() self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [True]) self.daemon_log.check_line("Polling will be paused", timeout=1) # simulate some battery drain during sleep for which we then # can check after we 'woke up' self.testbed.set_attribute(bat0, 'energy_now', '40000000') self.logind_obj.EmitSignal('', 'PrepareForSleep', 'b', [False]) self.daemon_log.check_line("Polling will be resumed", timeout=1) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 40.0) self.stop_daemon() @unittest.skipIf(parse_version(dbusmock.__version__) <= parse_version('0.23.1'), 'Not supported in dbusmock version') def test_prevent_sleep_until_critical_action_is_executed(self): '''check that critical action is executed when trying to suspend''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5.0\n") config.write("CriticalPowerAction=Hibernate\n") config.close() self.start_daemon(cfgfile=config.name) # delay inhibitor taken self.assertEqual(len(self.logind_obj.ListInhibitors()), 1) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') # critical action is scheduled, a block inhibitor lock is taken besides a delay inhibitor lock time.sleep(0.5) self.assertEventually(lambda: self.get_dbus_display_property('WarningLevel'), value=UP_DEVICE_LEVEL_ACTION) self.assertEqual(len(self.logind_obj.ListInhibitors()), 2) self.daemon_log.check_line("About to call logind method Hibernate", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # block inhibitor lock is released self.assertEqual(len(self.logind_obj.ListInhibitors()), 1) def test_critical_action_is_taken_repeatedly(self): '''check that critical action works repeatedly (eg. after resume)''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5.0\n") config.write("CriticalPowerAction=Hibernate\n") config.close() self.start_daemon(cfgfile=config.name) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method Hibernate", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # simulate that battery was charged to 100% during sleep self.testbed.set_attribute(bat0, 'energy_now', '60000000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) # simulate that battery was drained to 1% again self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method Hibernate", timeout=UP_DAEMON_ACTION_DELAY + 0.5) self.stop_daemon() os.unlink(config.name) def test_critical_action_is_suspend_and_AllowRiskyCriticalPowerAction_is_true(self): '''check that critical action is suspend''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5\n") config.write("AllowRiskyCriticalPowerAction=true\n") config.write("CriticalPowerAction=Suspend\n") config.close() self.start_daemon(cfgfile=config.name, warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # check warning message when CriticalPowerAction=Suspend and AllowRiskyCriticalPowerAction=true self.daemon_log.check_line( "The \"Suspend\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. Use AllowRiskyCriticalPowerAction=false to disable" " support for risky settings.", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method Suspend", timeout=UP_DAEMON_ACTION_DELAY + 0.5) self.stop_daemon() os.unlink(config.name) def test_critical_action_is_suspend_and_AllowRiskyCriticalPowerAction_is_false(self): '''check that critical action is suspend''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5\n") config.write("AllowRiskyCriticalPowerAction=false\n") config.write("CriticalPowerAction=Suspend\n") config.close() self.start_daemon(cfgfile=config.name, warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # check warning message when CriticalPowerAction=Suspend and AllowRiskyCriticalPowerAction=false self.daemon_log.check_line( "The \"Suspend\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. The system will perform \"HybridSleep\" instead." " Use AllowRiskyCriticalPowerAction=true to enable support for" " risky settings.", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method HybridSleep", timeout=UP_DAEMON_ACTION_DELAY + 0.5) self.stop_daemon() os.unlink(config.name) def test_critical_action_is_ignore_and_AllowRiskyCriticalPowerAction_is_true(self): '''check that critical action is ignore''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5\n") config.write("AllowRiskyCriticalPowerAction=true\n") config.write("CriticalPowerAction=Ignore\n") config.close() self.start_daemon(cfgfile=config.name, warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # check warning message when CriticalPowerAction=Ignore and AllowRiskyCriticalPowerAction=true self.daemon_log.check_line( "The \"Ignore\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. Use AllowRiskyCriticalPowerAction=false to disable" " support for risky settings.", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method Ignore", timeout=UP_DAEMON_ACTION_DELAY + 0.5) self.stop_daemon() os.unlink(config.name) def test_critical_action_is_ignore_and_AllowRiskyCriticalPowerAction_is_false(self): '''check that critical action is ignore''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') config.write("[UPower]\n") config.write("UsePercentageForPolicy=true\n") config.write("PercentageAction=5\n") config.write("AllowRiskyCriticalPowerAction=false\n") config.write("CriticalPowerAction=Ignore\n") config.close() self.start_daemon(cfgfile=config.name, warns=True) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # check warning message when CriticalPowerAction=Ignore and AllowRiskyCriticalPowerAction=true self.daemon_log.check_line( "The \"Ignore\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. The system will perform \"HybridSleep\" instead." " Use AllowRiskyCriticalPowerAction=true to enable support for" " risky settings.", timeout=UP_DAEMON_ACTION_DELAY + 0.5) # simulate that battery has 1% (less than PercentageAction) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_ACTION) self.daemon_log.check_line("About to call logind method HybridSleep", timeout=UP_DAEMON_ACTION_DELAY + 0.5) self.stop_daemon() os.unlink(config.name) def test_low_battery_changes_history_save_interval(self): '''check that we save the history more quickly on low battery''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.daemon_log.check_line(f"saving in {UP_HISTORY_SAVE_INTERVAL} seconds", timeout=1) # simulate that battery has 1% (less than 10%) self.testbed.set_attribute(bat0, 'energy_now', '600000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('Percentage'), 1) self.daemon_log.check_line("saving to disk earlier due to low power") self.daemon_log.check_line(f"saving in {UP_HISTORY_SAVE_INTERVAL_LOW_POWER} seconds") # simulate that battery was charged to 100% during sleep self.testbed.set_attribute(bat0, 'energy_now', '60000000') self.testbed.uevent(bat0, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_display_property('Percentage'), 100) # The 5 seconds were not up yet, and the shorter timeout sticks self.daemon_log.check_line("deferring as earlier timeout is already queued") self.stop_daemon() def test_battery_id_change(self): '''check that we save/load the history correctly when the ID changes''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'manufacturer', 'FDO', 'model_name', 'Fake Battery', 'serial_number', '001', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '50000000', 'voltage_now', '12000000'], []) self.start_daemon() self.daemon_log.check_line("using id: Fake_Battery-80-001", timeout=1) # Change the serial of the battery self.testbed.set_attribute(bat0, 'energy_full_design', '90000000') self.testbed.set_attribute(bat0, 'serial_number', '002') self.testbed.uevent(bat0, 'change') # This saves the old history, and then opens a new one self.daemon_log.check_line_re("saved .*/history-time-empty-Fake_Battery-80-001.dat", timeout=1) self.daemon_log.check_line("using id: Fake_Battery-90-002", timeout=1) # Only happens once self.daemon_log.check_no_line("using id:", wait=1.0) # Remove the battery self.testbed.set_attribute(bat0, 'present', '0') self.testbed.uevent(bat0, 'change') # This saves the old history, and does *not* open a new one self.daemon_log.check_line_re("saved .*/history-time-empty-Fake_Battery-90-002.dat", timeout=1) self.daemon_log.check_no_line("using id:", wait=1.0) self.stop_daemon() def test_percentage_low_icon_set(self): '''Without battery level, PercentageLow is limit for icon change''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '100000000', 'energy_full_design', '100000000', 'energy_now', '15000000', 'capacity', '15', 'voltage_now', '12000000'], []) config = tempfile.NamedTemporaryFile(delete=False, mode='w') # Low, Critical and Action are all needed to avoid fallback to defaults config.write("[UPower]\n") config.write("PercentageLow=20.0\n") config.write("PercentageCritical=3.0\n") config.write("PercentageAction=2.0\n") config.close() self.start_daemon(cfgfile=config.name) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # capacity_level is unused because a 'capacity' attribute is present and used instead self.assertEqual(self.get_dbus_dev_property(bat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_NONE) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 15.0) # Battery below 20% from config, should set 'caution' icon even if over default (10%) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'IconName'), 'battery-caution-symbolic') self.stop_daemon() os.unlink(config.name) def test_vendor_strings(self): '''manufacturer/model_name/serial_number with valid and invalid strings''' bat0 = self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000', # valid ASCII string 'serial_number', '123ABC', # valid UTF-8 string 'manufacturer', '⍾ Batt Inc. ☢'], []) # string with invalid chars self.testbed.set_attribute_binary(bat0, 'model_name', b'AB\xFFC12\x013') self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Serial'), '123ABC') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Vendor'), '⍾ Batt Inc. ☢') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), 'ABC123') self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Energy'), 1.5) self.stop_daemon() def _add_bt_mouse(self): '''Add a bluetooth mouse to testbed''' self.testbed.add_device('bluetooth', 'usb1/bluetooth/hci0/hci0:01', None, [], []) self.testbed.add_device( 'input', 'usb1/bluetooth/hci0/hci0:01/input2/mouse3', None, ['uniq', '11:22:33:44:aa:bb'], ['DEVNAME', 'input/mouse3', 'ID_INPUT_MOUSE', '1']) mousebat0 = self.testbed.add_device( 'power_supply', 'usb1/bluetooth/hci0/hci0:01/1/power_supply/hid-11:22:33:44:aa:bb-battery', None, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '30', 'model_name', 'Fancy BT mouse'], []) return mousebat0 def test_absent_device_battery(self): '''absent battery''' self.testbed.add_device('bluetooth', 'usb1/bluetooth/hci0/hci0:01', None, [], []) self.testbed.add_device( 'input', 'usb1/bluetooth/hci0/hci0:01/input2/mouse3', None, ['uniq', '11:22:33:44:aa:bb'], ['DEVNAME', 'input/mouse3', 'ID_INPUT_MOUSE', '1']) mousebat0 = self.testbed.add_device( 'power_supply', 'usb1/bluetooth/hci0/hci0:01/1/power_supply/hid-11:22:33:44:aa:bb-battery', None, ['type', 'Battery', 'scope', 'Device', 'online', '1', 'present', '0', 'status', 'Discharging', 'capacity', '0', 'model_name', 'Fancy BT mouse'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Fancy BT mouse') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'IsPresent'), False) self.testbed.set_attribute(mousebat0, 'capacity', '100') self.testbed.set_attribute(mousebat0, 'present', '1') self.testbed.uevent(mousebat0, 'change') self.assertEventually(lambda: self.get_dbus_dev_property(mousebat0_up, 'IsPresent'), value=True) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'IsPresent'), True) self.testbed.set_attribute(mousebat0, 'capacity', '0') self.testbed.set_attribute(mousebat0, 'present', '0') self.testbed.uevent(mousebat0, 'change') self.assertEventually(lambda: self.get_dbus_dev_property(mousebat0_up, 'IsPresent'), value=False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'IsPresent'), False) def test_bluetooth_mouse(self): '''bluetooth mouse battery''' self._add_bt_mouse() self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Fancy BT mouse') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 30) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_dup_bluetooth_mouse(self): '''BT mouse that also supports HID++''' # power_supply interface self._add_bt_mouse() # BlueZ BATT service alias = 'Arc Touch Mouse SE' battery_level = 99 device_properties = { 'Appearance': dbus.UInt16(0x03c2, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) def test_dup_logitech_unifying_usb(self): 'De-duplicate Logitech HID++ USB/Unifying mice' self.testbed.add_from_file(os.path.join(edir, 'tests/logitech-g903.device')) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) self.stop_daemon() def test_bluetooth_mouse_reconnect(self): '''bluetooth mouse powerdown/reconnect''' mb = self._add_bt_mouse() self.start_daemon(warns=True) devs_before = self.proxy.EnumerateDevices() self.assertEqual(len(devs_before), 1) self.testbed.uevent(mb, 'remove') time.sleep(1) self.assertEqual(self.proxy.EnumerateDevices(), []) self.testbed.uevent(mb, 'add') time.sleep(0.5) devs_after = self.proxy.EnumerateDevices() self.assertEqual(devs_before, devs_after) # second add, which should be treated as change self.testbed.uevent(mb, 'add') time.sleep(0.5) devs_after = self.proxy.EnumerateDevices() self.assertEqual(devs_before, devs_after) # with BT devices, original devices don't get removed on powerdown, but # on wakeup we'll get a new one which ought to replace the previous; # emulate that kernel bug os.unlink(os.path.join(self.testbed.get_sys_dir(), 'class', 'power_supply', 'hid-11:22:33:44:aa:bb-battery')) mb1 = self.testbed.add_device( 'power_supply', 'usb1/bluetooth/hci0/hci0:01/2/power_supply/hid-11:22:33:44:aa:bb-battery', None, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '20', 'model_name', 'Fancy BT mouse'], []) self.testbed.uevent(mb1, 'add') time.sleep(0.5) devs_after = self.proxy.EnumerateDevices() self.assertEqual(devs_before, devs_after) mb1_up = devs_after[0] self.assertEqual(self.get_dbus_dev_property(mb1_up, 'Model'), 'Fancy BT mouse') self.assertEqual(self.get_dbus_dev_property(mb1_up, 'Percentage'), 20) self.assertEqual(self.get_dbus_dev_property(mb1_up, 'PowerSupply'), False) self.stop_daemon() def test_hidpp_mouse(self): '''HID++ mouse battery''' parent = self.testbed.add_device('usb', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2', None, [], []) parent = self.testbed.add_device('hid', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009', parent, [], []) dev = self.testbed.add_device('hid', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A', parent, [], []) parent = dev self.testbed.add_device( 'input', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A/input/input22', parent, [], ['DEVNAME', 'input/mouse3', 'ID_INPUT_MOUSE', '1']) self.testbed.add_device( 'power_supply', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A/power_supply/hidpp_battery_3', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '30', 'serial_number', '123456', 'model_name', 'Fancy Logitech mouse'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Fancy Logitech mouse') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 30) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Serial'), '123456') self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_usb_joypad(self): '''DualShock 4 joypad connected via USB''' dev = self.testbed.add_device('usb', '/devices/pci0000:00/0000:00:14.0/usb3/3-9', None, [], []) parent = dev self.testbed.add_device( 'input', '/devices/pci0000:00/0000:00:14.0/usb3/3-9/3-9:1.3/0003:054C:09CC.0007/input/input51', parent, ['name', 'Sony Interactive Entertainment Wireless Controller', 'uniq', 'ff:ff:ff:ff:ff:ff'], ['ID_INPUT', '1', 'ID_INPUT_JOYSTICK', '1']) dev = self.testbed.add_device( 'power_supply', '/devices/pci0000:00/0000:00:14.0/usb3/3-9/3-9:1.3/0003:054C:09CC.0007/power_supply/sony_controller_battery_ff:ff:ff:ff:ff:ff', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'status', 'Charging', 'capacity', '20',], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) joypadbat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(joypadbat0_up, 'Model'), 'Sony Interactive Entertainment Wireless Controller') self.assertEqual(self.get_dbus_dev_property(joypadbat0_up, 'Serial'), 'ff:ff:ff:ff:ff:ff') self.assertEqual(self.get_dbus_dev_property(joypadbat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(joypadbat0_up, 'Type'), UP_DEVICE_KIND_GAMING_INPUT) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) def test_hidpp_touchpad_race(self): '''HID++ touchpad with input node that appears later''' parent = self.testbed.add_device('usb', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2', None, [], []) parent = self.testbed.add_device('hid', '0003:046D:C52B.0009', parent, [], []) dev = self.testbed.add_device('hid', '0003:046D:4101.000A', parent, [], []) parent = dev batt_dev = self.testbed.add_device( 'power_supply', 'power_supply/hidpp_battery_3', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity_level', 'Full\n', 'serial_number', '123456', 'model_name', 'Logitech T650'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Logitech T650') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_BATTERY) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Serial'), '123456') self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) # Now test all the levels self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 100) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_FULL) self.testbed.add_device( 'input', 'input/input22', parent, [], ['DEVNAME', 'input/mouse3', 'ID_INPUT_TOUCHPAD', '1', 'ID_INPUT_MOUSE', '1']) self.testbed.uevent(batt_dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_TOUCHPAD) def test_hidpp_touchpad(self): '''HID++ touchpad battery with 5 capacity levels''' parent = self.testbed.add_device('usb', '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2', None, [], []) parent = self.testbed.add_device('hid', '0003:046D:C52B.0009', parent, [], []) dev = self.testbed.add_device('hid', '0003:046D:4101.000A', parent, [], []) parent = dev self.testbed.add_device( 'input', 'input/input22', parent, [], ['DEVNAME', 'input/mouse3', 'ID_INPUT_TOUCHPAD', '1', 'ID_INPUT_MOUSE', '1']) dev = self.testbed.add_device( 'power_supply', 'power_supply/hidpp_battery_3', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity_level', 'Full\n', 'serial_number', '123456', 'model_name', 'Logitech T650'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Logitech T650') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_TOUCHPAD) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Serial'), '123456') self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) # Now test all the levels self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 100) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_FULL) self.testbed.set_attribute(dev, 'capacity_level', 'Critical\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_CRITICAL) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'WarningLevel'), UP_DEVICE_LEVEL_CRITICAL) self.testbed.set_attribute(dev, 'capacity_level', 'Low\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 10) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_LOW) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'WarningLevel'), UP_DEVICE_LEVEL_LOW) self.testbed.set_attribute(dev, 'capacity_level', 'High\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 70) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_HIGH) self.testbed.set_attribute(dev, 'capacity_level', 'Normal\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 55) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_NORMAL) self.testbed.set_attribute(dev, 'capacity_level', 'Unknown\n') self.testbed.set_attribute(dev, 'status', 'Charging\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 50.0) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_UNKNOWN) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'State'), UP_DEVICE_STATE_CHARGING) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'IconName'), 'battery-good-charging-symbolic') self.testbed.set_attribute(dev, 'capacity_level', 'Full\n') self.testbed.set_attribute(dev, 'status', 'Full\n') self.testbed.uevent(dev, 'change') time.sleep(0.5) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 100) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'BatteryLevel'), UP_DEVICE_LEVEL_FULL) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'State'), UP_DEVICE_STATE_FULLY_CHARGED) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'IconName'), 'battery-full-charged-symbolic') self.stop_daemon() def test_bluetooth_hid_mouse(self): '''bluetooth HID mouse battery''' dev = self.testbed.add_device( 'bluetooth', '/devices/pci0000:00/0000:00:14.0/usb2/2-7/2-7:1.0/bluetooth/hci0', None, [], []) parent = dev dev = self.testbed.add_device( 'bluetooth', 'hci0:256', parent, [], ['DEVTYPE', 'link']) parent = dev dev = self.testbed.add_device( 'hid', '0005:046D:B00D.0002', parent, [], ['HID_NAME', 'Fancy BT Mouse']) parent = dev self.testbed.add_device( 'power_supply', 'power_supply/hid-00:1f:20:96:33:47-battery', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '30', 'model_name', 'Fancy BT mouse'], []) dev = self.testbed.add_device( 'input', 'input/input22', parent, [], ['ID_INPUT_MOUSE', '1']) parent = dev self.testbed.add_device( 'input', 'mouse1', parent, [], ['ID_INPUT_MOUSE', '1']) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Fancy BT mouse') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 30) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_virtual_unparented_device(self): '''Unparented virtual input device''' dev = self.testbed.add_device( 'input', 'virtual/input/input18', None, [], []) acpi = self.testbed.add_device('acpi', 'PNP0C0A:00', None, [], []) bat0 = self.testbed.add_device('power_supply', 'BAT0', acpi, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) # Generated a critical in older versions of upower self.start_daemon() devs = self.proxy.EnumerateDevices() self.stop_daemon() def test_bluetooth_hid_mouse_no_legacy_subdevice(self): '''bluetooth HID mouse battery''' dev = self.testbed.add_device( 'bluetooth', '/devices/pci0000:00/0000:00:14.0/usb2/2-7/2-7:1.0/bluetooth/hci0', None, [], []) parent = dev dev = self.testbed.add_device( 'bluetooth', 'hci0:256', parent, [], ['DEVTYPE', 'link']) parent = dev dev = self.testbed.add_device( 'hid', '0005:046D:B00D.0002', parent, [], ['HID_NAME', 'Fancy BT Mouse']) parent = dev self.testbed.add_device( 'power_supply', 'power_supply/hid-00:1f:20:96:33:47-battery', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '30', 'model_name', 'Fancy BT mouse'], []) self.testbed.add_device( 'input', 'input/input22', parent, [], ['ID_INPUT_MOUSE', '1']) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) mousebat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Fancy BT mouse') self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 30) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_bluetooth_keyboard(self): '''bluetooth keyboard battery''' dev = self.testbed.add_device('bluetooth', 'usb2/bluetooth/hci0/hci0:1', None, [], []) parent = dev self.testbed.add_device( 'input', 'input3/event4', parent, [], ['DEVNAME', 'input/event4', 'ID_INPUT_KEYBOARD', '1']) self.testbed.add_device( 'power_supply', 'power_supply/hid-00:22:33:44:55:66-battery', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '40', 'model_name', 'Monster Typist'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) kbdbat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Model'), 'Monster Typist') self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Percentage'), 40) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Type'), UP_DEVICE_KIND_KEYBOARD) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_bluetooth_mouse_with_keyboard(self): '''mouse with a few keys (but not a keyboard)''' dev = self.testbed.add_device('bluetooth', 'usb2/bluetooth/hci0/hci0:1', None, [], []) parent = dev self.testbed.add_device( 'input', 'input3/event3', parent, [], ['DEVNAME', 'input/event3', 'ID_INPUT_KEYBOARD', '1', 'ID_INPUT_MOUSE', '1']) self.testbed.add_device( 'power_supply', 'power_supply/hid-00:22:33:44:55:66-battery', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '40', 'model_name', 'Monster Mouse'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) kbdbat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Model'), 'Monster Mouse') self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Percentage'), 40) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def test_bluetooth_mouse_and_keyboard(self): '''keyboard/mouse combo battery''' dev = self.testbed.add_device('bluetooth', 'usb2/bluetooth/hci0/hci0:1', None, [], []) parent = dev self.testbed.add_device( 'input', 'input3/event3', parent, [], ['DEVNAME', 'input/event3', 'ID_INPUT_MOUSE', '1']) self.testbed.add_device( 'input', 'input3/event4', parent, [], ['DEVNAME', 'input/event4', 'ID_INPUT_KEYBOARD', '1']) self.testbed.add_device( 'power_supply', 'power_supply/hid-00:22:33:44:55:66-battery', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '40', 'model_name', 'Monster Typist Mouse/Keyboard Combo'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) kbdbat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Model'), 'Monster Typist Mouse/Keyboard Combo') self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Percentage'), 40) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(kbdbat0_up, 'Type'), UP_DEVICE_KIND_KEYBOARD) self.assertEqual(self.get_dbus_property('OnBattery'), False) self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE) self.stop_daemon() def _add_bluez_battery_device(self, alias, device_properties, battery_level): if not self.bluez: self.start_bluez() # Add an adapter to both bluez and udev adapter_name = 'hci0' path = self.bluez_obj.AddAdapter(adapter_name, 'my-computer') self.assertEqual(path, '/org/bluez/' + adapter_name) dev = self.testbed.add_device('bluetooth', 'usb2/bluetooth/hci0/hci0:1', None, [], []) # Add a device to bluez address = '11:22:33:44:AA:BB' path = self.bluez_obj.AddDevice(adapter_name, address, alias) device = self.dbus_con.get_object('org.bluez', path) if device_properties: try: # The properties are only installed for umockdev newer than 0.25.0 device.UpdateProperties(DEVICE_IFACE, device_properties) except dbus.exceptions.DBusException: device.AddProperties(DEVICE_IFACE, device_properties) battery_properties = { 'Percentage': dbus.Byte(battery_level, variant_level=1), } device.AddProperties(BATTERY_IFACE, battery_properties) bluez_manager = self.dbus_con.get_object('org.bluez', '/') bluez_manager.EmitSignal(dbusmock.OBJECT_MANAGER_IFACE, 'InterfacesAdded', 'oa{sa{sv}}', [ dbus.ObjectPath(path, variant_level=1), {BATTERY_IFACE: battery_properties}, ]) if not self.daemon: self.start_daemon() # process = subprocess.Popen(['gdbus', 'introspect', '--system', '--dest', 'org.bluez', '--object-path', '/org/bluez/hci0/dev_11_22_33_44_AA_BB']) # Wait for UPower to process the new device time.sleep(0.5) return self.proxy.EnumerateDevices() def test_bluetooth_le_mouse(self): '''Bluetooth LE mouse''' alias = 'Arc Touch Mouse SE' battery_level = 99 device_properties = { 'Appearance': dbus.UInt16(0x03c2, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) mouse_bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'UpdateTime') != 0, True) self.stop_daemon() def test_bluetooth_le_device(self): '''Bluetooth LE Device''' '''See https://gitlab.freedesktop.org/upower/upower/issues/100''' alias = 'Satechi M1 Mouse' battery_level = 99 device_properties = { 'Class': dbus.UInt32(0, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) mouse_bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(mouse_bat0_up, 'Type'), UP_DEVICE_KIND_BLUETOOTH_GENERIC) self.stop_daemon() def test_bluetooth_headphones(self): '''Bluetooth Headphones''' alias = 'WH-1000XM3' battery_level = 99 device_properties = { 'Class': dbus.UInt32(0x240404, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_HEADSET) self.stop_daemon() def test_bluetooth_wireless_earbuds(self): '''Bluetooth Wireless Earbuds''' alias = 'QCY-qs2_R' battery_level = 99 device_properties = { 'Class': dbus.UInt32(0x240418, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_HEADPHONES) self.stop_daemon() def test_bluetooth_phone(self): '''Bluetooth Phone''' alias = 'Phone' battery_level = 99 device_properties = { 'Class': dbus.UInt32(0x5a020c, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_PHONE) self.stop_daemon() def test_bluetooth_computer(self): '''Bluetooth Computer''' alias = 'Computer' battery_level = 99 device_properties = { 'Class': dbus.UInt32(0x6c010c, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_COMPUTER) self.stop_daemon() def test_bluetooth_heart_rate_monitor(self): '''Bluetooth Heart Rate Monitor''' alias = 'Polar H7' battery_level = 99 device_properties = { 'Appearance': dbus.UInt16(0x0341, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) self.assertEqual(len(devs), 1) bat0_up = devs[0] self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), battery_level) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_BLUETOOTH_GENERIC) self.stop_daemon() def test_bluetooth_hidpp_mouse(self): '''Logitech Bluetooth LE mouse with HID++ kernel support''' self.start_bluez() self.start_daemon() udevs = [] # Add Bluetooth LE device alias = 'Logitech Bluetooth Name' battery_level = 99 device_properties = { 'Appearance': dbus.UInt16(0x03c2, variant_level=1) } devs = self._add_bluez_battery_device(alias, device_properties, battery_level) bluez_dev_path = '/org/bluez/hci0/dev_11_22_33_44_AA_BB' self.assertEqual(len(devs), 1) # Add HID++ kernel device parent = self.testbed.add_device('usb', 'pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2', None, [], []) udevs.insert(0, parent) parent = self.testbed.add_device('hid', '0003:046D:C52B.0009', parent, [], []) udevs.insert(0, parent) dev = self.testbed.add_device('hid', '0003:046D:4101.000A', parent, [], []) udevs.insert(0, dev) parent = dev _dev = self.testbed.add_device( 'input', 'input/input22', parent, [], ['DEVNAME', 'input/mouse3', 'ID_INPUT_MOUSE', '1']) udevs.insert(0, _dev) _dev = self.testbed.add_device( 'power_supply', 'power_supply/hidpp_battery_3', parent, ['type', 'Battery', 'scope', 'Device', 'present', '1', 'online', '1', 'status', 'Discharging', 'capacity', '30', 'serial_number', '11:22:33:44:aa:bb', 'model_name', 'Logitech HID++ name'], []) udevs.insert(0, _dev) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) bat0_up = devs[0] # Check we have the Bluetooth name self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Model'), alias) # Check we have the kernel percentage self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Percentage'), 30) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'PowerSupply'), False) self.assertEqual(self.get_dbus_dev_property(bat0_up, 'Type'), UP_DEVICE_KIND_MOUSE) bluez_dev = self.dbus_con.get_object('org.bluez', bluez_dev_path) bluez_dev.UpdateProperties(DEVICE_IFACE, { 'ServicesResolved': dbus.Boolean(False, variant_level=1) }) # Remove device from kernel # process = subprocess.Popen(['find', os.path.join(self.testbed.get_root_dir())]) for path in udevs: self.testbed.uevent(path, 'remove') self.testbed.remove_device(path) # Remove device from bluez bluez_manager = self.dbus_con.get_object('org.bluez', '/') bluez_manager.EmitSignal(dbusmock.OBJECT_MANAGER_IFACE, 'InterfacesRemoved', 'oas', [ dbus.ObjectPath(bluez_dev_path, variant_level=1), [BATTERY_IFACE], ]) adapter = self.dbus_con.get_object('org.bluez', '/org/bluez/hci0') adapter.RemoveDevice(bluez_dev_path) time.sleep(0.5) devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 0) self.stop_daemon() def test_charge_cycles(self): '''Charge cycles''' # one well charged, one low self.testbed.add_device('power_supply', 'BAT0', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '48000000', 'voltage_now', '12000000'], []) self.testbed.add_device('power_supply', 'BAT1', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000', 'cycle_count', '2000'], []) self.testbed.add_device('power_supply', 'BAT2', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000', 'cycle_count', '0'], []) self.testbed.add_device('power_supply', 'BAT3', None, ['type', 'Battery', 'present', '1', 'status', 'Discharging', 'energy_full', '60000000', 'energy_full_design', '80000000', 'energy_now', '1500000', 'voltage_now', '12000000', 'cycle_count', '-1'], []) self.start_daemon() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 4) self.assertEqual(self.get_dbus_dev_property(devs[0], 'ChargeCycles'), -1) self.assertEqual(self.get_dbus_dev_property(devs[1], 'ChargeCycles'), 2000) self.assertEqual(self.get_dbus_dev_property(devs[2], 'ChargeCycles'), -1) self.assertEqual(self.get_dbus_dev_property(devs[3], 'ChargeCycles'), -1) self.stop_daemon() def test_wacom_dongle(self): 'Wacom tablet connected through wireless USB dongle' self.start_daemon() self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-dongle-waiting.device')) time.sleep(0.5) self.assertDevs({}) self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-dongle-active.device')) time.sleep(0.5) self.assertDevs({ 'battery_wacom_battery_11': { 'NativePath': 'wacom_battery_11', 'Model': 'Wacom Intuos5 touch M (WL)', 'Type': UP_DEVICE_KIND_TABLET, 'PowerSupply': False, 'HasHistory': True, 'Online': False, 'Percentage': 19.0, 'IsPresent': True, 'State': UP_DEVICE_STATE_CHARGING, 'IsRechargeable': True, } }) def test_headset_detection(self): 'Detect USB wireless headsets and other audio devices' self.testbed.add_from_file(os.path.join(edir, 'tests/usb-headset.device')) self.start_daemon() self.assertDevs({ 'battery_hidpp_battery_0': { 'NativePath': 'hidpp_battery_0', 'Model': 'G935 Gaming Headset', 'Type': UP_DEVICE_KIND_HEADSET, 'PowerSupply': False, 'HasHistory': True, 'Percentage': 3.0, 'IsPresent': True, 'State': UP_DEVICE_STATE_DISCHARGING, 'IsRechargeable': True, } }) self.stop_daemon() def test_headset_hotplug(self): 'Detect USB headset when hotplugged' self.start_daemon() self.testbed.add_from_file(os.path.join(edir, 'tests/steelseries-headset.device')) card = '/sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1' self.wait_for_mainloop() devs = self.proxy.EnumerateDevices() self.assertEqual(len(devs), 1) headset_up = devs[0] self.assertEqual(self.get_dbus_dev_property(headset_up, 'Type'), UP_DEVICE_KIND_BATTERY) self.testbed.set_property(card, 'SOUND_INITIALIZED', '1') self.testbed.set_property(card, 'SOUND_FORM_FACTOR', 'headset') self.testbed.uevent(card, 'change') self.assertEqual(self.get_dbus_dev_property(headset_up, 'Type'), UP_DEVICE_KIND_HEADSET) self.stop_daemon() def test_headset_wireless_status(self): 'Hide devices when wireless_status is disconnected' self.testbed.add_from_file(os.path.join(edir, 'tests/steelseries-headset.device')) card = '/sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1' self.testbed.set_property(card, 'SOUND_INITIALIZED', '1') self.testbed.set_property(card, 'SOUND_FORM_FACTOR', 'headset') intf = '/sys/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3' self.testbed.set_attribute(intf, 'wireless_status', 'connected') num_devices = 0 self.start_daemon() devs = self.proxy.EnumerateDevices() num_devices = len(devs) self.assertEqual(num_devices, 1) headset_up = devs[0] self.assertEqual(self.get_dbus_dev_property(headset_up, 'Percentage'), 69.0) client = UPowerGlib.Client.new() def device_added_cb(client, device): nonlocal num_devices num_devices += 1 def device_removed_cb(client, path): nonlocal num_devices num_devices -= 1 client.connect('device-added', device_added_cb) client.connect('device-removed', device_removed_cb) self.testbed.set_attribute(intf, 'wireless_status', 'disconnected') self.testbed.uevent(intf, 'change') self.wait_for_mainloop() self.assertEqual(num_devices, 0) self.testbed.set_attribute(intf, 'wireless_status', 'connected') self.testbed.uevent(intf, 'change') self.wait_for_mainloop() self.assertEqual(num_devices, 1) devs = self.proxy.EnumerateDevices() headset_up = devs[0] self.assertEqual(self.get_dbus_dev_property(headset_up, 'Percentage'), 69.0) self.stop_daemon() def test_daemon_restart(self): self.testbed.add_from_file(os.path.join(edir, 'tests/usb-headset.device')) bat = '/sys/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0' self.start_daemon() process = subprocess.Popen([self.upower_path, '-m']) for i in range(10): # Replace daemon self.start_daemon() self.testbed.uevent(bat, 'change') # Check that upower is still running self.assertIsNone(process.returncode) process.terminate() self.stop_daemon() def test_remove(self): 'Test removing when parent ID lookup stops working' self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-dongle-waiting.device')) self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-dongle-active.device')) self.start_daemon() self.assertDevs({ 'battery_wacom_battery_11': {} }) # Destroy sysfs enough to break the parent ID lookup os.unlink(os.path.join(self.testbed.get_root_dir(), 'sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F', 'subsystem')) self.get_dbus_dev_property('/org/freedesktop/UPower/devices/battery_wacom_battery_11', 'State') # This should remove all devices that UPower tracks self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2', 'remove') self.testbed.uevent('/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1', 'remove') self.daemon_log.check_line('No devices with parent /sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1 left', timeout=2) # Ensure the object is really gone from the bus, # the second case could happen if a reference is leaked. self.assertDevs({}) with self.assertRaisesRegex(GLib.Error, 'Object does not exist at path'): self.get_dbus_dev_property('/org/freedesktop/UPower/devices/battery_wacom_battery_11', 'State') self.stop_daemon() def test_wacom_bluetooth(self): 'Wacom tablet connected through wireless USB dongle' self.start_daemon() self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-bluetooth-active.device')) time.sleep(0.5) self.assertDevs({ 'battery_wacom_battery_10': { 'NativePath': 'wacom_battery_10', 'Model': 'Wacom Intuos5 touch M (WL)', 'Type': UP_DEVICE_KIND_TABLET, 'PowerSupply': False, 'HasHistory': True, 'Online': False, 'Percentage': 100.0, 'IsPresent': True, # XXX: This is "Discharging" in sysfs 'State': UP_DEVICE_STATE_FULLY_CHARGED, 'IsRechargeable': True, } }) self.stop_daemon() def test_sibling_priority_no_overwrite(self): 'Test siblings using the fallback device do not overwrite previous guesses' self.start_daemon() self.testbed.add_from_file(os.path.join(edir, 'tests/wacom-pen-digitiser.device')) self.assertDevs({ 'battery_wacom_battery_0': { 'NativePath': 'wacom_battery_0', 'Model': 'Wacom HID 52D5', 'Type': UP_DEVICE_KIND_TABLET, 'PowerSupply': False, 'HasHistory': True, 'Percentage': 100.0, 'IsPresent': True, 'State': UP_DEVICE_STATE_FULLY_CHARGED, 'IsRechargeable': True, } }) self.stop_daemon() def test_ignore_unknown_power_supply_type(self): ''' Ignore devices with unknown power supply type and doesn't look like a charger. ''' # Sample data taken from Fairphone 4, running Linux kernel 4.19 w/ # vendor patches (abbreviated). # Actual battery. battery = self.testbed.add_device('power_supply', 'battery', None, ['capacity', '77', 'charging_enabled', '1', 'health', 'Good', 'present', '1', 'status', 'Charging', 'technology', 'Li-ion', 'type', 'Battery', 'voltage_max', '4400000', 'voltage_now', '4268584'], []) # BMS (should be ignored) bms = self.testbed.add_device('power_supply', 'bms', None, ['type', 'BMS', 'capacity', '77', 'capacity_raw', '7685', 'current_avg', '-1677247', 'current_now', '-1543885', 'power_avg', '29886557', 'power_now', '52842898', 'real_capacity', '77', 'temp', '300', 'voltage_avg', '4322887', 'voltage_max', '4400000', 'voltage_min', '3400000', 'voltage_now', '4298363', 'voltage_ocv', '4102200'], []) # "Charge pump master" (not sure what it is either, should be ignored) charge_pump_master = self.testbed.add_device( 'power_supply', 'charge_pump_master', None, ['chip_version', '3', 'min_icl', '1000000', 'model_name', 'SMB1398_V2', 'parallel_mode', '1', 'parallel_output_mode', '2', 'type', 'Nothing attached'], []) self.start_daemon(warns=True) devs = self.proxy.EnumerateDevices() # Only the battery should be listed, not the BMS or charge pump master. self.assertEqual(len(devs), 1) self.stop_daemon() # # libupower-glib tests (through introspection) # def test_lib_daemon_properties(self): '''library GI: daemon properties''' self.start_daemon() client = UPowerGlib.Client.new() self.assertRegex(client.get_daemon_version(), '^[0-9.]+$') self.assertIn(client.get_lid_is_present(), [False, True]) self.assertIn(client.get_lid_is_closed(), [False, True]) self.assertEqual(client.get_on_battery(), False) self.assertEqual(client.get_critical_action(), 'HybridSleep') self.stop_daemon() def test_lib_up_client_async(self): '''Test up_client_async_new()''' ac = self.testbed.add_device('power_supply', 'AC', None, ['type', 'Mains', 'online', '1'], []) self.start_daemon() def client_new_cb(obj, res): nonlocal ml, client client = UPowerGlib.Client.new_finish(res) self.assertRegex(client.get_daemon_version(), '^[0-9.]+$') ml.quit() def get_devices_cb(obj, res): nonlocal ml, client devs = client.get_devices_finish(res) self.assertEqual(len(devs), 1) ml.quit() client = None ml = GLib.MainLoop() UPowerGlib.Client.new_async(None, client_new_cb) ml.run() # This will crash, see: # https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/305 # client.get_devices_async(None, get_devices_cb) # ml.run() # # Helper methods # @classmethod def _props_to_str(cls, properties): '''Convert a properties dictionary to uevent text representation.''' prop_str = '' if properties: for k, v in properties.items(): prop_str += '%s=%s\n' % (k, v) return prop_str if __name__ == '__main__': try: import gi from gi.repository import GLib from gi.repository import Gio gi.require_version('UPowerGlib', '1.0') from gi.repository import UPowerGlib except ImportError as e: sys.stderr.write('Skipping tests, PyGobject not available for Python 3, or missing GI typelibs: %s\n' % str(e)) sys.exit(77) try: gi.require_version('UMockdev', '1.0') from gi.repository import UMockdev except ImportError: sys.stderr.write('Skipping tests, umockdev not available (https://github.com/martinpitt/umockdev)\n') sys.exit(77) # run ourselves under umockdev if 'umockdev' not in os.environ.get('LD_PRELOAD', ''): os.execvp('umockdev-wrapper', ['umockdev-wrapper'] + sys.argv) unittest.main() 0707010000005D000081A400000000000000000000000166EA481400000330000000000000000000000000000000000000002400000000upower-1.90.6/src/linux/meson.buildidevice_sources = [] if idevice_dep.found() idevice_sources = [ 'up-device-idevice.c', 'up-device-idevice.h', ] endif upshared += { 'linux': static_library('upshared', sources: [ 'up-device-supply.c', 'up-device-supply.h', 'up-device-supply-battery.c', 'up-device-supply-battery.h', 'up-device-hid.c', 'up-device-hid.h', 'up-device-wup.c', 'up-device-wup.h', 'up-device-bluez.c', 'up-device-bluez.h', 'up-input.c', 'up-input.h', 'up-backend.c', 'up-native.c', 'up-enumerator-udev.c', idevice_sources ], c_args: [ '-DG_LOG_DOMAIN="UPower-Linux"' ], dependencies: [ gudev_dep, upowerd_deps, idevice_dep, plist_dep ], build_by_default: false, )} 0707010000005E000081A400000000000000000000000166EA481400001925000000000000000000000000000000000000002A00000000upower-1.90.6/src/linux/output_checker.py#! /usr/bin/env python3 # Copyright © 2020, RedHat Inc. # # 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.1 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 library. If not, see <http://www.gnu.org/licenses/>. # Authors: # Benjamin Berg <bberg@redhat.com> import os import sys import fcntl import io import re import time import threading import select import errno class OutputChecker(object): def __init__(self, out=sys.stdout): self._output = out self._pipe_fd_r, self._pipe_fd_w = os.pipe() self._partial_buf = b'' self._lines_sem = threading.Semaphore() self._lines = [] self._reader_io = io.StringIO() # Just to be sure, shouldn't be a problem even if we didn't set it fcntl.fcntl(self._pipe_fd_r, fcntl.F_SETFL, fcntl.fcntl(self._pipe_fd_r, fcntl.F_GETFL) | os.O_CLOEXEC | os.O_NONBLOCK) fcntl.fcntl(self._pipe_fd_w, fcntl.F_SETFL, fcntl.fcntl(self._pipe_fd_w, fcntl.F_GETFL) | os.O_CLOEXEC) # Start copier thread self._thread = threading.Thread(target=self._copy, daemon=True) self._thread.start() def _copy(self): p = select.poll() p.register(self._pipe_fd_r) while True: try: # Be lazy and wake up occasionally in case _pipe_fd_r became invalid # The reason to do this is because os.read() will *not* return if the # FD is forcefully closed. p.poll(0.1) r = os.read(self._pipe_fd_r, 1024) if not r: os.close(self._pipe_fd_r) self._pipe_fd_r = -1 self._lines_sem.release() return except OSError as e: if e.errno == errno.EWOULDBLOCK: continue # We get a bad file descriptor error when the outside closes the FD if self._pipe_fd_r >= 0: os.close(self._pipe_fd_r) self._pipe_fd_r = -1 self._lines_sem.release() return l = r.split(b'\n') l[0] = self._partial_buf + l[0] self._lines.extend(l[:-1]) self._partial_buf = l[-1] self._lines_sem.release() os.write(self._output.fileno(), r) def check_line_re(self, needle_re, timeout=0, failmsg=None): deadline = time.time() + timeout if isinstance(needle_re, str): needle_re = needle_re.encode('ascii') r = re.compile(needle_re) ret = [] while True: try: l = self._lines.pop(0) except IndexError: # EOF, throw error if self._pipe_fd_r == -1: if failmsg: raise AssertionError("No further messages: " % failmsg) from None else: raise AssertionError('No client waiting for needle %s' % (str(needle_re))) from None # Check if should wake up if not self._lines_sem.acquire(timeout = deadline - time.time()): if failmsg: raise AssertionError(failmsg) from None else: raise AssertionError('Timed out waiting for needle %s (timeout: %0.2f)' % (str(needle_re), timeout)) from None continue ret.append(l) if r.search(l): return ret def check_line(self, needle, timeout=0, failmsg=None): if isinstance(needle, str): needle = needle.encode('ascii') needle_re = re.escape(needle) return self.check_line_re(needle_re, timeout=timeout, failmsg=failmsg) def check_no_line_re(self, needle_re, wait=0, failmsg=None): deadline = time.time() + wait if isinstance(needle_re, str): needle_re = needle_re.encode('ascii') r = re.compile(needle_re) ret = [] while True: try: l = self._lines.pop(0) except IndexError: # EOF, so everything good if self._pipe_fd_r == -1: break # Check if should wake up if not self._lines_sem.acquire(timeout = deadline - time.time()): # Timed out, so everything is good break continue ret.append(l) if r.search(l): if failmsg: raise AssertionError(failmsg) else: raise AssertionError('Found needle %s but shouldn\'t have been there (timeout: %0.2f)' % (str(needle_re), wait)) return ret def check_no_line(self, needle, wait=0, failmsg=None): if isinstance(needle, str): needle = needle.encode('ascii') needle_re = re.escape(needle) return self.check_no_line_re(needle_re, wait=wait, failmsg=failmsg) def clear(self): ret = self._lines self._lines = [] return ret def assert_closed(self, timeout=1): self._thread.join(timeout) if self._thread.is_alive() != False: raise AssertionError("OutputCheck: Write side has not been closed yet!") def force_close(self): fd = self._pipe_fd_r self._pipe_fd_r = -1 if fd >= 0: os.close(fd) self._thread.join() @property def fd(self): return self._pipe_fd_w def writer_attached(self): os.close(self._pipe_fd_w) self._pipe_fd_w = -1 def __del__(self): if self._pipe_fd_r >= 0: os.close(self._pipe_fd_r) self._pipe_fd_r = -1 if self._pipe_fd_w >= 0: os.close(self._pipe_fd_w) self._pipe_fd_w = -1 0707010000005F000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001E00000000upower-1.90.6/src/linux/tests07070100000060000081A400000000000000000000000166EA4814000070CB000000000000000000000000000000000000003300000000upower-1.90.6/src/linux/tests/logitech-g903.deviceP: /devices/pci0000:00/0000:00:14.0/usb1/1-10 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10 E: SUBSYSTEM=usb E: DEVNAME=/dev/bus/usb/001/020 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=46d/c539/3904 E: TYPE=0/0/0 E: BUSNUM=001 E: DEVNUM=020 E: MAJOR=189 E: MINOR=19 E: USEC_INITIALIZED=5276743770 E: ID_BUS=usb E: ID_MODEL=USB_Receiver E: ID_MODEL_ENC=USB\x20Receiver E: ID_MODEL_ID=c539 E: ID_SERIAL=Logitech_USB_Receiver E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=3904 E: ID_USB_MODEL=USB_Receiver E: ID_USB_MODEL_ENC=USB\x20Receiver E: ID_USB_MODEL_ID=c539 E: ID_USB_SERIAL=Logitech_USB_Receiver E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=3904 E: ID_USB_INTERFACES=:030101:030102:030000: E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_MODEL_FROM_DATABASE=Lightspeed Receiver E: ID_PATH=pci-0000:00:14.0-usb-0:10 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10 E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_10 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/c539/3904 E: TYPE=0/0/0 E: INTERFACE=3/1/1 E: MODALIAS=usb:v046DpC539d3904dc00dsc00dp00ic03isc01ip01in00 E: USEC_INITIALIZED=5276761476 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_MODEL_FROM_DATABASE=Lightspeed Receiver P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/0003:046D:C539.0021 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/0003:046D:C539.0021 E: SUBSYSTEM=hid E: DRIVER=logitech-djreceiver E: HID_ID=0003:0000046D:0000C539 E: HID_NAME=Logitech USB Receiver E: HID_PHYS=usb-0000:00:14.0-10/input0 E: HID_UNIQ= E: MODALIAS=hid:b0003g0001v0000046Dp0000C539 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/0003:046D:C539.0021/hidraw/hidraw5 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.0/0003:046D:C539.0021/hidraw/hidraw5 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw5 E: MAJOR=243 E: MINOR=5 E: USEC_INITIALIZED=5276787787 E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_0 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_10_1_0 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/c539/3904 E: TYPE=0/0/0 E: INTERFACE=3/1/2 E: MODALIAS=usb:v046DpC539d3904dc00dsc00dp00ic03isc01ip02in01 E: USEC_INITIALIZED=5276768698 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_MODEL_FROM_DATABASE=Lightspeed Receiver P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/0003:046D:C539.0022 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/0003:046D:C539.0022 E: SUBSYSTEM=hid E: DRIVER=logitech-djreceiver E: HID_ID=0003:0000046D:0000C539 E: HID_NAME=Logitech USB Receiver E: HID_PHYS=usb-0000:00:14.0-10/input1 E: HID_UNIQ= E: MODALIAS=hid:b0003g0001v0000046Dp0000C539 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/0003:046D:C539.0022/hidraw/hidraw6 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/0003:046D:C539.0022/hidraw/hidraw6 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw6 E: MAJOR=243 E: MINOR=6 E: USEC_INITIALIZED=5276795187 E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.1 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_1 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_10_1_1 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/usbmisc/hiddev2 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.1/usbmisc/hiddev2 E: SUBSYSTEM=usbmisc E: DEVNAME=/dev/usb/hiddev2 E: MAJOR=180 E: MINOR=98 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/c539/3904 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v046DpC539d3904dc00dsc00dp00ic03isc00ip00in02 E: USEC_INITIALIZED=5276770147 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_MODEL_FROM_DATABASE=Lightspeed Receiver P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023 E: SUBSYSTEM=hid E: DRIVER=logitech-djreceiver E: HID_ID=0003:0000046D:0000C539 E: HID_NAME=Logitech USB Receiver E: HID_PHYS=usb-0000:00:14.0-10/input2 E: HID_UNIQ= E: MODALIAS=hid:b0003g0001v0000046Dp0000C539 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024 E: SUBSYSTEM=hid E: DRIVER=logitech-hidpp-device E: HID_ID=0003:0000046D:00004067 E: HID_NAME=Logitech G903 E: HID_PHYS=usb-0000:00:14.0-10/input2:1 E: HID_UNIQ=e8-ce-cd-45 E: MODALIAS=hid:b0003g0102v0000046Dp00004067 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/hidraw/hidraw8 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/hidraw/hidraw8 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw8 E: MAJOR=243 E: MINOR=8 E: USEC_INITIALIZED=5276841631 E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50 E: SUBSYSTEM=input E: PRODUCT=3/46d/4067/111 E: NAME="Logitech G903" E: PHYS="usb-0000:00:14.0-10/input2:1" E: UNIQ="e8-ce-cd-45" E: PROP=0 E: EV=120017 E: KEY=ffff0000 1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe E: REL=1943 E: MSC=10 E: LED=1f E: MODALIAS=input:b0003v046Dp4067e0111-e0,1,2,4,11,14,k71,72,73,74,75,77,79,7A,7B,7C,7D,7E,7F,80,81,82,83,84,85,86,87,88,89,8A,8C,8E,96,98,9E,9F,A1,A3,A4,A5,A6,AD,B0,B1,B2,B3,B4,B7,B8,B9,BA,BB,BC,BD,BE,BF,C0,C1,C2,F0,110,111,112,113,114,115,116,117,118,119,11A,11B,11C,11D,11E,11F,r0,1,6,8,B,C,am4,l0,1,2,3,4,sfw E: USEC_INITIALIZED=5276827691 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_BUS=usb E: ID_MODEL=USB_Receiver E: ID_MODEL_ENC=USB\x20Receiver E: ID_MODEL_ID=c539 E: ID_SERIAL=Logitech_USB_Receiver E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=3904 E: ID_TYPE=hid E: ID_USB_MODEL=USB_Receiver E: ID_USB_MODEL_ENC=USB\x20Receiver E: ID_USB_MODEL_ID=c539 E: ID_USB_SERIAL=Logitech_USB_Receiver E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=3904 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030101:030102:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: A: uniq=e8-ce-cd-45\n P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/event13 S: input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse S: input/by-path/pci-0000:00:14.0-usb-0:10:1.2-event-mouse E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/event13 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event13 E: MAJOR=13 E: MINOR=77 E: USEC_INITIALIZED=5276881026 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_BUS=usb E: ID_MODEL=USB_Receiver E: ID_MODEL_ENC=USB\x20Receiver E: ID_MODEL_ID=c539 E: ID_SERIAL=Logitech_USB_Receiver E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=3904 E: ID_TYPE=hid E: ID_USB_MODEL=USB_Receiver E: ID_USB_MODEL_ENC=USB\x20Receiver E: ID_USB_MODEL_ID=c539 E: ID_USB_SERIAL=Logitech_USB_Receiver E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=3904 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030101:030102:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: LIBINPUT_DEVICE_GROUP=3/46d/4067:usb-0000:00:14.0-10 E: DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:10:1.2-event-mouse E: TAGS=:power-switch: E: CURRENT_TAGS=:power-switch: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::capslock E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::capslock E: SUBSYSTEM=leds E: USEC_INITIALIZED=5276832373 E: NVME_HOST_IFACE=none E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=leds-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::compose E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::compose E: SUBSYSTEM=leds E: USEC_INITIALIZED=5276832198 E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=leds-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::kana E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::kana E: SUBSYSTEM=leds E: USEC_INITIALIZED=5276836962 E: NVME_HOST_IFACE=none E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=leds-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::numlock E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::numlock E: SUBSYSTEM=leds E: USEC_INITIALIZED=5276832097 E: NVME_HOST_IFACE=none E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=leds-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::scrolllock E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/input50::scrolllock E: SUBSYSTEM=leds E: USEC_INITIALIZED=5276832342 E: NVME_HOST_IFACE=none E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=leds-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/mouse1 S: input/by-path/pci-0000:00:14.0-usb-0:10:1.2-mouse S: input/by-id/usb-Logitech_USB_Receiver-if02-mouse E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/input/input50/mouse1 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse1 E: MAJOR=13 E: MINOR=33 E: USEC_INITIALIZED=5276846840 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_BUS=usb E: ID_MODEL=USB_Receiver E: ID_MODEL_ENC=USB\x20Receiver E: ID_MODEL_ID=c539 E: ID_SERIAL=Logitech_USB_Receiver E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=3904 E: ID_TYPE=hid E: ID_USB_MODEL=USB_Receiver E: ID_USB_MODEL_ENC=USB\x20Receiver E: ID_USB_MODEL_ID=c539 E: ID_USB_SERIAL=Logitech_USB_Receiver E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=3904 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030101:030102:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: DEVLINKS=/dev/input/by-path/pci-0000:00:14.0-usb-0:10:1.2-mouse /dev/input/by-id/usb-Logitech_USB_Receiver-if02-mouse P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=hidpp_battery_5 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_ONLINE=0 E: POWER_SUPPLY_STATUS=Unknown E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_MODEL_NAME=G903 WiLogitech G903 WiLogitech E: POWER_SUPPLY_MANUFACTURER=Logitech E: POWER_SUPPLY_SERIAL_NUMBER=e8-ce-cd-45 E: POWER_SUPPLY_CAPACITY=100 E: POWER_SUPPLY_VOLTAGE_NOW=4159000 E: USEC_INITIALIZED=5353378239 E: NVME_HOST_IFACE=none A: type=Battery\n A: model_name=G903 Logitech Unifying\n A: status=Unknown\n A: scope=Device\n A: capacity=0\n P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5/hwmon5 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5/hwmon5 E: SUBSYSTEM=hwmon P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5/wakeup35 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/0003:046D:4067.0024/power_supply/hidpp_battery_5/wakeup35 E: SUBSYSTEM=wakeup P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/hidraw/hidraw7 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:046D:C539.0023/hidraw/hidraw7 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw7 E: MAJOR=243 E: MINOR=7 E: USEC_INITIALIZED=5276796478 E: ID_PATH=pci-0000:00:14.0-usb-0:10:1.2 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_10_1_2 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_10_1_2 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/usbmisc/hiddev3 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/usbmisc/hiddev3 E: SUBSYSTEM=usbmisc E: DEVNAME=/dev/usb/hiddev3 E: MAJOR=180 E: MINOR=99 P: /devices/pci0000:00/0000:00:14.0/usb1/1-10/wakeup/wakeup34 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-10/wakeup/wakeup34 E: SUBSYSTEM=wakeup P: /devices/pci0000:00/0000:00:14.0/usb1/1-8 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8 E: SUBSYSTEM=usb E: DEVNAME=/dev/bus/usb/001/022 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=46d/c086/702 E: TYPE=0/0/0 E: BUSNUM=001 E: DEVNUM=022 E: MAJOR=189 E: MINOR=21 E: USEC_INITIALIZED=5364687992 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_INTERFACES=:030102:030000: E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_PATH=pci-0000:00:14.0-usb-0:8 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8 E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_8 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/c086/702 E: TYPE=0/0/0 E: INTERFACE=3/1/2 E: MODALIAS=usb:v046DpC086d0702dc00dsc00dp00ic03isc01ip02in00 E: USEC_INITIALIZED=5364706614 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027 E: SUBSYSTEM=hid E: DRIVER=logitech-hidpp-device E: HID_ID=0003:0000046D:0000C086 E: HID_NAME=Logitech Logitech G903 Wired/Wireless Gaming Mouse E: HID_PHYS=usb-0000:00:14.0-8/input0 E: HID_UNIQ=017C385C3837 E: MODALIAS=hid:b0003g0001v0000046Dp0000C086 P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/hidraw/hidraw9 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/hidraw/hidraw9 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw9 E: MAJOR=243 E: MINOR=9 E: USEC_INITIALIZED=5364742565 E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_8_1_0 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53 E: SUBSYSTEM=input E: PRODUCT=3/46d/c086/111 E: NAME="Logitech Logitech G903 Wired/Wireless Gaming Mouse" E: PHYS="usb-0000:00:14.0-8/input0" E: UNIQ="017C385C3837" E: PROP=0 E: EV=17 E: KEY=ffff0000 0 0 0 0 E: REL=1943 E: MSC=10 E: MODALIAS=input:b0003v046DpC086e0111-e0,1,2,4,k110,111,112,113,114,115,116,117,118,119,11A,11B,11C,11D,11E,11F,r0,1,6,8,B,C,am4,lsfw E: USEC_INITIALIZED=5364715762 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_TYPE=hid E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030102:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_8_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53/event14 S: input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-event-mouse S: input/by-path/pci-0000:00:14.0-usb-0:8:1.0-event-mouse E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53/event14 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event14 E: MAJOR=13 E: MINOR=78 E: USEC_INITIALIZED=5364823612 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_TYPE=hid E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030102:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: LIBINPUT_DEVICE_GROUP=3/46d/c086:usb-0000:00:14.0-8 E: DEVLINKS=/dev/input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-event-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:8:1.0-event-mouse P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53/mouse2 S: input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-mouse S: input/by-path/pci-0000:00:14.0-usb-0:8:1.0-mouse E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/0003:046D:C086.0027/input/input53/mouse2 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse2 E: MAJOR=13 E: MINOR=34 E: USEC_INITIALIZED=5364733642 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_TYPE=hid E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030102:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: DEVLINKS=/dev/input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:8:1.0-mouse P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/c086/702 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v046DpC086d0702dc00dsc00dp00ic03isc00ip00in01 E: USEC_INITIALIZED=5364711433 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028 E: SUBSYSTEM=hid E: DRIVER=logitech-hidpp-device E: HID_ID=0003:0000046D:0000C086 E: HID_NAME=Logitech G903 WiLogitech G903 Wired/Wirel E: HID_PHYS=usb-0000:00:14.0-8/input1 E: HID_UNIQ=e8-ce-cd-45 E: MODALIAS=hid:b0003g0001v0000046Dp0000C086 P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/hidraw/hidraw11 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/hidraw/hidraw11 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw11 E: MAJOR=243 E: MINOR=11 E: USEC_INITIALIZED=5364743407 E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.1 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_1 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_8_1_1 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/input/input54 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/input/input54 E: SUBSYSTEM=input E: PRODUCT=3/46d/c086/111 E: NAME="Logitech G903 WiLogitech G903 Wired/Wirel" E: PHYS="usb-0000:00:14.0-8/input1" E: UNIQ="e8-ce-cd-45" E: PROP=0 E: EV=10001f E: KEY=33eff 0 0 483ffff17aff32d bfd4444600000000 1 130ff38b17c007 ffe77bfad941dfff febeffdfffefffff fffffffffffffffe E: REL=1040 E: ABS=100000000 E: MSC=10 E: MODALIAS=input:b0003v046DpC086e0111-e0,1,2,3,4,14,k71,72,73,74,75,77,79,7A,7B,7C,7D,7E,7F,80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8E,8F,90,96,98,9B,9C,9E,9F,A1,A3,A4,A5,A6,A7,A8,A9,AB,AC,AD,AE,B0,B1,B2,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF,C0,C1,C2,CE,CF,D0,D1,D2,D4,D8,D9,DB,DF,E0,E1,E4,E5,E6,E7,E8,E9,EA,EB,F0,F1,F4,100,161,162,166,16A,16E,172,174,176,177,178,179,17A,17B,17C,17D,17F,180,182,183,185,188,189,18C,18D,18E,18F,190,191,192,193,195,197,198,199,19A,19C,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA,1AB,1AC,1AD,1AE,1AF,1B0,1B1,1B7,1BA,240,241,242,243,244,245,246,247,249,24A,24B,24C,24D,250,251,r6,C,a20,m4,lsfw E: USEC_INITIALIZED=5364721175 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_TYPE=hid E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030102:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.1 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_1 E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_8_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: A: uniq=e8-ce-cd-45\n P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/input/input54/event16 S: input/by-path/pci-0000:00:14.0-usb-0:8:1.1-event-kbd S: input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-if01-event-kbd E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/input/input54/event16 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event16 E: MAJOR=13 E: MINOR=80 E: USEC_INITIALIZED=5364770101 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_BUS=usb E: ID_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_MODEL_ID=c086 E: ID_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_SERIAL_SHORT=017C385C3837 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0702 E: ID_TYPE=hid E: ID_USB_MODEL=Logitech_G903_Wired_Wireless_Gaming_Mouse E: ID_USB_MODEL_ENC=Logitech\x20G903\x20Wired\x2fWireless\x20Gaming\x20Mouse E: ID_USB_MODEL_ID=c086 E: ID_USB_SERIAL=Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837 E: ID_USB_SERIAL_SHORT=017C385C3837 E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0702 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:030102:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.1 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_1 E: LIBINPUT_DEVICE_GROUP=3/46d/c086:usb-0000:00:14.0-8 E: DEVLINKS=/dev/input/by-path/pci-0000:00:14.0-usb-0:8:1.1-event-kbd /dev/input/by-id/usb-Logitech_Logitech_G903_Wired_Wireless_Gaming_Mouse_017C385C3837-if01-event-kbd E: TAGS=:power-switch: E: CURRENT_TAGS=:power-switch: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=hidpp_battery_6 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_ONLINE=1 E: POWER_SUPPLY_STATUS=Charging E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_MODEL_NAME=G903 WiLogitech G903 Wiing Mouse E: POWER_SUPPLY_MANUFACTURER=Logitech E: POWER_SUPPLY_SERIAL_NUMBER= E: POWER_SUPPLY_CAPACITY=99 E: POWER_SUPPLY_VOLTAGE_NOW=4159000 E: USEC_INITIALIZED=5364847363 E: NVME_HOST_IFACE=none A: type=Battery\n A: model_name=G903 Logitech USB\n A: status=Charging\n A: scope=Device\n A: capacity=3\n P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6/hwmon7 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6/hwmon7 E: SUBSYSTEM=hwmon P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6/wakeup37 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/0003:046D:C086.0028/power_supply/hidpp_battery_6/wakeup37 E: SUBSYSTEM=wakeup P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/usbmisc/hiddev4 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1/usbmisc/hiddev4 E: SUBSYSTEM=usbmisc E: DEVNAME=/dev/usb/hiddev4 E: MAJOR=180 E: MINOR=100 07070100000061000081A400000000000000000000000166EA481400002543000000000000000000000000000000000000003900000000upower-1.90.6/src/linux/tests/steelseries-headset.deviceP: /devices/pci0000:00/0000:00:14.0/usb1/1-5 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5 E: SUBSYSTEM=usb E: DEVNAME=/dev/bus/usb/001/040 E: DEVTYPE=usb_device E: PRODUCT=1038/12b6/107 E: TYPE=0/0/0 E: BUSNUM=001 E: DEVNUM=040 E: SEQNUM=8781 E: USEC_INITIALIZED=142325092265 E: ID_BUS=usb E: ID_MODEL=SteelSeries_Arctis_1_Wireless E: ID_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_MODEL_ID=12b6 E: ID_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_VENDOR=SteelSeries E: ID_VENDOR_ENC=SteelSeries E: ID_VENDOR_ID=1038 E: ID_REVISION=0107 E: ID_USB_MODEL=SteelSeries_Arctis_1_Wireless E: ID_USB_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_USB_MODEL_ID=12b6 E: ID_USB_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_USB_VENDOR=SteelSeries E: ID_USB_VENDOR_ENC=SteelSeries E: ID_USB_VENDOR_ID=1038 E: ID_USB_REVISION=0107 E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_VENDOR_FROM_DATABASE=SteelSeries ApS E: DRIVER=usb E: ID_PATH=pci-0000:00:14.0-usb-0:5 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5 E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_5 E: MAJOR=189 E: MINOR=39 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: PRODUCT=1038/12b6/107 E: TYPE=0/0/0 E: INTERFACE=1/1/0 E: MODALIAS=usb:v1038p12B6d0107dc00dsc00dp00ic01isc01ip00in00 E: SEQNUM=8782 E: USEC_INITIALIZED=142325114275 E: ID_VENDOR_FROM_DATABASE=SteelSeries ApS E: DRIVER=snd-usb-audio P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.1 (usb) E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.1 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=snd-usb-audio E: PRODUCT=1038/12b6/107 E: TYPE=0/0/0 E: INTERFACE=1/2/0 E: MODALIAS=usb:v1038p12B6d0107dc00dsc00dp00ic01isc02ip00in01 E: SEQNUM=8788 E: USEC_INITIALIZED=142325118299 E: ID_VENDOR_FROM_DATABASE=SteelSeries ApS P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1 E: SUBSYSTEM=sound E: SEQNUM=8783 E: USEC_INITIALIZED=142325120356 E: ID_PATH=pci-0000:00:14.0-usb-0:5:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_0 E: ID_FOR_SEAT=sound-pci-0000_00_14_0-usb-0_5_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.2 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.2 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=snd-usb-audio E: PRODUCT=1038/12b6/107 E: TYPE=0/0/0 E: INTERFACE=1/2/0 E: MODALIAS=usb:v1038p12B6d0107dc00dsc00dp00ic01isc02ip00in02 E: SEQNUM=8790 E: USEC_INITIALIZED=142325120775 E: ID_VENDOR_FROM_DATABASE=SteelSeries ApS P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: PRODUCT=1038/12b6/107 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v1038p12B6d0107dc00dsc00dp00ic03isc00ip00in03 E: SEQNUM=8792 E: USEC_INITIALIZED=142325122585 E: ID_VENDOR_FROM_DATABASE=SteelSeries ApS E: DRIVER=usbhid P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027 E: SUBSYSTEM=hid E: HID_ID=0003:00001038:000012B6 E: HID_NAME=SteelSeries SteelSeries Arctis 1 Wireless E: HID_PHYS=usb-0000:00:14.0-5/input3 E: HID_UNIQ= E: MODALIAS=hid:b0003g0001v00001038p000012B6 E: SEQNUM=8793 E: USEC_INITIALIZED=142325130800 E: DRIVER=steelseries P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/pcmC1D0p E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/pcmC1D0p E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/pcmC1D0p E: DEVTYPE=pcm E: SEQNUM=8784 E: USEC_INITIALIZED=142325130818 E: MAJOR=116 E: MINOR=2 E: TAGS=:uaccess: E: CURRENT_TAGS=:uaccess: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/pcmC1D0c E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/pcmC1D0c E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/pcmC1D0c E: DEVTYPE=pcm E: SEQNUM=8785 E: USEC_INITIALIZED=142325138081 E: MAJOR=116 E: MINOR=3 E: TAGS=:uaccess: E: CURRENT_TAGS=:uaccess: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/usbmisc/hiddev1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/usbmisc/hiddev1 E: SUBSYSTEM=usbmisc E: DEVNAME=/dev/usb/hiddev1 E: SEQNUM=8796 E: USEC_INITIALIZED=142325138795 E: MAJOR=180 E: MINOR=97 P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/input/input65 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/input/input65 E: SUBSYSTEM=input E: PRODUCT=3/1038/12b6/111 E: NAME="SteelSeries SteelSeries Arctis 1 Wireless" E: PHYS="usb-0000:00:14.0-5/input3" E: UNIQ="" E: PROP=0 E: EV=1b E: KEY=3800000000 c000000000000 0 E: ABS=10000000000 E: MSC=10 E: MODALIAS=input:b0003v1038p12B6e0111-e0,1,3,4,k72,73,A3,A4,A5,ra28,m4,lsfw E: SEQNUM=8794 E: USEC_INITIALIZED=142325141154 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_BUS=usb E: ID_MODEL=SteelSeries_Arctis_1_Wireless E: ID_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_MODEL_ID=12b6 E: ID_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_VENDOR=SteelSeries E: ID_VENDOR_ENC=SteelSeries E: ID_VENDOR_ID=1038 E: ID_REVISION=0107 E: ID_TYPE=hid E: ID_USB_MODEL=SteelSeries_Arctis_1_Wireless E: ID_USB_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_USB_MODEL_ID=12b6 E: ID_USB_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_USB_VENDOR=SteelSeries E: ID_USB_VENDOR_ENC=SteelSeries E: ID_USB_VENDOR_ID=1038 E: ID_USB_REVISION=0107 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=03 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:5:1.3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_3 E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_5_1_3 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/controlC1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.0/sound/card1/controlC1 E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/controlC1 E: SEQNUM=8786 E: USEC_INITIALIZED=142325143213 E: ID_BUS=usb E: ID_MODEL=SteelSeries_Arctis_1_Wireless E: ID_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_MODEL_ID=12b6 E: ID_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_VENDOR=SteelSeries E: ID_VENDOR_ENC=SteelSeries E: ID_VENDOR_ID=1038 E: ID_REVISION=0107 E: ID_TYPE=audio E: ID_USB_MODEL=SteelSeries_Arctis_1_Wireless E: ID_USB_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_USB_MODEL_ID=12b6 E: ID_USB_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_USB_VENDOR=SteelSeries E: ID_USB_VENDOR_ENC=SteelSeries E: ID_USB_VENDOR_ID=1038 E: ID_USB_REVISION=0107 E: ID_USB_TYPE=audio E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=snd-usb-audio E: ID_PATH=pci-0000:00:14.0-usb-0:5:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_0 E: SYSTEMD_WANTS=sound.target E: SYSTEMD_USER_WANTS=sound.target E: MAJOR=116 E: MINOR=4 E: DEVLINKS=/dev/snd/by-id/usb-SteelSeries_SteelSeries_Arctis_1_Wireless-00 /dev/snd/by-path/pci-0000:00:14.0-usb-0:5:1.0 E: TAGS=:uaccess:systemd: E: CURRENT_TAGS=:uaccess:systemd: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/hidraw/hidraw0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/hidraw/hidraw0 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw0 E: SEQNUM=8797 E: USEC_INITIALIZED=142325174785 E: MAJOR=243 E: MINOR=0 P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/input/input65/event3 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/input/input65/event3 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event3 E: SEQNUM=8795 E: USEC_INITIALIZED=142325216894 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_BUS=usb E: ID_MODEL=SteelSeries_Arctis_1_Wireless E: ID_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_MODEL_ID=12b6 E: ID_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_VENDOR=SteelSeries E: ID_VENDOR_ENC=SteelSeries E: ID_VENDOR_ID=1038 E: ID_REVISION=0107 E: ID_TYPE=hid E: ID_USB_MODEL=SteelSeries_Arctis_1_Wireless E: ID_USB_MODEL_ENC=SteelSeries\x20Arctis\x201\x20Wireless E: ID_USB_MODEL_ID=12b6 E: ID_USB_SERIAL=SteelSeries_SteelSeries_Arctis_1_Wireless E: ID_USB_VENDOR=SteelSeries E: ID_USB_VENDOR_ENC=SteelSeries E: ID_USB_VENDOR_ID=1038 E: ID_USB_REVISION=0107 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=03 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:5:1.3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_3 E: LIBINPUT_DEVICE_GROUP=3/1038/12b6:usb-0000:00:14.0-5 E: MAJOR=13 E: MINOR=67 E: DEVLINKS=/dev/input/by-id/usb-SteelSeries_SteelSeries_Arctis_1_Wireless-event-if03 /dev/input/by-path/pci-0000:00:14.0-usb-0:5:1.3-event E: TAGS=:power-switch: E: CURRENT_TAGS=:power-switch: P: /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/power_supply/steelseries_headset_battery_0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:1038:12B6.0027/power_supply/steelseries_headset_battery_0 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=steelseries_headset_battery_0 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_PRESENT=1 E: POWER_SUPPLY_STATUS=Unknown E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_CAPACITY=100 E: USEC_INITIALIZED=203905231 E: NVME_HOST_IFACE=none A: type=Battery\n A: status=Discharging\n A: scope=Device\n A: capacity=69\n A: present=1\n 07070100000062000081A400000000000000000000000166EA48140000299F000000000000000000000000000000000000003100000000upower-1.90.6/src/linux/tests/usb-headset.deviceP: /devices/pci0000:00/0000:00:14.0/usb1/1-8 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8 E: SUBSYSTEM=usb E: DEVNAME=/dev/bus/usb/001/005 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=46d/a87/112 E: TYPE=0/0/0 E: BUSNUM=001 E: DEVNUM=005 E: MAJOR=189 E: MINOR=4 E: USEC_INITIALIZED=11086369 E: ID_BUS=usb E: ID_MODEL=G935_Gaming_Headset E: ID_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_MODEL_ID=0a87 E: ID_SERIAL=Logitech_G935_Gaming_Headset E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0112 E: ID_USB_MODEL=G935_Gaming_Headset E: ID_USB_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_USB_MODEL_ID=0a87 E: ID_USB_SERIAL=Logitech_G935_Gaming_Headset E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0112 E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_PATH=pci-0000:00:14.0-usb-0:8 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8 E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_8 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=snd-usb-audio E: PRODUCT=46d/a87/112 E: TYPE=0/0/0 E: INTERFACE=1/1/0 E: MODALIAS=usb:v046Dp0A87d0112dc00dsc00dp00ic01isc01ip00in00 E: USEC_INITIALIZED=11136922 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0 E: SUBSYSTEM=sound E: USEC_INITIALIZED=11967897 E: NVME_HOST_IFACE=none E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: ID_FOR_SEAT=sound-pci-0000_00_14_0-usb-0_8_1_0 E: SOUND_INITIALIZED=1 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_BUS=usb E: ID_MODEL=G935_Gaming_Headset E: ID_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_MODEL_ID=0a87 E: ID_SERIAL=Logitech_G935_Gaming_Headset E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0112 E: ID_TYPE=audio E: ID_USB_MODEL=G935_Gaming_Headset E: ID_USB_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_USB_MODEL_ID=0a87 E: ID_USB_SERIAL=Logitech_G935_Gaming_Headset E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0112 E: ID_USB_TYPE=audio E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=snd-usb-audio E: ID_ID=usb-Logitech_G935_Gaming_Headset-00 E: SOUND_FORM_FACTOR=headset E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/controlC0 S: snd/by-id/usb-Logitech_G935_Gaming_Headset-00 S: snd/by-path/pci-0000:00:14.0-usb-0:8:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/controlC0 E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/controlC0 E: MAJOR=116 E: MINOR=4 E: USEC_INITIALIZED=11978600 E: ID_BUS=usb E: ID_MODEL=G935_Gaming_Headset E: ID_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_MODEL_ID=0a87 E: ID_SERIAL=Logitech_G935_Gaming_Headset E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0112 E: ID_TYPE=audio E: ID_USB_MODEL=G935_Gaming_Headset E: ID_USB_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_USB_MODEL_ID=0a87 E: ID_USB_SERIAL=Logitech_G935_Gaming_Headset E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0112 E: ID_USB_TYPE=audio E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_USB_DRIVER=snd-usb-audio E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_0 E: SYSTEMD_WANTS=sound.target E: SYSTEMD_USER_WANTS=sound.target E: DEVLINKS=/dev/snd/by-id/usb-Logitech_G935_Gaming_Headset-00 /dev/snd/by-path/pci-0000:00:14.0-usb-0:8:1.0 E: TAGS=:systemd:uaccess: E: CURRENT_TAGS=:systemd:uaccess: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/pcmC0D0c E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/pcmC0D0c E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/pcmC0D0c E: DEVTYPE=pcm E: MAJOR=116 E: MINOR=3 E: USEC_INITIALIZED=11976269 E: TAGS=:uaccess: E: CURRENT_TAGS=:uaccess: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/pcmC0D0p E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/sound/card0/pcmC0D0p E: SUBSYSTEM=sound E: DEVNAME=/dev/snd/pcmC0D0p E: DEVTYPE=pcm E: MAJOR=116 E: MINOR=2 E: USEC_INITIALIZED=11973216 E: TAGS=:uaccess: E: CURRENT_TAGS=:uaccess: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.1 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=snd-usb-audio E: PRODUCT=46d/a87/112 E: TYPE=0/0/0 E: INTERFACE=1/2/0 E: MODALIAS=usb:v046Dp0A87d0112dc00dsc00dp00ic01isc02ip00in01 E: USEC_INITIALIZED=11141119 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.2 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.2 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=snd-usb-audio E: PRODUCT=46d/a87/112 E: TYPE=0/0/0 E: INTERFACE=1/2/0 E: MODALIAS=usb:v046Dp0A87d0112dc00dsc00dp00ic01isc02ip00in02 E: USEC_INITIALIZED=11144379 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=46d/a87/112 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v046Dp0A87d0112dc00dsc00dp00ic03isc00ip00in03 E: USEC_INITIALIZED=11125344 E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: NVME_HOST_IFACE=none P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004 E: SUBSYSTEM=hid E: DRIVER=logitech-hidpp-device E: HID_ID=0003:0000046D:00000A87 E: HID_NAME=Logitech G935 Gaming Headset E: HID_PHYS=usb-0000:00:14.0-8/input3 E: HID_UNIQ= E: MODALIAS=hid:b0003g0001v0000046Dp00000A87 P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/hidraw/hidraw3 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/hidraw/hidraw3 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw3 E: MAJOR=243 E: MINOR=3 E: USEC_INITIALIZED=11206489 E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_3 E: ID_FOR_SEAT=hidraw-pci-0000_00_14_0-usb-0_8_1_3 E: TAGS=:uaccess:seat: E: CURRENT_TAGS=:uaccess:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/input/input12 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/input/input12 E: SUBSYSTEM=input E: PRODUCT=3/46d/a87/111 E: NAME="Logitech G935 Gaming Headset" E: PHYS="usb-0000:00:14.0-8/input3" E: UNIQ="" E: PROP=0 E: EV=1b E: KEY=100000000000000 0 c000000000000 0 E: ABS=10000000000 E: MSC=10 E: MODALIAS=input:b0003v046Dp0A87e0111-e0,1,3,4,k72,73,F8,ra28,m4,lsfw E: USEC_INITIALIZED=11174082 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_BUS=usb E: ID_MODEL=G935_Gaming_Headset E: ID_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_MODEL_ID=0a87 E: ID_SERIAL=Logitech_G935_Gaming_Headset E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0112 E: ID_TYPE=hid E: ID_USB_MODEL=G935_Gaming_Headset E: ID_USB_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_USB_MODEL_ID=0a87 E: ID_USB_SERIAL=Logitech_G935_Gaming_Headset E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0112 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=03 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_3 E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_8_1_3 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/input/input12/event7 S: input/by-path/pci-0000:00:14.0-usb-0:8:1.3-event S: input/by-id/usb-Logitech_G935_Gaming_Headset-event-if03 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/input/input12/event7 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event7 E: MAJOR=13 E: MINOR=71 E: USEC_INITIALIZED=11421774 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_BUS=usb E: ID_MODEL=G935_Gaming_Headset E: ID_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_MODEL_ID=0a87 E: ID_SERIAL=Logitech_G935_Gaming_Headset E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: ID_REVISION=0112 E: ID_TYPE=hid E: ID_USB_MODEL=G935_Gaming_Headset E: ID_USB_MODEL_ENC=G935\x20Gaming\x20Headset E: ID_USB_MODEL_ID=0a87 E: ID_USB_SERIAL=Logitech_G935_Gaming_Headset E: ID_USB_VENDOR=Logitech E: ID_USB_VENDOR_ENC=Logitech E: ID_USB_VENDOR_ID=046d E: ID_USB_REVISION=0112 E: ID_USB_TYPE=hid E: ID_USB_INTERFACES=:010100:010200:030000: E: ID_USB_INTERFACE_NUM=03 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:14.0-usb-0:8:1.3 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_8_1_3 E: LIBINPUT_DEVICE_GROUP=3/46d/a87:usb-0000:00:14.0-8 E: DEVLINKS=/dev/input/by-path/pci-0000:00:14.0-usb-0:8:1.3-event /dev/input/by-id/usb-Logitech_G935_Gaming_Headset-event-if03 E: TAGS=:power-switch: E: CURRENT_TAGS=:power-switch: P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=hidpp_battery_0 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_ONLINE=1 E: POWER_SUPPLY_STATUS=Discharging E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_MODEL_NAME=G935 Gaming Headset E: POWER_SUPPLY_MANUFACTURER=Logitech E: POWER_SUPPLY_SERIAL_NUMBER= E: POWER_SUPPLY_CAPACITY=3 E: POWER_SUPPLY_VOLTAGE_NOW=3468000 E: USEC_INITIALIZED=49310511 E: NVME_HOST_IFACE=none A: type=Battery\n A: model_name=G935 Gaming Headset\n A: status=Discharging\n A: scope=Device\n A: capacity=3\n P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0/hwmon1 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0/hwmon1 E: SUBSYSTEM=hwmon P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0/wakeup25 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/0003:046D:0A87.0004/power_supply/hidpp_battery_0/wakeup25 E: SUBSYSTEM=wakeup P: /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/usbmisc/hiddev2 E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.3/usbmisc/hiddev2 E: SUBSYSTEM=usbmisc E: DEVNAME=/dev/usb/hiddev2 E: MAJOR=180 E: MINOR=98 07070100000063000081A400000000000000000000000166EA481400002803000000000000000000000000000000000000003C00000000upower-1.90.6/src/linux/tests/wacom-bluetooth-active.deviceP: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69 E: SUBSYSTEM=bluetooth E: DEVTYPE=link E: USEC_INITIALIZED=796084718828 E: SYSTEMD_ALIAS=/sys/subsystem/bluetooth/devices/hci0:69 E: SYSTEMD_WANTS=bluetooth.target E: SYSTEMD_USER_WANTS=bluetooth.target E: TAGS=:systemd: E: CURRENT_TAGS=:systemd: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B E: SUBSYSTEM=hid E: DRIVER=wacom E: HID_ID=0005:0000056A:00000360 E: HID_NAME=CL IntuosPro M E: HID_PHYS=00:1b:dc:06:6a:57 E: HID_UNIQ=00:00:00:00:02:06 E: MODALIAS=hid:b0005g0101v0000056Ap00000360 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/hidraw/hidraw0 N: hidraw0 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/hidraw/hidraw0 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw0 E: MAJOR=239 E: MINOR=0 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104 E: SUBSYSTEM=input E: PRODUCT=5/56a/360/0 E: NAME="Wacom Intuos Pro M Pen" E: PHYS="00:1b:dc:06:6a:57" E: UNIQ="00:00:00:00:02:06" E: PROP=1 E: EV=1f E: KEY=1cdf 1f0000 0 0 0 0 E: REL=100 E: ABS=1000f000167 E: MSC=1 E: MODALIAS=input:b0005v056Ap0360e0000-e0,1,2,3,4,k110,111,112,113,114,140,141,142,143,144,146,147,14A,14B,14C,r8,a0,1,2,5,6,8,18,19,1A,1B,28,m0,lsfw E: USEC_INITIALIZED=796085091545 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_BUS=bluetooth E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=input-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104/event27 N: input/event27 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104/event27 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event27 E: MAJOR=13 E: MINOR=91 E: USEC_INITIALIZED=796085135161 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_WIDTH_MM=224 E: ID_INPUT_HEIGHT_MM=148 E: ID_BUS=bluetooth E: LIBINPUT_DEVICE_GROUP=5/56a/360:00:1b:dc:06:6a:57 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104/mouse3 N: input/mouse3 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input104/mouse3 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse3 E: MAJOR=13 E: MINOR=35 E: USEC_INITIALIZED=796085099029 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_BUS=bluetooth P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105 E: SUBSYSTEM=input E: PRODUCT=5/56a/360/0 E: NAME="Wacom Intuos Pro M Finger" E: PHYS="00:1b:dc:06:6a:57" E: UNIQ="00:00:00:00:02:06" E: PROP=1 E: EV=2b E: KEY=e520 0 0 0 0 0 E: ABS=263800000000003 E: SW=4000 E: MODALIAS=input:b0005v056Ap0360e0000-e0,1,3,5,k145,148,14A,14D,14E,14F,ra0,1,2F,30,31,35,36,39,mlsfwE, E: USEC_INITIALIZED=796085094227 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_INPUT_SWITCH=1 E: ID_BUS=bluetooth E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=input-pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_INPUT_TABLET=1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105/event28 N: input/event28 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105/event28 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event28 E: MAJOR=13 E: MINOR=92 E: USEC_INITIALIZED=796085188983 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_INPUT_SWITCH=1 E: ID_INPUT_WIDTH_MM=224 E: ID_INPUT_HEIGHT_MM=148 E: ID_BUS=bluetooth E: ID_INPUT_TABLET=1 E: ID_INPUT_TOUCHPAD_INTEGRATION=external E: LIBINPUT_DEVICE_GROUP=5/56a/360:00:1b:dc:06:6a:57 E: LIBINPUT_FUZZ_35=4 E: LIBINPUT_FUZZ_36=4 E: TAGS=:power-switch: E: CURRENT_TAGS=:power-switch: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105/mouse4 N: input/mouse4 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input105/mouse4 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse4 E: MAJOR=13 E: MINOR=36 E: USEC_INITIALIZED=796085109604 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_INPUT_SWITCH=1 E: ID_BUS=bluetooth P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106 E: SUBSYSTEM=input E: PRODUCT=5/56a/360/0 E: NAME="Wacom Intuos Pro M Pad" E: PHYS="00:1b:dc:06:6a:57" E: UNIQ="00:00:00:00:02:06" E: PROP=0 E: EV=b E: KEY=800 1ff 0 0 0 0 E: ABS=10000000103 E: MODALIAS=input:b0005v056Ap0360e0000-e0,1,3,k100,101,102,103,104,105,106,107,108,14B,ra0,1,8,28,mlsfw E: USEC_INITIALIZED=796085094226 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_BUS=bluetooth E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=input-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/event29 N: input/event29 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/event29 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event29 E: MAJOR=13 E: MINOR=93 E: USEC_INITIALIZED=796085137050 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_BUS=bluetooth E: LIBINPUT_DEVICE_GROUP=5/56a/360:00:1b:dc:06:6a:57 P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.0 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.0 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796085101975 E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=leds-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.1 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.1 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796085110250 E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=leds-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.2 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.2 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796085109511 E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=leds-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.3 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/input106::wacom-0.3 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796085107946 E: ID_PATH=pci-0000:00:1d.0-usb-0:1.3:1.0 E: ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_3_1_0 E: ID_FOR_SEAT=leds-pci-0000_00_1d_0-usb-0_1_3_1_0 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/js4 N: input/js4 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/input/input106/js4 E: SUBSYSTEM=input E: DEVNAME=/dev/input/js4 E: MAJOR=13 E: MINOR=4 E: USEC_INITIALIZED=796085107124 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_BUS=bluetooth P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=wacom_battery_10 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_MODEL_NAME=Wacom Intuos Pro M E: POWER_SUPPLY_PRESENT=1 E: POWER_SUPPLY_STATUS=Discharging E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_CAPACITY=100 A: type=Battery\n A: model_name=Wacom Intuos5 touch M (WL)\n A: present=1\n A: status=Discharging\n A: scope=Device\n A: capacity=100\n P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10/hwmon3 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10/hwmon3 E: SUBSYSTEM=hwmon P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10/wakeup22 E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/hci0:69/0005:056A:0360.001B/power_supply/wacom_battery_10/wakeup22 E: SUBSYSTEM=wakeup 07070100000064000081A400000000000000000000000166EA4814000033D3000000000000000000000000000000000000003900000000upower-1.90.6/src/linux/tests/wacom-dongle-active.deviceP: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=wacom_battery_11 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_MODEL_NAME=Wacom Intuos5 touch M (WL) E: POWER_SUPPLY_PRESENT=1 E: POWER_SUPPLY_STATUS=Charging E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_CAPACITY=19 A: type=Battery\n A: model_name=Wacom Intuos5 touch M (WL)\n A: present=1\n A: status=Charging\n A: scope=Device\n A: capacity=19\n P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11/hwmon3 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11/hwmon3 E: SUBSYSTEM=hwmon P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11/wakeup22 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/power_supply/wacom_battery_11/wakeup22 E: SUBSYSTEM=wakeup P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125 E: SUBSYSTEM=input E: PRODUCT=3/56a/27/100 E: NAME="Wacom Intuos5 touch M (WL) Pen" E: PHYS="usb-0000:00:1a.0-1.1/input1" E: UNIQ="" E: PROP=1 E: EV=1f E: KEY=1cdf 1f0000 0 0 0 0 E: REL=100 E: ABS=1000f000167 E: MSC=1 E: MODALIAS=input:b0003v056Ap0027e0100-e0,1,2,3,4,k110,111,112,113,114,140,141,142,143,144,146,147,14A,14B,14C,r8,a0,1,2,5,6,8,18,19,1A,1B,28,m0,lsfw E: USEC_INITIALIZED=796256700167 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=input-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125/event27 N: input/event27 S: input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-event-mouse S: input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-event-mouse E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125/event27 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event27 E: MAJOR=13 E: MINOR=91 E: USEC_INITIALIZED=796256821585 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_WIDTH_MM=223 E: ID_INPUT_HEIGHT_MM=139 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: LIBINPUT_DEVICE_GROUP=3/56a/27:usb-0000:00:1a.0-1 E: DEVLINKS=/dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-event-mouse /dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-event-mouse P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125/mouse3 N: input/mouse3 S: input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-mouse S: input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-mouse E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input125/mouse3 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse3 E: MAJOR=13 E: MINOR=35 E: USEC_INITIALIZED=796256735599 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: DEVLINKS=/dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-mouse /dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-mouse P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127 E: SUBSYSTEM=input E: PRODUCT=3/56a/27/100 E: NAME="Wacom Intuos5 touch M (WL) Pad" E: PHYS="usb-0000:00:1a.0-1.1/input1" E: UNIQ="" E: PROP=0 E: EV=b E: KEY=800 1ff 0 0 0 0 E: ABS=10000000103 E: MODALIAS=input:b0003v056Ap0027e0100-e0,1,3,k100,101,102,103,104,105,106,107,108,14B,ra0,1,8,28,mlsfw E: USEC_INITIALIZED=796256700525 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=input-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/event28 N: input/event28 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/event28 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event28 E: MAJOR=13 E: MINOR=92 E: USEC_INITIALIZED=796256822568 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: LIBINPUT_DEVICE_GROUP=3/56a/27:usb-0000:00:1a.0-1 E: DEVLINKS=/dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-event-mouse /dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-event-mouse P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.0 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.0 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796256705692 E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=leds-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.1 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.1 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796256706780 E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=leds-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.2 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.2 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796256718088 E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=leds-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.3 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/input127::wacom-0.3 E: SUBSYSTEM=leds E: USEC_INITIALIZED=796256720889 E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: ID_FOR_SEAT=leds-pci-0000_00_1a_0-usb-0_1_1_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/js4 N: input/js4 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/input/input127/js4 E: SUBSYSTEM=input E: DEVNAME=/dev/input/js4 E: MAJOR=13 E: MINOR=4 E: USEC_INITIALIZED=796256732062 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_TABLET_PAD=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=01 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 E: DEVLINKS=/dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if01-mouse /dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.1-mouse P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129 E: SUBSYSTEM=input E: PRODUCT=3/56a/27/100 E: NAME="Wacom Intuos5 touch M (WL) Finger" E: PHYS="usb-0000:00:1a.0-1.1/input2" E: UNIQ="" E: PROP=1 E: EV=b E: KEY=e520 0 0 0 0 0 E: ABS=263800000000003 E: MODALIAS=input:b0003v056Ap0027e0100-e0,1,3,k145,148,14A,14D,14E,14F,ra0,1,2F,30,31,35,36,39,mlsfw E: USEC_INITIALIZED=796256711675 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2 E: ID_FOR_SEAT=input-pci-0000_00_1a_0-usb-0_1_1_1_2 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129/event29 N: input/event29 S: input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2-event-mouse S: input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if02-event-mouse E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129/event29 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event29 E: MAJOR=13 E: MINOR=93 E: USEC_INITIALIZED=796256926202 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_INPUT_WIDTH_MM=227 E: ID_INPUT_HEIGHT_MM=141 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2 E: ID_INPUT_TABLET=1 E: ID_INPUT_TOUCHPAD_INTEGRATION=external E: LIBINPUT_DEVICE_GROUP=3/56a/27:usb-0000:00:1a.0-1 E: LIBINPUT_FUZZ_35=4 E: LIBINPUT_FUZZ_36=4 E: DEVLINKS=/dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2-event-mouse /dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if02-event-mouse P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129/mouse4 N: input/mouse4 S: input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if02-mouse S: input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2-mouse E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/input/input129/mouse4 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse4 E: MAJOR=13 E: MINOR=36 E: USEC_INITIALIZED=796256743786 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_TYPE=hid E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_USB_INTERFACE_NUM=02 E: ID_USB_DRIVER=usbhid E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2 E: DEVLINKS=/dev/input/by-id/usb-Wacom_Co._Ltd._Wacom_Wireless_Receiver-if02-mouse /dev/input/by-path/pci-0000:00:1a.0-usb-0:1.1:1.2-mouse 07070100000065000081A400000000000000000000000166EA481400001193000000000000000000000000000000000000003A00000000upower-1.90.6/src/linux/tests/wacom-dongle-waiting.deviceP: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1 N: bus/usb/001/005 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1 E: SUBSYSTEM=usb E: DEVNAME=/dev/bus/usb/001/005 E: DEVTYPE=usb_device E: DRIVER=usb E: PRODUCT=56a/84/111 E: TYPE=0/0/0 E: BUSNUM=001 E: DEVNUM=005 E: MAJOR=189 E: MINOR=4 E: USEC_INITIALIZED=796229411781 E: ID_VENDOR=Wacom_Co._Ltd. E: ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd. E: ID_VENDOR_ID=056a E: ID_MODEL=Wacom_Wireless_Receiver E: ID_MODEL_ENC=Wacom\x20Wireless\x20Receiver E: ID_MODEL_ID=0084 E: ID_REVISION=0111 E: ID_SERIAL=Wacom_Co._Ltd._Wacom_Wireless_Receiver E: ID_BUS=usb E: ID_USB_INTERFACES=:030000: E: ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd E: ID_MODEL_FROM_DATABASE=ACK-40401 [Wireless Accessory Kit] E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1 E: ID_FOR_SEAT=usb-pci-0000_00_1a_0-usb-0_1_1 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=56a/84/111 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v056Ap0084d0111dc00dsc00dp00ic03isc00ip00in00 E: USEC_INITIALIZED=796229425004 E: ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd E: ID_MODEL_FROM_DATABASE=ACK-40401 [Wireless Accessory Kit] E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.0 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_0 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F E: SUBSYSTEM=hid E: DRIVER=wacom E: HID_ID=0003:0000056A:00000084 E: HID_NAME=Wacom Co.,Ltd. Wacom Wireless Receiver E: HID_PHYS=usb-0000:00:1a.0-1.1/input0 E: HID_UNIQ= E: MODALIAS=hid:b0003g0101v0000056Ap00000084 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/hidraw/hidraw0 N: hidraw0 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:056A:0084.001F/hidraw/hidraw0 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw0 E: MAJOR=239 E: MINOR=0 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=56a/84/111 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v056Ap0084d0111dc00dsc00dp00ic03isc00ip00in01 E: USEC_INITIALIZED=796229426617 E: ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd E: ID_MODEL_FROM_DATABASE=ACK-40401 [Wireless Accessory Kit] E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.1 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_1 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020 E: SUBSYSTEM=hid E: DRIVER=wacom E: HID_ID=0003:0000056A:00000084 E: HID_NAME=Wacom Co.,Ltd. Wacom Wireless Receiver E: HID_PHYS=usb-0000:00:1a.0-1.1/input1 E: HID_UNIQ= E: MODALIAS=hid:b0003g0101v0000056Ap00000084 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/hidraw/hidraw1 N: hidraw1 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.1/0003:056A:0084.0020/hidraw/hidraw1 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw1 E: MAJOR=239 E: MINOR=1 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2 E: SUBSYSTEM=usb E: DEVTYPE=usb_interface E: DRIVER=usbhid E: PRODUCT=56a/84/111 E: TYPE=0/0/0 E: INTERFACE=3/0/0 E: MODALIAS=usb:v056Ap0084d0111dc00dsc00dp00ic03isc00ip00in02 E: USEC_INITIALIZED=796229426512 E: ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd E: ID_MODEL_FROM_DATABASE=ACK-40401 [Wireless Accessory Kit] E: ID_PATH=pci-0000:00:1a.0-usb-0:1.1:1.2 E: ID_PATH_TAG=pci-0000_00_1a_0-usb-0_1_1_1_2 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021 E: SUBSYSTEM=hid E: DRIVER=wacom E: HID_ID=0003:0000056A:00000084 E: HID_NAME=Wacom Co.,Ltd. Wacom Wireless Receiver E: HID_PHYS=usb-0000:00:1a.0-1.1/input2 E: HID_UNIQ= E: MODALIAS=hid:b0003g0101v0000056Ap00000084 P: /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/hidraw/hidraw2 N: hidraw2 E: DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.2/0003:056A:0084.0021/hidraw/hidraw2 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw2 E: MAJOR=239 E: MINOR=2 07070100000066000081A400000000000000000000000166EA4814000017E3000000000000000000000000000000000000003900000000upower-1.90.6/src/linux/tests/wacom-pen-digitiser.deviceP: /devices/LNXSYSTM:00/LNXSYBUS:00/AMDI0010:01/WACF2200:00 E: DEVPATH=/devices/LNXSYSTM:00/LNXSYBUS:00/AMDI0010:01/WACF2200:00 E: SUBSYSTEM=acpi E: MODALIAS=acpi:WACF2200:PNP0C50: E: USEC_INITIALIZED=7055138 E: ID_VENDOR_FROM_DATABASE=Wacom Tech P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00 E: SUBSYSTEM=i2c E: DRIVER=i2c_hid_acpi E: MODALIAS=acpi:WACF2200:PNP0C50: E: USEC_INITIALIZED=7092824 E: ID_VENDOR_FROM_DATABASE=Wacom Tech P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001 E: SUBSYSTEM=hid E: DRIVER=wacom E: HID_ID=0018:0000056A:000052D5 E: HID_NAME=WACF2200:00 056A:52D5 E: HID_PHYS=i2c-WACF2200:00 E: HID_UNIQ= E: MODALIAS=hid:b0018g0101v0000056Ap000052D5 P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/hidraw/hidraw0 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/hidraw/hidraw0 E: SUBSYSTEM=hidraw E: DEVNAME=/dev/hidraw0 E: MAJOR=242 E: MINOR=0 P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23 E: SUBSYSTEM=input E: PRODUCT=18/56a/52d5/100 E: NAME="Wacom HID 52D5 Pen" E: PHYS="i2c-WACF2200:00" E: UNIQ="" E: PROP=2 E: EV=1b E: KEY=1c03 0 0 0 0 0 E: ABS=1000d000003 E: MSC=21 E: MODALIAS=input:b0018v056Ap52D5e0100-e0,1,3,4,k140,141,14A,14B,14C,ra0,1,18,1A,1B,28,m0,5,lsfw E: USEC_INITIALIZED=7859843 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_SERIAL=noserial E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 E: ID_FOR_SEAT=input-platform-AMDI0010_01 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23/event14 S: input/by-path/platform-AMDI0010:01-event-mouse E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23/event14 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event14 E: MAJOR=13 E: MINOR=78 E: USEC_INITIALIZED=7962246 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_INPUT_WIDTH_MM=301 E: ID_INPUT_HEIGHT_MM=188 E: ID_SERIAL=noserial E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 E: LIBINPUT_DEVICE_GROUP=18/56a/52d5:i2c-WACF2200:00 E: DEVLINKS=/dev/input/by-path/platform-AMDI0010:01-event-mouse P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23/mouse0 S: input/by-path/platform-AMDI0010:01-mouse E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input23/mouse0 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse0 E: MAJOR=13 E: MINOR=32 E: USEC_INITIALIZED=7860940 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: ID_SERIAL=noserial E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 E: DEVLINKS=/dev/input/by-path/platform-AMDI0010:01-mouse P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24 E: SUBSYSTEM=input E: PRODUCT=18/56a/52d5/100 E: NAME="Wacom HID 52D5 Finger" E: PHYS="i2c-WACF2200:00" E: UNIQ="" E: PROP=2 E: EV=1b E: KEY=400 0 0 0 0 0 E: ABS=260800000000003 E: MSC=20 E: MODALIAS=input:b0018v056Ap52D5e0100-e0,1,3,4,k14A,ra0,1,2F,35,36,39,m5,lsfw E: USEC_INITIALIZED=7859406 E: ID_INPUT=1 E: ID_INPUT_TOUCHSCREEN=1 E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 E: ID_FOR_SEAT=input-platform-AMDI0010_01 E: TAGS=:seat: E: CURRENT_TAGS=:seat: P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24/event15 S: input/by-path/platform-AMDI0010:01-event E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24/event15 E: SUBSYSTEM=input E: DEVNAME=/dev/input/event15 E: MAJOR=13 E: MINOR=79 E: USEC_INITIALIZED=8111172 E: ID_INPUT=1 E: ID_INPUT_TOUCHSCREEN=1 E: ID_INPUT_WIDTH_MM=301 E: ID_INPUT_HEIGHT_MM=188 E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 E: LIBINPUT_DEVICE_GROUP=18/56a/52d5:i2c-WACF2200:00 E: LIBINPUT_FUZZ_35=4 E: LIBINPUT_FUZZ_36=4 E: DEVLINKS=/dev/input/by-path/platform-AMDI0010:01-event P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24/mouse1 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/input/input24/mouse1 E: SUBSYSTEM=input E: DEVNAME=/dev/input/mouse1 E: MAJOR=13 E: MINOR=33 E: USEC_INITIALIZED=7860064 E: ID_INPUT=1 E: ID_INPUT_TOUCHSCREEN=1 E: ID_PATH=platform-AMDI0010:01 E: ID_PATH_TAG=platform-AMDI0010_01 P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0 E: SUBSYSTEM=power_supply E: POWER_SUPPLY_NAME=wacom_battery_0 E: POWER_SUPPLY_TYPE=Battery E: POWER_SUPPLY_MODEL_NAME=Wacom HID 52D5 E: POWER_SUPPLY_PRESENT=1 E: POWER_SUPPLY_STATUS=Unknown E: POWER_SUPPLY_SCOPE=Device E: POWER_SUPPLY_CAPACITY=100 E: USEC_INITIALIZED=31207836 E: NVME_HOST_IFACE=none A: type=Battery\n A: model_name=Wacom HID 52D5\n A: status=Unknown\n A: scope=Device\n A: capacity=100\n A: present=1\n P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0/hwmon6 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0/hwmon6 E: SUBSYSTEM=hwmon P: /devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0/wakeup50 E: DEVPATH=/devices/platform/AMDI0010:01/i2c-1/i2c-WACF2200:00/0018:056A:52D5.0001/power_supply/wacom_battery_0/wakeup50 E: SUBSYSTEM=wakeup P: /devices/pnp0/00:02 E: DEVPATH=/devices/pnp0/00:02 E: SUBSYSTEM=pnp E: DRIVER=i8042 kbd E: USEC_INITIALIZED=7100176 E: ID_MODEL=Serial Wacom Tablet FUJ7401 PNP0303 E: ID_INPUT=1 E: ID_INPUT_TABLET=1 E: NAME=Serial Wacom Tablet FUJ7401 PNP0303 07070100000067000081ED00000000000000000000000166EA481400000676000000000000000000000000000000000000002E00000000upower-1.90.6/src/linux/unittest_inspector.py#! /usr/bin/env python3 # Copyright © 2020, 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.1 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 library. If not, see <http://www.gnu.org/licenses/>. # Authors: # Marco Trevisan <marco.trevisan@canonical.com> import argparse import importlib.util import inspect import os import unittest def list_tests(module): tests = [] for name, obj in inspect.getmembers(module): if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): cases = unittest.defaultTestLoader.getTestCaseNames(obj) tests += [ (obj, '{}.{}'.format(name, t)) for t in cases ] return tests if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('unittest_source', type=argparse.FileType('r')) args = parser.parse_args() source_path = args.unittest_source.name spec = importlib.util.spec_from_file_location( os.path.basename(source_path), source_path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) for machine, human in list_tests(module): print(human) 07070100000068000081A400000000000000000000000166EA481400005E05000000000000000000000000000000000000002500000000upower-1.90.6/src/linux/up-backend.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * * 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 <stdlib.h> #include <stdio.h> #include <math.h> #include <sys/wait.h> #include <glib/gi18n.h> #include <gio/gio.h> #include <gio/gunixfdlist.h> #include <gudev/gudev.h> #include "up-backend.h" #include "up-daemon.h" #include "up-device.h" #include "up-enumerator-udev.h" #include "up-device-supply.h" #include "up-device-wup.h" #include "up-device-hid.h" #include "up-device-bluez.h" #include "up-input.h" #include "up-config.h" #ifdef HAVE_IDEVICE #include "up-device-idevice.h" #endif /* HAVE_IDEVICE */ static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" struct UpBackendPrivate { UpDaemon *daemon; UpDeviceList *device_list; GUdevClient *gudev_client; UpInput *lid_device; UpConfig *config; GDBusProxy *logind_proxy; guint logind_sleep_id; int logind_delay_inhibitor_fd; UpEnumerator *udev_enum; /* BlueZ */ guint bluez_watch_id; GDBusObjectManager *bluez_client; }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (UpBackend, up_backend, G_TYPE_OBJECT) static void input_switch_changed_cb (UpInput *input, gboolean switch_value, UpBackend *backend) { up_daemon_set_lid_is_closed (backend->priv->daemon, switch_value); } static void up_backend_uevent_signal_handler_cb (GUdevClient *client, const gchar *action, GUdevDevice *device, gpointer user_data) { UpBackend *backend = UP_BACKEND (user_data); g_autoptr(UpInput) input = NULL; if (backend->priv->lid_device) return; if (g_strcmp0 (action, "add") != 0) return; /* check if the input device is a lid */ input = up_input_new (); if (up_input_coldplug (input, device)) { up_daemon_set_lid_is_present (backend->priv->daemon, TRUE); g_signal_connect (G_OBJECT (input), "switch-changed", G_CALLBACK (input_switch_changed_cb), backend); up_daemon_set_lid_is_closed (backend->priv->daemon, up_input_get_switch_value (input)); backend->priv->lid_device = g_steal_pointer (&input); } } static UpDevice * find_duplicate_device (UpBackend *backend, UpDevice *device) { GPtrArray *array; g_autofree char *serial = NULL; UpDevice *ret = NULL; guint i; g_object_get (G_OBJECT (device), "serial", &serial, NULL); if (!serial) return NULL; array = up_device_list_get_array (backend->priv->device_list); for (i = 0; i < array->len; i++) { g_autofree char *s = NULL; UpDevice *d; d = UP_DEVICE (g_ptr_array_index (array, i)); if (d == device) continue; g_object_get (G_OBJECT (d), "serial", &s, NULL); if (s && g_ascii_strcasecmp (s, serial) == 0) { ret = g_object_ref (d); break; } } g_ptr_array_unref (array); return ret; } /* Returns TRUE if the added_device should be visible */ static gboolean update_added_duplicate_device (UpBackend *backend, UpDevice *added_device) { g_autoptr(UpDevice) other_device = NULL; UpDevice *bluez_device = NULL; UpDevice *unreg_device = NULL; g_autofree char *serial = NULL; other_device = find_duplicate_device (backend, added_device); if (!other_device) return TRUE; if (UP_IS_DEVICE_BLUEZ (added_device)) bluez_device = added_device; else if (UP_IS_DEVICE_BLUEZ (other_device)) bluez_device = other_device; if (bluez_device) { UpDevice *non_bluez_device; non_bluez_device = bluez_device == added_device ? other_device : added_device; g_object_bind_property (bluez_device, "model", non_bluez_device, "model", G_BINDING_SYNC_CREATE); unreg_device = bluez_device; } else { UpDeviceState state; UpDevice *tested_device; tested_device = added_device; g_object_get (G_OBJECT (tested_device), "state", &state, NULL); if (state != UP_DEVICE_STATE_UNKNOWN) { tested_device = other_device; g_object_get (G_OBJECT (tested_device), "state", &state, NULL); } if (state != UP_DEVICE_STATE_UNKNOWN) { g_object_get (G_OBJECT (added_device), "serial", &serial, NULL); g_debug ("Device %s is a duplicate, but we don't know if most interesting", serial); return TRUE; } unreg_device = tested_device; } g_object_get (G_OBJECT (unreg_device), "serial", &serial, NULL); if (up_device_is_registered (unreg_device)) { g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, unreg_device); up_device_unregister (unreg_device); } g_debug ("Hiding duplicate device %s", serial); return unreg_device != added_device; } static void update_removed_duplicate_device (UpBackend *backend, UpDevice *removed_device) { g_autoptr(UpDevice) other_device = NULL; other_device = find_duplicate_device (backend, removed_device); if (!other_device) return; /* Re-add the old duplicate device that got hidden */ if (up_device_register (other_device)) g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, other_device); } static gboolean is_interesting_iface_proxy (GDBusProxy *interface_proxy) { const char *iface; iface = g_dbus_proxy_get_interface_name (interface_proxy); return g_str_equal (iface, "org.bluez.Battery1") || g_str_equal (iface, "org.bluez.Device1"); } static gboolean has_battery_iface (GDBusObject *object) { GDBusInterface *iface; iface = g_dbus_object_get_interface (object, "org.bluez.Battery1"); if (!iface) return FALSE; g_object_unref (iface); return TRUE; } static void bluez_proxies_changed (GDBusObjectManagerClient *manager, GDBusObjectProxy *object_proxy, GDBusProxy *interface_proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer user_data) { UpBackend *backend = user_data; GObject *object; UpDeviceBluez *bluez; if (!is_interesting_iface_proxy (interface_proxy)) return; object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (object_proxy)); if (!object) return; bluez = UP_DEVICE_BLUEZ (object); up_device_bluez_update (bluez, changed_properties); g_object_unref (object); } static void bluez_interface_removed (GDBusObjectManager *manager, GDBusObject *bus_object, GDBusInterface *interface, gpointer user_data) { UpBackend *backend = user_data; GObject *object; /* It might be another iface on another device that got removed */ if (has_battery_iface (bus_object)) return; object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (bus_object)); if (!object) return; g_debug ("emitting device-removed: %s", g_dbus_object_get_object_path (bus_object)); if (up_device_is_registered (UP_DEVICE (object))) g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, UP_DEVICE (object)); g_object_unref (object); } static void bluez_interface_added (GDBusObjectManager *manager, GDBusObject *bus_object, GDBusInterface *interface, gpointer user_data) { g_autoptr(UpDevice) device = NULL; UpBackend *backend = user_data; GObject *object; if (!has_battery_iface (bus_object)) return; object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (bus_object)); if (object != NULL) { g_object_unref (object); return; } device = g_initable_new (UP_TYPE_DEVICE_BLUEZ, NULL, NULL, "daemon", backend->priv->daemon, "native", G_OBJECT (bus_object), NULL); if (device) { g_debug ("emitting device-added: %s", g_dbus_object_get_object_path (bus_object)); if (update_added_duplicate_device (backend, device)) g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, device); } } static void bluez_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { UpBackend *backend = user_data; GError *error = NULL; GList *objects, *l; g_assert (backend->priv->bluez_client == NULL); backend->priv->bluez_client = g_dbus_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, "org.bluez", "/", NULL, NULL, NULL, NULL, &error); if (!backend->priv->bluez_client) { g_warning ("Failed to create object manager for BlueZ: %s", error->message); g_error_free (error); return; } g_debug ("BlueZ appeared"); g_signal_connect (backend->priv->bluez_client, "interface-proxy-properties-changed", G_CALLBACK (bluez_proxies_changed), backend); g_signal_connect (backend->priv->bluez_client, "interface-removed", G_CALLBACK (bluez_interface_removed), backend); g_signal_connect (backend->priv->bluez_client, "interface-added", G_CALLBACK (bluez_interface_added), backend); objects = g_dbus_object_manager_get_objects (backend->priv->bluez_client); for (l = objects; l != NULL; l = l->next) { GDBusObject *object = l->data; GList *interfaces, *k; interfaces = g_dbus_object_get_interfaces (object); for (k = interfaces; k != NULL; k = k->next) { GDBusInterface *iface = k->data; bluez_interface_added (backend->priv->bluez_client, object, iface, backend); g_object_unref (iface); } g_list_free (interfaces); g_object_unref (object); } g_list_free (objects); } static void bluez_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { UpBackend *backend = user_data; GPtrArray *array; guint i; g_debug ("BlueZ disappeared"); array = up_device_list_get_array (backend->priv->device_list); for (i = 0; i < array->len; i++) { UpDevice *device = UP_DEVICE (g_ptr_array_index (array, i)); if (UP_IS_DEVICE_BLUEZ (device)) { GDBusObject *object; object = G_DBUS_OBJECT (up_device_get_native (device)); g_debug ("emitting device-removed: %s", g_dbus_object_get_object_path (object)); if (up_device_is_registered (device)) g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, device); } } g_ptr_array_unref (array); g_clear_object (&backend->priv->bluez_client); } static void up_device_disconnected_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) { UpBackend *backend = user_data; g_autofree char *path = NULL; gboolean disconnected; g_object_get (gobject, "native-path", &path, "disconnected", &disconnected, NULL); if (disconnected) { g_debug("Device %s became disconnected, hiding device", path); if (up_device_is_registered (UP_DEVICE (gobject))) { g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, gobject); up_device_unregister (UP_DEVICE (gobject)); } } else { g_debug ("Device %s became connected, showing device", path); if (up_device_register (UP_DEVICE (gobject))) g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, gobject); } } static void udev_device_added_cb (UpBackend *backend, UpDevice *device) { g_debug ("Got new device from udev enumerator: %p", device); g_signal_connect (device, "notify::disconnected", G_CALLBACK (up_device_disconnected_cb), backend); if (update_added_duplicate_device (backend, device)) g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, device); } static void udev_device_removed_cb (UpBackend *backend, UpDevice *device) { g_debug ("Removing device from udev enumerator: %p", device); update_removed_duplicate_device (backend, device); g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, device); } /** * up_backend_coldplug: * @backend: The %UpBackend class instance * @daemon: The %UpDaemon controlling instance * * Finds all the devices already plugged in, and emits device-add signals for * each of them. * * Return value: %TRUE for success **/ gboolean up_backend_coldplug (UpBackend *backend, UpDaemon *daemon) { g_autolist(GUdevDevice) devices = NULL; GList *l; backend->priv->daemon = g_object_ref (daemon); backend->priv->device_list = up_daemon_get_device_list (daemon); /* Watch udev for input devices to find the lid switch */ backend->priv->gudev_client = g_udev_client_new ((const char *[]){ "input", NULL }); g_signal_connect (backend->priv->gudev_client, "uevent", G_CALLBACK (up_backend_uevent_signal_handler_cb), backend); /* add all subsystems */ devices = g_udev_client_query_by_subsystem (backend->priv->gudev_client, "input"); for (l = devices; l != NULL; l = l->next) up_backend_uevent_signal_handler_cb (backend->priv->gudev_client, "add", G_UDEV_DEVICE (l->data), backend); backend->priv->bluez_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, "org.bluez", G_BUS_NAME_WATCHER_FLAGS_NONE, bluez_appeared, bluez_vanished, backend, NULL); backend->priv->udev_enum = g_object_new (UP_TYPE_ENUMERATOR_UDEV, "daemon", daemon, NULL); g_signal_connect_swapped (backend->priv->udev_enum, "device-added", G_CALLBACK (udev_device_added_cb), backend); g_signal_connect_swapped (backend->priv->udev_enum, "device-removed", G_CALLBACK (udev_device_removed_cb), backend); g_assert (g_initable_init (G_INITABLE (backend->priv->udev_enum), NULL, NULL)); return TRUE; } /** * up_backend_unplug: * @backend: The %UpBackend class instance * * Forget about all learned devices, effectively undoing up_backend_coldplug. * Resources are released without emitting signals. */ void up_backend_unplug (UpBackend *backend) { g_clear_object (&backend->priv->gudev_client); g_clear_object (&backend->priv->udev_enum); g_clear_object (&backend->priv->device_list); g_clear_object (&backend->priv->lid_device); g_clear_object (&backend->priv->daemon); if (backend->priv->bluez_watch_id > 0) { g_bus_unwatch_name (backend->priv->bluez_watch_id); backend->priv->bluez_watch_id = 0; } g_clear_object (&backend->priv->bluez_client); } static gboolean check_action_result (GVariant *result) { if (result) { const char *s; g_variant_get (result, "(&s)", &s); if (g_strcmp0 (s, "yes") == 0) return TRUE; } return FALSE; } /** * up_backend_get_critical_action: * @backend: The %UpBackend class instance * * Which action will be taken when %UP_DEVICE_LEVEL_ACTION * warning-level occurs. **/ const char * up_backend_get_critical_action (UpBackend *backend) { struct { const gchar *method; const gchar *can_method; } actions[] = { { "Suspend", "CanSuspend" }, { "HybridSleep", "CanHybridSleep" }, { "Hibernate", "CanHibernate" }, { "PowerOff", NULL }, { "Ignore", NULL }, }; g_autofree gchar *action = NULL; gboolean can_risky = FALSE; guint i = 1; g_return_val_if_fail (backend->priv->logind_proxy != NULL, NULL); can_risky = up_config_get_boolean (backend->priv->config, "AllowRiskyCriticalPowerAction"); /* find the configured action first */ action = up_config_get_string (backend->priv->config, "CriticalPowerAction"); /* safeguard for the risky actions */ if (!can_risky) { if (!g_strcmp0 (action, "Suspend") || !g_strcmp0 (action, "Ignore")) { g_free (action); action = g_strdup_printf ("HybridSleep"); } } if (action != NULL) { for (i = 0; i < G_N_ELEMENTS (actions); i++) if (g_str_equal (actions[i].method, action)) break; if (i >= G_N_ELEMENTS (actions)) i = 1; } for (; i < G_N_ELEMENTS (actions); i++) { GVariant *result; if (actions[i].can_method) { gboolean action_available; /* Check whether we can use the method */ result = g_dbus_proxy_call_sync (backend->priv->logind_proxy, actions[i].can_method, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); action_available = check_action_result (result); g_variant_unref (result); if (!action_available) continue; } return actions[i].method; } g_assert_not_reached (); } /** * up_backend_take_action: * @backend: The %UpBackend class instance * * Act upon the %UP_DEVICE_LEVEL_ACTION warning-level. **/ void up_backend_take_action (UpBackend *backend) { const char *method; method = up_backend_get_critical_action (backend); g_assert (method != NULL); /* Take action */ g_debug ("About to call logind method %s", method); /* Do nothing if the action is set to "Ignore" */ if (g_strcmp0 (method, "Ignore") == 0) { return; } g_dbus_proxy_call (backend->priv->logind_proxy, method, g_variant_new ("(b)", FALSE), G_DBUS_CALL_FLAGS_NONE, G_MAXINT, NULL, NULL, NULL); } /** * up_backend_inhibitor_lock_take: * @backend: The %UpBackend class instance * @reason: Why the inhibitor lock is taken * @mode: The mode of the lock ('delay' or 'block') * * Acquire a sleep inhibitor lock via systemd's logind that will * inhibit going to sleep until the lock is released again by * closing the file descriptor. */ int up_backend_inhibitor_lock_take (UpBackend *backend, const char *reason, const char *mode) { GVariant *out, *input; GUnixFDList *fds = NULL; int fd; GError *error = NULL; g_return_val_if_fail (reason != NULL, -1); g_return_val_if_fail (mode != NULL, -1); g_return_val_if_fail (g_str_equal (mode, "delay") || g_str_equal (mode, "block"), -1); input = g_variant_new ("(ssss)", "sleep", /* what */ "UPower", /* who */ reason, /* why */ mode); /* mode */ out = g_dbus_proxy_call_with_unix_fd_list_sync (backend->priv->logind_proxy, "Inhibit", input, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &fds, NULL, &error); if (out == NULL) { g_warning ("Could not acquire inhibitor lock: %s", error ? error->message : "Unknown reason"); g_clear_error (&error); return -1; } if (g_unix_fd_list_get_length (fds) != 1) { g_warning ("Unexpected values returned by logind's 'Inhibit'"); g_variant_unref (out); g_object_unref (fds); return -1; } fd = g_unix_fd_list_get (fds, 0, NULL); g_variant_unref (out); g_object_unref (fds); g_debug ("Acquired inhibitor lock (%i, %s)", fd, mode); return fd; } /** * up_backend_prepare_for_sleep: * * Callback for logind's PrepareForSleep signal. It receives * a boolean that indicates if we are about to sleep (TRUE) * or waking up (FALSE). * In case of the waking up we refresh the devices so we are * up to date, especially w.r.t. battery levels, since they * might have changed drastically. **/ static void up_backend_prepare_for_sleep (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { UpBackend *backend = user_data; gboolean will_sleep; GPtrArray *array; guint i; if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(b)"))) { g_warning ("logind PrepareForSleep has unexpected parameter(s)"); return; } g_variant_get (parameters, "(b)", &will_sleep); if (will_sleep) { up_daemon_pause_poll (backend->priv->daemon); if (backend->priv->logind_delay_inhibitor_fd >= 0) { close (backend->priv->logind_delay_inhibitor_fd); backend->priv->logind_delay_inhibitor_fd = -1; } return; } if (backend->priv->logind_delay_inhibitor_fd < 0) backend->priv->logind_delay_inhibitor_fd = up_backend_inhibitor_lock_take (backend, "Pause device polling", "delay"); /* we are waking up, lets refresh all battery devices */ g_debug ("Woke up from sleep; about to refresh devices"); array = up_device_list_get_array (backend->priv->device_list); for (i = 0; i < array->len; i++) { UpDevice *device = UP_DEVICE (g_ptr_array_index (array, i)); up_device_refresh_internal (device, UP_REFRESH_RESUME); } g_ptr_array_unref (array); up_daemon_resume_poll (backend->priv->daemon); } static void up_backend_class_init (UpBackendClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_backend_finalize; signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); } static void up_backend_init (UpBackend *backend) { GDBusConnection *bus; guint sleep_id; backend->priv = up_backend_get_instance_private (backend); backend->priv->config = up_config_new (); backend->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, NULL); bus = g_dbus_proxy_get_connection (backend->priv->logind_proxy); sleep_id = g_dbus_connection_signal_subscribe (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_INTERFACE, "PrepareForSleep", LOGIND_DBUS_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE, up_backend_prepare_for_sleep, backend, NULL); backend->priv->logind_sleep_id = sleep_id; backend->priv->logind_delay_inhibitor_fd = -1; backend->priv->logind_delay_inhibitor_fd = up_backend_inhibitor_lock_take (backend, "Pause device polling", "delay"); } static void up_backend_finalize (GObject *object) { UpBackend *backend; GDBusConnection *bus; g_return_if_fail (UP_IS_BACKEND (object)); backend = UP_BACKEND (object); if (backend->priv->bluez_watch_id > 0) { g_bus_unwatch_name (backend->priv->bluez_watch_id); backend->priv->bluez_watch_id = 0; } g_clear_object (&backend->priv->bluez_client); g_clear_object (&backend->priv->config); g_clear_object (&backend->priv->daemon); g_clear_object (&backend->priv->device_list); g_clear_object (&backend->priv->gudev_client); bus = g_dbus_proxy_get_connection (backend->priv->logind_proxy); g_dbus_connection_signal_unsubscribe (bus, backend->priv->logind_sleep_id); if (backend->priv->logind_delay_inhibitor_fd >= 0) close (backend->priv->logind_delay_inhibitor_fd); g_clear_object (&backend->priv->logind_proxy); g_clear_object (&backend->priv->lid_device); G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } /** * up_backend_new: * * Return value: a new %UpBackend object. **/ UpBackend * up_backend_new (void) { return g_object_new (UP_TYPE_BACKEND, NULL); } 07070100000069000081A400000000000000000000000166EA481400001D96000000000000000000000000000000000000002A00000000upower-1.90.6/src/linux/up-device-bluez.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2017 Bastien Nocera <hadess@hadess.net> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <gio/gio.h> #include "up-types.h" #include "up-device-bluez.h" G_DEFINE_TYPE (UpDeviceBluez, up_device_bluez, UP_TYPE_DEVICE) static UpDeviceKind appearance_to_kind (guint16 appearance) { switch ((appearance & 0xffc0) >> 6) { case 0x01: return UP_DEVICE_KIND_PHONE; case 0x02: return UP_DEVICE_KIND_COMPUTER; case 0x05: return UP_DEVICE_KIND_MONITOR; case 0x0a: return UP_DEVICE_KIND_MEDIA_PLAYER; case 0x0f: /* HID Generic */ switch (appearance & 0x3f) { case 0x01: return UP_DEVICE_KIND_KEYBOARD; case 0x02: return UP_DEVICE_KIND_MOUSE; case 0x03: case 0x04: return UP_DEVICE_KIND_GAMING_INPUT; case 0x05: return UP_DEVICE_KIND_TABLET; case 0x0e: case 0x0f: return UP_DEVICE_KIND_PEN; } break; } return UP_DEVICE_KIND_BLUETOOTH_GENERIC; } /** * class_to_kind: * @class: a Bluetooth device class * * Returns value: the type of device corresponding to the given @class value. **/ static UpDeviceKind class_to_kind (guint32 class) { /* * See Bluetooth Assigned Numbers for Baseband * https://www.bluetooth.com/specifications/assigned-numbers/baseband/ */ switch ((class & 0x1f00) >> 8) { case 0x01: return UP_DEVICE_KIND_COMPUTER; case 0x02: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: case 0x03: case 0x05: return UP_DEVICE_KIND_PHONE; case 0x04: return UP_DEVICE_KIND_MODEM; } break; case 0x03: return UP_DEVICE_KIND_NETWORK; case 0x04: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: return UP_DEVICE_KIND_HEADSET; case 0x05: return UP_DEVICE_KIND_SPEAKERS; case 0x06: return UP_DEVICE_KIND_HEADPHONES; case 0x0b: /* VCR */ case 0x0c: /* Video Camera */ case 0x0d: /* Camcorder */ return UP_DEVICE_KIND_VIDEO; default: return UP_DEVICE_KIND_OTHER_AUDIO; } break; case 0x05: switch ((class & 0xc0) >> 6) { case 0x00: switch ((class & 0x1e) >> 2) { case 0x01: case 0x02: return UP_DEVICE_KIND_GAMING_INPUT; case 0x03: return UP_DEVICE_KIND_REMOTE_CONTROL; } break; case 0x01: return UP_DEVICE_KIND_KEYBOARD; case 0x02: switch ((class & 0x1e) >> 2) { case 0x05: return UP_DEVICE_KIND_TABLET; default: return UP_DEVICE_KIND_MOUSE; } } break; case 0x06: if (class & 0x80) return UP_DEVICE_KIND_PRINTER; if (class & 0x40) return UP_DEVICE_KIND_SCANNER; if (class & 0x20) return UP_DEVICE_KIND_CAMERA; if (class & 0x10) return UP_DEVICE_KIND_MONITOR; break; case 0x07: return UP_DEVICE_KIND_WEARABLE; case 0x08: return UP_DEVICE_KIND_TOY; } return UP_DEVICE_KIND_BLUETOOTH_GENERIC; } /** * up_device_bluez_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_bluez_coldplug (UpDevice *device) { GDBusObjectProxy *object_proxy; GDBusProxy *proxy; GError *error = NULL; UpDeviceKind kind; const char *uuid; const char *model; GVariant *v; guchar percentage; /* Static device properties */ object_proxy = G_DBUS_OBJECT_PROXY (up_device_get_native (device)); proxy = g_dbus_proxy_new_sync (g_dbus_object_proxy_get_connection (object_proxy), G_DBUS_PROXY_FLAGS_NONE, NULL, "org.bluez", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy)), "org.bluez.Device1", NULL, &error); if (!proxy) { g_warning ("Failed to get proxy for %s (iface org.bluez.Device1)", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy))); return FALSE; } v = g_dbus_proxy_get_cached_property (proxy, "Appearance"); if (v && g_variant_get_uint16 (v) != 0) { guint16 appearance; appearance = g_variant_get_uint16 (v); kind = appearance_to_kind (appearance); g_variant_unref (v); } else if ((v = g_dbus_proxy_get_cached_property (proxy, "Class"))) { guint32 class; class = g_variant_get_uint32 (v); kind = class_to_kind (class); g_variant_unref (v); } else { kind = UP_DEVICE_KIND_BLUETOOTH_GENERIC; } v = g_dbus_proxy_get_cached_property (proxy, "Address"); uuid = g_variant_get_string (v, NULL); g_variant_unref (v); v = g_dbus_proxy_get_cached_property (proxy, "Alias"); model = g_variant_get_string (v, NULL); g_variant_unref (v); /* hardcode some values */ g_object_set (device, "type", kind, "serial", uuid, "model", model, "power-supply", FALSE, "has-history", TRUE, NULL); g_object_unref (proxy); /* Initial battery values */ proxy = g_dbus_proxy_new_sync (g_dbus_object_proxy_get_connection (object_proxy), G_DBUS_PROXY_FLAGS_NONE, NULL, "org.bluez", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy)), "org.bluez.Battery1", NULL, &error); if (!proxy) { g_warning ("Failed to get proxy for %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy))); return FALSE; } percentage = g_variant_get_byte (g_dbus_proxy_get_cached_property (proxy, "Percentage")); g_object_set (device, "is-present", TRUE, "percentage", (gdouble) percentage, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); g_object_unref (proxy); return TRUE; } static void up_device_bluez_init (UpDeviceBluez *bluez) { } void up_device_bluez_update (UpDeviceBluez *bluez, GVariant *properties) { UpDevice *device = UP_DEVICE (bluez); GVariantIter iter; const gchar *key; GVariant *value; g_variant_iter_init (&iter, properties); while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { if (g_str_equal (key, "Percentage")) { g_object_set (device, "percentage", (gdouble) g_variant_get_byte (value), "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); } else if (g_str_equal (key, "Alias")) { g_object_set (device, "model", g_variant_get_string (value, NULL), NULL); } else { char *str = g_variant_print (value, TRUE); g_debug ("Unhandled key: %s value: %s", key, str); g_free (str); } g_variant_unref (value); } } static void up_device_bluez_class_init (UpDeviceBluezClass *klass) { UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); device_class->coldplug = up_device_bluez_coldplug; } 0707010000006A000081A400000000000000000000000166EA4814000007B3000000000000000000000000000000000000002A00000000upower-1.90.6/src/linux/up-device-bluez.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera <hadess@hadess.net> * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_BLUEZ_H__ #define __UP_DEVICE_BLUEZ_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_BLUEZ (up_device_bluez_get_type ()) #define UP_DEVICE_BLUEZ(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_BLUEZ, UpDeviceBluez)) #define UP_DEVICE_BLUEZ_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_BLUEZ, UpDeviceBluezClass)) #define UP_IS_DEVICE_BLUEZ(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_BLUEZ)) #define UP_IS_DEVICE_BLUEZ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_BLUEZ)) #define UP_DEVICE_BLUEZ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_BLUEZ, UpDeviceBluezClass)) typedef struct { UpDevice parent; } UpDeviceBluez; typedef struct { UpDeviceClass parent_class; } UpDeviceBluezClass; GType up_device_bluez_get_type (void); void up_device_bluez_update (UpDeviceBluez *bluez, GVariant *properties); G_END_DECLS #endif /* __UP_DEVICE_BLUEZ_H__ */ 0707010000006B000081A400000000000000000000000166EA48140000326D000000000000000000000000000000000000002800000000upower-1.90.6/src/linux/up-device-hid.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes <richard@hughsie.com> * * Based on hid-ups.c: Copyright (c) 2001 Vojtech Pavlik <vojtech@ucw.cz> * Copyright (c) 2001 Paul Stewart <hiddev@wetlogic.net> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <glib.h> #include <glib/gstdio.h> #include <glib/gprintf.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include <gudev/gudev.h> /* asm/types.h required for __s32 in linux/hiddev.h */ #include <asm/types.h> #include <errno.h> #include <fcntl.h> #include <linux/hiddev.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include "up-common.h" #include "up-device-hid.h" #include "up-constants.h" #define UP_DEVICE_HID_REFRESH_TIMEOUT 30l #define UP_DEVICE_HID_USAGE 0x840000 #define UP_DEVICE_HID_SERIAL 0x8400fe #define UP_DEVICE_HID_CHEMISTRY 0x850089 #define UP_DEVICE_HID_CAPACITY_MODE 0x85002c #define UP_DEVICE_HID_BATTERY_VOLTAGE 0x840030 #define UP_DEVICE_HID_BELOW_RCL 0x840042 #define UP_DEVICE_HID_SHUTDOWN_IMMINENT 0x840069 #define UP_DEVICE_HID_PRODUCT 0x8400fe #define UP_DEVICE_HID_SERIAL_NUMBER 0x8400ff #define UP_DEVICE_HID_CHARGING 0x850044 #define UP_DEVICE_HID_DISCHARGING 0x850045 #define UP_DEVICE_HID_REMAINING_CAPACITY 0x850066 #define UP_DEVICE_HID_RUNTIME_TO_EMPTY 0x850068 #define UP_DEVICE_HID_AC_PRESENT 0x8500d0 #define UP_DEVICE_HID_BATTERY_PRESENT 0x8500d1 #define UP_DEVICE_HID_DESIGN_CAPACITY 0x850083 #define UP_DEVICE_HID_DEVICE_NAME 0x850088 #define UP_DEVICE_HID_DEVICE_CHEMISTRY 0x850089 #define UP_DEVICE_HID_RECHARGEABLE 0x85008b #define UP_DEVICE_HID_OEM_INFORMATION 0x85008f #define UP_DEVICE_HID_PAGE_GENERIC_DESKTOP 0x01 #define UP_DEVICE_HID_PAGE_CONSUMER_PRODUCT 0x0c #define UP_DEVICE_HID_PAGE_USB_MONITOR 0x80 #define UP_DEVICE_HID_PAGE_USB_ENUMERATED_VALUES 0x81 #define UP_DEVICE_HID_PAGE_VESA_VIRTUAL_CONTROLS 0x82 #define UP_DEVICE_HID_PAGE_RESERVED_MONITOR 0x83 #define UP_DEVICE_HID_PAGE_POWER_DEVICE 0x84 #define UP_DEVICE_HID_PAGE_BATTERY_SYSTEM 0x85 struct UpDeviceHidPrivate { int fd; gboolean fake_device; }; G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceHid, up_device_hid, UP_TYPE_DEVICE) static gboolean up_device_hid_refresh (UpDevice *device, UpRefreshReason reason); /** * up_device_hid_is_ups: **/ static gboolean up_device_hid_is_ups (UpDeviceHid *hid) { guint i; int retval; gboolean ret = FALSE; struct hiddev_devinfo device_info; /* get device info */ retval = ioctl (hid->priv->fd, HIDIOCGDEVINFO, &device_info); if (retval < 0) { g_debug ("HIDIOCGDEVINFO failed: %s", strerror (errno)); goto out; } /* can we use the hid device as a UPS? */ for (i = 0; i < device_info.num_applications; i++) { retval = ioctl (hid->priv->fd, HIDIOCAPPLICATION, i); if (retval >> 16 == UP_DEVICE_HID_PAGE_POWER_DEVICE) { ret = TRUE; goto out; } } out: return ret; } /** * up_device_hid_get_string: **/ static const gchar * up_device_hid_get_string (UpDeviceHid *hid, int sindex) { static struct hiddev_string_descriptor sdesc; /* nothing to get */ if (sindex == 0) return ""; sdesc.index = sindex; /* failed */ if (ioctl (hid->priv->fd, HIDIOCGSTRING, &sdesc) < 0) return ""; g_debug ("value: '%s'", sdesc.value); return sdesc.value; } /** * up_device_hid_set_values: **/ static gboolean up_device_hid_set_values (UpDeviceHid *hid, guint32 code, gint32 value) { const gchar *type; gboolean ret = TRUE; UpDevice *device = UP_DEVICE (hid); switch (code) { case UP_DEVICE_HID_REMAINING_CAPACITY: g_object_set (device, "percentage", (gfloat) CLAMP (value, 0, 100), NULL); break; case UP_DEVICE_HID_RUNTIME_TO_EMPTY: g_object_set (device, "time-to-empty", (gint64) value, NULL); break; case UP_DEVICE_HID_CHARGING: if (value != 0) g_object_set (device, "state", UP_DEVICE_STATE_CHARGING, NULL); break; case UP_DEVICE_HID_DISCHARGING: if (value != 0) g_object_set (device, "state", UP_DEVICE_STATE_DISCHARGING, NULL); break; case UP_DEVICE_HID_BATTERY_PRESENT: g_object_set (device, "is-present", (value != 0), NULL); break; case UP_DEVICE_HID_DEVICE_NAME: g_object_set (device, "device-name", up_device_hid_get_string (hid, value), NULL); break; case UP_DEVICE_HID_CHEMISTRY: type = up_device_hid_get_string (hid, value); g_object_set (device, "technology", up_convert_device_technology (type), NULL); break; case UP_DEVICE_HID_RECHARGEABLE: g_object_set (device, "is-rechargeable", (value != 0), NULL); break; case UP_DEVICE_HID_OEM_INFORMATION: g_object_set (device, "vendor", up_device_hid_get_string (hid, value), NULL); break; case UP_DEVICE_HID_PRODUCT: g_object_set (device, "model", up_device_hid_get_string (hid, value), NULL); break; case UP_DEVICE_HID_SERIAL_NUMBER: g_object_set (device, "serial", up_device_hid_get_string (hid, value), NULL); break; case UP_DEVICE_HID_DESIGN_CAPACITY: g_object_set (device, "energy-full-design", (gfloat) value, NULL); break; default: ret = FALSE; break; } return ret; } /** * up_device_hid_get_all_data: **/ static gboolean up_device_hid_get_all_data (UpDeviceHid *hid) { struct hiddev_report_info rinfo; struct hiddev_field_info finfo; struct hiddev_usage_ref uref; int rtype; guint i, j; gboolean ret = FALSE; /* get all results */ for (rtype = HID_REPORT_TYPE_MIN; rtype <= HID_REPORT_TYPE_MAX; rtype++) { rinfo.report_type = rtype; rinfo.report_id = HID_REPORT_ID_FIRST; while (ioctl (hid->priv->fd, HIDIOCGREPORTINFO, &rinfo) >= 0) { for (i = 0; i < rinfo.num_fields; i++) { memset (&finfo, 0, sizeof (finfo)); finfo.report_type = rinfo.report_type; finfo.report_id = rinfo.report_id; finfo.field_index = i; ioctl (hid->priv->fd, HIDIOCGFIELDINFO, &finfo); memset (&uref, 0, sizeof (uref)); for (j = 0; j < finfo.maxusage; j++) { uref.report_type = finfo.report_type; uref.report_id = finfo.report_id; uref.field_index = i; uref.usage_index = j; ioctl (hid->priv->fd, HIDIOCGUCODE, &uref); ioctl (hid->priv->fd, HIDIOCGUSAGE, &uref); /* process each */ up_device_hid_set_values (hid, uref.usage_code, uref.value); /* we got some data */ ret = TRUE; } } rinfo.report_id |= HID_REPORT_ID_NEXT; } } return ret; } /** * up_device_hid_fixup_state: **/ static void up_device_hid_fixup_state (UpDevice *device) { gdouble percentage; /* map states the UPS cannot express */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < UP_DAEMON_EPSILON) g_object_set (device, "state", UP_DEVICE_STATE_EMPTY, NULL); if (percentage > (100.0 - UP_DAEMON_EPSILON)) g_object_set (device, "state", UP_DEVICE_STATE_FULLY_CHARGED, NULL); } /** * up_device_hid_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_hid_coldplug (UpDevice *device) { UpDeviceHid *hid = UP_DEVICE_HID (device); GUdevDevice *native; gboolean ret = FALSE; const gchar *device_file; const gchar *type; const gchar *vendor; /* detect what kind of device we are */ native = G_UDEV_DEVICE (up_device_get_native (device)); type = g_udev_device_get_property (native, "UPOWER_BATTERY_TYPE"); if (type == NULL || g_strcmp0 (type, "ups") != 0) goto out; /* get the device file */ device_file = g_udev_device_get_device_file (native); if (device_file == NULL) { g_debug ("could not get device file for HID device"); goto out; } /* first check that we are an UPS */ hid->priv->fake_device = g_udev_device_has_property (native, "UPOWER_FAKE_DEVICE"); if (!hid->priv->fake_device) { /* connect to the device */ g_debug ("using device: %s", device_file); hid->priv->fd = open (device_file, O_RDONLY | O_NONBLOCK); if (hid->priv->fd < 0) { g_debug ("cannot open device file %s", device_file); goto out; } ret = up_device_hid_is_ups (hid); if (!ret) { g_debug ("not a HID device: %s", device_file); goto out; } } /* prefer UPOWER names */ vendor = g_udev_device_get_property (native, "UPOWER_VENDOR"); if (vendor == NULL) vendor = g_udev_device_get_property (native, "ID_VENDOR"); /* hardcode some values */ g_object_set (device, "type", UP_DEVICE_KIND_UPS, "is-rechargeable", TRUE, "power-supply", TRUE, "is-present", TRUE, "vendor", vendor, "has-history", TRUE, "has-statistics", TRUE, NULL); /* coldplug everything */ if (hid->priv->fake_device) { ret = TRUE; if (g_udev_device_get_property_as_boolean (native, "UPOWER_FAKE_HID_CHARGING")) up_device_hid_set_values (hid, UP_DEVICE_HID_CHARGING, 1); else up_device_hid_set_values (hid, UP_DEVICE_HID_DISCHARGING, 1); up_device_hid_set_values (hid, UP_DEVICE_HID_REMAINING_CAPACITY, g_udev_device_get_property_as_int (native, "UPOWER_FAKE_HID_PERCENTAGE")); } else { ret = up_device_hid_get_all_data (hid); if (!ret) { g_debug ("failed to coldplug UPS: %s", device_file); goto out; } } /* fix up device states */ up_device_hid_fixup_state (device); g_object_set (device, "poll-timeout", UP_DEVICE_HID_REFRESH_TIMEOUT, NULL); out: return ret; } /** * up_device_hid_refresh: * * Return %TRUE on success, %FALSE if we failed to refresh or no data **/ static gboolean up_device_hid_refresh (UpDevice *device, UpRefreshReason reason) { gboolean set = FALSE; gboolean ret = FALSE; guint i; struct hiddev_event ev[64]; int rd; UpDeviceHid *hid = UP_DEVICE_HID (device); if (hid->priv->fake_device) goto update_time; /* read any data */ rd = read (hid->priv->fd, ev, sizeof (ev)); /* it's okay if there's nothing as we are non-blocking */ if (rd == -1) { g_debug ("no data"); ret = FALSE; goto out; } /* did we read enough data? */ if (rd < (int) sizeof (ev[0])) { g_warning ("incomplete read (%i<%i)", rd, (int) sizeof (ev[0])); goto out; } /* process each event */ for (i=0; i < rd / sizeof (ev[0]); i++) { set = up_device_hid_set_values (hid, ev[i].hid, ev[i].value); /* if only takes one match to make refresh a success */ if (set) ret = TRUE; } /* fix up device states */ up_device_hid_fixup_state (device); update_time: /* reset time */ g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); out: return ret; } /** * up_device_hid_get_on_battery: **/ static gboolean up_device_hid_get_on_battery (UpDevice *device, gboolean *on_battery) { UpDeviceHid *hid = UP_DEVICE_HID (device); UpDeviceKind type; UpDeviceState state; gboolean is_present; g_return_val_if_fail (UP_IS_DEVICE_HID (hid), FALSE); g_return_val_if_fail (on_battery != NULL, FALSE); g_object_get (device, "type", &type, "state", &state, "is-present", &is_present, NULL); if (type != UP_DEVICE_KIND_UPS) return FALSE; if (state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (!is_present) return FALSE; *on_battery = (state == UP_DEVICE_STATE_DISCHARGING); return TRUE; } /** * up_device_hid_init: **/ static void up_device_hid_init (UpDeviceHid *hid) { hid->priv = up_device_hid_get_instance_private (hid); hid->priv->fd = -1; } /** * up_device_hid_finalize: **/ static void up_device_hid_finalize (GObject *object) { UpDeviceHid *hid; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_DEVICE_HID (object)); hid = UP_DEVICE_HID (object); g_return_if_fail (hid->priv != NULL); if (hid->priv->fd > 0) close (hid->priv->fd); G_OBJECT_CLASS (up_device_hid_parent_class)->finalize (object); } /** * up_device_hid_class_init: **/ static void up_device_hid_class_init (UpDeviceHidClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); object_class->finalize = up_device_hid_finalize; device_class->coldplug = up_device_hid_coldplug; device_class->get_on_battery = up_device_hid_get_on_battery; device_class->refresh = up_device_hid_refresh; } 0707010000006C000081A400000000000000000000000166EA48140000070F000000000000000000000000000000000000002800000000upower-1.90.6/src/linux/up-device-hid.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_HID_H__ #define __UP_DEVICE_HID_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_HID (up_device_hid_get_type ()) #define UP_DEVICE_HID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_HID, UpDeviceHid)) #define UP_DEVICE_HID_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_HID, UpDeviceHidClass)) #define UP_IS_DEVICE_HID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_HID)) #define UP_IS_DEVICE_HID_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_HID)) #define UP_DEVICE_HID_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_HID, UpDeviceHidClass)) typedef struct UpDeviceHidPrivate UpDeviceHidPrivate; typedef struct { UpDevice parent; UpDeviceHidPrivate *priv; } UpDeviceHid; typedef struct { UpDeviceClass parent_class; } UpDeviceHidClass; GType up_device_hid_get_type (void); G_END_DECLS #endif /* __UP_DEVICE_HID_H__ */ 0707010000006D000081A400000000000000000000000166EA481400002835000000000000000000000000000000000000002C00000000upower-1.90.6/src/linux/up-device-idevice.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera <hadess@hadess.net> * Copyright (C) 2005-2010 Richard Hughes <richard@hughsie.com> * Copyright (C) 2004 Sergey V. Udaltsov <svu@gnome.org> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <glib.h> #include <glib/gstdio.h> #include <glib/gprintf.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include <gudev/gudev.h> #include <libimobiledevice/libimobiledevice.h> #include <libimobiledevice/lockdown.h> #include <plist/plist.h> #include "up-constants.h" #include "up-types.h" #include "up-device-idevice.h" struct UpDeviceIdevicePrivate { idevice_t dev; }; G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceIdevice, up_device_idevice, UP_TYPE_DEVICE) static gboolean up_device_idevice_refresh (UpDevice *device, UpRefreshReason reason); static const char * lockdownd_error_to_string (lockdownd_error_t lerr) { switch (lerr) { case LOCKDOWN_E_SUCCESS: return "LOCKDOWN_E_SUCCESS"; case LOCKDOWN_E_INVALID_ARG: return "LOCKDOWN_E_INVALID_ARG"; case LOCKDOWN_E_INVALID_CONF: return "LOCKDOWN_E_INVALID_CONF"; case LOCKDOWN_E_PLIST_ERROR: return "LOCKDOWN_E_PLIST_ERROR"; case LOCKDOWN_E_PAIRING_FAILED: return "LOCKDOWN_E_PAIRING_FAILED"; case LOCKDOWN_E_SSL_ERROR: return "LOCKDOWN_E_SSL_ERROR"; case LOCKDOWN_E_DICT_ERROR: return "LOCKDOWN_E_DICT_ERROR"; case -7: /* Either LOCKDOWN_E_NOT_ENOUGH_DATA or * LOCKDOWN_E_RECEIVE_TIMEOUT depending on version */ return "LOCKDOWN_E_RECEIVE_TIMEOUT"; case LOCKDOWN_E_MUX_ERROR: return "LOCKDOWN_E_MUX_ERROR"; case LOCKDOWN_E_NO_RUNNING_SESSION: return "LOCKDOWN_E_NO_RUNNING_SESSION"; case LOCKDOWN_E_INVALID_RESPONSE: return "LOCKDOWN_E_INVALID_RESPONSE"; case LOCKDOWN_E_MISSING_KEY: return "LOCKDOWN_E_MISSING_KEY"; case LOCKDOWN_E_MISSING_VALUE: return "LOCKDOWN_E_MISSING_VALUE"; case LOCKDOWN_E_GET_PROHIBITED: return "LOCKDOWN_E_GET_PROHIBITED"; case LOCKDOWN_E_SET_PROHIBITED: return "LOCKDOWN_E_SET_PROHIBITED"; case LOCKDOWN_E_REMOVE_PROHIBITED: return "LOCKDOWN_E_REMOVE_PROHIBITED"; case LOCKDOWN_E_IMMUTABLE_VALUE: return "LOCKDOWN_E_IMMUTABLE_VALUE"; case LOCKDOWN_E_PASSWORD_PROTECTED: return "LOCKDOWN_E_PASSWORD_PROTECTED"; case LOCKDOWN_E_USER_DENIED_PAIRING: return "LOCKDOWN_E_USER_DENIED_PAIRING"; case LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING: return "LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING"; case LOCKDOWN_E_MISSING_HOST_ID: return "LOCKDOWN_E_MISSING_HOST_ID"; case LOCKDOWN_E_INVALID_HOST_ID: return "LOCKDOWN_E_INVALID_HOST_ID"; case LOCKDOWN_E_SESSION_ACTIVE: return "LOCKDOWN_E_SESSION_ACTIVE"; case LOCKDOWN_E_SESSION_INACTIVE: return "LOCKDOWN_E_SESSION_INACTIVE"; case LOCKDOWN_E_MISSING_SESSION_ID: return "LOCKDOWN_E_MISSING_SESSION_ID"; case LOCKDOWN_E_INVALID_SESSION_ID: return "LOCKDOWN_E_INVALID_SESSION_ID"; case LOCKDOWN_E_MISSING_SERVICE: return "LOCKDOWN_E_MISSING_SERVICE"; case LOCKDOWN_E_INVALID_SERVICE: return "LOCKDOWN_E_INVALID_SERVICE"; case LOCKDOWN_E_SERVICE_LIMIT: return "LOCKDOWN_E_SERVICE_LIMIT"; case LOCKDOWN_E_MISSING_PAIR_RECORD: return "LOCKDOWN_E_MISSING_PAIR_RECORD"; case LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED: return "LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED"; case LOCKDOWN_E_INVALID_PAIR_RECORD: return "LOCKDOWN_E_INVALID_PAIR_RECORD"; case LOCKDOWN_E_INVALID_ACTIVATION_RECORD: return "LOCKDOWN_E_INVALID_ACTIVATION_RECORD"; case LOCKDOWN_E_MISSING_ACTIVATION_RECORD: return "LOCKDOWN_E_MISSING_ACTIVATION_RECORD"; case LOCKDOWN_E_SERVICE_PROHIBITED: return "LOCKDOWN_E_SERVICE_PROHIBITED"; case LOCKDOWN_E_ESCROW_LOCKED: return "LOCKDOWN_E_ESCROW_LOCKED"; case LOCKDOWN_E_UNKNOWN_ERROR: return "LOCKDOWN_E_UNKNOWN_ERROR"; default: return "unknown error"; } } static char * get_device_uuid (GUdevDevice *native) { const char *uuid; char *retval; uuid = g_udev_device_get_property (native, "ID_SERIAL_SHORT"); if (uuid == NULL) return NULL; if (strlen (uuid) != 24) return g_strdup (uuid); /* new style UDID: add hyphen between first 8 and following 16 digits */ retval = g_malloc0 (24 + 1 + 1); memcpy (&retval[0], &uuid[0], 8); retval[8] = '-'; memcpy (&retval[9], &uuid[8], 16); return retval; } /** * up_device_idevice_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_idevice_coldplug (UpDevice *device) { UpDeviceIdevice *idevice = UP_DEVICE_IDEVICE (device); GUdevDevice *native; char *uuid; const gchar *model; UpDeviceKind kind; /* Is it an iDevice? */ native = G_UDEV_DEVICE (up_device_get_native (device)); if (g_udev_device_get_property_as_boolean (native, "USBMUX_SUPPORTED") == FALSE) return FALSE; /* Get the UUID */ uuid = get_device_uuid (native); if (uuid == NULL) return FALSE; /* find the kind of device */ model = g_udev_device_get_property (native, "ID_MODEL"); kind = UP_DEVICE_KIND_PHONE; if (model != NULL && g_strstr_len (model, -1, "iPad")) { kind = UP_DEVICE_KIND_COMPUTER; } else if (model != NULL && g_strstr_len (model, -1, "iPod")) { kind = UP_DEVICE_KIND_MEDIA_PLAYER; } /* hardcode some values */ g_object_set (device, "type", kind, "serial", uuid, "vendor", g_udev_device_get_property (native, "ID_VENDOR"), "model", model, "power-supply", FALSE, "is-present", FALSE, "is-rechargeable", TRUE, "has-history", TRUE, NULL); g_object_set (idevice, "poll-timeout", 5, NULL); g_free (uuid); return TRUE; } /** * up_device_idevice_refresh: * * Return %TRUE on success, %FALSE if we failed to refresh or no data **/ static gboolean up_device_idevice_refresh (UpDevice *device, UpRefreshReason reason) { UpDeviceIdevice *idevice = UP_DEVICE_IDEVICE (device); idevice_t dev = idevice->priv->dev; lockdownd_client_t client = NULL; lockdownd_error_t lerr; char *name = NULL; plist_t dict, node; guint64 percentage; guint8 charging, has_battery; UpDeviceState state; gboolean retval = FALSE; /* No device yet, try to open it */ if (!dev) { g_autofree char *uuid = NULL; g_object_get (G_OBJECT (idevice), "serial", &uuid, NULL); g_assert (uuid); /* Connect to the device */ if (idevice_new (&dev, uuid) != IDEVICE_E_SUCCESS) goto out; } if ((lerr = lockdownd_client_new_with_handshake (dev, &client, "upower")) != LOCKDOWN_E_SUCCESS) { g_debug ("Could not start lockdownd client: %s (%d)", lockdownd_error_to_string (lerr), lerr); goto out; } if (lockdownd_get_device_name (client, &name) == LOCKDOWN_E_SUCCESS) { /* Prefer the user-chosen name for the device when available */ g_object_set (device, "vendor", NULL, "model", name, NULL); free (name); } if (lockdownd_get_value (client, "com.apple.mobile.battery", NULL, &dict) != LOCKDOWN_E_SUCCESS) goto out; node = plist_dict_get_item (dict, "HasBattery"); if (node) { plist_get_bool_val (node, &has_battery); if (!has_battery) { plist_free(dict); goto out; } } /* get battery status */ node = plist_dict_get_item (dict, "BatteryCurrentCapacity"); if (!node) { plist_free (dict); goto out; } plist_get_uint_val (node, &percentage); g_object_set (device, "percentage", (double) percentage, NULL); g_debug ("percentage=%"G_GUINT64_FORMAT, percentage); /* get charging status */ node = plist_dict_get_item (dict, "BatteryIsCharging"); if (!node) { plist_free(dict); goto out; } plist_get_bool_val (node, &charging); if (percentage == 100) state = UP_DEVICE_STATE_FULLY_CHARGED; else if (percentage == 0) state = UP_DEVICE_STATE_EMPTY; else if (charging) state = UP_DEVICE_STATE_CHARGING; else state = UP_DEVICE_STATE_DISCHARGING; /* upower doesn't have a "not charging" state */ g_object_set (device, "state", state, NULL); g_debug ("state=%s", up_device_state_to_string (state)); plist_free (dict); /* reset time */ g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); retval = TRUE; if (!idevice->priv->dev) { /* Device is working, mark as present and poll less frequently */ g_object_set (G_OBJECT (idevice), "is-present", TRUE, NULL); g_object_set (idevice, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL); idevice->priv->dev = dev; } out: /* Free device if we created it and it was not stored. */ if (dev && !idevice->priv->dev) idevice_free (dev); lockdownd_client_free (client); return retval; } /** * up_device_idevice_init: **/ static void up_device_idevice_init (UpDeviceIdevice *idevice) { idevice->priv = up_device_idevice_get_instance_private (idevice); } /** * up_device_idevice_finalize: **/ static void up_device_idevice_finalize (GObject *object) { UpDeviceIdevice *idevice; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_DEVICE_IDEVICE (object)); idevice = UP_DEVICE_IDEVICE (object); g_return_if_fail (idevice->priv != NULL); if (idevice->priv->dev != NULL) idevice_free (idevice->priv->dev); G_OBJECT_CLASS (up_device_idevice_parent_class)->finalize (object); } /** * up_device_idevice_class_init: **/ static void up_device_idevice_class_init (UpDeviceIdeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); object_class->finalize = up_device_idevice_finalize; device_class->coldplug = up_device_idevice_coldplug; device_class->refresh = up_device_idevice_refresh; } 0707010000006E000081A400000000000000000000000166EA4814000007E0000000000000000000000000000000000000002C00000000upower-1.90.6/src/linux/up-device-idevice.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera <hadess@hadess.net> * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_IDEVICE_H__ #define __UP_DEVICE_IDEVICE_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_IDEVICE (up_device_idevice_get_type ()) #define UP_DEVICE_IDEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdevice)) #define UP_DEVICE_IDEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdeviceClass)) #define UP_IS_DEVICE_IDEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_IDEVICE)) #define UP_IS_DEVICE_IDEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_IDEVICE)) #define UP_DEVICE_IDEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdeviceClass)) typedef struct UpDeviceIdevicePrivate UpDeviceIdevicePrivate; typedef struct { UpDevice parent; UpDeviceIdevicePrivate *priv; } UpDeviceIdevice; typedef struct { UpDeviceClass parent_class; } UpDeviceIdeviceClass; GType up_device_idevice_get_type (void); G_END_DECLS #endif /* __UP_DEVICE_IDEVICE_H__ */ 0707010000006F000081A400000000000000000000000166EA481400003B16000000000000000000000000000000000000003300000000upower-1.90.6/src/linux/up-device-supply-battery.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <glib.h> #include <glib/gstdio.h> #include <glib/gprintf.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include <gudev/gudev.h> #include "up-config.h" #include "up-common.h" #include "up-types.h" #include "up-constants.h" #include "up-device-supply-battery.h" /* For up_device_supply_get_state */ #include "up-device-supply.h" enum { PROP_0, PROP_IGNORE_SYSTEM_PERCENTAGE }; struct _UpDeviceSupplyBattery { UpDeviceBattery parent; gboolean has_coldplug_values; gboolean coldplug_units; gdouble *energy_old; guint energy_old_first; gdouble rate_old; gboolean shown_invalid_voltage_warning; gboolean ignore_system_percentage; }; G_DEFINE_TYPE (UpDeviceSupplyBattery, up_device_supply_battery, UP_TYPE_DEVICE_BATTERY) static gdouble up_device_supply_battery_get_design_voltage (UpDeviceSupplyBattery *self, GUdevDevice *native) { gdouble voltage; const gchar *device_type = NULL; /* design maximum */ voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_max_design") / 1000000.0; if (voltage > 1.00f) { g_debug ("using max design voltage"); return voltage; } /* design minimum */ voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_min_design") / 1000000.0; if (voltage > 1.00f) { g_debug ("using min design voltage"); return voltage; } /* current voltage, alternate form */ voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_now") / 1000000.0; if (voltage > 1.00f) { g_debug ("using present voltage (alternate)"); return voltage; } /* is this a USB device? */ device_type = g_udev_device_get_sysfs_attr (native, "type"); if (device_type != NULL && g_ascii_strcasecmp (device_type, "USB") == 0) { g_debug ("USB device, so assuming 5v"); voltage = 5.0f; return voltage; } /* no valid value found; display a warning the first time for each * device */ if (!self->shown_invalid_voltage_warning) { self->shown_invalid_voltage_warning = TRUE; g_warning ("no valid voltage value found for device %s, assuming 10V", g_udev_device_get_sysfs_path (native)); } /* completely guess, to avoid getting zero values */ g_debug ("no voltage values for device %s, using 10V as approximation", g_udev_device_get_sysfs_path (native)); voltage = 10.0f; return voltage; } static char* get_sysfs_attr_uncached (GUdevDevice *native, const gchar *key) { g_autofree char *value = NULL; /* get value, and strip to remove spaces */ value = g_strdup (g_udev_device_get_sysfs_attr_uncached (native, key)); if (!value) return NULL; g_strstrip (value); if (value[0] == '\0') return NULL; return g_steal_pointer (&value); } static gboolean up_device_supply_battery_convert_to_double (const gchar *str_value, gdouble *value) { gdouble conv_value; gchar *end = NULL; if (str_value == NULL || value == NULL) return FALSE; conv_value = g_ascii_strtod (str_value, &end); if (end == str_value || conv_value < 0.0 || conv_value > 100.0) return FALSE; *value = conv_value; return TRUE; } static gboolean up_device_supply_battery_get_charge_control_limits (GUdevDevice *native, UpBatteryInfo *info) { const gchar *charge_limit; g_auto(GStrv) pairs = NULL; gdouble charge_control_start_threshold; gdouble charge_control_end_threshold; charge_limit = g_udev_device_get_property (native, "CHARGE_LIMIT"); if (charge_limit == NULL) return FALSE; pairs = g_strsplit (charge_limit, ",", 0); if (g_strv_length (pairs) != 2) { g_warning("Could not parse CHARGE_LIMIT, expected 'number,number', got '%s'", charge_limit); return FALSE; } if (g_strcmp0 (pairs[0], "_") == 0) { g_debug ("charge_control_start_threshold is disabled"); charge_control_start_threshold = G_MAXUINT; } else if (!up_device_supply_battery_convert_to_double (pairs[0], &charge_control_start_threshold)) { g_warning ("failed to convert charge_control_start_threshold: %s", pairs[0]); return FALSE; } if (g_strcmp0 (pairs[1], "_") == 0) { g_debug ("charge_control_end_threshold is disabled"); charge_control_end_threshold = G_MAXUINT; } else if (!up_device_supply_battery_convert_to_double (pairs[1], &charge_control_end_threshold)) { g_warning ("failed to convert charge_control_start_threshold: %s", pairs[0]); return FALSE; } info->charge_control_start_threshold = charge_control_start_threshold; info->charge_control_end_threshold = charge_control_end_threshold; return TRUE; } static gboolean up_device_supply_battery_refresh (UpDevice *device, UpRefreshReason reason) { UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (device); UpDeviceBattery *battery = UP_DEVICE_BATTERY (device); GUdevDevice *native; UpBatteryInfo info = { 0 }; UpBatteryValues values = { 0 }; native = G_UDEV_DEVICE (up_device_get_native (device)); /* * Reload battery information. * NOTE: If we assume that a udev event is guaranteed to happen, then * we can restrict this to updates other than UP_REFRESH_POLL. * NOTE: Only energy.full and cycle_count can change for a battery. */ info.present = TRUE; if (g_udev_device_has_sysfs_attr (native, "present")) info.present = g_udev_device_get_sysfs_attr_as_boolean_uncached (native, "present"); if (!info.present) { up_device_battery_update_info (battery, &info); return TRUE; } info.vendor = up_make_safe_string (get_sysfs_attr_uncached (native, "manufacturer")); info.model = up_make_safe_string (get_sysfs_attr_uncached (native, "model_name")); info.serial = up_make_safe_string (get_sysfs_attr_uncached (native, "serial_number")); info.voltage_design = up_device_supply_battery_get_design_voltage (self, native); info.charge_cycles = g_udev_device_get_sysfs_attr_as_int_uncached (native, "cycle_count"); info.units = UP_BATTERY_UNIT_ENERGY; info.energy.full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full") / 1000000.0; info.energy.design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_full_design") / 1000000.0; /* Assume we couldn't read anything if energy.full is extremely small */ if (info.energy.full < 0.01) { info.units = UP_BATTERY_UNIT_CHARGE; info.energy.full = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full") / 1000000.0; info.energy.design = g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_full_design") / 1000000.0; } info.technology = up_convert_device_technology (get_sysfs_attr_uncached (native, "technology")); if (up_device_supply_battery_get_charge_control_limits (native, &info)) { info.charge_control_supported = TRUE; info.charge_control_enabled = FALSE; } else { info.charge_control_enabled = FALSE; info.charge_control_supported = FALSE; } /* NOTE: We used to warn about full > design, but really that is prefectly fine to happen. */ /* Update the battery information (will only fire events for actual changes) */ up_device_battery_update_info (battery, &info); /* * Load dynamic information. */ values.units = info.units; values.voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_now") / 1000000.0; if (values.voltage < 0.01) values.voltage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "voltage_avg") / 1000000.0; switch (values.units) { case UP_BATTERY_UNIT_CHARGE: /* QUIRK: * Some batteries (Nexus 7?) may report a separate energy_now. * This appears to be more accurate (as it takes into account * the dropping voltage). However, we ignore this here for * consistency (but we used to read it in the past). * * See https://bugs.freedesktop.org/show_bug.cgi?id=60104#c2 * whichs reports energy_now of 15.05 Wh while our calculation * will be ~16.4Wh by multiplying charge with voltage). */ values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "current_now") / 1000000.0); values.energy.cur = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "charge_now") / 1000000.0); break; case UP_BATTERY_UNIT_ENERGY: values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "power_now") / 1000000.0); values.energy.cur = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_now") / 1000000.0); if (values.energy.cur < 0.01) values.energy.cur = g_udev_device_get_sysfs_attr_as_double_uncached (native, "energy_avg") / 1000000.0; /* Legacy case: If we have energy units but no power_now, then current_now is in uW. */ if (values.energy.rate < 0) values.energy.rate = fabs (g_udev_device_get_sysfs_attr_as_double_uncached (native, "current_now") / 1000000.0); break; default: g_assert_not_reached (); } /* NOTE: * The old code tried to special case the 0xffff ACPI value of the energy rate. * That doesn't really make any sense after doing the floating point math. */ if (!self->ignore_system_percentage) { values.percentage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "capacity"); values.percentage = CLAMP(values.percentage, 0.0f, 100.0f); } values.state = up_device_supply_get_state (native); values.temperature = g_udev_device_get_sysfs_attr_as_double_uncached (native, "temp") / 10.0; up_device_battery_report (battery, &values, reason); return TRUE; } /** * up_device_supply_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_supply_coldplug (UpDevice *device) { GUdevDevice *native; const gchar *native_path; const gchar *scope; const gchar *type; /* detect what kind of device we are */ native = G_UDEV_DEVICE (up_device_get_native (device)); native_path = g_udev_device_get_sysfs_path (native); if (native_path == NULL) { g_warning ("could not get native path for %p", device); return FALSE; } /* try to work out if the device is powering the system */ scope = g_udev_device_get_sysfs_attr (native, "scope"); if (scope != NULL && g_ascii_strcasecmp (scope, "device") == 0) return FALSE; /* Complain about a non-system scope, while accepting no scope information */ if (scope != NULL && g_ascii_strcasecmp (scope, "system") != 0) g_warning ("Assuming system scope even though scope is %s", scope); /* type must be a battery. */ type = g_udev_device_get_sysfs_attr (native, "type"); if (!type || g_ascii_strcasecmp (type, "battery") != 0) return FALSE; return TRUE; } static void up_device_supply_battery_init (UpDeviceSupplyBattery *self) { } static void up_device_supply_battery_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (object); switch (property_id) { case PROP_IGNORE_SYSTEM_PERCENTAGE: self->ignore_system_percentage = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } } static void up_device_supply_battery_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UpDeviceSupplyBattery *self = UP_DEVICE_SUPPLY_BATTERY (object); switch (property_id) { case PROP_IGNORE_SYSTEM_PERCENTAGE: g_value_set_flags (value, self->ignore_system_percentage); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } } static char * up_device_supply_device_path (GUdevDevice *device) { const char *root; root = g_getenv ("UMOCKDEV_DIR"); if (!root || *root == '\0') { return g_strdup (g_udev_device_get_sysfs_path (device)); } return g_build_filename (root, g_udev_device_get_sysfs_path (device), NULL); } static gboolean up_device_supply_battery_set_battery_charge_thresholds(UpDevice *device, guint start, guint end, GError **error) { guint err_count = 0; GUdevDevice *native; g_autofree gchar *native_path = NULL; g_autofree gchar *start_filename = NULL; g_autofree gchar *end_filename = NULL; g_autoptr (GString) start_str = g_string_new (NULL); g_autoptr (GString) end_str = g_string_new (NULL); native = G_UDEV_DEVICE (up_device_get_native (device)); native_path = up_device_supply_device_path (native); start_filename = g_build_filename (native_path, "charge_control_start_threshold", NULL); end_filename = g_build_filename (native_path, "charge_control_end_threshold", NULL); if (start != G_MAXUINT) { g_string_printf (start_str, "%d", CLAMP (start, 0, 100)); if (!g_file_set_contents_full (start_filename, start_str->str, start_str->len, G_FILE_SET_CONTENTS_ONLY_EXISTING, 0644, error)) { err_count++; } } else { g_debug ("Ignore charge_control_start_threshold setting"); } if (end != G_MAXUINT) { g_string_printf (end_str, "%d", CLAMP (end, 0, 100)); if (!g_file_set_contents_full (end_filename, end_str->str, end_str->len, G_FILE_SET_CONTENTS_ONLY_EXISTING, 0644, error)) { err_count++; } } else { g_debug ("Ignore charge_control_end_threshold setting"); } if (err_count == 2) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to set charge control thresholds"); return FALSE; } return TRUE; } static void up_device_supply_battery_class_init (UpDeviceSupplyBatteryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); UpDeviceBatteryClass *battery_class = UP_DEVICE_BATTERY_CLASS (klass); object_class->set_property = up_device_supply_battery_set_property; object_class->get_property = up_device_supply_battery_get_property; device_class->coldplug = up_device_supply_coldplug; device_class->refresh = up_device_supply_battery_refresh; battery_class->set_battery_charge_thresholds = up_device_supply_battery_set_battery_charge_thresholds; g_object_class_install_property (object_class, PROP_IGNORE_SYSTEM_PERCENTAGE, g_param_spec_boolean ("ignore-system-percentage", "Ignore system percentage", "Ignore system provided battery percentage", FALSE, G_PARAM_READWRITE)); } 07070100000070000081A400000000000000000000000166EA481400000483000000000000000000000000000000000000003300000000upower-1.90.6/src/linux/up-device-supply-battery.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #pragma once #include "up-device-battery.h" G_BEGIN_DECLS #define MAX_DISCHARGE_RATE 300 #define UP_TYPE_DEVICE_SUPPLY_BATTERY (up_device_supply_battery_get_type ()) G_DECLARE_FINAL_TYPE (UpDeviceSupplyBattery, up_device_supply_battery, UP, DEVICE_SUPPLY_BATTERY, UpDeviceBattery) G_END_DECLS 07070100000071000081A400000000000000000000000166EA481400004DC3000000000000000000000000000000000000002B00000000upower-1.90.6/src/linux/up-device-supply.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <glib.h> #include <glib/gstdio.h> #include <glib/gprintf.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include <gudev/gudev.h> #include "up-config.h" #include "up-types.h" #include "up-constants.h" #include "up-device-supply.h" #include "up-common.h" struct UpDeviceSupplyPrivate { gboolean has_coldplug_values; gboolean shown_invalid_voltage_warning; }; G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceSupply, up_device_supply, UP_TYPE_DEVICE) static gboolean up_device_supply_refresh (UpDevice *device, UpRefreshReason reason); static UpDeviceKind up_device_supply_guess_type (GUdevDevice *native, const char *native_path); static gboolean up_device_supply_refresh_line_power (UpDeviceSupply *supply, UpRefreshReason reason) { UpDevice *device = UP_DEVICE (supply); GUdevDevice *native; gboolean online_old, online_new; /* get new AC value */ native = G_UDEV_DEVICE (up_device_get_native (device)); g_object_get (device, "online", &online_old, NULL); online_new = g_udev_device_get_sysfs_attr_as_int_uncached (native, "online"); /* Avoid notification if the value did not change. */ if (online_old != online_new) g_object_set (device, "online", online_new, NULL); return TRUE; } /** * up_device_supply_reset_values: **/ static void up_device_supply_reset_values (UpDeviceSupply *supply) { supply->priv->has_coldplug_values = FALSE; /* reset to default */ g_object_set (supply, "vendor", NULL, "model", NULL, "serial", NULL, "update-time", (guint64) 0, "online", FALSE, "energy", (gdouble) 0.0, "is-present", FALSE, "is-rechargeable", FALSE, "has-history", FALSE, "has-statistics", FALSE, "state", UP_DEVICE_STATE_UNKNOWN, "capacity", (gdouble) 0.0, "energy-empty", (gdouble) 0.0, "energy-full", (gdouble) 0.0, "energy-full-design", (gdouble) 0.0, "energy-rate", (gdouble) 0.0, "voltage", (gdouble) 0.0, "time-to-empty", (gint64) 0, "time-to-full", (gint64) 0, "percentage", (gdouble) 0.0, "temperature", (gdouble) 0.0, "technology", UP_DEVICE_TECHNOLOGY_UNKNOWN, "charge-cycles", -1, "charge-start-threshold", 0, "charge-end-threshold", 100, "charge-threshold-enabled", FALSE, "charge-threshold-supported", FALSE, NULL); } /** * up_device_supply_get_online: **/ static gboolean up_device_supply_get_online (UpDevice *device, gboolean *online) { UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device); UpDeviceKind type; gboolean online_tmp; g_return_val_if_fail (UP_IS_DEVICE_SUPPLY (supply), FALSE); g_return_val_if_fail (online != NULL, FALSE); g_object_get (device, "type", &type, "online", &online_tmp, NULL); if (type != UP_DEVICE_KIND_LINE_POWER) return FALSE; *online = online_tmp; return TRUE; } /** * up_device_supply_get_string: **/ static gchar * up_device_supply_get_string (GUdevDevice *native, const gchar *key) { gchar *value; /* get value, and strip to remove spaces */ value = g_strdup (g_udev_device_get_sysfs_attr_uncached (native, key)); if (value) g_strstrip (value); /* no value */ if (value == NULL) goto out; /* empty value */ if (value[0] == '\0') { g_free (value); value = NULL; goto out; } out: return value; } UpDeviceState up_device_supply_get_state (GUdevDevice *native) { UpDeviceState state; gchar *status; status = up_device_supply_get_string (native, "status"); if (status == NULL || g_ascii_strcasecmp (status, "unknown") == 0 || *status == '\0') { state = UP_DEVICE_STATE_UNKNOWN; } else if (g_ascii_strcasecmp (status, "charging") == 0) state = UP_DEVICE_STATE_CHARGING; else if (g_ascii_strcasecmp (status, "discharging") == 0) state = UP_DEVICE_STATE_DISCHARGING; else if (g_ascii_strcasecmp (status, "full") == 0) state = UP_DEVICE_STATE_FULLY_CHARGED; else if (g_ascii_strcasecmp (status, "empty") == 0) state = UP_DEVICE_STATE_EMPTY; else if (g_ascii_strcasecmp (status, "not charging") == 0) state = UP_DEVICE_STATE_PENDING_CHARGE; else { g_warning ("unknown status string: %s", status); state = UP_DEVICE_STATE_UNKNOWN; } g_free (status); return state; } static gdouble sysfs_get_capacity_level (GUdevDevice *native, UpDeviceLevel *level) { char *str; gdouble ret = -1.0; guint i; struct { const char *str; gdouble percentage; UpDeviceLevel level; } levels[] = { /* In order of most likely to least likely, * Keep in sync with up_daemon_compute_warning_level() */ { "Normal", 55.0, UP_DEVICE_LEVEL_NORMAL }, { "High", 70.0, UP_DEVICE_LEVEL_HIGH }, { "Low", 10.0, UP_DEVICE_LEVEL_LOW }, { "Critical", 5.0, UP_DEVICE_LEVEL_CRITICAL }, { "Full", 100.0, UP_DEVICE_LEVEL_FULL }, { "Unknown", 50.0, UP_DEVICE_LEVEL_UNKNOWN } }; g_return_val_if_fail (level != NULL, -1.0); if (!g_udev_device_has_sysfs_attr_uncached (native, "capacity_level")) { g_debug ("capacity_level doesn't exist, skipping"); *level = UP_DEVICE_LEVEL_NONE; return -1.0; } *level = UP_DEVICE_LEVEL_UNKNOWN; str = g_strchomp (g_strdup (g_udev_device_get_sysfs_attr_uncached (native, "capacity_level"))); if (!str) { g_debug ("Failed to read capacity_level!"); return ret; } for (i = 0; i < G_N_ELEMENTS(levels); i++) { if (strcmp (levels[i].str, str) == 0) { ret = levels[i].percentage; *level = levels[i].level; break; } } if (ret < 0.0) g_debug ("Could not find a percentage for capacity level '%s'", str); g_free (str); return ret; } static gboolean up_device_supply_refresh_device (UpDeviceSupply *supply, UpRefreshReason reason) { UpDeviceState state; UpDevice *device = UP_DEVICE (supply); GUdevDevice *native; gdouble percentage = 0.0f; UpDeviceLevel level = UP_DEVICE_LEVEL_NONE; gboolean is_present = TRUE; native = G_UDEV_DEVICE (up_device_get_native (device)); /* initial values */ if (!supply->priv->has_coldplug_values) { gchar *model_name; gchar *serial_number; /* get values which may be blank */ model_name = up_device_supply_get_string (native, "model_name"); serial_number = up_device_supply_get_string (native, "serial_number"); /* some vendors fill this with binary garbage */ up_make_safe_string (model_name); up_make_safe_string (serial_number); g_object_set (device, "model", model_name, "serial", serial_number, "is-rechargeable", TRUE, "has-history", TRUE, "has-statistics", TRUE, NULL); /* we only coldplug once, as these values will never change */ supply->priv->has_coldplug_values = TRUE; g_free (model_name); g_free (serial_number); } /* Some devices change whether they're present or not */ if (g_udev_device_has_sysfs_attr_uncached (native, "present")) is_present = g_udev_device_get_sysfs_attr_as_boolean_uncached (native, "present"); /* get a precise percentage */ percentage = g_udev_device_get_sysfs_attr_as_double_uncached (native, "capacity"); if (percentage == 0.0f) percentage = sysfs_get_capacity_level (native, &level); if (percentage < 0.0) { /* Probably talking to the device over Bluetooth */ state = UP_DEVICE_STATE_UNKNOWN; g_object_set (device, "state", state, "is-present", is_present, NULL); return FALSE; } state = up_device_supply_get_state (native); /* Override whatever the device might have told us * because a number of them are always discharging */ if (percentage == 100.0) state = UP_DEVICE_STATE_FULLY_CHARGED; g_object_set (device, "percentage", percentage, "battery-level", level, "state", state, "is-present", is_present, NULL); return TRUE; } static void up_device_supply_sibling_discovered_guess_type (UpDevice *device, GObject *sibling) { GUdevDevice *input; UpDeviceKind cur_type, new_type; char *model_name; char *serial_number; int i; struct { const char *prop; UpDeviceKind type; } types[] = { /* In order of type priority (*within* one input node). */ { "SOUND_INITIALIZED", UP_DEVICE_KIND_OTHER_AUDIO }, { "ID_INPUT_TABLET", UP_DEVICE_KIND_TABLET }, { "ID_INPUT_TOUCHPAD", UP_DEVICE_KIND_TOUCHPAD }, { "ID_INPUT_MOUSE", UP_DEVICE_KIND_MOUSE }, { "ID_INPUT_JOYSTICK", UP_DEVICE_KIND_GAMING_INPUT }, { "ID_INPUT_KEYBOARD", UP_DEVICE_KIND_KEYBOARD }, }; /* The type priority if we have multiple siblings, * i.e. we select the first of the current type of the found type. * Give a new priority for device type since the GAMING_INPUT may include * a keyboard, a touchpad, and... etc, for example Sony DualShock4 joystick. * A mouse and a touchpad may include a mouse and a keyboard. * Therefore, the priority is: * 1. Audio * 2. Gaming_input * 3. Keyboard * 4. Tablet * 5. Touchpad * 6. Mouse */ UpDeviceKind priority[] = { UP_DEVICE_KIND_OTHER_AUDIO, UP_DEVICE_KIND_GAMING_INPUT, UP_DEVICE_KIND_KEYBOARD, UP_DEVICE_KIND_TABLET, UP_DEVICE_KIND_TOUCHPAD, UP_DEVICE_KIND_MOUSE }; /* Form-factors set in rules.d/78-sound-card.rules in systemd */ struct { const char *form_factor; UpDeviceKind kind; } sound_types[] = { { "webcam", UP_DEVICE_KIND_VIDEO }, { "speaker", UP_DEVICE_KIND_SPEAKERS }, { "headphone", UP_DEVICE_KIND_HEADPHONES }, { "headset", UP_DEVICE_KIND_HEADSET }, /* unhandled: * - handset * - microphone */ }; input = G_UDEV_DEVICE (sibling); /* Do not process if we already have a "good" guess for the device type. */ g_object_get (device, "type", &cur_type, NULL); if (cur_type == UP_DEVICE_KIND_LINE_POWER) return; if (g_strcmp0 (g_udev_device_get_subsystem (input), "input") != 0 && g_strcmp0 (g_udev_device_get_subsystem (input), "sound") != 0) return; /* Only process "card" devices, as those are tagged with form-factor */ if (g_str_equal (g_udev_device_get_subsystem (input), "sound") && !g_str_has_prefix (g_udev_device_get_name (input), "card")) return; g_object_get (device, "model", &model_name, "serial", &serial_number, NULL); if (model_name == NULL) { model_name = up_device_supply_get_string (input, "name"); up_make_safe_string (model_name); g_object_set (device, "model", model_name, NULL); g_free (model_name); } if (serial_number == NULL) { serial_number = up_device_supply_get_string (input, "uniq"); up_make_safe_string (serial_number); g_object_set (device, "serial", serial_number, NULL); g_free (serial_number); } new_type = UP_DEVICE_KIND_UNKNOWN; for (i = 0; i < G_N_ELEMENTS (types); i++) { if (g_udev_device_get_property_as_boolean (input, types[i].prop)) { new_type = types[i].type; break; } } for (i = 0; i < G_N_ELEMENTS (priority); i++) { if (priority[i] == cur_type || priority[i] == new_type) { new_type = priority[i]; break; } } /* Match audio sub-type */ if (new_type == UP_DEVICE_KIND_OTHER_AUDIO) { const char *form_factor = g_udev_device_get_property (input, "SOUND_FORM_FACTOR"); g_debug ("Guessing audio sub-type from SOUND_FORM_FACTOR='%s'", form_factor); for (i = 0; form_factor != NULL && i < G_N_ELEMENTS (sound_types); i++) { if (g_strcmp0 (form_factor, sound_types[i].form_factor) == 0) { new_type = sound_types[i].kind; break; } } } /* TODO: Add a heuristic here (and during initial discovery) that uses * the model name. */ /* Fall back to "keyboard" if we didn't find anything. */ if (new_type == UP_DEVICE_KIND_UNKNOWN) { if (cur_type != UP_DEVICE_KIND_UNKNOWN) { g_debug ("Not overwriting existing type '%s'", up_device_kind_to_string(cur_type)); return; } new_type = UP_DEVICE_KIND_KEYBOARD; } if (cur_type != new_type) { g_debug ("Type changed from %s to %s", up_device_kind_to_string(cur_type), up_device_kind_to_string(new_type)); g_object_set (device, "type", new_type, NULL); } } static void up_device_supply_sibling_discovered_handle_wireless_status (UpDevice *device, GObject *obj) { const char *status; GUdevDevice *sibling = G_UDEV_DEVICE (obj); status = g_udev_device_get_sysfs_attr_uncached (sibling, "wireless_status"); if (!status) return; if (!g_str_equal (status, "connected") && !g_str_equal (status, "disconnected")) { g_warning ("Unhandled wireless_status value '%s' on %s", status, g_udev_device_get_sysfs_path (sibling)); return; } g_debug ("Detected wireless_status '%s' on %s", status, g_udev_device_get_sysfs_path (sibling)); g_object_set (G_OBJECT (device), "disconnected", g_str_equal (status, "disconnected"), NULL); } static void up_device_supply_sibling_discovered (UpDevice *device, GObject *sibling) { GUdevDevice *native; if (!G_UDEV_IS_DEVICE (sibling)) return; native = G_UDEV_DEVICE (up_device_get_native (device)); g_debug ("up_device_supply_sibling_discovered (device: %s, sibling: %s)", g_udev_device_get_sysfs_path (native), g_udev_device_get_sysfs_path (G_UDEV_DEVICE (sibling))); up_device_supply_sibling_discovered_guess_type (device, sibling); up_device_supply_sibling_discovered_handle_wireless_status (device, sibling); } static UpDeviceKind up_device_supply_guess_type (GUdevDevice *native, const char *native_path) { gchar *device_type; UpDeviceKind type = UP_DEVICE_KIND_UNKNOWN; device_type = up_device_supply_get_string (native, "type"); if (device_type == NULL) return type; if (g_ascii_strcasecmp (device_type, "mains") == 0) { type = UP_DEVICE_KIND_LINE_POWER; goto out; } if (g_ascii_strcasecmp (device_type, "battery") == 0) { type = UP_DEVICE_KIND_BATTERY; } else if (g_ascii_strcasecmp (device_type, "USB") == 0) { /* USB supplies should have a usb_type attribute which we would * ideally decode further. * * For historic reasons, we have a heuristic for wacom tablets * that can be dropped in the future. * As of May 2022, it is expected to be fixed in kernel 5.19. * https://patchwork.kernel.org/project/linux-input/patch/20220407115406.115112-1-hadess@hadess.net/ */ if (g_udev_device_has_sysfs_attr (native, "usb_type") && g_udev_device_has_sysfs_attr (native, "online")) type = UP_DEVICE_KIND_LINE_POWER; else if (g_strstr_len (native_path, -1, "wacom_") != NULL) type = UP_DEVICE_KIND_TABLET; else g_warning ("USB power supply %s without usb_type property, please report", native_path); } else { g_warning ("did not recognise type %s, please report", device_type); } out: g_free (device_type); return type; } /** * up_device_supply_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_supply_coldplug (UpDevice *device) { UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device); GUdevDevice *native; const gchar *native_path; const gchar *scope; UpDeviceKind type; gboolean is_power_supply; up_device_supply_reset_values (supply); /* detect what kind of device we are */ native = G_UDEV_DEVICE (up_device_get_native (device)); native_path = g_udev_device_get_sysfs_path (native); if (native_path == NULL) { g_warning ("could not get native path for %p", device); return FALSE; } /* try to work out if the device is powering the system */ scope = g_udev_device_get_sysfs_attr (native, "scope"); if (scope != NULL && g_ascii_strcasecmp (scope, "device") == 0) { is_power_supply = FALSE; } else if (scope != NULL && g_ascii_strcasecmp (scope, "system") == 0) { is_power_supply = TRUE; } else { g_debug ("taking a guess for power supply scope"); is_power_supply = TRUE; } /* we don't use separate ACs for devices */ if (is_power_supply == FALSE && !g_udev_device_has_sysfs_attr_uncached (native, "capacity") && !g_udev_device_has_sysfs_attr_uncached (native, "capacity_level")) { g_debug ("Ignoring device AC, we'll monitor the device battery"); return FALSE; } /* try to detect using the device type */ type = up_device_supply_guess_type (native, native_path); /* if reading the device type did not work, use heuristic */ if (type == UP_DEVICE_KIND_UNKNOWN) { if (g_udev_device_has_sysfs_attr_uncached (native, "online")) { g_debug ("'online' attribute was found. " "Assume it is a line power supply."); type = UP_DEVICE_KIND_LINE_POWER; } else { /* * This might be a battery or a UPS, but it might also * be something else that we really don't know how to * handle (e.g. BMS, exposed by Android-centric vendor * kernels in parallel to actual battery). * * As such, we have no choice but to assume that we * can't handle this device, and ignore it. */ return FALSE; } } /* set the value */ g_object_set (device, "type", type, "power-supply", is_power_supply, NULL); /* Handled by separate battery class */ if (is_power_supply) g_assert (type == UP_DEVICE_KIND_LINE_POWER); if (type != UP_DEVICE_KIND_LINE_POWER) g_object_set (device, "poll-timeout", UP_DAEMON_SHORT_TIMEOUT, NULL); return TRUE; } static gboolean up_device_supply_refresh (UpDevice *device, UpRefreshReason reason) { gboolean updated; UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device); UpDeviceKind type; g_object_get (device, "type", &type, NULL); if (type == UP_DEVICE_KIND_LINE_POWER) { updated = up_device_supply_refresh_line_power (supply, reason); } else { updated = up_device_supply_refresh_device (supply, reason); } /* reset time if we got new data */ if (updated) g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); return updated; } /** * up_device_supply_init: **/ static void up_device_supply_init (UpDeviceSupply *supply) { supply->priv = up_device_supply_get_instance_private (supply); supply->priv->shown_invalid_voltage_warning = FALSE; } /** * up_device_supply_finalize: **/ static void up_device_supply_finalize (GObject *object) { UpDeviceSupply *supply; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_DEVICE_SUPPLY (object)); supply = UP_DEVICE_SUPPLY (object); g_return_if_fail (supply->priv != NULL); G_OBJECT_CLASS (up_device_supply_parent_class)->finalize (object); } /** * up_device_supply_class_init: **/ static void up_device_supply_class_init (UpDeviceSupplyClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); object_class->finalize = up_device_supply_finalize; device_class->get_online = up_device_supply_get_online; device_class->coldplug = up_device_supply_coldplug; device_class->sibling_discovered = up_device_supply_sibling_discovered; device_class->refresh = up_device_supply_refresh; } 07070100000072000081A400000000000000000000000166EA4814000007CB000000000000000000000000000000000000002B00000000upower-1.90.6/src/linux/up-device-supply.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_SUPPLY_H__ #define __UP_DEVICE_SUPPLY_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_SUPPLY (up_device_supply_get_type ()) #define UP_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupply)) #define UP_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupplyClass)) #define UP_IS_DEVICE_SUPPLY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_SUPPLY)) #define UP_IS_DEVICE_SUPPLY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_SUPPLY)) #define UP_DEVICE_SUPPLY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_SUPPLY, UpDeviceSupplyClass)) typedef struct UpDeviceSupplyPrivate UpDeviceSupplyPrivate; typedef struct { UpDevice parent; UpDeviceSupplyPrivate *priv; } UpDeviceSupply; typedef struct { UpDeviceClass parent_class; } UpDeviceSupplyClass; GType up_device_supply_get_type (void); UpDeviceState up_device_supply_get_state (GUdevDevice *native); G_END_DECLS #endif /* __UP_DEVICE_SUPPLY_H__ */ 07070100000073000081A400000000000000000000000166EA481400002AF8000000000000000000000000000000000000002800000000upower-1.90.6/src/linux/up-device-wup.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Richard Hughes <richard@hughsie.com> * * Data values taken from wattsup.c: Copyright (C) 2005 Patrick Mochel * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <math.h> #include <glib.h> #include <glib-object.h> #include <gudev/gudev.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <ctype.h> #include <getopt.h> #include <errno.h> #include "up-types.h" #include "up-device-wup.h" #define UP_DEVICE_WUP_REFRESH_TIMEOUT 10 /* seconds */ #define UP_DEVICE_WUP_RESPONSE_OFFSET_WATTS 0x0 #define UP_DEVICE_WUP_RESPONSE_OFFSET_VOLTS 0x1 #define UP_DEVICE_WUP_RESPONSE_OFFSET_AMPS 0x2 #define UP_DEVICE_WUP_RESPONSE_OFFSET_KWH 0x3 #define UP_DEVICE_WUP_RESPONSE_OFFSET_COST 0x4 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MONTHLY_KWH 0x5 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MONTHLY_COST 0x6 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MAX_WATTS 0x7 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MAX_VOLTS 0x8 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MAX_AMPS 0x9 #define UP_DEVICE_WUP_RESPONSE_OFFSET_MIN_WATTS 0xa #define UP_DEVICE_WUP_RESPONSE_OFFSET_MIN_VOLTS 0xb #define UP_DEVICE_WUP_RESPONSE_OFFSET_MIN_AMPS 0xc #define UP_DEVICE_WUP_RESPONSE_OFFSET_POWER_FACTOR 0xd #define UP_DEVICE_WUP_RESPONSE_OFFSET_DUTY_CYCLE 0xe #define UP_DEVICE_WUP_RESPONSE_OFFSET_POWER_CYCLE 0xf /* commands can never be bigger then this */ #define UP_DEVICE_WUP_COMMAND_LEN 256 struct UpDeviceWupPrivate { int fd; }; G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceWup, up_device_wup, UP_TYPE_DEVICE) static gboolean up_device_wup_refresh (UpDevice *device, UpRefreshReason reason); /** * up_device_wup_set_speed: **/ static gboolean up_device_wup_set_speed (UpDeviceWup *wup) { struct termios t; int retval; retval = tcgetattr (wup->priv->fd, &t); if (retval != 0) { g_debug ("failed to get speed"); return FALSE; } cfmakeraw (&t); cfsetispeed (&t, B115200); cfsetospeed (&t, B115200); tcflush (wup->priv->fd, TCIFLUSH); t.c_iflag |= IGNPAR; t.c_cflag &= ~CSTOPB; retval = tcsetattr (wup->priv->fd, TCSANOW, &t); if (retval != 0) { g_debug ("failed to set speed"); return FALSE; } return TRUE; } /** * up_device_wup_write_command: * * data: a command string in the form "#command,subcommand,datalen,data[n]", e.g. "#R,W,0" **/ static gboolean up_device_wup_write_command (UpDeviceWup *wup, const gchar *data) { guint ret = TRUE; gint retval; gint length; length = strlen (data); g_debug ("writing [%s]", data); retval = write (wup->priv->fd, data, length); if (retval != length) { g_debug ("Writing [%s] to device failed", data); ret = FALSE; } return ret; } /** * up_device_wup_read_command: * * Return value: Some data to parse **/ static gchar * up_device_wup_read_command (UpDeviceWup *wup) { int retval; gchar buffer[UP_DEVICE_WUP_COMMAND_LEN]; retval = read (wup->priv->fd, &buffer, UP_DEVICE_WUP_COMMAND_LEN); if (retval < 0) { g_debug ("failed to read from fd: %s", strerror (errno)); return NULL; } return g_strdup (buffer); } /** * up_device_wup_parse_command: * * Return value: Som data to parse **/ static gboolean up_device_wup_parse_command (UpDeviceWup *wup, const gchar *data) { gboolean ret = FALSE; gchar command; gchar subcommand; gchar **tokens = NULL; gchar *packet = NULL; guint i; guint size; guint length; guint number_tokens; UpDevice *device = UP_DEVICE (wup); const guint offset = 3; /* invalid */ if (data == NULL) goto out; /* Try to find a valid packet in the data stream * Data may be sdfsd#P,-,0;sdfs and we only want this bit: * \-----/ * so try to find the start and the end */ /* ensure we have a long enough response */ length = strlen (data); if (length < 3) { g_debug ("not enough data '%s'", data); goto out; } /* strip to the first '#' char */ for (i=0; i<length-1; i++) if (data[i] == '#') packet = g_strdup (data+i); /* does packet exist? */ if (packet == NULL) { g_debug ("no start char in %s", data); goto out; } /* replace the first ';' char with a NULL if it exists */ length = strlen (packet); for (i=0; i<length; i++) { if (packet[i] < 0x20 || packet[i] > 0x7e) packet[i] = '?'; if (packet[i] == ';') { packet[i] = '\0'; break; } } /* check we have enough data inthe packet */ tokens = g_strsplit (packet, ",", -1); number_tokens = g_strv_length (tokens); if (number_tokens < 3) { g_debug ("not enough tokens '%s'", packet); goto out; } /* remove leading or trailing whitespace in tokens */ for (i=0; i<number_tokens; i++) g_strstrip (tokens[i]); /* check the first token */ length = strlen (tokens[0]); if (length != 2) { g_debug ("expected command '#?' but got '%s'", tokens[0]); goto out; } if (tokens[0][0] != '#') { g_debug ("expected command '#?' but got '%s'", tokens[0]); goto out; } command = tokens[0][1]; /* check the second token */ length = strlen (tokens[1]); if (length != 1) { g_debug ("expected command '?' but got '%s'", tokens[1]); goto out; } subcommand = tokens[1][0]; /* expect to be '-' */ /* check the length is present */ length = strlen (tokens[2]); if (length == 0) { g_debug ("length value not present"); goto out; } /* check the length matches what data we've got*/ size = atoi (tokens[2]); if (size != number_tokens - offset) { g_debug ("size expected to be '%i' but got '%i'", number_tokens - offset, size); goto out; } /* update the command fields */ if (command == 'd' && subcommand == '-' && number_tokens - offset == 18) { g_object_set (device, "energy-rate", strtod (tokens[offset+UP_DEVICE_WUP_RESPONSE_OFFSET_WATTS], NULL) / 10.0f, "voltage", strtod (tokens[offset+UP_DEVICE_WUP_RESPONSE_OFFSET_VOLTS], NULL) / 10.0f, NULL); ret = TRUE; } else { g_debug ("ignoring command '%c'", command); } out: g_free (packet); g_strfreev (tokens); return ret; } /** * up_device_wup_coldplug: * * Return %TRUE on success, %FALSE if we failed to get data and should be removed **/ static gboolean up_device_wup_coldplug (UpDevice *device) { UpDeviceWup *wup = UP_DEVICE_WUP (device); GUdevDevice *native; gboolean ret = FALSE; const gchar *device_file; const gchar *type; gchar *data; const gchar *vendor; const gchar *product; g_autofree char *serial = NULL; /* detect what kind of device we are */ native = G_UDEV_DEVICE (up_device_get_native (device)); type = g_udev_device_get_property (native, "UP_MONITOR_TYPE"); if (type == NULL || g_strcmp0 (type, "wup") != 0) goto out; /* get the device file */ device_file = g_udev_device_get_device_file (native); if (device_file == NULL) { g_debug ("could not get device file for WUP device"); goto out; } /* connect to the device */ wup->priv->fd = open (device_file, O_RDWR | O_NONBLOCK); if (wup->priv->fd < 0) { g_debug ("cannot open device file %s", device_file); goto out; } g_debug ("opened %s", device_file); /* set speed */ ret = up_device_wup_set_speed (wup); if (!ret) { g_debug ("not a WUP device (cannot set speed): %s", device_file); goto out; } /* attempt to clear */ ret = up_device_wup_write_command (wup, "#R,W,0;"); if (!ret) g_debug ("failed to clear, nonfatal"); /* setup logging interval */ data = g_strdup_printf ("#L,W,3,E,1,%i;", UP_DEVICE_WUP_REFRESH_TIMEOUT); ret = up_device_wup_write_command (wup, data); if (!ret) g_debug ("failed to setup logging interval, nonfatal"); g_free (data); /* dummy read */ data = up_device_wup_read_command (wup); g_debug ("data after clear %s", data); /* shouldn't do anything */ up_device_wup_parse_command (wup, data); g_free (data); /* prefer UPOWER names */ vendor = g_udev_device_get_property (native, "UPOWER_VENDOR"); if (vendor == NULL) vendor = g_udev_device_get_property (native, "ID_VENDOR"); product = g_udev_device_get_property (native, "UPOWER_PRODUCT"); if (product == NULL) product = g_udev_device_get_property (native, "ID_PRODUCT"); /* hardcode some values */ serial = g_strdup (g_udev_device_get_sysfs_attr (native, "serial")); if (serial) g_strstrip (serial); g_object_set (device, "type", UP_DEVICE_KIND_MONITOR, "is-rechargeable", FALSE, "power-supply", FALSE, "is-present", FALSE, "vendor", vendor, "model", product, "serial", serial, "has-history", TRUE, "state", UP_DEVICE_STATE_DISCHARGING, "poll-timeout", UP_DEVICE_WUP_REFRESH_TIMEOUT, NULL); out: return ret; } /** * up_device_wup_refresh: * * Return %TRUE on success, %FALSE if we failed to refresh or no data **/ static gboolean up_device_wup_refresh (UpDevice *device, UpRefreshReason reason) { gboolean ret = FALSE; gchar *data = NULL; UpDeviceWup *wup = UP_DEVICE_WUP (device); /* get data */ data = up_device_wup_read_command (wup); if (data == NULL) { g_debug ("no data"); goto out; } /* parse */ ret = up_device_wup_parse_command (wup, data); if (!ret) { g_debug ("failed to parse %s", data); goto out; } /* reset time */ g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); out: g_free (data); /* FIXME: always true? */ return TRUE; } /** * up_device_wup_init: **/ static void up_device_wup_init (UpDeviceWup *wup) { wup->priv = up_device_wup_get_instance_private (wup); wup->priv->fd = -1; } /** * up_device_wup_finalize: **/ static void up_device_wup_finalize (GObject *object) { UpDeviceWup *wup; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_DEVICE_WUP (object)); wup = UP_DEVICE_WUP (object); g_return_if_fail (wup->priv != NULL); if (wup->priv->fd > 0) close (wup->priv->fd); G_OBJECT_CLASS (up_device_wup_parent_class)->finalize (object); } /** * up_device_wup_class_init: **/ static void up_device_wup_class_init (UpDeviceWupClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); object_class->finalize = up_device_wup_finalize; device_class->coldplug = up_device_wup_coldplug; device_class->refresh = up_device_wup_refresh; } 07070100000074000081A400000000000000000000000166EA48140000070F000000000000000000000000000000000000002800000000upower-1.90.6/src/linux/up-device-wup.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_WUP_H__ #define __UP_DEVICE_WUP_H__ #include <glib-object.h> #include "up-device.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_WUP (up_device_wup_get_type ()) #define UP_DEVICE_WUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_WUP, UpDeviceWup)) #define UP_DEVICE_WUP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_WUP, UpDeviceWupClass)) #define UP_IS_DEVICE_WUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_WUP)) #define UP_IS_DEVICE_WUP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_WUP)) #define UP_DEVICE_WUP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_WUP, UpDeviceWupClass)) typedef struct UpDeviceWupPrivate UpDeviceWupPrivate; typedef struct { UpDevice parent; UpDeviceWupPrivate *priv; } UpDeviceWup; typedef struct { UpDeviceClass parent_class; } UpDeviceWupClass; GType up_device_wup_get_type (void); G_END_DECLS #endif /* __UP_DEVICE_WUP_H__ */ 07070100000075000081A400000000000000000000000166EA4814000031B3000000000000000000000000000000000000002D00000000upower-1.90.6/src/linux/up-enumerator-udev.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <gudev/gudev.h> #include "up-device.h" #include "up-config.h" #include "up-enumerator-udev.h" #include "up-device-supply.h" #include "up-device-supply-battery.h" #include "up-device-hid.h" #include "up-device-wup.h" #ifdef HAVE_IDEVICE #include "up-device-idevice.h" #endif /* HAVE_IDEVICE */ struct _UpEnumeratorUdev { UpEnumerator parent; GUdevClient *udev; /* Contains either a GUdevDevice or a UpDevice wrapping it. */ GHashTable *known; GHashTable *siblings; }; G_DEFINE_TYPE (UpEnumeratorUdev, up_enumerator_udev, UP_TYPE_ENUMERATOR) static char* device_parent_id (GUdevDevice *dev) { g_autoptr(GUdevDevice) parent = NULL; const char *subsystem; parent = g_udev_device_get_parent (dev); if (!parent) return NULL; subsystem = g_udev_device_get_subsystem (parent); /* Refusing using certain subsystems as parents. * In particular, refuse input as we'll already insert that parent. */ if (g_strcmp0 (subsystem, "platform") == 0 || g_strcmp0 (subsystem, "input") == 0) return NULL; /* Continue walk if the parent is a "hid" device */ if (g_strcmp0 (subsystem, "hid") == 0) return device_parent_id (parent); /* Also skip over USB interfaces, we care about full devices */ if (g_strcmp0 (subsystem, "usb") == 0 && g_strcmp0 (g_udev_device_get_devtype (parent), "usb_interface") == 0) return device_parent_id (parent); return g_strdup (g_udev_device_get_sysfs_path (parent)); } static gpointer is_macbook (gpointer data) { g_autofree char *product = NULL; if (!g_file_get_contents ("/sys/devices/virtual/dmi/id/product_name", &product, NULL, NULL) || product == NULL) return GINT_TO_POINTER(FALSE); return GINT_TO_POINTER(g_str_has_prefix (product, "MacBook")); } static UpDevice * device_new (UpEnumeratorUdev *self, GUdevDevice *native) { UpDaemon *daemon; const gchar *subsys; const gchar *native_path; daemon = up_enumerator_get_daemon (UP_ENUMERATOR (self)); subsys = g_udev_device_get_subsystem (native); if (g_strcmp0 (subsys, "power_supply") == 0) { UpDevice *device; device = g_initable_new (UP_TYPE_DEVICE_SUPPLY_BATTERY, NULL, NULL, "daemon", daemon, "native", native, "ignore-system-percentage", GPOINTER_TO_INT (is_macbook (NULL)), NULL); if (device) return device; return g_initable_new (UP_TYPE_DEVICE_SUPPLY, NULL, NULL, "daemon", daemon, "native", native, NULL); } else if (g_strcmp0 (subsys, "tty") == 0) { return g_initable_new (UP_TYPE_DEVICE_WUP, NULL, NULL, "daemon", daemon, "native", native, NULL); } else if (g_strcmp0 (subsys, "usb") == 0) { #ifdef HAVE_IDEVICE UpDevice *device; device = g_initable_new (UP_TYPE_DEVICE_IDEVICE, NULL, NULL, "daemon", daemon, "native", native, NULL); if (device) return device; #endif /* HAVE_IDEVICE */ return NULL; } else if (g_strcmp0 (subsys, "usbmisc") == 0) { #ifdef HAVE_IDEVICE UpDevice *device; device = g_initable_new (UP_TYPE_DEVICE_IDEVICE, NULL, NULL, "daemon", daemon, "native", native, NULL); if (device) return device; #endif /* HAVE_IDEVICE */ return g_initable_new (UP_TYPE_DEVICE_HID, NULL, NULL, "daemon", daemon, "native", native, NULL); } else if (g_strcmp0 (subsys, "input") == 0 || g_strcmp0 (subsys, "sound") == 0) { /* Ignore, we only resolve them to see siblings. */ return NULL; } else { native_path = g_udev_device_get_sysfs_path (native); g_warning ("native path %s (%s) ignoring", native_path, subsys); return NULL; } } /* As GUdevDevice are static and do not update when the sysfs device * changes, this helps get a GUdevDevice with updated properties */ static GUdevDevice * get_latest_udev_device (UpEnumeratorUdev *self, GObject *obj) { const char *sysfs_path; sysfs_path = g_udev_device_get_sysfs_path (G_UDEV_DEVICE (obj)); return g_udev_client_query_by_sysfs_path (self->udev, sysfs_path); } static void emit_changes_for_siblings (UpEnumeratorUdev *self, GUdevDevice *device) { GPtrArray *devices = NULL; g_autofree char *parent_id = NULL; char *parent_id_key = NULL; int i; parent_id = device_parent_id (device); if (!parent_id) return; g_hash_table_lookup_extended (self->siblings, parent_id, (gpointer*)&parent_id_key, (gpointer*)&devices); if (!devices) return; for (i = 0; i < devices->len; i++) { GObject *sibling = g_ptr_array_index (devices, i); if (UP_IS_DEVICE (sibling)) { up_device_sibling_discovered (UP_DEVICE (sibling), G_OBJECT (device)); break; } } } static void uevent_signal_handler_cb (UpEnumeratorUdev *self, const gchar *action, GUdevDevice *device, GUdevClient *client) { const char *device_key = g_udev_device_get_sysfs_path (device); g_debug ("Received uevent %s on device %s", action, device_key); /* Work around the fact that we don't get a REMOVE event in some cases. */ if (g_strcmp0 (g_udev_device_get_subsystem (device), "power_supply") == 0) device_key = g_udev_device_get_name (device); /* It appears that we may not always receive an "add" event. As such, * treat "add"/"change" in the same way, by first checking if we have * seen the device. * Even worse, we may not get a "remove" event in some odd cases, so * if there is an "add" but we find the device (as the power_supply * node has the same name), then remove it first before adding the * new one. */ if (g_strcmp0 (action, "change") == 0 || g_strcmp0 (action, "add") == 0) { GObject *obj; obj = g_hash_table_lookup (self->known, device_key); if (UP_IS_DEVICE (obj) && g_strcmp0 (action, "add") == 0 && g_strcmp0 (g_udev_device_get_sysfs_path (device), g_udev_device_get_sysfs_path (G_UDEV_DEVICE (up_device_get_native (UP_DEVICE (obj))))) != 0) { uevent_signal_handler_cb (self, "remove", device, client); obj = NULL; } if (!obj) { g_autoptr(UpDevice) up_dev = NULL; g_autofree char *parent_id = NULL; up_dev = device_new (self, device); /* We work with `obj` further down, which is the UpDevice * if we have it, or the GUdevDevice if not. */ if (up_dev) obj = G_OBJECT (up_dev); else obj = G_OBJECT (device); g_hash_table_insert (self->known, (char*) device_key, g_object_ref (obj)); /* Fire relevant sibling events and insert into lookup table */ parent_id = device_parent_id (device); g_debug ("device %s has parent id: %s", device_key, parent_id); if (parent_id) { GPtrArray *devices = NULL; char *parent_id_key = NULL; int i; g_hash_table_lookup_extended (self->siblings, parent_id, (gpointer*)&parent_id_key, (gpointer*)&devices); if (!devices) devices = g_ptr_array_new_with_free_func (g_object_unref); for (i = 0; i < devices->len; i++) { GObject *sibling = g_ptr_array_index (devices, i); if (up_dev) { g_autoptr(GUdevDevice) d = get_latest_udev_device (self, sibling); if (d) up_device_sibling_discovered (up_dev, G_OBJECT (d)); } if (UP_IS_DEVICE (sibling)) up_device_sibling_discovered (UP_DEVICE (sibling), obj); } g_ptr_array_add (devices, g_object_ref (obj)); if (!parent_id_key) { parent_id_key = g_strdup (parent_id); g_hash_table_insert (self->siblings, parent_id_key, devices); } /* Just a reference to the hash table key */ g_object_set_data (obj, "udev-parent-id", parent_id_key); } if (up_dev) g_signal_emit_by_name (self, "device-added", up_dev); } else { if (!UP_IS_DEVICE (obj)) { g_autoptr(GUdevDevice) d = get_latest_udev_device (self, obj); if (d) emit_changes_for_siblings (self, d); return; } g_debug ("refreshing device for path %s", g_udev_device_get_sysfs_path (device)); if (!up_device_refresh_internal (UP_DEVICE (obj), UP_REFRESH_EVENT)) g_debug ("no changes on %s", up_device_get_object_path (UP_DEVICE (obj))); } } else if (g_strcmp0 (action, "remove") == 0) { g_autoptr(GObject) obj = NULL; const char *key = NULL; g_hash_table_steal_extended (self->known, device_key, (gpointer*) &key, (gpointer*) &obj); if (obj) { char *parent_id; g_debug ("removing device for path %s", g_udev_device_get_sysfs_path (device)); parent_id = g_object_get_data (obj, "udev-parent-id"); /* Remove from siblings table. */ if (parent_id) { GPtrArray *devices; devices = g_hash_table_lookup (self->siblings, parent_id); g_ptr_array_remove_fast (devices, obj); if (devices->len == 0) { g_debug ("No devices with parent %s left", parent_id); g_hash_table_remove (self->siblings, parent_id); } } } if (obj && UP_IS_DEVICE (obj)) { g_signal_emit_by_name (self, "device-removed", obj); } else if (!obj) g_debug ("ignored remove event on %s", g_udev_device_get_sysfs_path (device)); } } static void up_enumerator_udev_init (UpEnumeratorUdev *self) { self->known = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); self->siblings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); } static void up_enumerator_udev_initable_init (UpEnumerator *enumerator) { g_autoptr(UpConfig) config = NULL; UpEnumeratorUdev *self = UP_ENUMERATOR_UDEV (enumerator); GUdevDevice *native; guint i; const gchar **subsystems; /* List "input" first just to avoid some sibling hotplugging later */ const gchar *subsystems_no_wup[] = {"input", "power_supply", "usb", "usbmisc", "sound", NULL}; const gchar *subsystems_wup[] = {"input", "power_supply", "usb", "usbmisc", "sound", "tty", NULL}; config = up_config_new (); if (up_config_get_boolean (config, "EnableWattsUpPro")) subsystems = subsystems_wup; else subsystems = subsystems_no_wup; self->udev = g_udev_client_new (subsystems); g_signal_connect_swapped (self->udev, "uevent", G_CALLBACK (uevent_signal_handler_cb), self); /* Emulate hotplug for existing devices */ for (i = 0; subsystems[i] != NULL; i++) { g_autolist(GUdevDevice) devices = NULL; GList *l; g_debug ("registering subsystem : %s", subsystems[i]); devices = g_udev_client_query_by_subsystem (self->udev, subsystems[i]); for (l = devices; l != NULL; l = l->next) { native = l->data; uevent_signal_handler_cb (self, "add", native, self->udev); } } } static void up_enumerator_udev_dispose (GObject *obj) { UpEnumeratorUdev *self = UP_ENUMERATOR_UDEV (obj); g_clear_object (&self->udev); g_hash_table_remove_all (self->known); g_hash_table_remove_all (self->siblings); G_OBJECT_CLASS (up_enumerator_udev_parent_class)->dispose (obj); } static void up_enumerator_udev_finalize (GObject *obj) { UpEnumeratorUdev *self = UP_ENUMERATOR_UDEV (obj); g_clear_pointer (&self->known, g_hash_table_unref); g_clear_pointer (&self->siblings, g_hash_table_unref); G_OBJECT_CLASS (up_enumerator_udev_parent_class)->finalize (obj); } static void up_enumerator_udev_class_init (UpEnumeratorUdevClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = up_enumerator_udev_dispose; object_class->finalize = up_enumerator_udev_finalize; UP_ENUMERATOR_CLASS (klass)->initable_init = up_enumerator_udev_initable_init; } 07070100000076000081A400000000000000000000000166EA481400000447000000000000000000000000000000000000002D00000000upower-1.90.6/src/linux/up-enumerator-udev.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #pragma once #include "up-enumerator.h" G_BEGIN_DECLS #define UP_TYPE_ENUMERATOR_UDEV (up_enumerator_udev_get_type ()) G_DECLARE_FINAL_TYPE (UpEnumeratorUdev, up_enumerator_udev, UP, ENUMERATOR_UDEV, UpEnumerator) G_END_DECLS 07070100000077000081A400000000000000000000000166EA48140000271B000000000000000000000000000000000000002300000000upower-1.90.6/src/linux/up-input.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <linux/input.h> #include <glib.h> #include <glib/gstdio.h> #include <glib-object.h> #include "up-input.h" struct _UpInput { GObject parent_instance; guint watched_switch; int last_switch_state; struct input_event event; gsize offset; GIOChannel *channel; }; G_DEFINE_TYPE (UpInput, up_input, G_TYPE_OBJECT) enum { PROP_0, PROP_WATCHED_SWITCH }; enum { SWITCH_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; /* we must use this kernel-compatible implementation */ #define BITS_PER_LONG (sizeof(long) * 8) #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) #define OFF(x) ((x)%BITS_PER_LONG) #define BIT(x) (1UL<<OFF(x)) #define LONG(x) ((x)/BITS_PER_LONG) #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) /** * up_input_get_device_sysfs_path: **/ static char * up_input_get_device_sysfs_path (GUdevDevice *device) { const char *root; g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); root = g_getenv ("UMOCKDEV_DIR"); if (!root || *root == '\0') return g_strdup (g_udev_device_get_sysfs_path (device)); return g_build_filename (root, g_udev_device_get_sysfs_path (device), NULL); } /** * up_input_str_to_bitmask: **/ static gint up_input_str_to_bitmask (const gchar *s, glong *bitmask, size_t max_size) { gint i, j; gchar **v; gint num_bits_set = 0; memset (bitmask, 0, max_size); v = g_strsplit (s, " ", max_size); for (i = g_strv_length (v) - 1, j = 0; i >= 0; i--, j++) { gulong val; val = strtoul (v[i], NULL, 16); bitmask[j] = val; while (val != 0) { num_bits_set++; val &= (val - 1); } } g_strfreev(v); return num_bits_set; } /** * up_input_event_io: **/ static gboolean up_input_event_io (GIOChannel *channel, GIOCondition condition, gpointer data) { UpInput *input = (UpInput*) data; GError *error = NULL; gsize read_bytes; glong bitmask[NBITS(SW_MAX)]; /* uninteresting */ if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) return FALSE; /* read event */ while (g_io_channel_read_chars (channel, ((gchar*)&input->event) + input->offset, sizeof(struct input_event) - input->offset, &read_bytes, &error) == G_IO_STATUS_NORMAL) { /* not enough data */ if (input->offset + read_bytes < sizeof (struct input_event)) { input->offset = input->offset + read_bytes; g_debug ("incomplete read"); goto out; } /* we have all the data */ input->offset = 0; g_debug ("event.value=%d ; event.code=%d (0x%02x)", input->event.value, input->event.code, input->event.code); /* switch? */ if (input->event.type != EV_SW) { g_debug ("not a switch event"); continue; } /* is not the watched switch */ if (input->event.code != input->watched_switch) { g_debug ("not the watched switch"); continue; } /* check switch state */ if (ioctl (g_io_channel_unix_get_fd(channel), EVIOCGSW(sizeof (bitmask)), bitmask) < 0) { g_debug ("ioctl EVIOCGSW failed"); continue; } /* are we set */ input->last_switch_state = test_bit (input->event.code, bitmask); g_signal_emit_by_name (G_OBJECT (input), "switch-changed", input->last_switch_state); } out: return TRUE; } /** * up_input_coldplug: **/ gboolean up_input_coldplug (UpInput *input, GUdevDevice *d) { gboolean ret = FALSE; gchar *path; gchar *contents = NULL; gchar *native_path = NULL; const gchar *device_file; GError *error = NULL; glong bitmask[NBITS(SW_MAX)]; gint num_bits; GIOStatus status; int eventfd; /* get sysfs path */ native_path = up_input_get_device_sysfs_path (d); /* is a switch */ path = g_build_filename (native_path, "../capabilities/sw", NULL); if (!g_file_test (path, G_FILE_TEST_EXISTS)) { char *path2; path2 = g_build_filename (native_path, "capabilities/sw", NULL); if (!g_file_test (path2, G_FILE_TEST_EXISTS)) { g_debug ("not a switch [%s]", path); g_debug ("not a switch [%s]", path2); g_free (path2); goto out; } g_free (path); path = path2; } /* get caps */ ret = g_file_get_contents (path, &contents, NULL, &error); if (!ret) { g_debug ("failed to get contents for [%s]: %s", path, error->message); g_error_free (error); goto out; } /* convert to a bitmask */ num_bits = up_input_str_to_bitmask (contents, bitmask, sizeof (bitmask)); if ((num_bits == 0) || (num_bits >= SW_CNT)) { g_debug ("invalid bitmask entry for %s", native_path); ret = FALSE; goto out; } /* is this the watched switch? */ if (!test_bit (input->watched_switch, bitmask)) { g_debug ("not the watched switch: %s", native_path); ret = FALSE; goto out; } /* get device file */ device_file = g_udev_device_get_device_file (d); if (device_file == NULL || device_file[0] == '\0') { g_debug ("no device file: %s", native_path); ret = FALSE; goto out; } /* open device file */ eventfd = open (device_file, O_RDONLY | O_NONBLOCK); if (eventfd < 0) { g_warning ("cannot open '%s': %s", device_file, strerror (errno)); ret = FALSE; goto out; } /* get initial state */ if (ioctl (eventfd, EVIOCGSW(sizeof (bitmask)), bitmask) < 0) { g_warning ("ioctl EVIOCGSW on %s failed", native_path); close(eventfd); ret = FALSE; goto out; } /* create channel */ g_debug ("watching %s (%i)", device_file, eventfd); input->channel = g_io_channel_unix_new (eventfd); g_io_channel_set_close_on_unref (input->channel, TRUE); /* set binary encoding */ status = g_io_channel_set_encoding (input->channel, NULL, &error); if (status != G_IO_STATUS_NORMAL) { g_warning ("failed to set encoding: %s", error->message); g_error_free (error); ret = FALSE; goto out; } /* watch this */ g_io_add_watch (input->channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, up_input_event_io, input); /* set if we are closed */ g_debug ("using %s for watched switch event", native_path); input->last_switch_state = test_bit (input->watched_switch, bitmask); out: g_free (native_path); g_free (path); g_free (contents); return ret; } /** * up_input_init: **/ static void up_input_init (UpInput *input) { input->last_switch_state = -1; } /** * up_input_finalize: **/ static void up_input_finalize (GObject *object) { UpInput *input; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_INPUT (object)); input = UP_INPUT (object); if (input->channel) { g_io_channel_shutdown (input->channel, FALSE, NULL); g_io_channel_unref (input->channel); } G_OBJECT_CLASS (up_input_parent_class)->finalize (object); } static void up_input_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { UpInput *input = UP_INPUT (object); switch (property_id) { case PROP_WATCHED_SWITCH: input->watched_switch = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } } static void up_input_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UpInput *input = UP_INPUT (object); switch (property_id) { case PROP_WATCHED_SWITCH: g_value_set_uint (value, input->watched_switch); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } } /** * up_input_class_init: **/ static void up_input_class_init (UpInputClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_input_finalize; object_class->set_property = up_input_set_property; object_class->get_property = up_input_get_property; g_object_class_install_property (object_class, PROP_WATCHED_SWITCH, g_param_spec_uint("watched-switch", "Watched switch", "The input switch to watch", SW_LID, SW_MAX, SW_LID, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); signals[SWITCH_CHANGED] = g_signal_new ("switch-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); } /** * up_input_new: * * Returns a #UpInput that watches the computer lid switch. **/ UpInput * up_input_new (void) { return g_object_new (UP_TYPE_INPUT, NULL); } /** * up_input_new_for_switch: * @watched_switch: the identifier for the `SW_` switch to watch * * Returns a #UpInput that watches the switched passed as argument. **/ UpInput * up_input_new_for_switch (guint watched_switch) { return g_object_new (UP_TYPE_INPUT, "watched-switch", watched_switch, NULL); } /** * up_input_get_switch_value: * @input: a #UpInput * * Returns the last state of the switch. It is an error * to call this without having successfully run * up_input_coldplug(). **/ gboolean up_input_get_switch_value (UpInput *input) { g_return_val_if_fail (UP_IS_INPUT(input), FALSE); g_return_val_if_fail (input->last_switch_state != -1, FALSE); return input->last_switch_state; } 07070100000078000081A400000000000000000000000166EA481400000567000000000000000000000000000000000000002300000000upower-1.90.6/src/linux/up-input.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_INPUT_H__ #define __UP_INPUT_H__ #include <glib-object.h> #include <gudev/gudev.h> G_BEGIN_DECLS #define UP_TYPE_INPUT (up_input_get_type ()) G_DECLARE_FINAL_TYPE (UpInput, up_input, UP, INPUT, GObject) GType up_input_get_type (void); UpInput *up_input_new (void); UpInput *up_input_new_for_switch (guint watched_switch); gboolean up_input_coldplug (UpInput *input, GUdevDevice *d); gboolean up_input_get_switch_value (UpInput *input); G_END_DECLS #endif /* __UP_INPUT_H__ */ 07070100000079000081A400000000000000000000000166EA4814000008EC000000000000000000000000000000000000002400000000upower-1.90.6/src/linux/up-native.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <glib.h> #include <gio/gio.h> #include <gudev/gudev.h> #include "up-native.h" /** * up_native_get_native_path: * @object: the native tracking object * * This converts a GObject used as the device data into a native path. * This would be implemented on a Linux system using: * g_udev_device_get_sysfs_path (G_UDEV_DEVICE (object)) or * g_dbus_object_get_object_path (G_DBUS_OBJECT (object)) for Bluetooth LE * devices (handled by BlueZ). * * Return value: Device name for devices of subsystem "power_supply", otherwise * the native path for the device which is unique. **/ const gchar * up_native_get_native_path (GObject *object) { GUdevDevice *device; /* That's a UpBluez */ if (G_IS_DBUS_OBJECT (object)) return g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); device = G_UDEV_DEVICE (object); /* Device names within the same subsystem must be unique. To avoid * treating the same power supply device on variable buses as different * only because e. g. the USB or bluetooth tree layout changed, only * use their name as identification. Also see * http://bugzilla.kernel.org/show_bug.cgi?id=62041 */ if (g_strcmp0 (g_udev_device_get_subsystem (device), "power_supply") == 0) return g_udev_device_get_name (device); /* we do not expect other devices than power_supply, but provide this * fallback for completeness */ return g_udev_device_get_sysfs_path (device); } 0707010000007A000081A400000000000000000000000166EA481400001190000000000000000000000000000000000000001E00000000upower-1.90.6/src/meson.build upowerd_deps = declare_dependency( include_directories: [ include_directories('.'), include_directories('..'), include_directories('../dbus'), ], dependencies: [ m_dep, glib_dep, gobject_dep, gio_dep, gio_unix_dep, libupower_glib_dep, upowerd_dbus_dep, polkit ], compile_args: [ '-DUP_COMPILATION', '-DHISTORY_DIR="@0@"'.format(historydir), '-DSTATE_DIR="@0@"'.format(statedir), ], ) upshared = {} subdir('dummy') subdir('linux') subdir('bsd') subdir('openbsd') subdir('freebsd') # Everything that is also needed by the tests upowerd_private = static_library('upowerd-private', sources: [ 'up-constants.h', 'up-config.h', 'up-config.c', 'up-daemon.h', 'up-daemon.c', 'up-device.h', 'up-device.c', 'up-device-battery.h', 'up-device-battery.c', 'up-device-list.h', 'up-device-list.c', 'up-enumerator.c', 'up-enumerator.h', 'up-kbd-backlight.h', 'up-kbd-backlight.c', 'up-history.h', 'up-history.c', 'up-backend.h', 'up-native.h', 'up-common.h', 'up-common.c', 'up-polkit.c', 'up-polkit.h', ], dependencies: [ upowerd_deps ], c_args: [ '-DG_LOG_DOMAIN="UPower"' ], ) upowerd = executable('upowerd', sources: [ 'up-main.c', ], dependencies: upowerd_deps, link_with: [ upowerd_private, upshared[os_backend] ], gnu_symbol_visibility: 'hidden', install: true, install_dir: get_option('prefix') / get_option('libexecdir'), c_args: [ '-DG_LOG_DOMAIN="UPower"' ], ) up_self_test = executable('up_self_test', sources: [ 'up-self-test.c', ], c_args: [ '-DUPOWER_CONF_PATH="@0@"'.format(meson.project_source_root() / 'etc' / 'UPower.conf'), '-DG_LOG_DOMAIN="UPower"', ], dependencies: upowerd_deps, link_with: [ upowerd_private, upshared['dummy'] ], gnu_symbol_visibility: 'hidden', build_by_default: true, install: false, ) ############# # Data/Config files ############# install_emptydir(historydir) cdata = configuration_data() cdata.set('libexecdir', get_option('prefix') / get_option('libexecdir')) cdata.set('historydir', historydir) configure_file( input: 'org.freedesktop.UPower.service.in', output: 'org.freedesktop.UPower.service', install_dir: dbusdir / 'system-services', configuration: cdata, ) configure_file( input: 'org.freedesktop.UPower.conf.in', output: 'org.freedesktop.UPower.conf', install_dir: dbusdir / 'system.d', configuration: cdata, ) if systemdsystemunitdir != 'no' configure_file( input: 'upower.service.in', output: 'upower.service', install_dir: systemdsystemunitdir, configuration: cdata, ) endif ############# # Tests ############# test( 'self-test', up_self_test, ) # On Linux, we can run the additional integration test; # defined here as we would have a circular dependency otherwise. if os_backend == 'linux' and gobject_introspection.found() env = environment() env.prepend('top_builddir', join_paths(meson.project_build_root())) env.prepend('LD_LIBRARY_PATH', join_paths(meson.project_build_root(), 'libupower-glib')) env.prepend('GI_TYPELIB_PATH', join_paths(meson.project_build_root(), 'libupower-glib')) python3 = find_program('python3') unittest_inspector = find_program('linux/unittest_inspector.py') r = run_command(unittest_inspector, files('linux/integration-test.py'), check: false) unit_tests = r.stdout().strip().split('\n') foreach ut: unit_tests ut_args = files('linux/integration-test.py') ut_args += ut test(ut, python3, args: ut_args, env: env, depends: [ libupower_glib_typelib, upowerd ], timeout: 80, ) endforeach install_data( [ 'linux/integration-test.py', 'linux/output_checker.py', ], install_dir: get_option('prefix') / get_option('libexecdir') / 'upower' ) install_subdir('linux/tests/', install_dir: get_option('prefix') / get_option('libexecdir') / 'upower' ) configure_file( input: 'upower-integration.test.in', output: 'upower-integration.test', install_dir: get_option('datadir') / 'installed-tests' / 'upower', configuration: cdata ) endif 0707010000007B000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001A00000000upower-1.90.6/src/openbsd0707010000007C000081A400000000000000000000000166EA48140000012B000000000000000000000000000000000000002600000000upower-1.90.6/src/openbsd/meson.buildupshared += { 'openbsd': static_library('upshared', sources: [ 'up-backend.c', 'up-native.c', 'up-apm-native.h', ], c_args: [ '-DG_LOG_DOMAIN="UPower-Openbsd"' ], dependencies: [ gudev_dep, upowerd_deps, upshared_common_dep ], build_by_default: false, )} 0707010000007D000081A400000000000000000000000166EA481400000B10000000000000000000000000000000000000002A00000000upower-1.90.6/src/openbsd/up-apm-native.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Landry Breuil <landry@openbsd.org> * * 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 __UP_APM_NATIVE_H__ #define __UP_APM_NATIVE_H__ /* os-specific headers */ #include <errno.h> /* errno */ #include <fcntl.h> /* open() */ /* kevent() */ #include <sys/types.h> #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE #include <sys/event.h> #endif #include <sys/time.h> #include <sys/ioctl.h> /* ioctl() */ /* APM macros */ #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE #include <machine/apmvar.h> /* sensor struct defs */ #include <sys/sensors.h> /* sysctl() */ #include <sys/param.h> #include <sys/sysctl.h> #else struct sensordev { }; struct apm_power_info { enum { APM_BATT_HIGH, APM_BATT_LOW, APM_BATT_CRITICAL, APM_BATT_CHARGING, APM_BATT_UNKNOWN, APM_BATTERY_ABSENT, } battery_state; enum { APM_AC_OFF, APM_AC_ON, APM_AC_BACKUP, APM_AC_UNKNOWN, } ac_state; int battery_life; int minutes_left; }; #endif #include <glib.h> #include <glib-object.h> G_BEGIN_DECLS #define UP_TYPE_APM_NATIVE (up_apm_native_get_type ()) #define UP_APM_NATIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_APM_NATIVE, UpApmNative)) #define UP_APM_NATIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_APM_NATIVE, UpApmNativeClass)) #define UP_IS_APM_NATIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_APM_NATIVE)) #define UP_IS_APM_NATIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_APM_NATIVE)) #define UP_APM_NATIVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_APM_NATIVE, UpApmNativeClass)) typedef struct { GObject parent; gchar* path; } UpApmNative; typedef struct { GObjectClass parent_class; } UpApmNativeClass; // XX in .c ? //GType up_apm_native_get_type (void); //G_DEFINE_TYPE (UpApmNative, up_apm_native, G_TYPE_OBJECT) UpApmNative* up_apm_native_new (const char*); const gchar * up_apm_native_get_path(UpApmNative*); int up_apm_get_fd(); gboolean up_native_is_laptop(); gboolean up_native_get_sensordev(const char*, struct sensordev*); G_END_DECLS #endif 0707010000007E000081A400000000000000000000000166EA481400004B8C000000000000000000000000000000000000002700000000upower-1.90.6/src/openbsd/up-backend.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Landry Breuil <landry@openbsd.org> * * 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 "up-apm-native.h" #include "up-backend.h" #include "up-daemon.h" #include "up-device.h" #include "up-config.h" #include "up-backend-bsd-private.h" #include <string.h> /* strcmp() */ static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); static gboolean up_backend_apm_get_power_info(struct apm_power_info*); static gpointer up_backend_apm_event_thread(gpointer object); UpDeviceState up_backend_apm_get_battery_state_value(u_char battery_state); static void up_backend_update_acpibat_state(UpDevice*, struct sensordev); static void up_backend_update_lid_status(UpDaemon*); static gboolean up_apm_device_get_on_battery (UpDevice *device, gboolean *on_battery); static gboolean up_apm_device_get_online (UpDevice *device, gboolean *online); static gboolean up_apm_device_refresh (UpDevice *device, UpRefreshReason reason); struct UpBackendPrivate { UpDaemon *daemon; UpDevice *ac; UpDevice *battery; GThread *apm_thread; gboolean is_laptop; UpConfig *config; GDBusProxy *seat_manager_proxy; }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (UpBackend, up_backend, G_TYPE_OBJECT) /** * functions called by upower daemon **/ /* those three ripped from freebsd/up-device-supply.c */ gboolean up_apm_device_get_on_battery (UpDevice *device, gboolean * on_battery) { UpDeviceKind type; UpDeviceState state; gboolean is_present; g_return_val_if_fail (on_battery != NULL, FALSE); g_object_get (device, "type", &type, "state", &state, "is-present", &is_present, (void*) NULL); if (type != UP_DEVICE_KIND_BATTERY) return FALSE; if (state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (!is_present) return FALSE; *on_battery = (state == UP_DEVICE_STATE_DISCHARGING); return TRUE; } gboolean up_apm_device_get_online (UpDevice *device, gboolean * online) { UpDeviceKind type; gboolean online_tmp; g_return_val_if_fail (online != NULL, FALSE); g_object_get (device, "type", &type, "online", &online_tmp, (void*) NULL); if (type != UP_DEVICE_KIND_LINE_POWER) return FALSE; *online = online_tmp; return TRUE; } /** * up_backend_coldplug: * @backend: The %UpBackend class instance * @daemon: The %UpDaemon controlling instance * * Finds all the devices already plugged in, and emits device-add signals for * each of them. * * Return value: %TRUE for success **/ gboolean up_backend_coldplug (UpBackend *backend, UpDaemon *daemon) { GError *err = NULL; UpDeviceClass *device_class; gint64 current_time; backend->priv = up_backend_get_instance_private (backend); backend->priv->daemon = g_object_ref (daemon); backend->priv->is_laptop = up_native_is_laptop(); g_debug("is_laptop:%d",backend->priv->is_laptop); if (backend->priv->is_laptop) { UpApmNative *acnative = NULL; UpApmNative *battnative = NULL; acnative = up_apm_native_new("/ac"); battnative = up_apm_native_new("/batt"); backend->priv->ac = UP_DEVICE(up_device_new (backend->priv->daemon, G_OBJECT(acnative))); backend->priv->battery = UP_DEVICE(up_device_new (backend->priv->daemon, G_OBJECT(battnative))); g_object_unref (acnative); g_object_unref (battnative); device_class = UP_DEVICE_GET_CLASS (backend->priv->battery); device_class->get_on_battery = up_apm_device_get_on_battery; device_class->get_online = up_apm_device_get_online; device_class->refresh = up_apm_device_refresh; device_class = UP_DEVICE_GET_CLASS (backend->priv->ac); device_class->get_on_battery = up_apm_device_get_on_battery; device_class->get_online = up_apm_device_get_online; device_class->refresh = up_apm_device_refresh; /* creates thread */ if((backend->priv->apm_thread = (GThread*) g_thread_try_new("apm-poller",(GThreadFunc)up_backend_apm_event_thread, (void*) backend, &err)) == NULL) { g_warning("Thread create failed: %s", err->message); g_error_free (err); } /* setup dummy */ current_time = g_get_real_time () / G_USEC_PER_SEC; g_object_set (backend->priv->battery, "type", UP_DEVICE_KIND_BATTERY, "power-supply", TRUE, "is-present", TRUE, "is-rechargeable", TRUE, "has-history", TRUE, "state", UP_DEVICE_STATE_UNKNOWN, "percentage", 0.0f, "time-to-empty", (gint64) 0, "update-time", (guint64) current_time, (void*) NULL); g_object_set (backend->priv->ac, "type", UP_DEVICE_KIND_LINE_POWER, "online", TRUE, "power-supply", TRUE, "update-time", (guint64) current_time, (void*) NULL); up_backend_update_lid_status(daemon); if (!g_initable_init (G_INITABLE (backend->priv->ac), NULL, NULL)) g_warning ("failed to coldplug ac"); else g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, backend->priv->ac); if (!g_initable_init (G_INITABLE (backend->priv->battery), NULL, NULL)) g_warning ("failed to coldplug battery"); else g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, backend->priv->battery); } return TRUE; } /** * up_backend_unplug: * @backend: The %UpBackend class instance * * Forget about all learned devices, effectively undoing up_backend_coldplug. * Resources are released without emitting signals. */ void up_backend_unplug (UpBackend *backend) { if (backend->priv->daemon != NULL) { g_object_unref (backend->priv->daemon); backend->priv->daemon = NULL; } } /** * up_backend_get_seat_manager_proxy: * @backend: The %UpBackend class instance * * Returns the seat manager object or NULL on error. [transfer none] */ GDBusProxy * up_backend_get_seat_manager_proxy (UpBackend *backend) { g_return_val_if_fail (UP_IS_BACKEND (backend), NULL); return backend->priv->seat_manager_proxy; } /** * up_backend_get_config: * @backend: The %UpBackend class instance * * Returns the UpConfig object or NULL on error. [transfer none] */ UpConfig * up_backend_get_config (UpBackend *backend) { g_return_val_if_fail (UP_IS_BACKEND (backend), NULL); return backend->priv->config; } /** * OpenBSD specific code **/ static gboolean up_backend_apm_get_power_info(struct apm_power_info *bstate) { bstate->battery_state = 255; bstate->ac_state = 255; bstate->battery_life = 0; bstate->minutes_left = -1; #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE if (-1 == ioctl(up_apm_get_fd(), APM_IOC_GETPOWER, bstate)) { g_error("ioctl on apm fd failed : %s", g_strerror(errno)); return FALSE; } #endif return TRUE; } UpDeviceState up_backend_apm_get_battery_state_value(u_char battery_state) { switch(battery_state) { case APM_BATT_HIGH: return UP_DEVICE_STATE_FULLY_CHARGED; case APM_BATT_LOW: return UP_DEVICE_STATE_DISCHARGING; // XXXX case APM_BATT_CRITICAL: return UP_DEVICE_STATE_EMPTY; case APM_BATT_CHARGING: return UP_DEVICE_STATE_CHARGING; case APM_BATTERY_ABSENT: return UP_DEVICE_STATE_EMPTY; case APM_BATT_UNKNOWN: return UP_DEVICE_STATE_UNKNOWN; } return -1; } static gboolean up_backend_update_ac_state(UpDevice* device) { gboolean ret, new_is_online, cur_is_online; struct apm_power_info a; up_backend_update_lid_status(up_device_get_daemon(device)); ret = up_backend_apm_get_power_info(&a); if (!ret) return ret; g_object_get (device, "online", &cur_is_online, (void*) NULL); /* XXX use acpiac0.indicator0 if available */ new_is_online = (a.ac_state == APM_AC_ON ? TRUE : FALSE); if (cur_is_online != new_is_online) { g_object_set (device, "online", new_is_online, (void*) NULL); return TRUE; } return FALSE; } static gboolean up_backend_update_battery_state(UpDevice* device) { gdouble percentage; gboolean ret, is_present; struct sensordev sdev; UpDeviceState cur_state, new_state = UP_DEVICE_STATE_UNKNOWN; gint64 cur_time_to_empty, new_time_to_empty; struct apm_power_info a; ret = up_backend_apm_get_power_info(&a); if (!ret) return ret; g_object_get (device, "state", &cur_state, "percentage", &percentage, "time-to-empty", &cur_time_to_empty, "is-present", &is_present, (void*) NULL); // zero out new_time_to empty if we're not discharging or minutes_left is negative new_time_to_empty = (new_state == UP_DEVICE_STATE_DISCHARGING && a.minutes_left > 0 ? a.minutes_left : 0); /* XXX use acpibat0.raw0 if available */ /* * XXX: Stop having a split brain regarding * up_backend_apm_get_battery_state_value(). Either move the state * setting code below into that function, or inline that function here. */ new_state = up_backend_apm_get_battery_state_value(a.battery_state); // if percentage/minutes goes down or ac is off, we're likely discharging.. if (percentage < a.battery_life || cur_time_to_empty < new_time_to_empty || a.ac_state == APM_AC_OFF) new_state = UP_DEVICE_STATE_DISCHARGING; /* * If we're on AC, we may either be charging, or the battery is already * fully charged. Figure out which. */ if (a.ac_state == APM_AC_ON) { if ((gdouble) a.battery_life >= 99.0) new_state = UP_DEVICE_STATE_FULLY_CHARGED; else new_state = UP_DEVICE_STATE_CHARGING; } if ((a.battery_state == APM_BATTERY_ABSENT) || (a.battery_state == APM_BATT_UNKNOWN)) { /* Reset some known fields which remain untouched below. */ g_object_set(device, "is-rechargeable", FALSE, "energy", (gdouble) 0.0, "energy-empty", (gdouble) 0.0, "energy-full", (gdouble) 0.0, "energy-full-design", (gdouble) 0.0, "energy-rate", (gdouble) 0.0, NULL); is_present = FALSE; if (a.battery_state == APM_BATTERY_ABSENT) new_state = UP_DEVICE_STATE_EMPTY; else new_state = UP_DEVICE_STATE_UNKNOWN; } else { is_present = TRUE; } if (cur_state != new_state || percentage != (gdouble) a.battery_life || cur_time_to_empty != new_time_to_empty) { g_object_set (device, "state", new_state, "percentage", (gdouble) a.battery_life, "time-to-empty", new_time_to_empty * 60, "is-present", is_present, (void*) NULL); if(up_native_get_sensordev("acpibat0", &sdev)) up_backend_update_acpibat_state(device, sdev); return TRUE; } return FALSE; } /* update acpibat properties */ static void up_backend_update_acpibat_state(UpDevice* device, struct sensordev s) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE enum sensor_type type; int numt; gdouble bst_volt, bst_rate, bif_cap, bif_lastfullcap, bst_cap, bif_lowcap, capacity; /* gdouble bif_dvolt; */ struct sensor sens; size_t slen = sizeof(sens); int mib[] = {CTL_HW, HW_SENSORS, 0, 0, 0}; mib[2] = s.num; for (type = 0; type < SENSOR_MAX_TYPES; type++) { mib[3] = type; for (numt = 0; numt < s.maxnumt[type]; numt++) { mib[4] = numt; if (sysctl(mib, 5, &sens, &slen, NULL, 0) < 0) g_error("failed to get sensor type %d(%s) numt %d on %s", type, sensor_type_s[type], numt, s.xname); else if (slen > 0 && (sens.flags & SENSOR_FINVALID) == 0) { if (sens.type == SENSOR_VOLTS_DC && !strcmp(sens.desc, "current voltage")) bst_volt = sens.value / 1000000.0f; if ((sens.type == SENSOR_AMPHOUR || sens.type == SENSOR_WATTHOUR) && !strcmp(sens.desc, "design capacity")) { bif_cap = (sens.type == SENSOR_AMPHOUR ? bst_volt : 1) * sens.value / 1000000.0f; } if ((sens.type == SENSOR_AMPHOUR || sens.type == SENSOR_WATTHOUR) && !strcmp(sens.desc, "last full capacity")) { bif_lastfullcap = (sens.type == SENSOR_AMPHOUR ? bst_volt : 1) * sens.value / 1000000.0f; } if ((sens.type == SENSOR_AMPHOUR || sens.type == SENSOR_WATTHOUR) && !strcmp(sens.desc, "low capacity")) { bif_lowcap = (sens.type == SENSOR_AMPHOUR ? bst_volt : 1) * sens.value / 1000000.0f; } if ((sens.type == SENSOR_AMPHOUR || sens.type == SENSOR_WATTHOUR) && !strcmp(sens.desc, "remaining capacity")) { bst_cap = (sens.type == SENSOR_AMPHOUR ? bst_volt : 1) * sens.value / 1000000.0f; } if ((sens.type == SENSOR_AMPS || sens.type == SENSOR_WATTS) && !strcmp(sens.desc, "rate")) { bst_rate = (sens.type == SENSOR_AMPS ? bst_volt : 1) * sens.value / 1000000.0f; } /* bif_dvolt = "voltage" = unused ? amphour1 = warning capacity ? raw0 = battery state */ } } } capacity = 0.0f; if(bif_lastfullcap > 0 && bif_cap > 0) { capacity = (bif_lastfullcap / bif_cap) * 100.0f; if (capacity < 0) capacity = 0.0f; if (capacity > 100.0) capacity = 100.0f; } g_object_set (device, "energy", bst_cap, "energy-full", bif_lastfullcap, "energy-full-design", bif_cap, "energy-rate", bst_rate, "energy-empty", bif_lowcap, "voltage", bst_volt, "capacity", capacity, (void*) NULL); #endif } /* callback updating the device */ static gboolean up_backend_apm_powerchange_event_cb(gpointer object) { UpBackend *backend; g_return_val_if_fail (UP_IS_BACKEND (object), FALSE); backend = UP_BACKEND (object); up_device_refresh_internal (backend->priv->ac, UP_REFRESH_EVENT); up_device_refresh_internal (backend->priv->battery, UP_REFRESH_EVENT); /* return false to not endless loop */ return FALSE; } static gboolean up_apm_device_refresh(UpDevice* device, UpRefreshReason reason) { UpDeviceKind type; gboolean ret; g_object_get (device, "type", &type, NULL); switch (type) { case UP_DEVICE_KIND_LINE_POWER: ret = up_backend_update_ac_state(device); break; case UP_DEVICE_KIND_BATTERY: ret = up_backend_update_battery_state(device); break; default: g_assert_not_reached (); break; } if (ret) g_object_set (device, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); return ret; } /* * Check the lid status, return TRUE if one was found, FALSE otherwise. */ static void up_backend_update_lid_status(UpDaemon *daemon) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE /* Use hw.sensors.acpibtn0.indicator0=On (lid open) */ struct sensordev sensordev; struct sensor sensor; size_t sdlen, slen; int dev, numt, mib[5] = {CTL_HW, HW_SENSORS, 0, 0, 0}; gboolean lid_found = FALSE; gboolean lid_open = FALSE; sdlen = sizeof(struct sensordev); slen = sizeof(struct sensor); /* go through all acpibtn devices, and check if one of the values match "lid" if so, use that device. */ for (dev = 0; ; dev++) { mib[2] = dev; if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { if (errno == ENXIO) continue; if (errno == ENOENT) break; } if (strstr(sensordev.xname, "acpibtn") != NULL) { mib[3] = SENSOR_INDICATOR; for (numt = 0; numt < sensordev.maxnumt[SENSOR_INDICATOR]; numt++) { mib[4] = numt; if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1) { if (errno != ENOENT) { g_warning("failed to get sensor data from %s", sensordev.xname); continue; } } /* * Found an acpibtn device, now check if the * description has got anything with a lid in it. */ if (strstr(sensor.desc, "lid open") == NULL) { g_warning ("nothing here for %s with %s\n", sensordev.xname, sensor.desc); continue; } else { lid_found = TRUE; if (sensor.value) lid_open = TRUE; else lid_open = FALSE; } } } } up_daemon_set_lid_is_present (daemon, lid_found); up_daemon_set_lid_is_closed (daemon, !lid_open); #endif } /* thread doing kqueue() on apm device */ static gpointer up_backend_apm_event_thread(gpointer object) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE int kq, nevents; struct kevent ev; struct timespec ts = {600, 0}, sts = {0, 0}; UpBackend *backend; g_return_val_if_fail (UP_IS_BACKEND (object), NULL); backend = UP_BACKEND (object); g_debug("setting up apm thread"); kq = kqueue(); if (kq <= 0) g_error("kqueue"); EV_SET(&ev, up_apm_get_fd(), EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, NULL); nevents = 1; if (kevent(kq, &ev, nevents, NULL, 0, &sts) < 0) g_error("kevent"); /* blocking wait on kqueue */ for (;;) { int rv; /* 10mn timeout */ sts = ts; if ((rv = kevent(kq, NULL, 0, &ev, 1, &sts)) < 0) break; if (!rv) continue; if (ev.ident == (guint) up_apm_get_fd() && APM_EVENT_TYPE(ev.data) == APM_POWER_CHANGE ) { /* g_idle_add the callback */ g_idle_add((GSourceFunc) up_backend_apm_powerchange_event_cb, backend); } } #endif return NULL; /* shouldnt be reached ? */ } /** * GObject class functions **/ /** * up_backend_new: * * Return value: a new %UpBackend object. **/ UpBackend * up_backend_new (void) { return g_object_new (UP_TYPE_BACKEND, NULL); } /** * up_backend_class_init: * @klass: The UpBackendClass **/ static void up_backend_class_init (UpBackendClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_backend_finalize; signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); } /** * up_backend_init: **/ static void up_backend_init (UpBackend *backend) { backend->priv = up_backend_get_instance_private (backend); backend->priv->config = up_config_new (); backend->priv->seat_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, CONSOLEKIT2_DBUS_NAME, CONSOLEKIT2_DBUS_PATH, CONSOLEKIT2_DBUS_INTERFACE, NULL, NULL); } /** * up_backend_finalize: **/ static void up_backend_finalize (GObject *object) { UpBackend *backend; g_return_if_fail (UP_IS_BACKEND (object)); backend = UP_BACKEND (object); g_object_unref (backend->priv->config); if (backend->priv->daemon != NULL) g_object_unref (backend->priv->daemon); if (backend->priv->battery != NULL) g_object_unref (backend->priv->battery); if (backend->priv->ac != NULL) g_object_unref (backend->priv->ac); g_clear_object (&backend->priv->seat_manager_proxy); /* XXX stop apm_thread ? */ G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } 0707010000007F000081A400000000000000000000000166EA481400000D2E000000000000000000000000000000000000002600000000upower-1.90.6/src/openbsd/up-native.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Landry Breuil <landry@openbsd.org> * * 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 "up-apm-native.h" #include "up-native.h" #include <unistd.h> /* close() */ #include <string.h> /* strcmp() */ /* XXX why does this macro needs to be in the .c ? */ G_DEFINE_TYPE (UpApmNative, up_apm_native, G_TYPE_OBJECT) static void up_apm_native_class_init (UpApmNativeClass *klass) { } static void up_apm_native_init (UpApmNative *self) { self->path = "empty"; } UpApmNative * up_apm_native_new(const gchar * path) { UpApmNative *native; native = UP_APM_NATIVE (g_object_new (UP_TYPE_APM_NATIVE, NULL)); native->path = g_strdup(path); return native; } const gchar * up_apm_native_get_path(UpApmNative * native) { return native->path; } int up_apm_get_fd() { static int apm_fd = -2; if (apm_fd == -2) { g_debug("apm_fd is not initialized yet, opening"); /* open /dev/apm */ if ((apm_fd = open("/dev/apm", O_RDONLY)) == -1) { if (errno != ENXIO && errno != ENOENT) g_error("cannot open device file"); } } return apm_fd; } /** * up_native_get_native_path: * @object: the native tracking object * * This converts a GObject used as the device data into a native path. * * Return value: The native path for the device which is unique, e.g. "/sys/class/power/BAT1" **/ const gchar * up_native_get_native_path (GObject *object) { return up_apm_native_get_path (UP_APM_NATIVE (object)); } /** * detect if we are on a desktop system or a laptop * heuristic : laptop if sysctl hw.acpiac0 is present (TODO) or if apm acstate != APM_AC_UNKNOWN */ gboolean up_native_is_laptop() { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE struct apm_power_info bstate; struct sensordev acpiac; if (up_native_get_sensordev("acpiac0", &acpiac)) return TRUE; if (-1 == ioctl(up_apm_get_fd(), APM_IOC_GETPOWER, &bstate)) g_error("ioctl on apm fd failed : %s", g_strerror(errno)); return bstate.ac_state != APM_AC_UNKNOWN; #else return TRUE; #endif } /** * get a sensordev by its xname (acpibatX/acpiacX) * returns a gboolean if found or not */ gboolean up_native_get_sensordev(const char * id, struct sensordev * snsrdev) { #ifndef UPOWER_CI_DISABLE_PLATFORM_CODE int devn; size_t sdlen = sizeof(struct sensordev); int mib[] = {CTL_HW, HW_SENSORS, 0, 0 ,0}; for (devn = 0 ; ; devn++) { mib[2] = devn; if (sysctl(mib, 3, snsrdev, &sdlen, NULL, 0) == -1) { if (errno == ENXIO) continue; if (errno == ENOENT) break; } if (!strcmp(snsrdev->xname, id)) return TRUE; } #endif return FALSE; } 07070100000080000081A400000000000000000000000166EA48140000052D000000000000000000000000000000000000003100000000upower-1.90.6/src/org.freedesktop.UPower.conf.in<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- --> <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <!-- Only root can own the service --> <policy user="root"> <allow own="org.freedesktop.UPower"/> </policy> <policy context="default"> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.DBus.Introspectable"/> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.DBus.Peer"/> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.DBus.Properties"/> <allow send_destination="org.freedesktop.UPower.Device" send_interface="org.freedesktop.DBus.Properties"/> <allow send_destination="org.freedesktop.UPower.KbdBacklight" send_interface="org.freedesktop.DBus.Properties"/> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.UPower"/> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.UPower.Device"/> <allow send_destination="org.freedesktop.UPower" send_interface="org.freedesktop.UPower.KbdBacklight"/> </policy> </busconfig> 07070100000081000081A400000000000000000000000166EA48140000006F000000000000000000000000000000000000003400000000upower-1.90.6/src/org.freedesktop.UPower.service.in[D-BUS Service] Name=org.freedesktop.UPower Exec=@libexecdir@/upowerd User=root SystemdService=upower.service 07070100000082000081A400000000000000000000000166EA4814000005D0000000000000000000000000000000000000002B00000000upower-1.90.6/src/up-backend-bsd-private.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2015 Eric Koegel <eric.koegel@gmail.com> * * 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 __UP_BACKEND_BSD_PRIVATE_H #define __UP_BACKEND_BSD_PRIVATE_H #include <gio/gio.h> #include "up-backend.h" #include "up-config.h" #define CONSOLEKIT2_DBUS_NAME "org.freedesktop.ConsoleKit" #define CONSOLEKIT2_DBUS_PATH "/org/freedesktop/ConsoleKit/Manager" #define CONSOLEKIT2_DBUS_INTERFACE "org.freedesktop.ConsoleKit.Manager" GDBusProxy *up_backend_get_seat_manager_proxy (UpBackend *backend); UpConfig *up_backend_get_config (UpBackend *backend); #endif /* __UP_BACKEND_BSD_PRIVATE_H */ 07070100000083000081A400000000000000000000000166EA481400000A6D000000000000000000000000000000000000001F00000000upower-1.90.6/src/up-backend.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 __UP_BACKEND_H #define __UP_BACKEND_H #include <glib-object.h> #include "config.h" #include "up-types.h" #include "up-device.h" #include "up-daemon.h" G_BEGIN_DECLS #define UP_TYPE_BACKEND (up_backend_get_type ()) #define UP_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_BACKEND, UpBackend)) #define UP_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_BACKEND, UpBackendClass)) #define UP_IS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_BACKEND)) #define UP_IS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_BACKEND)) #define UP_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_BACKEND, UpBackendClass)) #define UP_BACKEND_ERROR (up_backend_error_quark ()) #define UP_BACKEND_TYPE_ERROR (up_backend_error_get_type ()) typedef struct UpBackendPrivate UpBackendPrivate; typedef struct { GObject parent; UpBackendPrivate *priv; } UpBackend; typedef struct { GObjectClass parent_class; void (* device_added) (UpBackend *backend, GObject *native, UpDevice *device); void (* device_changed) (UpBackend *backend, GObject *native, UpDevice *device); void (* device_removed) (UpBackend *backend, GObject *native, UpDevice *device); } UpBackendClass; GType up_backend_get_type (void); UpBackend *up_backend_new (void); gboolean up_backend_coldplug (UpBackend *backend, UpDaemon *daemon); void up_backend_unplug (UpBackend *backend); void up_backend_take_action (UpBackend *backend); const char *up_backend_get_critical_action (UpBackend *backend); int up_backend_inhibitor_lock_take (UpBackend *backend, const char *reason, const char *mode); G_END_DECLS #endif /* __UP_BACKEND_H */ 07070100000084000081A400000000000000000000000166EA4814000008FF000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-common.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "up-common.h" #include <glib.h> char* up_make_safe_string (char *text) { guint i; guint idx = 0; /* no point checking */ if (text == NULL) return NULL; if (g_utf8_validate (text, -1, NULL)) return text; /* shunt up only safe chars */ for (i=0; text[i] != '\0'; i++) { if (g_ascii_isprint (text[i])) { /* only copy if the address is going to change */ if (idx != i) text[idx] = text[i]; idx++; } else { g_debug ("invalid char: 0x%02X", text[i]); } } /* ensure null terminated */ text[idx] = '\0'; return text; } UpDeviceTechnology up_convert_device_technology (const gchar *type) { if (type == NULL) return UP_DEVICE_TECHNOLOGY_UNKNOWN; /* every case combination of Li-Ion is commonly used.. */ if (g_ascii_strcasecmp (type, "li-ion") == 0 || g_ascii_strcasecmp (type, "lion") == 0) return UP_DEVICE_TECHNOLOGY_LITHIUM_ION; if (g_ascii_strcasecmp (type, "pb") == 0 || g_ascii_strcasecmp (type, "pbac") == 0) return UP_DEVICE_TECHNOLOGY_LEAD_ACID; if (g_ascii_strcasecmp (type, "lip") == 0 || g_ascii_strcasecmp (type, "lipo") == 0 || g_ascii_strcasecmp (type, "li-poly") == 0) return UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER; if (g_ascii_strcasecmp (type, "nimh") == 0) return UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE; if (g_ascii_strcasecmp (type, "life") == 0) return UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE; return UP_DEVICE_TECHNOLOGY_UNKNOWN; } 07070100000085000081A400000000000000000000000166EA4814000003EE000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-common.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #pragma once #include "up-types.h" char *up_make_safe_string (char *text); UpDeviceTechnology up_convert_device_technology (const gchar *type); 07070100000086000081A400000000000000000000000166EA48140000122F000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-config.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * * 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 <glib-object.h> #include <gio/gio.h> #include "up-config.h" static void up_config_finalize (GObject *object); /** * UpConfigPrivate: * * Private #UpConfig data **/ struct _UpConfigPrivate { GKeyFile *keyfile; }; G_DEFINE_TYPE_WITH_PRIVATE (UpConfig, up_config, G_TYPE_OBJECT) static gpointer up_config_object = NULL; /** * up_config_get_boolean: **/ gboolean up_config_get_boolean (UpConfig *config, const gchar *key) { return g_key_file_get_boolean (config->priv->keyfile, "UPower", key, NULL); } /** * up_config_get_uint: **/ guint up_config_get_uint (UpConfig *config, const gchar *key) { int val; val = g_key_file_get_integer (config->priv->keyfile, "UPower", key, NULL); if (val < 0) return 0; return val; } /** * up_config_get_double: **/ gdouble up_config_get_double (UpConfig *config, const gchar *key) { int val; val = g_key_file_get_double (config->priv->keyfile, "UPower", key, NULL); if (val < 0.0) return 0.0; return val; } /** * up_config_get_string: **/ gchar * up_config_get_string (UpConfig *config, const gchar *key) { return g_key_file_get_string (config->priv->keyfile, "UPower", key, NULL); } /** * up_config_class_init: **/ static void up_config_class_init (UpConfigClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_config_finalize; } /** * up_config_init: **/ static void up_config_init (UpConfig *config) { gboolean allow_risky_critical_action = FALSE; g_autofree gchar *critical_action = NULL; GError *error = NULL; g_autofree gchar *filename = NULL; gboolean ret; config->priv = up_config_get_instance_private (config); config->priv->keyfile = g_key_file_new (); filename = g_strdup (g_getenv ("UPOWER_CONF_FILE_NAME")); if (filename == NULL) filename = g_build_filename (PACKAGE_SYSCONF_DIR,"UPower", "UPower.conf", NULL); /* load */ ret = g_key_file_load_from_file (config->priv->keyfile, filename, G_KEY_FILE_NONE, &error); if (!ret) { g_warning ("failed to load config file '%s': %s", filename, error->message); g_error_free (error); } /* Warn for any dangerous configurations */ critical_action = up_config_get_string (config, "CriticalPowerAction"); allow_risky_critical_action = up_config_get_boolean (config, "AllowRiskyCriticalPowerAction"); if (!g_strcmp0 (critical_action, "Suspend") || !g_strcmp0 (critical_action, "Ignore")) { if (allow_risky_critical_action) { g_warning ("The \"%s\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. Use AllowRiskyCriticalPowerAction=false to disable" " support for risky settings.", critical_action); } else { g_warning ("The \"%s\" CriticalPowerAction setting is considered risky:" " abrupt power loss due to battery exhaustion may lead to data" " corruption. The system will perform \"HybridSleep\" instead." " Use AllowRiskyCriticalPowerAction=true to enable support for" " risky settings.", critical_action); } } } /** * up_config_finalize: **/ static void up_config_finalize (GObject *object) { UpConfig *config = UP_CONFIG (object); UpConfigPrivate *priv = config->priv; g_key_file_free (priv->keyfile); G_OBJECT_CLASS (up_config_parent_class)->finalize (object); } /** * up_config_new: **/ UpConfig * up_config_new (void) { if (up_config_object != NULL) { g_object_ref (up_config_object); } else { up_config_object = g_object_new (UP_TYPE_CONFIG, NULL); g_object_add_weak_pointer (up_config_object, &up_config_object); } return UP_CONFIG (up_config_object); } 07070100000087000081A400000000000000000000000166EA4814000007FC000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-config.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * * 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 __UP_CONFIG_H #define __UP_CONFIG_H #include <glib-object.h> G_BEGIN_DECLS #define UP_TYPE_CONFIG (up_config_get_type ()) #define UP_CONFIG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_CONFIG, UpConfig)) #define UP_CONFIG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_CONFIG, UpConfigClass)) #define UP_IS_CONFIG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_CONFIG)) typedef struct _UpConfigPrivate UpConfigPrivate; typedef struct _UpConfig UpConfig; typedef struct _UpConfigClass UpConfigClass; struct _UpConfig { GObject parent; UpConfigPrivate *priv; }; struct _UpConfigClass { GObjectClass parent_class; }; GType up_config_get_type (void); UpConfig *up_config_new (void); gboolean up_config_get_boolean (UpConfig *config, const gchar *key); guint up_config_get_uint (UpConfig *config, const gchar *key); gdouble up_config_get_double (UpConfig *config, const gchar *key); gchar *up_config_get_string (UpConfig *config, const gchar *key); G_DEFINE_AUTOPTR_CLEANUP_FUNC(UpConfig, g_object_unref) G_END_DECLS #endif /* __UP_CONFIG_H */ 07070100000088000081A400000000000000000000000166EA481400000647000000000000000000000000000000000000002100000000upower-1.90.6/src/up-constants.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2017 Bastien Nocera <hadess@hadess.net> * * 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 __UP_CONSTANTS_H #define __UP_CONSTANTS_H #include <glib-object.h> G_BEGIN_DECLS #define UP_DAEMON_UNKNOWN_TIMEOUT 1 /* second */ #define UP_DAEMON_UNKNOWN_POLL_TIME 5 /* second */ #define UP_DAEMON_ESTIMATE_TIMEOUT 5 /* second */ #define UP_DAEMON_SHORT_TIMEOUT 30 /* seconds */ #define UP_DAEMON_LONG_TIMEOUT 120 /* seconds */ #define UP_DAEMON_DISTRUST_RATE_TIMEOUT 10 /* second */ #define UP_FULLY_CHARGED_THRESHOLD 90 /* % */ #define UP_DAEMON_EPSILON 0.01 /* I can't believe it's not zero */ #define SECONDS_PER_HOUR 3600 /* seconds in an hour */ #define SECONDS_PER_HOUR_F 3600.0f G_END_DECLS #endif /* __UP_CONSTANTS_H */ 07070100000089000081A400000000000000000000000166EA48140000899D000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-daemon.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <stdlib.h> #include <glib.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include "up-config.h" #include "up-constants.h" #include "up-polkit.h" #include "up-device-list.h" #include "up-device.h" #include "up-backend.h" #include "up-daemon.h" struct UpDaemonPrivate { UpConfig *config; gboolean debug; UpPolkit *polkit; UpBackend *backend; UpDeviceList *power_devices; guint action_timeout_id; guint refresh_batteries_id; guint warning_level_id; gboolean poll_paused; GSource *poll_source; int critical_action_lock_fd; /* Display battery properties */ UpDevice *display_device; UpDeviceKind kind; UpDeviceState state; gdouble percentage; gdouble energy; gdouble energy_full; gdouble energy_rate; gint64 time_to_empty; gint64 time_to_full; /* WarningLevel configuration */ gboolean use_percentage_for_policy; gdouble low_percentage; gdouble critical_percentage; gdouble action_percentage; guint low_time; guint critical_time; guint action_time; /* environment variable override */ const char *state_dir_override; }; static void up_daemon_finalize (GObject *object); static gboolean up_daemon_get_on_battery_local (UpDaemon *daemon); static UpDeviceLevel up_daemon_get_warning_level_local(UpDaemon *daemon); static void up_daemon_update_warning_level (UpDaemon *daemon); static gboolean up_daemon_get_on_ac_local (UpDaemon *daemon, gboolean *has_ac); G_DEFINE_TYPE_WITH_PRIVATE (UpDaemon, up_daemon, UP_TYPE_EXPORTED_DAEMON_SKELETON) #define UP_DAEMON_ACTION_DELAY 20 /* seconds */ #define UP_INTERFACE_PREFIX "org.freedesktop.UPower." /** * up_daemon_get_on_battery_local: * * As soon as _any_ battery goes discharging, this is true **/ static gboolean up_daemon_get_on_battery_local (UpDaemon *daemon) { /* Use the cached composite state cached from the display device */ return daemon->priv->state == UP_DEVICE_STATE_DISCHARGING; } /** * up_daemon_get_number_devices_of_type: **/ guint up_daemon_get_number_devices_of_type (UpDaemon *daemon, UpDeviceKind type) { guint i; UpDevice *device; GPtrArray *array; UpDeviceKind type_tmp; guint count = 0; /* ask each device */ array = up_device_list_get_array (daemon->priv->power_devices); for (i=0; i<array->len; i++) { device = (UpDevice *) g_ptr_array_index (array, i); g_object_get (device, "type", &type_tmp, NULL); if (type == type_tmp && up_device_get_object_path (device) != NULL) count++; } g_ptr_array_unref (array); return count; } /** * up_daemon_update_display_battery: * * Update our internal state. * * Returns: %TRUE if the state changed. **/ static gboolean up_daemon_update_display_battery (UpDaemon *daemon) { guint i; GPtrArray *array; UpDeviceKind kind_total = UP_DEVICE_KIND_UNKNOWN; /* Abuse LAST to know if any battery had a state. */ UpDeviceState state_total = UP_DEVICE_STATE_LAST; gdouble percentage_total = 0.0; gdouble energy_total = 0.0; gdouble energy_full_total = 0.0; gdouble energy_rate_total = 0.0; gint64 time_to_empty_total = 0; gint64 time_to_full_total = 0; gboolean is_present_total = FALSE; guint num_batteries = 0; /* Gather state from each device */ array = up_device_list_get_array (daemon->priv->power_devices); for (i = 0; i < array->len; i++) { UpDevice *device; UpDeviceState state = UP_DEVICE_STATE_UNKNOWN; UpDeviceKind kind = UP_DEVICE_KIND_UNKNOWN; gdouble percentage = 0.0; gdouble energy = 0.0; gdouble energy_full = 0.0; gdouble energy_rate = 0.0; gint64 time_to_empty = 0; gint64 time_to_full = 0; gboolean power_supply = FALSE; device = g_ptr_array_index (array, i); g_object_get (device, "type", &kind, "state", &state, "percentage", &percentage, "energy", &energy, "energy-full", &energy_full, "energy-rate", &energy_rate, "time-to-empty", &time_to_empty, "time-to-full", &time_to_full, "power-supply", &power_supply, NULL); /* When we have a UPS, it's either a desktop, and * has no batteries, or a laptop, in which case we * ignore the batteries */ if (kind == UP_DEVICE_KIND_UPS) { kind_total = kind; state_total = state; energy_total = energy; energy_full_total = energy_full; energy_rate_total = energy_rate; time_to_empty_total = time_to_empty; time_to_full_total = time_to_full; percentage_total = percentage; is_present_total = TRUE; break; } if (kind != UP_DEVICE_KIND_BATTERY || power_supply == FALSE) continue; /* * If one battery is charging, the composite is charging * If one batteries is discharging, the composite is discharging * If one battery is unknown, and we don't have a charging/discharging state otherwise, mark unknown * If one battery is pending-charge and no other is charging or discharging, then the composite is pending-charge * If all batteries are fully charged, the composite is fully charged * If all batteries are empty, the composite is empty * Everything else is unknown */ /* Keep a charging/discharging state (warn about conflict) */ if (state_total == UP_DEVICE_STATE_CHARGING || state_total == UP_DEVICE_STATE_DISCHARGING) { if (state != state_total && (state == UP_DEVICE_STATE_CHARGING || state == UP_DEVICE_STATE_DISCHARGING)) g_warning ("Conflicting charge/discharge state between batteries!"); } else if (state == UP_DEVICE_STATE_CHARGING) state_total = UP_DEVICE_STATE_CHARGING; else if (state == UP_DEVICE_STATE_DISCHARGING) state_total = UP_DEVICE_STATE_DISCHARGING; else if (state == UP_DEVICE_STATE_UNKNOWN) state_total = UP_DEVICE_STATE_UNKNOWN; else if (state == UP_DEVICE_STATE_PENDING_CHARGE) state_total = UP_DEVICE_STATE_PENDING_CHARGE; else if (state == UP_DEVICE_STATE_FULLY_CHARGED && (state_total == UP_DEVICE_STATE_FULLY_CHARGED || state_total == UP_DEVICE_STATE_LAST)) state_total = UP_DEVICE_STATE_FULLY_CHARGED; else if (state == UP_DEVICE_STATE_EMPTY && (state_total == UP_DEVICE_STATE_EMPTY || state_total == UP_DEVICE_STATE_LAST)) state_total = UP_DEVICE_STATE_EMPTY; else state_total = UP_DEVICE_STATE_UNKNOWN; /* sum up composite */ kind_total = UP_DEVICE_KIND_BATTERY; is_present_total = TRUE; energy_total += energy; energy_full_total += energy_full; energy_rate_total += energy_rate; time_to_empty_total += time_to_empty; time_to_full_total += time_to_full; /* Will be recalculated for multiple batteries, no worries */ percentage_total += percentage; num_batteries++; } /* Handle multiple batteries */ if (num_batteries <= 1) goto out; g_debug ("Calculating percentage and time to full/to empty for %i batteries", num_batteries); /* use percentage weighted for each battery capacity * fall back to averaging the batteries. * ASSUMPTION: If one battery has energy data, then all batteries do */ if (energy_full_total > 0.0) percentage_total = 100.0 * energy_total / energy_full_total; else percentage_total = percentage_total / num_batteries; out: g_ptr_array_unref (array); /* No battery means LAST state. If we have an UNKNOWN state (with * a battery) then try to infer one. */ if (state_total == UP_DEVICE_STATE_LAST) { state_total = UP_DEVICE_STATE_UNKNOWN; } else if (state_total == UP_DEVICE_STATE_UNKNOWN) { gboolean has_ac, ac_online; ac_online = up_daemon_get_on_ac_local (daemon, &has_ac); if (has_ac && ac_online) { if (percentage_total >= UP_FULLY_CHARGED_THRESHOLD) state_total = UP_DEVICE_STATE_FULLY_CHARGED; else state_total = UP_DEVICE_STATE_CHARGING; } else { if (percentage_total < 1.0f) state_total = UP_DEVICE_STATE_EMPTY; else state_total = UP_DEVICE_STATE_DISCHARGING; } } /* calculate a quick and dirty time remaining value * NOTE: Keep in sync with per-battery estimation code! */ if (energy_rate_total > 0) { if (state_total == UP_DEVICE_STATE_DISCHARGING) time_to_empty_total = SECONDS_PER_HOUR * (energy_total / energy_rate_total); else if (state_total == UP_DEVICE_STATE_CHARGING) time_to_full_total = SECONDS_PER_HOUR * ((energy_full_total - energy_total) / energy_rate_total); } /* Did anything change? */ if (daemon->priv->kind == kind_total && daemon->priv->state == state_total && daemon->priv->energy == energy_total && daemon->priv->energy_full == energy_full_total && daemon->priv->energy_rate == energy_rate_total && daemon->priv->time_to_empty == time_to_empty_total && daemon->priv->time_to_full == time_to_full_total && daemon->priv->percentage == percentage_total) return FALSE; daemon->priv->kind = kind_total; daemon->priv->state = state_total; daemon->priv->energy = energy_total; daemon->priv->energy_full = energy_full_total; daemon->priv->energy_rate = energy_rate_total; daemon->priv->time_to_empty = time_to_empty_total; daemon->priv->time_to_full = time_to_full_total; daemon->priv->percentage = percentage_total; g_object_set (daemon->priv->display_device, "type", kind_total, "state", state_total, "energy", energy_total, "energy-full", energy_full_total, "energy-rate", energy_rate_total, "time-to-empty", time_to_empty_total, "time-to-full", time_to_full_total, "percentage", percentage_total, "is-present", is_present_total, "power-supply", TRUE, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); return TRUE; } /** * up_daemon_get_warning_level_local: * * As soon as _all_ batteries are low, this is true **/ static UpDeviceLevel up_daemon_get_warning_level_local (UpDaemon *daemon) { if (daemon->priv->kind != UP_DEVICE_KIND_UPS && daemon->priv->kind != UP_DEVICE_KIND_BATTERY) return UP_DEVICE_LEVEL_NONE; if (daemon->priv->kind == UP_DEVICE_KIND_UPS && daemon->priv->state != UP_DEVICE_STATE_DISCHARGING) return UP_DEVICE_LEVEL_NONE; /* Check to see if the batteries have not noticed we are on AC */ if (daemon->priv->kind == UP_DEVICE_KIND_BATTERY && up_daemon_get_on_ac_local (daemon, NULL)) return UP_DEVICE_LEVEL_NONE; return up_daemon_compute_warning_level (daemon, daemon->priv->state, daemon->priv->kind, TRUE, /* power_supply */ daemon->priv->percentage, daemon->priv->time_to_empty); } /** * up_daemon_get_on_ac_local: * * As soon as _any_ ac supply goes online, this is true **/ static gboolean up_daemon_get_on_ac_local (UpDaemon *daemon, gboolean *has_ac) { guint i; gboolean ret; gboolean result = FALSE; gboolean online; UpDevice *device; GPtrArray *array; if (has_ac) *has_ac = FALSE; /* ask each device */ array = up_device_list_get_array (daemon->priv->power_devices); for (i=0; i<array->len; i++) { device = (UpDevice *) g_ptr_array_index (array, i); ret = up_device_get_online (device, &online); if (has_ac && ret) *has_ac = TRUE; if (ret && online) { result = TRUE; break; } } g_ptr_array_unref (array); return result; } static gboolean up_daemon_refresh_battery_devices_idle (UpDaemon *daemon) { guint i; GPtrArray *array; UpDevice *device; /* refresh all devices in array */ array = up_device_list_get_array (daemon->priv->power_devices); for (i=0; i<array->len; i++) { UpDeviceKind type; gboolean power_supply; device = (UpDevice *) g_ptr_array_index (array, i); /* only refresh battery devices */ g_object_get (device, "type", &type, "power-supply", &power_supply, NULL); if (type == UP_DEVICE_KIND_BATTERY && power_supply) up_device_refresh_internal (device, UP_REFRESH_LINE_POWER); } g_ptr_array_unref (array); daemon->priv->refresh_batteries_id = 0; return G_SOURCE_REMOVE; } static void up_daemon_refresh_battery_devices (UpDaemon *daemon) { if (daemon->priv->refresh_batteries_id) return; daemon->priv->refresh_batteries_id = g_idle_add ((GSourceFunc) up_daemon_refresh_battery_devices_idle, daemon); } /** * up_daemon_enumerate_devices: **/ static gboolean up_daemon_enumerate_devices (UpExportedDaemon *skeleton, GDBusMethodInvocation *invocation, UpDaemon *daemon) { guint i; GPtrArray *array; GPtrArray *object_paths; UpDevice *device; /* build a pointer array of the object paths */ object_paths = g_ptr_array_new_with_free_func (g_free); array = up_device_list_get_array (daemon->priv->power_devices); for (i = 0; i < array->len; i++) { const char *object_path; device = (UpDevice *) g_ptr_array_index (array, i); object_path = up_device_get_object_path (device); if (object_path != NULL) g_ptr_array_add (object_paths, g_strdup (object_path)); } g_ptr_array_unref (array); g_ptr_array_add (object_paths, NULL); /* return it on the bus */ up_exported_daemon_complete_enumerate_devices (skeleton, invocation, (const gchar **) object_paths->pdata); /* free */ g_ptr_array_unref (object_paths); return TRUE; } /** * up_daemon_get_display_device: **/ static gboolean up_daemon_get_display_device (UpExportedDaemon *skeleton, GDBusMethodInvocation *invocation, UpDaemon *daemon) { up_exported_daemon_complete_get_display_device (skeleton, invocation, up_device_get_object_path (daemon->priv->display_device)); return TRUE; } /** * up_daemon_get_critical_action: **/ static gboolean up_daemon_get_critical_action (UpExportedDaemon *skeleton, GDBusMethodInvocation *invocation, UpDaemon *daemon) { up_exported_daemon_complete_get_critical_action (skeleton, invocation, up_backend_get_critical_action (daemon->priv->backend)); return TRUE; } /** * up_daemon_register_power_daemon: **/ static gboolean up_daemon_register_power_daemon (UpDaemon *daemon, GDBusConnection *connection) { GError *error = NULL; /* export our interface on the bus */ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon), connection, "/org/freedesktop/UPower", &error); if (error != NULL) { g_critical ("error registering daemon on system bus: %s", error->message); g_error_free (error); return FALSE; } /* Register the display device */ g_initable_init (G_INITABLE (daemon->priv->display_device), NULL, NULL); return TRUE; } /** * up_daemon_startup: **/ gboolean up_daemon_startup (UpDaemon *daemon, GDBusConnection *connection) { gboolean ret; UpDaemonPrivate *priv = daemon->priv; /* register on bus */ ret = up_daemon_register_power_daemon (daemon, connection); if (!ret) { g_warning ("failed to register"); goto out; } g_debug ("daemon now coldplug"); /* coldplug backend backend */ ret = up_backend_coldplug (priv->backend, daemon); if (!ret) { g_warning ("failed to coldplug backend"); goto out; } /* get battery state */ up_daemon_update_warning_level (daemon); /* Run mainloop now to avoid state changes on DBus */ while (g_main_context_iteration (NULL, FALSE)) { } g_debug ("daemon now not coldplug"); out: return ret; } /** * up_daemon_shutdown: * * Stop the daemon, release all devices and resources. **/ void up_daemon_shutdown (UpDaemon *daemon) { /* stop accepting new devices and clear backend state */ up_backend_unplug (daemon->priv->backend); /* forget about discovered devices */ up_device_list_clear (daemon->priv->power_devices); /* release UpDaemon reference */ g_object_run_dispose (G_OBJECT (daemon->priv->display_device)); } /** * up_daemon_get_device_list: **/ UpDeviceList * up_daemon_get_device_list (UpDaemon *daemon) { return g_object_ref (daemon->priv->power_devices); } /** * up_daemon_set_lid_is_closed: **/ void up_daemon_set_lid_is_closed (UpDaemon *daemon, gboolean lid_is_closed) { UpDaemonPrivate *priv = daemon->priv; /* check if we are ignoring the lid */ if (up_config_get_boolean (priv->config, "IgnoreLid")) { g_debug ("ignoring lid state"); return; } g_debug ("lid_is_closed = %s", lid_is_closed ? "yes" : "no"); up_exported_daemon_set_lid_is_closed (UP_EXPORTED_DAEMON (daemon), lid_is_closed); } /** * up_daemon_set_lid_is_present: **/ void up_daemon_set_lid_is_present (UpDaemon *daemon, gboolean lid_is_present) { UpDaemonPrivate *priv = daemon->priv; /* check if we are ignoring the lid */ if (up_config_get_boolean (priv->config, "IgnoreLid")) { g_debug ("ignoring lid state"); return; } g_debug ("lid_is_present = %s", lid_is_present ? "yes" : "no"); up_exported_daemon_set_lid_is_present (UP_EXPORTED_DAEMON (daemon), lid_is_present); } /** * up_daemon_set_on_battery: **/ void up_daemon_set_on_battery (UpDaemon *daemon, gboolean on_battery) { g_debug ("on_battery = %s", on_battery ? "yes" : "no"); up_exported_daemon_set_on_battery (UP_EXPORTED_DAEMON (daemon), on_battery); } static gboolean take_action_timeout_cb (UpDaemon *daemon) { /* Release the inhibitor lock first, otherwise our action may be canceled */ if (daemon->priv->critical_action_lock_fd >= 0) { close (daemon->priv->critical_action_lock_fd); daemon->priv->critical_action_lock_fd = -1; } up_backend_take_action (daemon->priv->backend); g_debug ("Backend was notified to take action. The timeout will be removed."); daemon->priv->action_timeout_id = 0; return G_SOURCE_REMOVE; } /** * up_daemon_set_warning_level: **/ void up_daemon_set_warning_level (UpDaemon *daemon, UpDeviceLevel warning_level) { UpDeviceLevel old_level; g_object_get (G_OBJECT (daemon->priv->display_device), "warning-level", &old_level, NULL); if (old_level == warning_level) return; g_debug ("warning_level = %s", up_device_level_to_string (warning_level)); g_object_set (G_OBJECT (daemon->priv->display_device), "warning-level", warning_level, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); if (warning_level == UP_DEVICE_LEVEL_ACTION) { if (daemon->priv->action_timeout_id == 0) { g_assert (daemon->priv->critical_action_lock_fd == -1); g_debug ("About to take action in %d seconds", UP_DAEMON_ACTION_DELAY); daemon->priv->critical_action_lock_fd = up_backend_inhibitor_lock_take (daemon->priv->backend, "Execute critical action", "block"); daemon->priv->action_timeout_id = g_timeout_add_seconds (UP_DAEMON_ACTION_DELAY, (GSourceFunc) take_action_timeout_cb, daemon); g_source_set_name_by_id (daemon->priv->action_timeout_id, "[upower] take_action_timeout_cb"); } else { g_debug ("Not taking action, timeout id already set"); } } else { if (daemon->priv->action_timeout_id > 0) { g_debug ("Removing timeout as action level changed"); g_clear_handle_id (&daemon->priv->action_timeout_id, g_source_remove); } if (daemon->priv->critical_action_lock_fd >= 0) { close (daemon->priv->critical_action_lock_fd); daemon->priv->critical_action_lock_fd = -1; } } } UpDeviceLevel up_daemon_compute_warning_level (UpDaemon *daemon, UpDeviceState state, UpDeviceKind kind, gboolean power_supply, gdouble percentage, gint64 time_to_empty) { gboolean use_percentage = TRUE; UpDeviceLevel default_level = UP_DEVICE_LEVEL_NONE; if (state != UP_DEVICE_STATE_DISCHARGING) return UP_DEVICE_LEVEL_NONE; /* Keyboard and mice usually have a coarser * battery level, so this avoids falling directly * into critical (or off) before any warnings */ if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_TOUCHPAD) { if (percentage <= 5.0f) return UP_DEVICE_LEVEL_CRITICAL; else if (percentage <= 10.0f) return UP_DEVICE_LEVEL_LOW; else return UP_DEVICE_LEVEL_NONE; } else if (kind == UP_DEVICE_KIND_UPS) { default_level = UP_DEVICE_LEVEL_DISCHARGING; } if (power_supply && !daemon->priv->use_percentage_for_policy && time_to_empty > 0.0) use_percentage = FALSE; if (use_percentage) { if (percentage > daemon->priv->low_percentage) return default_level; if (percentage > daemon->priv->critical_percentage) return UP_DEVICE_LEVEL_LOW; if (percentage > daemon->priv->action_percentage) return UP_DEVICE_LEVEL_CRITICAL; return UP_DEVICE_LEVEL_ACTION; } else { if (time_to_empty > daemon->priv->low_time) return default_level; if (time_to_empty > daemon->priv->critical_time) return UP_DEVICE_LEVEL_LOW; if (time_to_empty > daemon->priv->action_time) return UP_DEVICE_LEVEL_CRITICAL; return UP_DEVICE_LEVEL_ACTION; } g_assert_not_reached (); } static gboolean up_daemon_update_warning_level_idle (UpDaemon *daemon) { gboolean ret; UpDeviceLevel warning_level; up_daemon_update_display_battery (daemon); /* Check if the on_battery and warning_level state has changed */ ret = (up_daemon_get_on_battery_local (daemon) && !up_daemon_get_on_ac_local (daemon, NULL)); up_daemon_set_on_battery (daemon, ret); warning_level = up_daemon_get_warning_level_local (daemon); up_daemon_set_warning_level (daemon, warning_level); daemon->priv->warning_level_id = 0; return G_SOURCE_REMOVE; } static void up_daemon_update_warning_level (UpDaemon *daemon) { if (daemon->priv->warning_level_id) return; daemon->priv->warning_level_id = g_idle_add ((GSourceFunc) up_daemon_update_warning_level_idle, daemon); } const gchar * up_daemon_get_charge_icon (UpDaemon *daemon, gdouble percentage, UpDeviceLevel battery_level, gboolean charging) { if (battery_level == UP_DEVICE_LEVEL_NONE && daemon != NULL) { if (percentage <= daemon->priv->low_percentage) return charging ? "battery-caution-charging-symbolic" : "battery-caution-symbolic"; else if (percentage < 30) return charging ? "battery-low-charging-symbolic" : "battery-low-symbolic"; else if (percentage < 60) return charging ? "battery-good-charging-symbolic" : "battery-good-symbolic"; return charging ? "battery-full-charging-symbolic" : "battery-full-symbolic"; } else { switch (battery_level) { case UP_DEVICE_LEVEL_UNKNOWN: /* The lack of symmetry is on purpose */ return charging ? "battery-good-charging-symbolic" : "battery-caution-symbolic"; case UP_DEVICE_LEVEL_LOW: case UP_DEVICE_LEVEL_CRITICAL: return charging ? "battery-caution-charging-symbolic" : "battery-caution-symbolic"; case UP_DEVICE_LEVEL_NORMAL: return charging ? "battery-low-charging-symbolic" : "battery-low-symbolic"; case UP_DEVICE_LEVEL_HIGH: return charging ? "battery-good-charging-symbolic" : "battery-good-symbolic"; case UP_DEVICE_LEVEL_FULL: return charging ? "battery-full-charging-symbolic" : "battery-full-symbolic"; default: g_assert_not_reached (); } } } /** * up_daemon_polkit_is_allowed: **/ gboolean up_daemon_polkit_is_allowed (UpDaemon *daemon, const gchar *action_id, GDBusMethodInvocation *invocation) { #ifdef HAVE_POLKIT g_autoptr (PolkitSubject) subject = NULL; g_autoptr (GError) error = NULL; subject = up_polkit_get_subject (daemon->priv->polkit, invocation); if (subject == NULL) { g_debug ("Can't get sender subject"); return FALSE; } if (!up_polkit_is_allowed (daemon->priv->polkit, subject, action_id, &error)) { if (error != NULL) g_debug ("Error on Polkit check authority: %s", error->message); return FALSE; } #endif return TRUE; } /** * up_daemon_device_changed_cb: **/ static void up_daemon_device_changed_cb (UpDevice *device, GParamSpec *pspec, UpDaemon *daemon) { UpDeviceKind type; const char *prop; g_return_if_fail (UP_IS_DAEMON (daemon)); g_return_if_fail (UP_IS_DEVICE (device)); prop = g_param_spec_get_name (pspec); if (!daemon->priv->poll_paused && ((g_strcmp0 (prop, "poll-timeout") == 0) || (g_strcmp0 (prop, "last-refresh") == 0))) { g_source_set_ready_time (daemon->priv->poll_source, 0); return; } /* refresh battery devices when AC state changes */ g_object_get (device, "type", &type, NULL); if (type == UP_DEVICE_KIND_LINE_POWER && g_strcmp0 (prop, "online") == 0) { /* refresh now */ up_daemon_refresh_battery_devices (daemon); } up_daemon_update_warning_level (daemon); } static gboolean up_daemon_poll_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { UpDaemon *daemon = UP_DAEMON (user_data); UpDaemonPrivate *priv = daemon->priv; g_autoptr(GPtrArray) array = NULL; guint i; UpDevice *device; gint64 ready_time = G_MAXINT64; gint64 now = g_source_get_time (priv->poll_source); gint max_dispatch_timeout = 0; g_source_set_ready_time (priv->poll_source, -1); g_assert (callback == NULL); if (daemon->priv->poll_paused) return G_SOURCE_CONTINUE; /* Find the earliest device that needs a refresh. */ array = up_device_list_get_array (priv->power_devices); for (i = 0; i < array->len; i += 1) { gint timeout; gint64 last_refresh; gint64 poll_time; gint64 dispatch_time; device = (UpDevice *) g_ptr_array_index (array, i); g_object_get (device, "poll-timeout", &timeout, "last-refresh", &last_refresh, NULL); if (timeout <= 0) continue; poll_time = last_refresh + timeout * G_USEC_PER_SEC; /* Allow dispatching early if another device got dispatched. * i.e. device polling will synchronize eventually. */ dispatch_time = poll_time - MIN(timeout, max_dispatch_timeout) * G_USEC_PER_SEC / 2; if (now >= dispatch_time) { g_debug ("up_daemon_poll_dispatch: refreshing %s", up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device))); up_device_refresh_internal (device, UP_REFRESH_POLL); max_dispatch_timeout = MAX(max_dispatch_timeout, timeout); /* We'll wake up again immediately and then * calculate the correct time to re-poll. */ } ready_time = MIN(ready_time, poll_time); } if (ready_time == G_MAXINT64) ready_time = -1; /* Set the ready time (if it was not modified externally) */ if (g_source_get_ready_time (priv->poll_source) == -1) g_source_set_ready_time (priv->poll_source, ready_time); return G_SOURCE_CONTINUE; } GSourceFuncs poll_source_funcs = { .prepare = NULL, .check = NULL, .dispatch = up_daemon_poll_dispatch, .finalize = NULL, }; /** * up_daemon_pause_poll: * * Pause, i.e. stop, all registered poll sources. They can be * restarted via up_daemon_resume_poll(). **/ void up_daemon_pause_poll (UpDaemon *daemon) { g_debug ("Polling will be paused"); daemon->priv->poll_paused = TRUE; } /** * up_daemon_resume_poll: * * Resume all poll sources; the timeout will be recalculated. **/ void up_daemon_resume_poll (UpDaemon *daemon) { g_debug ("Polling will be resumed"); daemon->priv->poll_paused = FALSE; g_source_set_ready_time (daemon->priv->poll_source, 0); } void up_daemon_set_debug (UpDaemon *daemon, gboolean debug) { daemon->priv->debug = debug; } gboolean up_daemon_get_debug (UpDaemon *daemon) { return daemon->priv->debug; } /** * up_daemon_get_state_dir_env_override: * * Get UPOWER_STATE_DIR environment variable. **/ const gchar * up_daemon_get_state_dir_env_override (UpDaemon *daemon) { return daemon->priv->state_dir_override; } static void up_daemon_get_env_override (UpDaemon *self) { self->priv->state_dir_override = g_getenv ("UPOWER_STATE_DIR"); } /** * up_daemon_device_added_cb: **/ static void up_daemon_device_added_cb (UpBackend *backend, UpDevice *device, UpDaemon *daemon) { const gchar *object_path; UpDaemonPrivate *priv = daemon->priv; g_return_if_fail (UP_IS_DAEMON (daemon)); g_return_if_fail (UP_IS_DEVICE (device)); /* add to device list */ up_device_list_insert (priv->power_devices, device); /* connect, so we get changes */ g_signal_connect (device, "notify", G_CALLBACK (up_daemon_device_changed_cb), daemon); /* emit */ object_path = up_device_get_object_path (device); if (object_path == NULL) { g_debug ("Device %s was unregistered before it was on the bus", up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device))); return; } /* Ensure we poll the new device if needed */ g_source_set_ready_time (daemon->priv->poll_source, 0); g_debug ("emitting added: %s", object_path); up_daemon_update_warning_level (daemon); up_exported_daemon_emit_device_added (UP_EXPORTED_DAEMON (daemon), object_path); } /** * up_daemon_device_removed_cb: **/ static void up_daemon_device_removed_cb (UpBackend *backend, UpDevice *device, UpDaemon *daemon) { const gchar *object_path; UpDaemonPrivate *priv = daemon->priv; g_return_if_fail (UP_IS_DAEMON (daemon)); g_return_if_fail (UP_IS_DEVICE (device)); g_signal_handlers_disconnect_by_data (device, daemon); /* remove from list (device remains valid during the function call) */ up_device_list_remove (priv->power_devices, device); /* emit */ object_path = up_device_get_object_path (device); /* don't crash the session */ if (object_path == NULL) { g_debug ("not emitting device-removed for unregistered device: %s", up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device))); return; } g_debug ("emitting device-removed: %s", object_path); up_exported_daemon_emit_device_removed (UP_EXPORTED_DAEMON (daemon), object_path); /* In case a battery was removed */ up_daemon_refresh_battery_devices (daemon); up_daemon_update_warning_level (daemon); } #define LOAD_OR_DEFAULT(val, str, def) val = (load_default ? def : up_config_get_uint (daemon->priv->config, str)) #define LOAD_OR_DEFAULT_DOUBLE(val, str, def) val = (load_default ? def : up_config_get_double (daemon->priv->config, str)) static void load_percentage_policy (UpDaemon *daemon, gboolean load_default) { LOAD_OR_DEFAULT_DOUBLE (daemon->priv->low_percentage, "PercentageLow", 20.0); LOAD_OR_DEFAULT_DOUBLE (daemon->priv->critical_percentage, "PercentageCritical", 5.0); LOAD_OR_DEFAULT_DOUBLE (daemon->priv->action_percentage, "PercentageAction", 2.0); } static void load_time_policy (UpDaemon *daemon, gboolean load_default) { LOAD_OR_DEFAULT (daemon->priv->low_time, "TimeLow", 1200); LOAD_OR_DEFAULT (daemon->priv->critical_time, "TimeCritical", 300); LOAD_OR_DEFAULT (daemon->priv->action_time, "TimeAction", 120); } #define IS_DESCENDING(x, y, z) (x > y && y > z) static void policy_config_validate (UpDaemon *daemon) { if (daemon->priv->low_percentage >= 100.0 || daemon->priv->critical_percentage >= 100.0 || daemon->priv->action_percentage >= 100.0) { load_percentage_policy (daemon, TRUE); } else if (!IS_DESCENDING (daemon->priv->low_percentage, daemon->priv->critical_percentage, daemon->priv->action_percentage)) { load_percentage_policy (daemon, TRUE); } if (!IS_DESCENDING (daemon->priv->low_time, daemon->priv->critical_time, daemon->priv->action_time)) { load_time_policy (daemon, TRUE); } } /** * up_daemon_init: **/ static void up_daemon_init (UpDaemon *daemon) { daemon->priv = up_daemon_get_instance_private (daemon); daemon->priv->critical_action_lock_fd = -1; daemon->priv->polkit = up_polkit_new (); daemon->priv->config = up_config_new (); daemon->priv->power_devices = up_device_list_new (); daemon->priv->display_device = up_device_new (daemon, NULL); daemon->priv->poll_source = g_source_new (&poll_source_funcs, sizeof (GSource)); g_source_set_callback (daemon->priv->poll_source, NULL, daemon, NULL); g_source_set_name (daemon->priv->poll_source, "up-device-poll"); g_source_attach (daemon->priv->poll_source, NULL); /* g_source_destroy removes the last reference */ g_source_unref (daemon->priv->poll_source); daemon->priv->use_percentage_for_policy = up_config_get_boolean (daemon->priv->config, "UsePercentageForPolicy"); load_percentage_policy (daemon, FALSE); load_time_policy (daemon, FALSE); policy_config_validate (daemon); up_daemon_get_env_override (daemon); daemon->priv->backend = up_backend_new (); g_signal_connect (daemon->priv->backend, "device-added", G_CALLBACK (up_daemon_device_added_cb), daemon); g_signal_connect (daemon->priv->backend, "device-removed", G_CALLBACK (up_daemon_device_removed_cb), daemon); up_exported_daemon_set_daemon_version (UP_EXPORTED_DAEMON (daemon), PACKAGE_VERSION); g_signal_connect (daemon, "handle-enumerate-devices", G_CALLBACK (up_daemon_enumerate_devices), daemon); g_signal_connect (daemon, "handle-get-critical-action", G_CALLBACK (up_daemon_get_critical_action), daemon); g_signal_connect (daemon, "handle-get-display-device", G_CALLBACK (up_daemon_get_display_device), daemon); } static const GDBusErrorEntry up_daemon_error_entries[] = { { UP_DAEMON_ERROR_GENERAL, UP_INTERFACE_PREFIX "GeneralError" }, { UP_DAEMON_ERROR_NOT_SUPPORTED, UP_INTERFACE_PREFIX "NotSupported" }, { UP_DAEMON_ERROR_NO_SUCH_DEVICE, UP_INTERFACE_PREFIX "NoSuchDevice" }, }; /** * up_daemon_error_quark: **/ GQuark up_daemon_error_quark (void) { static volatile gsize quark_volatile = 0; g_dbus_error_register_error_domain ("up_daemon_error", &quark_volatile, up_daemon_error_entries, G_N_ELEMENTS (up_daemon_error_entries)); return quark_volatile; } /** * up_daemon_class_init: **/ static void up_daemon_class_init (UpDaemonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_daemon_finalize; } /** * up_daemon_finalize: **/ static void up_daemon_finalize (GObject *object) { UpDaemon *daemon = UP_DAEMON (object); UpDaemonPrivate *priv = daemon->priv; g_clear_handle_id (&priv->action_timeout_id, g_source_remove); g_clear_handle_id (&priv->refresh_batteries_id, g_source_remove); g_clear_handle_id (&priv->warning_level_id, g_source_remove); if (priv->critical_action_lock_fd >= 0) { close (priv->critical_action_lock_fd); priv->critical_action_lock_fd = -1; } g_clear_pointer (&daemon->priv->poll_source, g_source_destroy); g_object_unref (priv->power_devices); g_object_unref (priv->display_device); g_object_unref (priv->polkit); g_object_unref (priv->config); g_object_unref (priv->backend); G_OBJECT_CLASS (up_daemon_parent_class)->finalize (object); } /** * up_daemon_new: **/ UpDaemon * up_daemon_new (void) { return UP_DAEMON (g_object_new (UP_TYPE_DAEMON, NULL)); } 0707010000008A000081A400000000000000000000000166EA481400000DF8000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-daemon.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DAEMON_H__ #define __UP_DAEMON_H__ #include <dbus/up-daemon-generated.h> #include "up-types.h" #include "up-device-list.h" G_BEGIN_DECLS #define UP_TYPE_DAEMON (up_daemon_get_type ()) #define UP_DAEMON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DAEMON, UpDaemon)) #define UP_DAEMON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DAEMON, UpDaemonClass)) #define UP_IS_DAEMON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DAEMON)) #define UP_IS_DAEMON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DAEMON)) #define UP_DAEMON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DAEMON, UpDaemonClass)) typedef struct UpDaemonPrivate UpDaemonPrivate; typedef struct { UpExportedDaemonSkeleton parent; UpDaemonPrivate *priv; } UpDaemon; typedef struct { UpExportedDaemonSkeletonClass parent_class; } UpDaemonClass; typedef enum { UP_DAEMON_ERROR_GENERAL, UP_DAEMON_ERROR_NOT_SUPPORTED, UP_DAEMON_ERROR_NO_SUCH_DEVICE, UP_DAEMON_NUM_ERRORS } UpDaemonError; #define UP_DAEMON_ERROR up_daemon_error_quark () GQuark up_daemon_error_quark (void); GType up_daemon_get_type (void); UpDaemon *up_daemon_new (void); /* private */ guint up_daemon_get_number_devices_of_type (UpDaemon *daemon, UpDeviceKind type); UpDeviceList *up_daemon_get_device_list (UpDaemon *daemon); gboolean up_daemon_startup (UpDaemon *daemon, GDBusConnection *connection); void up_daemon_shutdown (UpDaemon *daemon); void up_daemon_set_lid_is_closed (UpDaemon *daemon, gboolean lid_is_closed); void up_daemon_set_lid_is_present (UpDaemon *daemon, gboolean lid_is_present); void up_daemon_set_on_battery (UpDaemon *daemon, gboolean on_battery); void up_daemon_set_warning_level (UpDaemon *daemon, UpDeviceLevel warning_level); UpDeviceLevel up_daemon_compute_warning_level(UpDaemon *daemon, UpDeviceState state, UpDeviceKind kind, gboolean power_supply, gdouble percentage, gint64 time_to_empty); const gchar *up_daemon_get_charge_icon (UpDaemon *daemon, gdouble percentage, UpDeviceLevel battery_level, gboolean charging); const gchar *up_daemon_get_state_dir_env_override (UpDaemon *daemon); gboolean up_daemon_polkit_is_allowed (UpDaemon *daemon, const gchar *action_id, GDBusMethodInvocation *invocation); void up_daemon_pause_poll (UpDaemon *daemon); void up_daemon_resume_poll (UpDaemon *daemon); void up_daemon_set_debug (UpDaemon *daemon, gboolean debug); gboolean up_daemon_get_debug (UpDaemon *daemon); G_END_DECLS #endif /* __UP_DAEMON_H__ */ 0707010000008B000081A400000000000000000000000166EA481400006064000000000000000000000000000000000000002600000000upower-1.90.6/src/up-device-battery.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <string.h> #include "up-constants.h" #include "up-config.h" #include "up-device-battery.h" /* Chosen to be quite big, in case there was a lot of re-polling */ #define MAX_ESTIMATION_POINTS 15 typedef struct { UpBatteryValues hw_data[MAX_ESTIMATION_POINTS]; gint hw_data_last; gint hw_data_len; gboolean present; gboolean units_changed_warning; /* static values (only changed if plugged/unplugged) */ gboolean disable_battery_poll; gdouble voltage_design; UpBatteryUnits units; /* mostly static values */ gdouble energy_full; gdouble energy_full_reported; gdouble energy_design; gint charge_cycles; gboolean trust_power_measurement; gint64 last_power_discontinuity; /* dynamic values */ gint64 fast_repoll_until; gboolean repoll_needed; /* state path */ const char *state_dir; } UpDeviceBatteryPrivate; G_DEFINE_TYPE_EXTENDED (UpDeviceBattery, up_device_battery, UP_TYPE_DEVICE, 0, G_ADD_PRIVATE (UpDeviceBattery)) static gboolean up_device_battery_get_on_battery (UpDevice *device, gboolean *on_battery) { UpDeviceState state; g_return_val_if_fail (on_battery != NULL, FALSE); g_object_get (device, "state", &state, NULL); *on_battery = (state == UP_DEVICE_STATE_DISCHARGING); return TRUE; } static gdouble up_device_battery_charge_to_energy (UpDeviceBattery *self, gdouble charge) { UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); /* We want to work with energy internally. * Note that this is a pretty bad way of estimating the energy, * we just assume that the voltage is always the same, which is * obviously not true. The voltage depends on at least: * - output current * - temperature * - charge * The easiest way to improve this would likely be "machine learning", * i.e. statistics through which we can calculate the actual * performance based on the factors we have. */ return priv->voltage_design * charge; } static void up_device_battery_estimate_power (UpDeviceBattery *self, UpBatteryValues *cur) { UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); UpDeviceState reported_state; UpBatteryValues *ref = NULL; gdouble energy_rate = 0.0; gint64 ref_td = 999 * G_USEC_PER_SEC; /* We need to be able to do math with this */ gint i; /* Same item, but it is copied in already. */ g_assert (cur->ts_us != priv->hw_data[priv->hw_data_last].ts_us); reported_state = cur->state; if (cur->state != UP_DEVICE_STATE_CHARGING && cur->state != UP_DEVICE_STATE_DISCHARGING && cur->state != UP_DEVICE_STATE_UNKNOWN) return; for (i = 0; i < priv->hw_data_len; i++) { int pos = (priv->hw_data_last - i + G_N_ELEMENTS (priv->hw_data)) % G_N_ELEMENTS (priv->hw_data); gint64 td; /* Stop searching if the hardware state changed. */ if (priv->hw_data[pos].state != reported_state) break; td = cur->ts_us - priv->hw_data[pos].ts_us; /* At least 15 seconds worth of data. */ if (td < 15 * G_USEC_PER_SEC) continue; /* Stop searching if the new reference is further away from the long timeout. */ if (ABS(UP_DAEMON_LONG_TIMEOUT * G_USEC_PER_SEC - ABS (td)) > ABS(UP_DAEMON_SHORT_TIMEOUT * G_USEC_PER_SEC - ref_td)) break; ref_td = td; ref = &priv->hw_data[pos]; } /* We rely solely on battery reports here, with dynamic power * usage (in particular during resume), lets just wait for a * bit longer before reporting anything to the user. * * Alternatively, we could assume that some old estimate for the * energy rate remains stable and do a time estimate based on that. * * For now, this is better than what we used to do. */ if (!ref) { priv->repoll_needed = TRUE; return; } /* energy is in Wh, rate in W */ energy_rate = (cur->energy.cur - ref->energy.cur) / (ref_td / ((gdouble) 3600 * G_USEC_PER_SEC)); /* Try to guess charge/discharge state based on rate. * Note that the history is discarded when the AC is plugged, as such * we should only err on the side of showing CHARGING for too long. */ if (cur->state == UP_DEVICE_STATE_UNKNOWN) { /* Consider a rate of 0.5W as "no change", otherwise set CHARGING/DISCHARGING */ if (ABS(energy_rate) < 0.5) return; else if (energy_rate < 0.0) cur->state = UP_DEVICE_STATE_DISCHARGING; else cur->state = UP_DEVICE_STATE_CHARGING; } /* QUIRK: No good reason, but define rate to be positive. */ if (cur->state == UP_DEVICE_STATE_DISCHARGING) energy_rate *= -1.0; /* This hopefully gives us sane values, but lets print a message if not. */ if (energy_rate < 0.1 || energy_rate > 300) { g_debug ("The estimated %scharge rate is %fW, which is not realistic", cur->state == UP_DEVICE_STATE_DISCHARGING ? "dis" : "", energy_rate); energy_rate = 0; } cur->energy.rate = energy_rate; } static void up_device_battery_update_poll_frequency (UpDeviceBattery *self, UpDeviceState state, UpRefreshReason reason) { UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); gint slow_poll_timeout; if (priv->disable_battery_poll) return; slow_poll_timeout = priv->repoll_needed ? UP_DAEMON_ESTIMATE_TIMEOUT : UP_DAEMON_SHORT_TIMEOUT; priv->repoll_needed = FALSE; /* We start fast-polling if the reason to update was not a normal POLL * and one of the following holds true: * 1. The current stat is unknown; we hope that this is transient * and re-poll. * 2. A change occured on a line power supply. This likely means that * batteries switch between charging/discharging which does not * always result in a separate uevent. * * For simplicity, we do the fast polling for a specific period of time. * If the reason to do fast-polling was an unknown state, then it would * also be reasonable to stop as soon as we got a proper state. */ if (reason != UP_REFRESH_POLL && (state == UP_DEVICE_STATE_UNKNOWN || reason == UP_REFRESH_LINE_POWER)) { g_debug ("unknown_poll: setting up fast re-poll"); g_object_set (self, "poll-timeout", UP_DAEMON_UNKNOWN_TIMEOUT, NULL); priv->fast_repoll_until = g_get_monotonic_time () + UP_DAEMON_UNKNOWN_POLL_TIME * G_USEC_PER_SEC; } else if (priv->fast_repoll_until == 0) { /* Not fast-repolling, check poll timeout is as expected */ gint poll_timeout; g_object_get (self, "poll-timeout", &poll_timeout, NULL); if (poll_timeout != slow_poll_timeout) g_object_set (self, "poll-timeout", slow_poll_timeout, NULL); } else if (priv->fast_repoll_until < g_get_monotonic_time ()) { g_debug ("unknown_poll: stopping fast repoll (giving up)"); priv->fast_repoll_until = 0; g_object_set (self, "poll-timeout", slow_poll_timeout, NULL); } } void up_device_battery_report (UpDeviceBattery *self, UpBatteryValues *values, UpRefreshReason reason) { UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); gint64 time_to_empty = 0; gint64 time_to_full = 0; if (!priv->present) { g_warning ("Got a battery report for a battery that is not present"); return; } g_assert (priv->units != UP_BATTERY_UNIT_UNDEFINED); values->ts_us = g_get_monotonic_time (); /* Discard all old measurements that can't be used for estimations. * * XXX: Should a state change also trigger an update of the timestamp * that is used to discard power/current measurements? */ if (reason == UP_REFRESH_RESUME || reason == UP_REFRESH_LINE_POWER) { priv->hw_data_len = 0; priv->last_power_discontinuity = values->ts_us; } /* QUIRK: * * There is an old bug where some Lenovo machine switched from reporting * energy to reporting charge numbers. The code used to react by * reloading everything, however, what apparently happens is that the * *energy* value simply starts being reported through *charge* * attributes. * The original report is * https://bugzilla.redhat.com/show_bug.cgi?id=587112 * and inspecting the numbers it is clear that the values are * really energy values that are unrealistically high as they get * incorrectly multiplied by the voltage. * * Said differently, just assuming the units did *not* change should * give us a saner value. Obviously, things will fall appart if upower * is restarted and this should be fixed in the kernel or firmware. * * Unfortunately, the hardware is quite old (X201s) which makes it hard * to even confirm that the bug was not fixed in the kernel or firmware. * * Note that a race condition could be the user swapping the battery * during suspend and us re-polling energy data before noticing that * the battery has changed. */ if (G_UNLIKELY (priv->units != values->units)) { if (!priv->units_changed_warning) { g_warning ("Battery unit type changed, assuming the old unit is still valid. This is likely a firmware or driver issue, please report!"); priv->units_changed_warning = TRUE; } values->units = priv->units; } if (values->units == UP_BATTERY_UNIT_CHARGE) { values->units = UP_BATTERY_UNIT_ENERGY; values->energy.cur = up_device_battery_charge_to_energy (self, values->charge.cur); values->energy.rate = up_device_battery_charge_to_energy (self, values->charge.rate); } /* QUIRK: Discard weird measurements (like a 300W power usage). */ if (values->energy.rate > 300) values->energy.rate = 0; /* Infer current energy if unknown */ if (values->energy.cur < 0.01 && values->percentage > 0) values->energy.cur = priv->energy_full * values->percentage / 100.0; /* QUIRK: Increase energy_full if energy.cur is higher */ if (values->energy.cur > priv->energy_full) { priv->energy_full = values->energy.cur; g_object_set (self, /* How healthy the battery is (clamp to 100% if it can hold more charge than expected) */ "capacity", MIN (priv->energy_full / priv->energy_design * 100.0, 100), "energy-full", priv->energy_full, NULL); } /* Infer percentage if unknown */ if (values->percentage <= 0) values->percentage = values->energy.cur / priv->energy_full * 100; /* NOTE: We used to do more for the UNKNOWN state. However, some of the * logic relies on only one battery device to be present. Plus, it * requires knowing the AC state. * Because of this complexity, the decision was made to only do this * type of inferring inside the DisplayDevice. There we can be sure * about the AC state and we only have "one" battery. */ /* QUIRK: No good reason, but define rate to be positive. * * It would be sane/reasonable to define it to be negative when * discharging. Only odd thing is that most common hardware appears * to always report positive values, which appeared in DBus unmodified. */ if (values->state == UP_DEVICE_STATE_DISCHARGING && values->energy.rate < 0) values->energy.rate = -values->energy.rate; /* NOTE: We got a (likely sane) reading. * Assume power/current readings are accurate from now on. */ if (values->energy.rate > 0.01) priv->trust_power_measurement = TRUE; if (priv->trust_power_measurement) { /* QUIRK: Do not trust readings after a discontinuity happened */ if (priv->last_power_discontinuity + UP_DAEMON_DISTRUST_RATE_TIMEOUT * G_USEC_PER_SEC > values->ts_us) values->energy.rate = 0.0; } else { up_device_battery_estimate_power (self, values); } /* Push into our ring buffer */ priv->hw_data_last = (priv->hw_data_last + 1) % G_N_ELEMENTS (priv->hw_data); priv->hw_data_len = MIN (priv->hw_data_len + 1, G_N_ELEMENTS (priv->hw_data)); priv->hw_data[priv->hw_data_last] = *values; if (values->energy.rate > 0.01) { /* Calculate time to full/empty * * Here we could factor in collected data about charge rates * FIXME: Use charge-stop-threshold here */ if (values->state == UP_DEVICE_STATE_CHARGING) time_to_full = 3600 * (priv->energy_full - values->energy.cur) / values->energy.rate; else time_to_empty = 3600 * values->energy.cur / values->energy.rate; } else { if (values->state == UP_DEVICE_STATE_CHARGING || values->state == UP_DEVICE_STATE_DISCHARGING) priv->repoll_needed = TRUE; } /* QUIRK: Do a FULL/EMPTY guess if the state is still unknown * Maybe limit to when we have good estimates * (would require rate/current information) */ if (values->state == UP_DEVICE_STATE_UNKNOWN) { if (values->percentage >= UP_FULLY_CHARGED_THRESHOLD) values->state = UP_DEVICE_STATE_FULLY_CHARGED; else if (values->percentage < 1.0) values->state = UP_DEVICE_STATE_EMPTY; } /* QUIRK: Some devices keep reporting PENDING_CHARGE even when full */ if (values->state == UP_DEVICE_STATE_PENDING_CHARGE && values->percentage >= UP_FULLY_CHARGED_THRESHOLD) values->state = UP_DEVICE_STATE_FULLY_CHARGED; /* Set the main properties (setting "update-time" last) */ g_object_set (self, "energy", values->energy.cur, "percentage", values->percentage, "state", values->state, "voltage", values->voltage, "temperature", values->temperature, "energy-rate", values->energy.rate, "time-to-empty", time_to_empty, "time-to-full", time_to_full, /* XXX: Move "update-time" updates elsewhere? */ "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, NULL); up_device_battery_update_poll_frequency (self, values->state, reason); } static gboolean up_device_battery_set_charge_thresholds(UpDeviceBattery *self, gdouble start, gdouble end, GError **error) { UpDeviceBatteryClass *klass = UP_DEVICE_BATTERY_GET_CLASS (self); if (klass->set_battery_charge_thresholds == NULL) return FALSE; return klass->set_battery_charge_thresholds(&self->parent_instance, start, end, error); } static const gchar * up_device_battery_get_state_dir (UpDeviceBattery *self) { UpDevice *device = UP_DEVICE (self); const gchar *state_dir_override = NULL; UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); if (priv->state_dir != NULL) return priv->state_dir; state_dir_override = up_device_get_state_dir_override (device); if (state_dir_override != NULL) priv->state_dir = state_dir_override; else priv->state_dir = STATE_DIR; return priv->state_dir; } static gboolean up_device_battery_get_battery_charge_threshold_config(UpDeviceBattery *self) { g_autofree gchar *filename = NULL; g_autofree gchar *data = NULL; g_autoptr(GError) error = NULL; g_autofree gchar *state_filename = NULL; const char *state_dir = NULL; state_filename = g_strdup_printf("charging-threshold-status"); state_dir = up_device_battery_get_state_dir (self); filename = g_build_filename (state_dir, state_filename, NULL); if (g_file_get_contents (filename, &data, NULL, &error) == FALSE) { g_debug ("failed to read battery charge threshold: %s", error->message); return FALSE; } if (g_strcmp0(data, "1") == 0) return TRUE; return FALSE; } static void up_device_battery_recover_battery_charging_threshold (UpDeviceBattery *self, UpBatteryInfo *info, gboolean *charge_threshold_enabled) { gboolean enabled = FALSE; GError *error = NULL; if (info == NULL) return; enabled = up_device_battery_get_battery_charge_threshold_config (self); if (info->charge_control_supported == TRUE) { if (enabled == TRUE) { up_device_battery_set_charge_thresholds (self, info->charge_control_start_threshold, info->charge_control_end_threshold, &error); if (error != NULL) { enabled = FALSE; g_warning ("Fail on setting charging threshold: %s", error->message); g_clear_error (&error); } } } *charge_threshold_enabled = enabled; } void up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info) { gboolean charge_threshold_enabled = FALSE; UpDeviceBatteryPrivate *priv = up_device_battery_get_instance_private (self); /* First, sanitize the information. */ if (info->present && info->units == UP_BATTERY_UNIT_UNDEFINED) { g_warning ("Battery without defined units, assuming unplugged"); info->present = FALSE; } /* Still not present, ignore. */ if (!info->present && !priv->present) return; /* Emulate an unplug if present but vendor, etc. changed. */ if (info->present && info->present == priv->present) { g_autofree gchar *vendor = NULL; g_autofree gchar *model = NULL; g_autofree gchar *serial = NULL; g_object_get (self, "vendor", &vendor, "model", &model, "serial", &serial, NULL); if (g_strcmp0 (vendor, info->vendor) != 0 || g_strcmp0 (model, info->model) != 0 || g_strcmp0 (serial, info->serial) != 0) { UpBatteryInfo unplugged = { .present = FALSE }; up_device_battery_update_info (self, &unplugged); } } if (info->present) { gdouble energy_full; gdouble energy_design; gint charge_cycles; /* See above, we have a (new) battery plugged in. */ if (!priv->present) { /* Set up battery charging threshold when a new battery was plugged in */ up_device_battery_recover_battery_charging_threshold (self, info, &charge_threshold_enabled); g_object_set (self, "is-present", TRUE, "vendor", info->vendor, "model", info->model, "serial", info->serial, "technology", info->technology, "has-history", TRUE, "has-statistics", TRUE, "charge-start-threshold", info->charge_control_start_threshold, "charge-end-threshold", info->charge_control_end_threshold, "charge-threshold-enabled", charge_threshold_enabled, "charge-threshold-supported", info->charge_control_supported, NULL); priv->present = TRUE; priv->units = info->units; } /* See comment in up_device_battery_report */ if (priv->units != info->units && !priv->units_changed_warning) { g_warning ("Battery unit type changed, assuming the old unit is still valid. This is likely a firmware or driver issue, please report!"); priv->units_changed_warning = TRUE; } priv->voltage_design = info->voltage_design; if (priv->units == UP_BATTERY_UNIT_CHARGE) { energy_full = up_device_battery_charge_to_energy (self, info->charge.full); energy_design = up_device_battery_charge_to_energy (self, info->charge.design); } else { energy_full = info->energy.full; energy_design = info->energy.design; } if (energy_full < 0.01) energy_full = energy_design; /* Force -1 for unknown value (where 0 is also an unknown value) */ charge_cycles = info->charge_cycles > 0 ? info->charge_cycles : -1; if (energy_full != priv->energy_full_reported || energy_design != priv->energy_design) { priv->energy_full = energy_full; priv->energy_full_reported = energy_full; priv->energy_design = energy_design; g_object_set (self, /* How healthy the battery is (clamp to 100% if it can hold more charge than expected) */ "capacity", MIN (priv->energy_full / priv->energy_design * 100.0, 100), "energy-full", priv->energy_full, "energy-full-design", priv->energy_design, NULL); } if (priv->charge_cycles != charge_cycles) { priv->charge_cycles = charge_cycles; g_object_set (self, "charge-cycles", charge_cycles, NULL); } /* NOTE: Assume a normal refresh will follow immediately (do not update timestamp). */ } else { priv->present = FALSE; priv->trust_power_measurement = FALSE; priv->hw_data_len = 0; priv->units = UP_BATTERY_UNIT_UNDEFINED; g_object_set (self, "is-present", FALSE, "vendor", NULL, "model", NULL, "serial", NULL, "technology", UP_DEVICE_TECHNOLOGY_UNKNOWN, "capacity", (gdouble) 0.0, "energy-full", (gdouble) 0.0, "energy-full-design", (gdouble) 0.0, "charge-cycles", -1, "has-history", FALSE, "has-statistics", FALSE, "update-time", (guint64) g_get_real_time () / G_USEC_PER_SEC, "charge-start-threshold", 0, "charge-end-threshold", 100, "charge-threshold-enabled", FALSE, "charge-threshold-supported", FALSE, NULL); } } static gboolean up_device_battery_charge_threshold_state_write(UpDeviceBattery *self, gboolean enabled, const gchar *state_file) { g_autofree gchar *filename = NULL; GError *error = NULL; const gchar *state_dir; state_dir = up_device_battery_get_state_dir (self); filename = g_build_filename (state_dir, state_file, NULL); if (!g_file_set_contents (filename, enabled ? "1": "0" , -1, &error)) { g_error ("failed to save battery charge threshold: %s", error->message); return FALSE; } return TRUE; } /** * up_device_battery_set_charge_threshold: **/ static gboolean up_device_battery_set_charge_threshold (UpExportedDevice *skeleton, GDBusMethodInvocation *invocation, gboolean enabled, UpDeviceBattery *self) { gboolean ret = FALSE; gboolean charge_threshold_enabled; gboolean charge_threshold_supported; guint charge_start_threshold = 0; guint charge_end_threshold = 100; g_autoptr (GError) error = NULL; g_autofree gchar *state_file = NULL; UpDevice *device = UP_DEVICE (self); if (device == NULL) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "Error on getting device"); return FALSE; } if (!up_device_polkit_is_allowed (device, invocation)) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "Operation is not allowed."); return TRUE; } g_object_get (self, "charge-threshold-enabled", &charge_threshold_enabled, "charge-threshold-supported", &charge_threshold_supported, "charge-start-threshold", &charge_start_threshold, "charge-end-threshold", &charge_end_threshold, NULL); if (!charge_threshold_supported) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "setting battery charge thresholds is unsupported"); return TRUE; } state_file = g_strdup_printf("charging-threshold-status"); if (!up_device_battery_charge_threshold_state_write (self, enabled, state_file)) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "writing charge limits state file '%s' failed", state_file); return TRUE; } if (enabled) ret = up_device_battery_set_charge_thresholds (self, charge_start_threshold, charge_end_threshold, &error); else ret = up_device_battery_set_charge_thresholds (self, 0, 100, &error); if (!ret) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "failed on setting charging threshold: %s", error->message); return TRUE; } g_object_set(self, "charge-threshold-enabled", enabled, NULL); up_exported_device_complete_enable_charge_threshold (skeleton, invocation); return TRUE; } static void up_device_battery_init (UpDeviceBattery *self) { g_object_set (self, "type", UP_DEVICE_KIND_BATTERY, "power-supply", TRUE, "is-rechargeable", TRUE, NULL); g_signal_connect (self, "handle-enable-charge-threshold", G_CALLBACK (up_device_battery_set_charge_threshold), self); } static void up_device_battery_class_init (UpDeviceBatteryClass *klass) { UpDeviceClass *device_class = UP_DEVICE_CLASS (klass); device_class->get_on_battery = up_device_battery_get_on_battery; } 0707010000008C000081A400000000000000000000000166EA48140000098A000000000000000000000000000000000000002600000000upower-1.90.6/src/up-device-battery.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #pragma once #include "up-device.h" G_BEGIN_DECLS #define MAX_DISCHARGE_RATE 300 #define UP_TYPE_DEVICE_BATTERY (up_device_battery_get_type ()) G_DECLARE_DERIVABLE_TYPE (UpDeviceBattery, up_device_battery, UP, DEVICE_BATTERY, UpDevice) struct _UpDeviceBatteryClass { UpDeviceClass parent_class; gboolean (* set_battery_charge_thresholds) (UpDevice *device, guint start, guint end, GError **error); }; typedef enum { UP_BATTERY_UNIT_UNDEFINED = 0, UP_BATTERY_UNIT_ENERGY, UP_BATTERY_UNIT_CHARGE, } UpBatteryUnits; typedef struct { gint64 ts_us; UpDeviceState state; UpBatteryUnits units; union { struct { gdouble cur; gdouble rate; } energy; struct { gdouble cur; gdouble rate; } charge; }; gdouble percentage; gdouble voltage; gdouble temperature; } UpBatteryValues; typedef struct { gboolean present; const char *vendor; const char *model; const char *serial; UpBatteryUnits units; union { struct { gdouble full; gdouble design; } energy; struct { gdouble full; gdouble design; } charge; }; UpDeviceTechnology technology; gdouble voltage_design; gint charge_cycles; /* battery charging threshold */ gboolean charge_control_enabled; gboolean charge_control_supported; guint charge_control_start_threshold; guint charge_control_end_threshold; } UpBatteryInfo; void up_device_battery_update_info (UpDeviceBattery *self, UpBatteryInfo *info); void up_device_battery_report (UpDeviceBattery *self, UpBatteryValues *values, UpRefreshReason reason); G_END_DECLS 0707010000008D000081A400000000000000000000000166EA481400001587000000000000000000000000000000000000002300000000upower-1.90.6/src/up-device-list.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> * * 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 <stdlib.h> #include <stdio.h> #include <glib.h> #include "up-native.h" #include "up-device-list.h" #include "up-device.h" static void up_device_list_finalize (GObject *object); struct UpDeviceListPrivate { GPtrArray *array; GHashTable *map_native_path_to_device; }; G_DEFINE_TYPE_WITH_PRIVATE (UpDeviceList, up_device_list, G_TYPE_OBJECT) /** * up_device_list_lookup: * * Convert a native %GObject into a %UpDevice -- we use the native path * to look these up as it's the only thing they share. * * Return value: the object, or %NULL if not found. Free with g_object_unref() **/ GObject * up_device_list_lookup (UpDeviceList *list, GObject *native) { GObject *device; const gchar *native_path; g_return_val_if_fail (UP_IS_DEVICE_LIST (list), NULL); /* does device exist in db? */ native_path = up_native_get_native_path (native); if (native_path == NULL) return NULL; device = g_hash_table_lookup (list->priv->map_native_path_to_device, native_path); if (device == NULL) return NULL; return g_object_ref (device); } /** * up_device_list_insert: * * Insert a %GObject device and it's mapping to a backing %UpDevice * into a list of devices. **/ gboolean up_device_list_insert (UpDeviceList *list, gpointer device) { GObject *native; const gchar *native_path; g_return_val_if_fail (UP_IS_DEVICE_LIST (list), FALSE); g_return_val_if_fail (device != NULL, FALSE); native = up_device_get_native (UP_DEVICE (device)); g_return_val_if_fail (native != NULL, FALSE); native_path = up_native_get_native_path (native); if (native_path == NULL) { g_warning ("failed to get native path"); return FALSE; } g_hash_table_insert (list->priv->map_native_path_to_device, g_strdup (native_path), g_object_ref (device)); g_ptr_array_add (list->priv->array, g_object_ref (device)); g_debug ("added %s", native_path); return TRUE; } /** * up_device_list_remove_cb: **/ static gboolean up_device_list_remove_cb (gpointer key, gpointer value, gpointer user_data) { if (value == user_data) { g_debug ("removed %s", (char *) key); return TRUE; } return FALSE; } /** * up_device_list_remove: **/ gboolean up_device_list_remove (UpDeviceList *list, gpointer device) { g_return_val_if_fail (UP_IS_DEVICE_LIST (list), FALSE); g_return_val_if_fail (device != NULL, FALSE); /* remove the device from the db */ g_hash_table_foreach_remove (list->priv->map_native_path_to_device, up_device_list_remove_cb, device); g_ptr_array_remove (list->priv->array, device); /* we're removed the last instance? */ if (!G_IS_OBJECT (device)) { g_warning ("INTERNAL STATE CORRUPT: we've removed the last instance of %p", device); return FALSE; } return TRUE; } /** * up_device_list_clear: * @list: This class instance * * Clear the contents of this list. **/ void up_device_list_clear (UpDeviceList *list) { g_return_if_fail (UP_IS_DEVICE_LIST (list)); g_hash_table_remove_all (list->priv->map_native_path_to_device); g_ptr_array_set_size (list->priv->array, 0); } /** * up_device_list_get_array: * * This is quick to iterate when we don't have GObject's to resolve * * Return value: the array, free with g_ptr_array_unref() **/ GPtrArray * up_device_list_get_array (UpDeviceList *list) { g_return_val_if_fail (UP_IS_DEVICE_LIST (list), NULL); return g_ptr_array_ref (list->priv->array); } /** * up_device_list_class_init: * @klass: The UpDeviceListClass **/ static void up_device_list_class_init (UpDeviceListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_device_list_finalize; } /** * up_device_list_init: * @list: This class instance **/ static void up_device_list_init (UpDeviceList *list) { list->priv = up_device_list_get_instance_private (list); list->priv->array = g_ptr_array_new_with_free_func (g_object_unref); list->priv->map_native_path_to_device = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } /** * up_device_list_finalize: * @object: The object to finalize **/ static void up_device_list_finalize (GObject *object) { UpDeviceList *list; g_return_if_fail (UP_IS_DEVICE_LIST (object)); list = UP_DEVICE_LIST (object); g_ptr_array_unref (list->priv->array); g_hash_table_unref (list->priv->map_native_path_to_device); G_OBJECT_CLASS (up_device_list_parent_class)->finalize (object); } /** * up_device_list_new: * * Return value: a new UpDeviceList object. **/ UpDeviceList * up_device_list_new (void) { return g_object_new (UP_TYPE_DEVICE_LIST, NULL); } 0707010000008E000081A400000000000000000000000166EA481400000974000000000000000000000000000000000000002300000000upower-1.90.6/src/up-device-list.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 __UP_DEVICE_LIST_H #define __UP_DEVICE_LIST_H #include <glib-object.h> #include "up-types.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE_LIST (up_device_list_get_type ()) #define UP_DEVICE_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_LIST, UpDeviceList)) #define UP_DEVICE_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_LIST, UpDeviceListClass)) #define UP_IS_DEVICE_LIST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_LIST)) #define UP_IS_DEVICE_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_LIST)) #define UP_DEVICE_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_LIST, UpDeviceListClass)) #define UP_DEVICE_LIST_ERROR (up_device_list_error_quark ()) #define UP_DEVICE_LIST_TYPE_ERROR (up_device_list_error_get_type ()) typedef struct UpDeviceListPrivate UpDeviceListPrivate; typedef struct { GObject parent; UpDeviceListPrivate *priv; } UpDeviceList; typedef struct { GObjectClass parent_class; } UpDeviceListClass; GType up_device_list_get_type (void); UpDeviceList *up_device_list_new (void); GObject *up_device_list_lookup (UpDeviceList *list, GObject *native); gboolean up_device_list_insert (UpDeviceList *list, gpointer device); gboolean up_device_list_remove (UpDeviceList *list, gpointer device); void up_device_list_clear (UpDeviceList *list); GPtrArray *up_device_list_get_array (UpDeviceList *list); G_END_DECLS #endif /* __UP_DEVICE_LIST_H */ 0707010000008F000081A400000000000000000000000166EA48140000668F000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-device.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <string.h> #include <glib.h> #include <glib/gstdio.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include "up-native.h" #include "up-device.h" #include "up-history.h" #include "up-history-item.h" #include "up-stats-item.h" typedef struct { UpDaemon *daemon; /* native == NULL implies display device */ GObject *native; UpHistory *history; gboolean has_ever_refresh; gint64 last_refresh; int poll_timeout; /* This is TRUE if the wireless_status property is present, and * its value is "disconnected" * See https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#c.usb_interface */ gboolean disconnected; } UpDevicePrivate; static void up_device_initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_EXTENDED (UpDevice, up_device, UP_TYPE_EXPORTED_DEVICE_SKELETON, 0, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, up_device_initable_iface_init) G_ADD_PRIVATE (UpDevice)) enum { PROP_0, PROP_DAEMON, PROP_NATIVE, PROP_LAST_REFRESH, PROP_POLL_TIMEOUT, PROP_DISCONNECTED, N_PROPS }; static GParamSpec *properties[N_PROPS]; #define UP_DEVICES_DBUS_PATH "/org/freedesktop/UPower/devices" static gchar * up_device_get_id (UpDevice *device); /* This needs to be called when one of those properties changes: * state * power_supply * percentage * time_to_empty * battery_level * * type should not change for non-display devices */ static void update_warning_level (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); UpDeviceLevel warning_level, battery_level; UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device); if (priv->native == NULL) return; /* If the battery level is available, and is critical, * we need to fallback to calculations to get the warning * level, as that might be "action" at this point */ battery_level = up_exported_device_get_battery_level (skeleton); if (battery_level != UP_DEVICE_LEVEL_NONE && battery_level != UP_DEVICE_LEVEL_CRITICAL) { if (battery_level == UP_DEVICE_LEVEL_LOW) warning_level = battery_level; else warning_level = UP_DEVICE_LEVEL_NONE; } else { warning_level = up_daemon_compute_warning_level (priv->daemon, up_exported_device_get_state (skeleton), up_exported_device_get_type_ (skeleton), up_exported_device_get_power_supply (skeleton), up_exported_device_get_percentage (skeleton), up_exported_device_get_time_to_empty (skeleton)); } up_exported_device_set_warning_level (skeleton, warning_level); } /* This needs to be called when one of those properties changes: * type * state * percentage * is-present */ static void update_icon_name (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); const gchar *icon_name = NULL; UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device); /* get the icon from some simple rules */ if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_LINE_POWER) { icon_name = "ac-adapter-symbolic"; } else { if (!up_exported_device_get_is_present (skeleton)) { icon_name = "battery-missing-symbolic"; } else { switch (up_exported_device_get_state (skeleton)) { case UP_DEVICE_STATE_EMPTY: icon_name = "battery-empty-symbolic"; break; case UP_DEVICE_STATE_FULLY_CHARGED: icon_name = "battery-full-charged-symbolic"; break; case UP_DEVICE_STATE_CHARGING: case UP_DEVICE_STATE_PENDING_CHARGE: icon_name = up_daemon_get_charge_icon (priv->daemon, up_exported_device_get_percentage (skeleton), up_exported_device_get_battery_level (skeleton), TRUE); break; case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: icon_name = up_daemon_get_charge_icon (priv->daemon, up_exported_device_get_percentage (skeleton), up_exported_device_get_battery_level (skeleton), FALSE); break; default: icon_name = "battery-missing-symbolic"; } } } up_exported_device_set_icon_name (skeleton, icon_name); } static void ensure_history (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); g_autofree char *id = NULL; if (priv->history) return; priv->history = up_history_new (); id = up_device_get_id (device); if (id) up_history_set_id (priv->history, id); } static gboolean up_device_history_filter (UpDevice *device, UpHistory *history) { UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device); if (up_exported_device_get_state (skeleton) == UP_DEVICE_STATE_UNKNOWN) { g_debug ("device %s has unknown state, not saving history", up_exported_device_get_native_path (skeleton)); return FALSE; } return TRUE; } static void update_history (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device); ensure_history (device); if (!up_device_history_filter (device, priv->history)) return; /* save new history */ up_history_set_state (priv->history, up_exported_device_get_state (skeleton)); up_history_set_charge_data (priv->history, up_exported_device_get_percentage (skeleton)); up_history_set_rate_data (priv->history, up_exported_device_get_energy_rate (skeleton)); up_history_set_time_full_data (priv->history, up_exported_device_get_time_to_full (skeleton)); up_history_set_time_empty_data (priv->history, up_exported_device_get_time_to_empty (skeleton)); } static void up_device_notify (GObject *object, GParamSpec *pspec) { UpDevice *device = UP_DEVICE (object); UpDevicePrivate *priv = up_device_get_instance_private (device); /* Not finished setting up the object? */ if (priv->daemon == NULL) return; G_OBJECT_CLASS (up_device_parent_class)->notify (object, pspec); if (g_strcmp0 (pspec->name, "type") == 0 || g_strcmp0 (pspec->name, "is-present") == 0) { update_icon_name (device); /* Clearing the history object for lazily loading when device id was changed. */ if (priv->history != NULL && !up_history_is_device_id_equal (priv->history, up_device_get_id(device))) g_clear_object (&priv->history); } else if (g_strcmp0 (pspec->name, "vendor") == 0 || g_strcmp0 (pspec->name, "model") == 0 || g_strcmp0 (pspec->name, "serial") == 0) { if (priv->history != NULL && !up_history_is_device_id_equal (priv->history, up_device_get_id(device))) g_clear_object (&priv->history); } else if (g_strcmp0 (pspec->name, "power-supply") == 0 || g_strcmp0 (pspec->name, "time-to-empty") == 0) { update_warning_level (device); } else if (g_strcmp0 (pspec->name, "state") == 0 || g_strcmp0 (pspec->name, "percentage") == 0 || g_strcmp0 (pspec->name, "battery-level") == 0) { update_warning_level (device); update_icon_name (device); } else if (g_strcmp0 (pspec->name, "update-time") == 0) { update_history (device); } } /** * up_device_get_on_battery: * * Note: Only implement for system devices, i.e. ones supplying the system **/ gboolean up_device_get_on_battery (UpDevice *device, gboolean *on_battery) { UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device); g_return_val_if_fail (UP_IS_DEVICE (device), FALSE); if (klass->get_on_battery == NULL) return FALSE; return klass->get_on_battery (device, on_battery); } /** * up_device_get_online: * * Note: Only implement for system devices, i.e. devices supplying the system **/ gboolean up_device_get_online (UpDevice *device, gboolean *online) { UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device); g_return_val_if_fail (UP_IS_DEVICE (device), FALSE); if (klass->get_online == NULL) return FALSE; return klass->get_online (device, online); } static gchar * up_device_get_id (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); GString *string; gchar *id = NULL; const char *model; const char *serial; UpExportedDevice *skeleton; if (priv->native == NULL) return NULL; skeleton = UP_EXPORTED_DEVICE (device); model = up_exported_device_get_model (skeleton); serial = up_exported_device_get_serial (skeleton); if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_LINE_POWER) { goto out; } else if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_BATTERY) { /* we don't have an ID if we are not present */ if (!up_exported_device_get_is_present (skeleton)) goto out; string = g_string_new (""); /* in an ideal world, model-capacity-serial */ if (model != NULL && strlen (model) > 2) { g_string_append (string, model); g_string_append_c (string, '-'); } if (up_exported_device_get_energy_full_design (skeleton) > 0) { /* FIXME: this may not be stable if we are using voltage_now */ g_string_append_printf (string, "%i", (guint) up_exported_device_get_energy_full_design (skeleton)); g_string_append_c (string, '-'); } if (serial != NULL && strlen (serial) > 2) { g_string_append (string, serial); g_string_append_c (string, '-'); } /* make sure we are sane */ if (string->len == 0) { /* just use something generic */ g_string_append (string, "generic_id"); } else { /* remove trailing '-' */ g_string_set_size (string, string->len - 1); } id = g_string_free (string, FALSE); } else { /* generic fallback, get what data we can */ string = g_string_new (""); if (up_exported_device_get_vendor (skeleton) != NULL) { g_string_append (string, up_exported_device_get_vendor (skeleton)); g_string_append_c (string, '-'); } if (model != NULL) { g_string_append (string, model); g_string_append_c (string, '-'); } if (serial != NULL) { g_string_append (string, serial); g_string_append_c (string, '-'); } /* make sure we are sane */ if (string->len == 0) { /* just use something generic */ g_string_append (string, "generic_id"); } else { /* remove trailing '-' */ g_string_set_size (string, string->len - 1); } id = g_string_free (string, FALSE); } /* the id may have invalid chars that need to be replaced */ g_strdelimit (id, "\\\t\"?' /,.", '_'); out: return id; } /** * up_device_get_daemon: * * Returns a refcounted #UpDaemon instance, or %NULL **/ UpDaemon * up_device_get_daemon (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); if (priv->daemon == NULL) return NULL; return g_object_ref (priv->daemon); } /** * up_device_polkit_is_allowed **/ gboolean up_device_polkit_is_allowed (UpDevice *device, GDBusMethodInvocation *invocation) { UpDevicePrivate *priv = up_device_get_instance_private (device); if (!up_daemon_polkit_is_allowed (priv->daemon, "org.freedesktop.UPower.enable-charging-limit", invocation)) return FALSE; return TRUE; } static void up_device_export_skeleton (UpDevice *device, const gchar *object_path) { UpDevicePrivate *priv = up_device_get_instance_private (device); GError *error = NULL; g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (device), g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (priv->daemon)), object_path, &error); if (error != NULL) { g_critical ("error registering device on system bus: %s", error->message); g_error_free (error); } } static gchar * up_device_compute_object_path (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); gchar *basename; gchar *id; gchar *object_path; const gchar *native_path; const gchar *type; guint i; if (priv->native == NULL) { return g_build_filename (UP_DEVICES_DBUS_PATH, "DisplayDevice", NULL); } type = up_device_kind_to_string (up_exported_device_get_type_ (UP_EXPORTED_DEVICE (device))); native_path = up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device)); basename = g_path_get_basename (native_path); id = g_strjoin ("_", type, basename, NULL); /* make DBUS valid path */ for (i=0; id[i] != '\0'; i++) { if (id[i] == '-') id[i] = '_'; if (id[i] == '.') id[i] = 'x'; if (id[i] == ':') id[i] = 'o'; if (id[i] == '@') id[i] = '_'; } object_path = g_build_filename (UP_DEVICES_DBUS_PATH, id, NULL); g_free (basename); g_free (id); return object_path; } gboolean up_device_register (UpDevice *device) { g_autofree char *computed_object_path = NULL; if (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device)) != NULL) return FALSE; computed_object_path = up_device_compute_object_path (device); g_debug ("Exported UpDevice with path %s", computed_object_path); up_device_export_skeleton (device, computed_object_path); return TRUE; } void up_device_unregister (UpDevice *device) { g_autofree char *object_path = NULL; object_path = g_strdup (g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device))); if (object_path != NULL) { g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (device)); g_debug ("Unexported UpDevice with path %s", object_path); } } gboolean up_device_is_registered (UpDevice *device) { return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device)) != NULL; } /** * up_device_refresh: * * Return %TRUE on success, %FALSE if we failed to refresh or no data **/ static gboolean up_device_refresh (UpExportedDevice *skeleton, GDBusMethodInvocation *invocation, UpDevice *device) { up_device_refresh_internal (device, UP_REFRESH_POLL); up_exported_device_complete_refresh (skeleton, invocation); return TRUE; } static gboolean up_device_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { UpDevice *device = UP_DEVICE (initable); UpDevicePrivate *priv = up_device_get_instance_private (device); const gchar *native_path = "DisplayDevice"; UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device); int ret; g_return_val_if_fail (UP_IS_DEVICE (device), FALSE); if (up_daemon_get_debug (priv->daemon)) g_signal_connect (device, "handle-refresh", G_CALLBACK (up_device_refresh), device); if (priv->native) { native_path = up_native_get_native_path (priv->native); up_exported_device_set_native_path (UP_EXPORTED_DEVICE (device), native_path); } /* coldplug source */ if (klass->coldplug != NULL) { ret = klass->coldplug (device); if (!ret) { g_debug ("failed to coldplug %s", native_path); g_propagate_error (error, g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to coldplug %s", native_path)); return FALSE; } } /* force a refresh, although failure isn't fatal */ ret = up_device_refresh_internal (device, UP_REFRESH_INIT); if (!ret) { g_debug ("failed to refresh %s", native_path); /* XXX: We do not store a history if the initial refresh failed. * This doesn't seem sensible, but it was the case historically. */ goto register_device; } register_device: /* put on the bus */ up_device_register (device); return TRUE; } static void up_device_initable_iface_init (GInitableIface *iface) { iface->init = up_device_initable_init; } static gboolean up_device_get_statistics (UpExportedDevice *skeleton, GDBusMethodInvocation *invocation, const gchar *type, UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); GPtrArray *array = NULL; UpStatsItem *item; guint i; GVariantBuilder builder; if (!up_exported_device_get_has_statistics (skeleton)) { g_dbus_method_invocation_return_error_literal (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "device does not support getting stats"); goto out; } ensure_history (device); /* get the correct data */ if (g_strcmp0 (type, "charging") == 0) array = up_history_get_profile_data (priv->history, TRUE); else if (g_strcmp0 (type, "discharging") == 0) array = up_history_get_profile_data (priv->history, FALSE); /* maybe the device doesn't support histories */ if (array == NULL) { g_dbus_method_invocation_return_error_literal (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "device has no statistics"); goto out; } /* always 101 items of data */ if (array->len != 101) { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "statistics invalid as have %i items", array->len); goto out; } /* copy data to dbus struct */ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dd)")); for (i = 0; i < array->len; i++) { item = (UpStatsItem *) g_ptr_array_index (array, i); g_variant_builder_add (&builder, "(dd)", up_stats_item_get_value (item), up_stats_item_get_accuracy (item)); } up_exported_device_complete_get_statistics (skeleton, invocation, g_variant_builder_end (&builder)); out: if (array != NULL) g_ptr_array_unref (array); return TRUE; } static gboolean up_device_get_history (UpExportedDevice *skeleton, GDBusMethodInvocation *invocation, const gchar *type_string, guint timespan, guint resolution, UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); GPtrArray *array = NULL; UpHistoryItem *item; guint i; UpHistoryType type = UP_HISTORY_TYPE_UNKNOWN; GVariantBuilder builder; /* doesn't even try to support this */ if (!up_exported_device_get_has_history (skeleton)) { g_dbus_method_invocation_return_error_literal (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "device does not support getting history"); goto out; } /* get the correct data */ if (g_strcmp0 (type_string, "rate") == 0) type = UP_HISTORY_TYPE_RATE; else if (g_strcmp0 (type_string, "charge") == 0) type = UP_HISTORY_TYPE_CHARGE; else if (g_strcmp0 (type_string, "time-full") == 0) type = UP_HISTORY_TYPE_TIME_FULL; else if (g_strcmp0 (type_string, "time-empty") == 0) type = UP_HISTORY_TYPE_TIME_EMPTY; /* something recognised */ if (type != UP_HISTORY_TYPE_UNKNOWN) { ensure_history (device); array = up_history_get_data (priv->history, type, timespan, resolution); } /* maybe the device doesn't have any history */ if (array == NULL) { g_dbus_method_invocation_return_error_literal (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "device has no history"); goto out; } /* copy data to dbus struct */ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(udu)")); for (i = 0; i < array->len; i++) { item = (UpHistoryItem *) g_ptr_array_index (array, i); g_variant_builder_add (&builder, "(udu)", up_history_item_get_time (item), up_history_item_get_value (item), up_history_item_get_state (item)); } up_exported_device_complete_get_history (skeleton, invocation, g_variant_builder_end (&builder)); out: if (array != NULL) g_ptr_array_unref (array); return TRUE; } void up_device_sibling_discovered (UpDevice *device, GObject *sibling) { UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device); if (klass->sibling_discovered) klass->sibling_discovered (device, sibling); } gboolean up_device_refresh_internal (UpDevice *device, UpRefreshReason reason) { UpDevicePrivate *priv = up_device_get_instance_private (device); gboolean ret = FALSE; UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device); if (priv->native == NULL) return TRUE; /* not implemented */ if (klass->refresh == NULL) goto out; /* do the refresh, and change the property */ ret = klass->refresh (device, reason); priv->last_refresh = g_get_monotonic_time (); g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_LAST_REFRESH]); if (!ret) { g_debug ("no changes"); goto out; } /* the first time, print all properties */ if (!priv->has_ever_refresh) { g_debug ("added native-path: %s", up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device))); priv->has_ever_refresh = TRUE; goto out; } out: return ret; } const gchar * up_device_get_object_path (UpDevice *device) { g_return_val_if_fail (UP_IS_DEVICE (device), NULL); return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device)); } GObject * up_device_get_native (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); g_return_val_if_fail (UP_IS_DEVICE (device), NULL); return priv->native; } const gchar * up_device_get_state_dir_override (UpDevice *device) { UpDevicePrivate *priv = up_device_get_instance_private (device); if (priv->daemon == NULL) return NULL; return up_daemon_get_state_dir_env_override (priv->daemon); } static void up_device_init (UpDevice *device) { UpExportedDevice *skeleton; skeleton = UP_EXPORTED_DEVICE (device); up_exported_device_set_battery_level (skeleton, UP_DEVICE_LEVEL_NONE); g_signal_connect (device, "handle-get-history", G_CALLBACK (up_device_get_history), device); g_signal_connect (device, "handle-get-statistics", G_CALLBACK (up_device_get_statistics), device); } static void up_device_finalize (GObject *object) { UpDevicePrivate *priv = up_device_get_instance_private (UP_DEVICE (object)); g_clear_object (&priv->native); g_clear_object (&priv->daemon); g_clear_object (&priv->history); G_OBJECT_CLASS (up_device_parent_class)->finalize (object); } static void up_device_dispose (GObject *object) { UpDevicePrivate *priv = up_device_get_instance_private (UP_DEVICE (object)); g_clear_object (&priv->daemon); G_OBJECT_CLASS (up_device_parent_class)->dispose (object); } static void up_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UpDevice *device = UP_DEVICE (object); UpDevicePrivate *priv = up_device_get_instance_private (device); switch (prop_id) { case PROP_DAEMON: priv->daemon = g_value_dup_object (value); break; case PROP_NATIVE: priv->native = g_value_dup_object (value); break; case PROP_POLL_TIMEOUT: priv->poll_timeout = g_value_get_int (value); break; case PROP_DISCONNECTED: priv->disconnected = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void up_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { UpDevice *device = UP_DEVICE (object); UpDevicePrivate *priv = up_device_get_instance_private (device); switch (prop_id) { case PROP_POLL_TIMEOUT: g_value_set_int (value, priv->poll_timeout); break; case PROP_LAST_REFRESH: g_value_set_int64 (value, priv->last_refresh); break; case PROP_DISCONNECTED: g_value_set_boolean (value, priv->disconnected); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void up_device_class_init (UpDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->notify = up_device_notify; object_class->finalize = up_device_finalize; object_class->dispose = up_device_dispose; object_class->set_property = up_device_set_property; object_class->get_property = up_device_get_property; properties[PROP_DAEMON] = g_param_spec_object ("daemon", "UpDaemon", "UpDaemon reference", UP_TYPE_DAEMON, G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_NATIVE] = g_param_spec_object ("native", "Native", "Native Object", G_TYPE_OBJECT, G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); properties[PROP_POLL_TIMEOUT] = g_param_spec_int ("poll-timeout", "Poll timeout", "Time in seconds between polls", 0, 3600, 0, G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_READABLE); properties[PROP_LAST_REFRESH] = g_param_spec_int64 ("last-refresh", "Last Refresh", "Time of last refresh (in monotonic clock)", -1, G_MAXINT64, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); properties[PROP_DISCONNECTED] = g_param_spec_boolean ("disconnected", "Disconnected", "Whethe wireless device is disconnected", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_READABLE); g_object_class_install_properties (object_class, N_PROPS, properties); } UpDevice * up_device_new (UpDaemon *daemon, GObject *native) { return UP_DEVICE (g_object_new (UP_TYPE_DEVICE, "daemon", daemon, "native", native, NULL)); } 07070100000090000081A400000000000000000000000166EA481400000ABC000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-device.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_DEVICE_H__ #define __UP_DEVICE_H__ #include <dbus/up-device-generated.h> #include "up-daemon.h" G_BEGIN_DECLS #define UP_TYPE_DEVICE (up_device_get_type ()) G_DECLARE_DERIVABLE_TYPE (UpDevice, up_device, UP, DEVICE, UpExportedDeviceSkeleton) typedef enum { UP_REFRESH_INIT, UP_REFRESH_POLL, UP_REFRESH_RESUME, UP_REFRESH_EVENT, UP_REFRESH_LINE_POWER, } UpRefreshReason; struct _UpDeviceClass { UpExportedDeviceSkeletonClass parent_class; /* vtable */ gboolean (*coldplug) (UpDevice *device); void (*sibling_discovered) (UpDevice *device, GObject *sibling); gboolean (*refresh) (UpDevice *device, UpRefreshReason reason); const gchar *(*get_id) (UpDevice *device); gboolean (*get_on_battery) (UpDevice *device, gboolean *on_battery); gboolean (*get_online) (UpDevice *device, gboolean *online); }; GType up_device_get_type (void); UpDevice *up_device_new (UpDaemon *daemon, GObject *native); UpDaemon *up_device_get_daemon (UpDevice *device); GObject *up_device_get_native (UpDevice *device); const gchar *up_device_get_object_path (UpDevice *device); gboolean up_device_get_on_battery (UpDevice *device, gboolean *on_battery); gboolean up_device_get_online (UpDevice *device, gboolean *online); const gchar *up_device_get_state_dir_override (UpDevice *device); gboolean up_device_polkit_is_allowed (UpDevice *device, GDBusMethodInvocation *invocation); void up_device_sibling_discovered (UpDevice *device, GObject *sibling); gboolean up_device_refresh_internal (UpDevice *device, UpRefreshReason reason); void up_device_unregister (UpDevice *device); gboolean up_device_register (UpDevice *device); gboolean up_device_is_registered (UpDevice *device); G_END_DECLS #endif /* __UP_DEVICE_H__ */ 07070100000091000081A400000000000000000000000166EA481400000EE9000000000000000000000000000000000000002200000000upower-1.90.6/src/up-enumerator.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "up-daemon.h" #include "up-enumerator.h" #include "up-device.h" typedef struct { UpDaemon *daemon; } UpEnumeratorPrivate; static void up_enumerator_initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_EXTENDED (UpEnumerator, up_enumerator, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, up_enumerator_initable_iface_init) G_ADD_PRIVATE (UpEnumerator)) enum { PROP_0, PROP_DAEMON, N_PROPS }; static GParamSpec *properties[N_PROPS]; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, SIGNAL_LAST }; static guint signals [SIGNAL_LAST] = { 0 }; UpDaemon* up_enumerator_get_daemon (UpEnumerator *self) { UpEnumeratorPrivate *priv = up_enumerator_get_instance_private (self); return priv->daemon; } static void up_enumerator_init (UpEnumerator *self) { } static gboolean up_enumerator_initable_init (GInitable *obj, GCancellable *cancellable, GError **error) { UP_ENUMERATOR_GET_CLASS (obj)->initable_init (UP_ENUMERATOR (obj)); return TRUE; } static void up_enumerator_initable_iface_init (GInitableIface *iface) { iface->init = up_enumerator_initable_init; } static void up_enumerator_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { UpEnumerator *self = UP_ENUMERATOR (object); UpEnumeratorPrivate *priv = up_enumerator_get_instance_private (self); switch (prop_id) { case PROP_DAEMON: priv->daemon = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void up_enumerator_dispose (GObject *object) { UpEnumerator *self = UP_ENUMERATOR (object); UpEnumeratorPrivate *priv = up_enumerator_get_instance_private (self); g_clear_object (&priv->daemon); } static void up_enumerator_class_init (UpEnumeratorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = up_enumerator_dispose; object_class->set_property = up_enumerator_set_property; properties[PROP_DAEMON] = g_param_spec_object ("daemon", "UpDaemon", "UpDaemon reference", UP_TYPE_DAEMON, G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); signals [SIGNAL_DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); signals [SIGNAL_DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, UP_TYPE_DEVICE); g_object_class_install_properties (object_class, N_PROPS, properties); } 07070100000092000081A400000000000000000000000166EA4814000004CA000000000000000000000000000000000000002200000000upower-1.90.6/src/up-enumerator.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #pragma once #include <glib-object.h> G_BEGIN_DECLS #define UP_TYPE_ENUMERATOR (up_enumerator_get_type ()) G_DECLARE_DERIVABLE_TYPE (UpEnumerator, up_enumerator, UP, ENUMERATOR, GObject) struct _UpEnumeratorClass { GObjectClass parent_class; void (*initable_init) (UpEnumerator *self); }; UpDaemon *up_enumerator_get_daemon (UpEnumerator *self); G_END_DECLS 07070100000093000081A400000000000000000000000166EA4814000060BD000000000000000000000000000000000000001F00000000upower-1.90.6/src/up-history.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 <stdlib.h> #include <stdio.h> #include <math.h> #include <glib/gi18n.h> #include <gio/gio.h> #include "up-history.h" #include "up-stats-item.h" #include "up-history-item.h" static void up_history_finalize (GObject *object); #define UP_HISTORY_SAVE_INTERVAL (10*60) /* seconds */ #define UP_HISTORY_SAVE_INTERVAL_LOW_POWER 5 /* seconds */ #define UP_HISTORY_LOW_POWER_PERCENT 10 #define UP_HISTORY_DEFAULT_MAX_DATA_AGE (7*24*60*60) /* seconds */ struct UpHistoryPrivate { gchar *id; gdouble rate_last; gint64 time_full_last; gint64 time_empty_last; gdouble percentage_last; UpDeviceState state; GPtrArray *data_rate; GPtrArray *data_charge; GPtrArray *data_time_full; GPtrArray *data_time_empty; GSource *save_source; guint max_data_age; gchar *dir; }; enum { UP_HISTORY_PROGRESS, UP_HISTORY_LAST_SIGNAL }; G_DEFINE_TYPE_WITH_PRIVATE (UpHistory, up_history, G_TYPE_OBJECT) /** * up_history_set_max_data_age: **/ void up_history_set_max_data_age (UpHistory *history, guint max_data_age) { history->priv->max_data_age = max_data_age; } /** * up_history_array_copy_cb: **/ static void up_history_array_copy_cb (UpHistoryItem *item, GPtrArray *dest) { g_ptr_array_add (dest, g_object_ref (item)); } /** * up_history_array_limit_resolution: * @array: The data we have for a specific graph * @max_num: The max desired points * * We need to reduce the number of data points else the graph will take a long * time to plot accuracy we don't need at the larger scales. * This will not reduce the scale or range of the data. * * 100 + + | + | + | + + * | A | | | * 80 + + | + | + | + + * | | B C | | * 60 + + | + | + | + + * | | | | * 40 + + | + | + | + E + * | | | | D * 20 + + | + | + | + F + * | | | | * 0 +-----+-----+-----+-----+-----+ * 20 40 60 80 100 * * A = 15,90 * B = 30,70 * C = 52,70 * D = 80,30 * E = 85,40 * F = 90,20 * * 1 = 15,90 * 2 = 41,70 * 3 = 85,30 **/ static GPtrArray * up_history_array_limit_resolution (GPtrArray *array, guint max_num) { UpHistoryItem *item; UpHistoryItem *item_new; guint length; guint i; guint64 last; guint64 first; GPtrArray *new; UpDeviceState state = UP_DEVICE_STATE_UNKNOWN; guint64 time_s = 0; gdouble value = 0; guint64 count = 0; guint step = 1; new = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_debug ("length of array (before) %i", array->len); /* check length */ length = array->len; if (length == 0) goto out; if (length < max_num) { /* need to copy array */ g_ptr_array_foreach (array, (GFunc) up_history_array_copy_cb, new); goto out; } /* last element */ item = (UpHistoryItem *) g_ptr_array_index (array, length-1); last = up_history_item_get_time (item); item = (UpHistoryItem *) g_ptr_array_index (array, 0); first = up_history_item_get_time (item); /* Reduces the number of points to a pre-set level using a time * division algorithm so we don't keep diluting the previous * data with a conventional 1-in-x type algorithm. */ for (i = 0; i < length; i++) { guint64 preset; item = (UpHistoryItem *) g_ptr_array_index (array, i); preset = last + ((first - last) * (guint64) step) / max_num; /* if state changed or we went over the preset do a new point */ if (count > 0 && (up_history_item_get_time (item) > preset || up_history_item_get_state (item) != state)) { item_new = up_history_item_new (); up_history_item_set_time (item_new, time_s / count); up_history_item_set_value (item_new, value / count); up_history_item_set_state (item_new, state); g_ptr_array_add (new, item_new); step++; time_s = up_history_item_get_time (item); value = up_history_item_get_value (item); state = up_history_item_get_state (item); count = 1; } else { count++; time_s += up_history_item_get_time (item); value += up_history_item_get_value (item); } } /* only add if nonzero */ if (count > 0) { item_new = up_history_item_new (); up_history_item_set_time (item_new, time_s / count); up_history_item_set_value (item_new, value / count); up_history_item_set_state (item_new, state); g_ptr_array_add (new, item_new); } /* check length */ g_debug ("length of array (after) %i", new->len); out: return new; } /** * up_history_copy_array_timespan: **/ static GPtrArray * up_history_copy_array_timespan (const GPtrArray *array, guint timespan) { guint i; UpHistoryItem *item; GPtrArray *array_new; gint64 time_now; /* no data */ if (array->len == 0) return NULL; /* no limit on data */ if (timespan == 0) { array_new = g_ptr_array_ref ((GPtrArray *) array); goto out; } /* new data */ array_new = g_ptr_array_new (); time_now = g_get_real_time (); g_debug ("limiting data to last %i seconds", timespan); /* treat the timespan like a range, and search backwards */ timespan *= 0.95f; for (i=array->len-1; i>0; i--) { item = (UpHistoryItem *) g_ptr_array_index (array, i); if ((time_now / 1000000) - up_history_item_get_time (item) < timespan) g_ptr_array_add (array_new, g_object_ref (item)); } out: return array_new; } /** * up_history_get_data: **/ GPtrArray * up_history_get_data (UpHistory *history, UpHistoryType type, guint timespan, guint resolution) { GPtrArray *array; GPtrArray *array_resolution; const GPtrArray *array_data = NULL; g_return_val_if_fail (UP_IS_HISTORY (history), NULL); if (history->priv->id == NULL) return NULL; if (type == UP_HISTORY_TYPE_CHARGE) array_data = history->priv->data_charge; else if (type == UP_HISTORY_TYPE_RATE) array_data = history->priv->data_rate; else if (type == UP_HISTORY_TYPE_TIME_FULL) array_data = history->priv->data_time_full; else if (type == UP_HISTORY_TYPE_TIME_EMPTY) array_data = history->priv->data_time_empty; /* not recognised */ if (array_data == NULL) return NULL; /* only return a certain time */ array = up_history_copy_array_timespan (array_data, timespan); if (array == NULL) return NULL; /* only add a certain number of points */ array_resolution = up_history_array_limit_resolution (array, resolution); g_ptr_array_unref (array); return array_resolution; } /** * up_history_get_profile_data: **/ GPtrArray * up_history_get_profile_data (UpHistory *history, gboolean charging) { guint i; guint non_zero_accuracy = 0; gfloat average = 0.0f; guint bin; guint oldbin = 999; UpHistoryItem *item_last = NULL; UpHistoryItem *item; UpHistoryItem *item_old = NULL; UpStatsItem *stats; GPtrArray *array; GPtrArray *data; guint time_s; gdouble value; gdouble total_value = 0.0f; g_return_val_if_fail (UP_IS_HISTORY (history), NULL); /* create 100 item list and set to zero */ data = g_ptr_array_new_full (101, g_object_unref); for (i=0; i<101; i++) { stats = up_stats_item_new (); g_ptr_array_add (data, stats); } array = history->priv->data_charge; for (i=0; i<array->len; i++) { item = (UpHistoryItem *) g_ptr_array_index (array, i); if (item_last == NULL || up_history_item_get_state (item) != up_history_item_get_state (item_last)) { item_old = NULL; goto cont; } /* round to the nearest int */ bin = rint (up_history_item_get_value (item)); /* ensure bin is in range */ if (bin >= data->len) bin = data->len - 1; /* different */ if (oldbin != bin) { oldbin = bin; if (item_old != NULL) { /* not enough or too much difference */ value = fabs (up_history_item_get_value (item) - up_history_item_get_value (item_old)); if (value < 0.01f) { item_old = NULL; goto cont; } if (value > 3.0f) { item_old = NULL; goto cont; } time_s = up_history_item_get_time (item) - up_history_item_get_time (item_old); /* use the accuracy field as a counter for now */ if ((charging && up_history_item_get_state (item) == UP_DEVICE_STATE_CHARGING) || (!charging && up_history_item_get_state (item) == UP_DEVICE_STATE_DISCHARGING)) { stats = (UpStatsItem *) g_ptr_array_index (data, bin); up_stats_item_set_value (stats, up_stats_item_get_value (stats) + time_s); up_stats_item_set_accuracy (stats, up_stats_item_get_accuracy (stats) + 1); } } item_old = item; } cont: item_last = item; } /* divide the value by the number of samples to make the average */ for (i=0; i<101; i++) { stats = (UpStatsItem *) g_ptr_array_index (data, i); if (up_stats_item_get_accuracy (stats) != 0) up_stats_item_set_value (stats, up_stats_item_get_value (stats) / up_stats_item_get_accuracy (stats)); } /* find non-zero accuracy values for the average */ for (i=0; i<101; i++) { stats = (UpStatsItem *) g_ptr_array_index (data, i); if (up_stats_item_get_accuracy (stats) > 0) { total_value += up_stats_item_get_value (stats); non_zero_accuracy++; } } /* average */ if (non_zero_accuracy != 0) average = total_value / non_zero_accuracy; g_debug ("average is %f", average); /* make the values a factor of 0, so that 1.0 is twice the * average, and -1.0 is half the average */ for (i=0; i<101; i++) { stats = (UpStatsItem *) g_ptr_array_index (data, i); if (up_stats_item_get_accuracy (stats) > 0) up_stats_item_set_value (stats, (up_stats_item_get_value (stats) - average) / average); else up_stats_item_set_value (stats, 0.0f); } /* accuracy is a percentage scale, where each cycle = 20% */ for (i=0; i<101; i++) { stats = (UpStatsItem *) g_ptr_array_index (data, i); up_stats_item_set_accuracy (stats, up_stats_item_get_accuracy (stats) * 20.0f); } return data; } /** * up_history_get_filename: **/ static gchar * up_history_get_filename (UpHistory *history, const gchar *type) { gchar *path; gchar *filename; filename = g_strdup_printf ("history-%s-%s.dat", type, history->priv->id); path = g_build_filename (history->priv->dir, filename, NULL); g_free (filename); return path; } /** * up_history_set_directory: **/ void up_history_set_directory (UpHistory *history, const gchar *dir) { g_free (history->priv->dir); history->priv->dir = g_strdup (dir); g_mkdir_with_parents (dir, 0755); } /** * up_history_array_to_file: * @list: a valid #GPtrArray instance * @filename: a filename * * Saves a copy of the list to a file **/ static gboolean up_history_array_to_file (UpHistory *history, GPtrArray *list, const gchar *filename) { guint i; UpHistoryItem *item; gchar *part; GString *string; gboolean ret = TRUE; GError *error = NULL; gint64 time_now; guint time_item; guint cull_count = 0; /* get current time */ time_now = g_get_real_time (); /* generate data */ string = g_string_new (""); for (i=0; i<list->len; i++) { item = g_ptr_array_index (list, i); /* only save entries for the last 24 hours */ time_item = up_history_item_get_time (item); if ((time_now / 1000000) - time_item > history->priv->max_data_age) { cull_count++; continue; } part = up_history_item_to_string (item); if (part == NULL) { ret = FALSE; break; } g_string_append_printf (string, "%s\n", part); g_free (part); } part = g_string_free (string, FALSE); /* how many did we kill? */ g_debug ("culled %i of %i", cull_count, list->len); /* we failed to convert to string */ if (!ret) { g_warning ("failed to convert"); goto out; } /* save to disk */ ret = g_file_set_contents (filename, part, -1, &error); if (!ret) { g_warning ("failed to set data: %s", error->message); g_error_free (error); goto out; } g_debug ("saved %s", filename); out: g_free (part); return ret; } /** * up_history_array_from_file: * @list: a valid #GPtrArray instance * @filename: a filename * * Appends the list from a file **/ static gboolean up_history_array_from_file (GPtrArray *list, const gchar *filename) { gboolean ret; GError *error = NULL; gchar *data = NULL; gchar **parts = NULL; guint i; guint length; UpHistoryItem *item; /* do we exist */ ret = g_file_test (filename, G_FILE_TEST_EXISTS); if (!ret) { g_debug ("failed to get data from %s as file does not exist", filename); goto out; } /* get contents */ ret = g_file_get_contents (filename, &data, NULL, &error); if (!ret) { g_warning ("failed to get data: %s", error->message); g_error_free (error); goto out; } /* split by line ending */ parts = g_strsplit (data, "\n", 0); length = g_strv_length (parts); if (length == 0) { g_debug ("no data in %s", filename); goto out; } /* add valid entries */ g_debug ("loading %i items of data from %s", length, filename); for (i=0; i<length-1; i++) { item = up_history_item_new (); ret = up_history_item_set_from_string (item, parts[i]); if (ret) g_ptr_array_add (list, item); else g_object_unref (item); } out: g_strfreev (parts); g_free (data); return ret; } /** * up_history_save_data: **/ gboolean up_history_save_data (UpHistory *history) { gboolean ret = FALSE; gchar *filename_rate = NULL; gchar *filename_charge = NULL; gchar *filename_time_full = NULL; gchar *filename_time_empty = NULL; /* we have an ID? */ if (history->priv->id == NULL) { g_warning ("no ID, cannot save"); goto out; } /* get filenames */ filename_rate = up_history_get_filename (history, "rate"); filename_charge = up_history_get_filename (history, "charge"); filename_time_full = up_history_get_filename (history, "time-full"); filename_time_empty = up_history_get_filename (history, "time-empty"); /* save to disk */ ret = up_history_array_to_file (history, history->priv->data_rate, filename_rate); if (!ret) goto out; ret = up_history_array_to_file (history, history->priv->data_charge, filename_charge); if (!ret) goto out; ret = up_history_array_to_file (history, history->priv->data_time_full, filename_time_full); if (!ret) goto out; ret = up_history_array_to_file (history, history->priv->data_time_empty, filename_time_empty); if (!ret) goto out; out: g_free (filename_rate); g_free (filename_charge); g_free (filename_time_full); g_free (filename_time_empty); return ret; } /** * up_history_schedule_save_cb: **/ static gboolean up_history_schedule_save_cb (UpHistory *history) { up_history_save_data (history); g_clear_pointer (&history->priv->save_source, g_source_destroy); return FALSE; } /** * up_history_is_low_power: **/ static gboolean up_history_is_low_power (UpHistory *history) { guint length; UpHistoryItem *item; /* current status is always up to date */ if (history->priv->state != UP_DEVICE_STATE_DISCHARGING) return FALSE; /* have we got any data? */ length = history->priv->data_charge->len; if (length == 0) return FALSE; /* get the last saved charge object */ item = (UpHistoryItem *) g_ptr_array_index (history->priv->data_charge, length-1); if (up_history_item_get_state (item) != UP_DEVICE_STATE_DISCHARGING) return FALSE; /* high enough */ if (up_history_item_get_value (item) > UP_HISTORY_LOW_POWER_PERCENT) return FALSE; /* we are low power */ return TRUE; } /** * up_history_schedule_save: **/ static gboolean up_history_schedule_save (UpHistory *history) { gboolean ret; gint timeout = UP_HISTORY_SAVE_INTERVAL; /* if low power, then don't batch up save requests */ ret = up_history_is_low_power (history); if (ret) { g_debug ("saving to disk earlier due to low power"); timeout = UP_HISTORY_SAVE_INTERVAL_LOW_POWER; } /* we already have one saved, clear it if it will fire earlier */ if (history->priv->save_source) { guint64 ready = g_source_get_ready_time (history->priv->save_source); if (ready > g_source_get_time (history->priv->save_source) + timeout * G_USEC_PER_SEC) { g_clear_pointer (&history->priv->save_source, g_source_destroy); } else { g_debug ("deferring as earlier timeout is already queued"); return TRUE; } } /* nothing scheduled */ g_debug ("saving in %i seconds", timeout); history->priv->save_source = g_timeout_source_new_seconds (timeout); g_source_set_name (history->priv->save_source, "[upower] up_history_schedule_save_cb"); g_source_attach (history->priv->save_source, NULL); g_source_set_callback (history->priv->save_source, (GSourceFunc) up_history_schedule_save_cb, history, NULL); return TRUE; } /** * up_history_load_data: **/ static gboolean up_history_load_data (UpHistory *history) { gchar *filename; UpHistoryItem *item; /* load rate history from disk */ filename = up_history_get_filename (history, "rate"); up_history_array_from_file (history->priv->data_rate, filename); g_free (filename); /* load charge history from disk */ filename = up_history_get_filename (history, "charge"); up_history_array_from_file (history->priv->data_charge, filename); g_free (filename); /* load charge history from disk */ filename = up_history_get_filename (history, "time-full"); up_history_array_from_file (history->priv->data_time_full, filename); g_free (filename); /* load charge history from disk */ filename = up_history_get_filename (history, "time-empty"); up_history_array_from_file (history->priv->data_time_empty, filename); g_free (filename); /* save a marker so we don't use incomplete percentages */ item = up_history_item_new (); up_history_item_set_time_to_present (item); g_ptr_array_add (history->priv->data_rate, g_object_ref (item)); g_ptr_array_add (history->priv->data_charge, g_object_ref (item)); g_ptr_array_add (history->priv->data_time_full, g_object_ref (item)); g_ptr_array_add (history->priv->data_time_empty, g_object_ref (item)); g_object_unref (item); up_history_schedule_save (history); return TRUE; } /** * up_history_set_id: **/ gboolean up_history_set_id (UpHistory *history, const gchar *id) { gboolean ret; g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id != NULL) return FALSE; if (id == NULL) return FALSE; g_debug ("using id: %s", id); history->priv->id = g_strdup (id); /* load all previous data */ ret = up_history_load_data (history); return ret; } /** * up_history_set_state: **/ gboolean up_history_set_state (UpHistory *history, UpDeviceState state) { g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id == NULL) return FALSE; history->priv->state = state; return TRUE; } /** * up_history_set_charge_data: **/ gboolean up_history_set_charge_data (UpHistory *history, gdouble percentage) { UpHistoryItem *item; g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id == NULL) return FALSE; if (history->priv->state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (history->priv->percentage_last == percentage) return FALSE; /* add to array and schedule save file */ item = up_history_item_new (); up_history_item_set_time_to_present (item); up_history_item_set_value (item, percentage); up_history_item_set_state (item, history->priv->state); g_ptr_array_add (history->priv->data_charge, item); up_history_schedule_save (history); /* save last value */ history->priv->percentage_last = percentage; return TRUE; } /** * up_history_set_rate_data: **/ gboolean up_history_set_rate_data (UpHistory *history, gdouble rate) { UpHistoryItem *item; g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id == NULL) return FALSE; if (history->priv->state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (history->priv->rate_last == rate) return FALSE; /* add to array and schedule save file */ item = up_history_item_new (); up_history_item_set_time_to_present (item); up_history_item_set_value (item, rate); up_history_item_set_state (item, history->priv->state); g_ptr_array_add (history->priv->data_rate, item); up_history_schedule_save (history); /* save last value */ history->priv->rate_last = rate; return TRUE; } /** * up_history_set_time_full_data: **/ gboolean up_history_set_time_full_data (UpHistory *history, gint64 time_s) { UpHistoryItem *item; g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id == NULL) return FALSE; if (history->priv->state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (time_s < 0) return FALSE; if (history->priv->time_full_last == time_s) return FALSE; /* add to array and schedule save file */ item = up_history_item_new (); up_history_item_set_time_to_present (item); up_history_item_set_value (item, (gdouble) time_s); up_history_item_set_state (item, history->priv->state); g_ptr_array_add (history->priv->data_time_full, item); up_history_schedule_save (history); /* save last value */ history->priv->time_full_last = time_s; return TRUE; } /** * up_history_set_time_empty_data: **/ gboolean up_history_set_time_empty_data (UpHistory *history, gint64 time_s) { UpHistoryItem *item; g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (history->priv->id == NULL) return FALSE; if (history->priv->state == UP_DEVICE_STATE_UNKNOWN) return FALSE; if (time_s < 0) return FALSE; if (history->priv->time_empty_last == time_s) return FALSE; /* add to array and schedule save file */ item = up_history_item_new (); up_history_item_set_time_to_present (item); up_history_item_set_value (item, (gdouble) time_s); up_history_item_set_state (item, history->priv->state); g_ptr_array_add (history->priv->data_time_empty, item); up_history_schedule_save (history); /* save last value */ history->priv->time_empty_last = time_s; return TRUE; } /** * up_history_is_device_id_equal: **/ gboolean up_history_is_device_id_equal(UpHistory *history, const gchar *id) { g_return_val_if_fail (UP_IS_HISTORY (history), FALSE); if (!g_strcmp0 (history->priv->id, id)) return TRUE; return FALSE; } /** * up_history_class_init: * @klass: The UpHistoryClass **/ static void up_history_class_init (UpHistoryClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_history_finalize; } /** * up_history_init: * @history: This class instance **/ static void up_history_init (UpHistory *history) { history->priv = up_history_get_instance_private (history); history->priv->data_rate = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); history->priv->data_charge = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); history->priv->data_time_full = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); history->priv->data_time_empty = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); history->priv->max_data_age = UP_HISTORY_DEFAULT_MAX_DATA_AGE; if (g_getenv ("UPOWER_HISTORY_DIR")) up_history_set_directory (history, g_getenv ("UPOWER_HISTORY_DIR")); else up_history_set_directory (history, HISTORY_DIR); } /** * up_history_finalize: * @object: The object to finalize **/ static void up_history_finalize (GObject *object) { UpHistory *history; g_return_if_fail (UP_IS_HISTORY (object)); history = UP_HISTORY (object); /* save */ g_clear_pointer (&history->priv->save_source, g_source_destroy); if (history->priv->id != NULL) up_history_save_data (history); g_ptr_array_unref (history->priv->data_rate); g_ptr_array_unref (history->priv->data_charge); g_ptr_array_unref (history->priv->data_time_full); g_ptr_array_unref (history->priv->data_time_empty); g_free (history->priv->id); g_free (history->priv->dir); g_return_if_fail (history->priv != NULL); G_OBJECT_CLASS (up_history_parent_class)->finalize (object); } /** * up_history_new: * * Return value: a new UpHistory object. **/ UpHistory * up_history_new (void) { return g_object_new (UP_TYPE_HISTORY, NULL); } 07070100000094000081A400000000000000000000000166EA481400000C69000000000000000000000000000000000000001F00000000upower-1.90.6/src/up-history.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 __UP_HISTORY_H #define __UP_HISTORY_H #include <glib-object.h> #include "up-types.h" G_BEGIN_DECLS #define UP_TYPE_HISTORY (up_history_get_type ()) #define UP_HISTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_HISTORY, UpHistory)) #define UP_HISTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_HISTORY, UpHistoryClass)) #define UP_IS_HISTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_HISTORY)) #define UP_IS_HISTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_HISTORY)) #define UP_HISTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_HISTORY, UpHistoryClass)) #define UP_HISTORY_ERROR (up_history_error_quark ()) #define UP_HISTORY_TYPE_ERROR (up_history_error_get_type ()) typedef struct UpHistoryPrivate UpHistoryPrivate; typedef struct { GObject parent; UpHistoryPrivate *priv; } UpHistory; typedef struct { GObjectClass parent_class; } UpHistoryClass; typedef enum { UP_HISTORY_TYPE_CHARGE, UP_HISTORY_TYPE_RATE, UP_HISTORY_TYPE_TIME_FULL, UP_HISTORY_TYPE_TIME_EMPTY, UP_HISTORY_TYPE_UNKNOWN } UpHistoryType; GType up_history_get_type (void); gboolean up_history_is_device_id_equal (UpHistory *history, const gchar *id); UpHistory *up_history_new (void); GPtrArray *up_history_get_data (UpHistory *history, UpHistoryType type, guint timespan, guint resolution); GPtrArray *up_history_get_profile_data (UpHistory *history, gboolean charging); gboolean up_history_set_id (UpHistory *history, const gchar *id); gboolean up_history_set_state (UpHistory *history, UpDeviceState state); gboolean up_history_set_charge_data (UpHistory *history, gdouble percentage); gboolean up_history_set_rate_data (UpHistory *history, gdouble rate); gboolean up_history_set_time_full_data (UpHistory *history, gint64 time); gboolean up_history_set_time_empty_data (UpHistory *history, gint64 time); void up_history_set_max_data_age (UpHistory *history, guint max_data_age); gboolean up_history_save_data (UpHistory *history); void up_history_set_directory (UpHistory *history, const gchar *dir); G_END_DECLS #endif /* __UP_HISTORY_H */ 07070100000095000081A400000000000000000000000166EA4814000028EE000000000000000000000000000000000000002500000000upower-1.90.6/src/up-kbd-backlight.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * 2010 Alex Murray <murray.alex@gmail.com> * * 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 <glib.h> #include <glib/gi18n.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <dirent.h> #include <errno.h> #include "up-kbd-backlight.h" #include "up-daemon.h" #include "up-types.h" static void up_kbd_backlight_finalize (GObject *object); struct UpKbdBacklightPrivate { gint fd; gint fd_hw_changed; GIOChannel *channel_hw_changed; gint max_brightness; }; G_DEFINE_TYPE_WITH_PRIVATE (UpKbdBacklight, up_kbd_backlight, UP_TYPE_EXPORTED_KBD_BACKLIGHT_SKELETON) /** * up_kbd_backlight_emit_change: **/ static void up_kbd_backlight_emit_change(UpKbdBacklight *kbd_backlight, int value, const char *source) { up_exported_kbd_backlight_emit_brightness_changed (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value); up_exported_kbd_backlight_emit_brightness_changed_with_source (UP_EXPORTED_KBD_BACKLIGHT (kbd_backlight), value, source); } /** * up_kbd_backlight_brightness_read: **/ static gint up_kbd_backlight_brightness_read (UpKbdBacklight *kbd_backlight, int fd) { gchar buf[16]; gchar *end = NULL; ssize_t len; gint64 brightness = -1; g_return_val_if_fail (fd >= 0, brightness); lseek (fd, 0, SEEK_SET); len = read (fd, buf, G_N_ELEMENTS (buf) - 1); if (len > 0) { buf[len] = '\0'; brightness = g_ascii_strtoll (buf, &end, 10); if (brightness < 0 || brightness > kbd_backlight->priv->max_brightness || end == buf) { brightness = -1; g_warning ("failed to convert brightness: %s", buf); } } return brightness; } /** * up_kbd_backlight_brightness_write: **/ static gboolean up_kbd_backlight_brightness_write (UpKbdBacklight *kbd_backlight, gint value) { gchar *text = NULL; gint retval; gint length; gboolean ret = TRUE; /* write new values to backlight */ if (kbd_backlight->priv->fd < 0) { g_warning ("cannot write to kbd_backlight as file not open"); ret = FALSE; goto out; } /* limit to between 0 and max */ value = CLAMP (value, 0, kbd_backlight->priv->max_brightness); /* convert to text */ text = g_strdup_printf ("%i", value); length = strlen (text); /* write to file */ lseek (kbd_backlight->priv->fd, 0, SEEK_SET); retval = write (kbd_backlight->priv->fd, text, length); if (retval != length) { g_warning ("writing '%s' to device failed", text); ret = FALSE; goto out; } /* emit signal */ up_kbd_backlight_emit_change (kbd_backlight, value, "external"); out: g_free (text); return ret; } /** * up_kbd_backlight_get_brightness: * * Gets the current brightness **/ static gboolean up_kbd_backlight_get_brightness (UpExportedKbdBacklight *skeleton, GDBusMethodInvocation *invocation, UpKbdBacklight *kbd_backlight) { gint brightness; brightness = up_kbd_backlight_brightness_read (kbd_backlight, kbd_backlight->priv->fd); if (brightness >= 0) { up_exported_kbd_backlight_complete_get_brightness (skeleton, invocation, brightness); } else { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "error reading brightness"); } return TRUE; } /** * up_kbd_backlight_get_max_brightness: * * Gets the max brightness **/ static gboolean up_kbd_backlight_get_max_brightness (UpExportedKbdBacklight *skeleton, GDBusMethodInvocation *invocation, UpKbdBacklight *kbd_backlight) { up_exported_kbd_backlight_complete_get_max_brightness (skeleton, invocation, kbd_backlight->priv->max_brightness); return TRUE; } /** * up_kbd_backlight_set_brightness: **/ static gboolean up_kbd_backlight_set_brightness (UpExportedKbdBacklight *skeleton, GDBusMethodInvocation *invocation, gint value, UpKbdBacklight *kbd_backlight) { gboolean ret = FALSE; g_debug ("setting brightness to %i", value); ret = up_kbd_backlight_brightness_write (kbd_backlight, value); if (ret) { up_exported_kbd_backlight_complete_set_brightness (skeleton, invocation); } else { g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "error writing brightness %d", value); } return TRUE; } /** * up_kbd_backlight_class_init: **/ static void up_kbd_backlight_class_init (UpKbdBacklightClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_kbd_backlight_finalize; } /** * up_kbd_backlight_event_io: **/ static gboolean up_kbd_backlight_event_io (GIOChannel *channel, GIOCondition condition, gpointer data) { UpKbdBacklight *kbd_backlight = (UpKbdBacklight*) data; gint brightness; if (!(condition & G_IO_PRI)) return FALSE; brightness = up_kbd_backlight_brightness_read (kbd_backlight, kbd_backlight->priv->fd_hw_changed); if (brightness < 0 && errno == ENODEV) return FALSE; if (brightness >= 0) up_kbd_backlight_emit_change (kbd_backlight, brightness, "internal"); return TRUE; } /** * up_kbd_backlight_find: **/ static gboolean up_kbd_backlight_find (UpKbdBacklight *kbd_backlight) { gboolean ret; gboolean found = FALSE; GDir *dir; const gchar *filename; gchar *end = NULL; gchar *dir_path = NULL; gchar *path_max = NULL; gchar *path_now = NULL; gchar *path_hw_changed = NULL; gchar *buf_max = NULL; gchar *buf_now = NULL; GError *error = NULL; kbd_backlight->priv->fd = -1; /* open directory */ dir = g_dir_open ("/sys/class/leds", 0, &error); if (dir == NULL) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) g_warning ("failed to open directory: %s", error->message); g_error_free (error); goto out; } /* find a led device that is a keyboard device */ while ((filename = g_dir_read_name (dir)) != NULL) { if (g_strstr_len (filename, -1, "kbd_backlight") != NULL) { dir_path = g_build_filename ("/sys/class/leds", filename, NULL); break; } } /* nothing found */ if (dir_path == NULL) goto out; /* read max brightness */ path_max = g_build_filename (dir_path, "max_brightness", NULL); ret = g_file_get_contents (path_max, &buf_max, NULL, &error); if (!ret) { g_warning ("failed to get max brightness: %s", error->message); g_error_free (error); goto out; } kbd_backlight->priv->max_brightness = g_ascii_strtoull (buf_max, &end, 10); if (kbd_backlight->priv->max_brightness == 0 && end == buf_max) { g_warning ("failed to convert max brightness: %s", buf_max); goto out; } /* open the brightness file for read and write operations */ path_now = g_build_filename (dir_path, "brightness", NULL); kbd_backlight->priv->fd = open (path_now, O_RDWR); /* read brightness and check if it has an acceptable value */ if (up_kbd_backlight_brightness_read (kbd_backlight, kbd_backlight->priv->fd) < 0) goto out; path_hw_changed = g_build_filename (dir_path, "brightness_hw_changed", NULL); kbd_backlight->priv->fd_hw_changed = open (path_hw_changed, O_RDONLY); if (kbd_backlight->priv->fd_hw_changed >= 0) { kbd_backlight->priv->channel_hw_changed = g_io_channel_unix_new (kbd_backlight->priv->fd_hw_changed); g_io_add_watch (kbd_backlight->priv->channel_hw_changed, G_IO_PRI, up_kbd_backlight_event_io, kbd_backlight); } /* success */ found = TRUE; out: if (dir != NULL) g_dir_close (dir); g_free (dir_path); g_free (path_max); g_free (path_now); g_free (path_hw_changed); g_free (buf_max); g_free (buf_now); return found; } /** * up_kbd_backlight_init: **/ static void up_kbd_backlight_init (UpKbdBacklight *kbd_backlight) { kbd_backlight->priv = up_kbd_backlight_get_instance_private (kbd_backlight); g_signal_connect (kbd_backlight, "handle-get-brightness", G_CALLBACK (up_kbd_backlight_get_brightness), kbd_backlight); g_signal_connect (kbd_backlight, "handle-get-max-brightness", G_CALLBACK (up_kbd_backlight_get_max_brightness), kbd_backlight); g_signal_connect (kbd_backlight, "handle-set-brightness", G_CALLBACK (up_kbd_backlight_set_brightness), kbd_backlight); } /** * up_kbd_backlight_finalize: **/ static void up_kbd_backlight_finalize (GObject *object) { UpKbdBacklight *kbd_backlight; g_return_if_fail (object != NULL); g_return_if_fail (UP_IS_KBD_BACKLIGHT (object)); kbd_backlight = UP_KBD_BACKLIGHT (object); kbd_backlight->priv = up_kbd_backlight_get_instance_private (kbd_backlight); if (kbd_backlight->priv->channel_hw_changed) { g_io_channel_shutdown (kbd_backlight->priv->channel_hw_changed, FALSE, NULL); g_io_channel_unref (kbd_backlight->priv->channel_hw_changed); } if (kbd_backlight->priv->fd_hw_changed >= 0) close (kbd_backlight->priv->fd_hw_changed); /* close file */ if (kbd_backlight->priv->fd >= 0) close (kbd_backlight->priv->fd); G_OBJECT_CLASS (up_kbd_backlight_parent_class)->finalize (object); } /** * up_kbd_backlight_new: **/ UpKbdBacklight * up_kbd_backlight_new (void) { return g_object_new (UP_TYPE_KBD_BACKLIGHT, NULL); } void up_kbd_backlight_register (UpKbdBacklight *kbd_backlight, GDBusConnection *connection) { GError *error = NULL; /* find a kbd backlight in sysfs */ if (!up_kbd_backlight_find (kbd_backlight)) { g_debug ("cannot find a keyboard backlight"); return; } g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (kbd_backlight), connection, "/org/freedesktop/UPower/KbdBacklight", &error); if (error != NULL) { g_warning ("Cannot export KbdBacklight object to bus: %s", error->message); g_error_free (error); } } 07070100000096000081A400000000000000000000000166EA481400000880000000000000000000000000000000000000002500000000upower-1.90.6/src/up-kbd-backlight.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * 2010 Alex Murray <murray.alex@gmail.com> * * 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 __UP_KBD_BACKLIGHT_H #define __UP_KBD_BACKLIGHT_H #include <dbus/up-kbd-backlight-generated.h> G_BEGIN_DECLS #define UP_TYPE_KBD_BACKLIGHT (up_kbd_backlight_get_type ()) #define UP_KBD_BACKLIGHT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklight)) #define UP_KBD_BACKLIGHT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklightClass)) #define UP_IS_KBD_BACKLIGHT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_KBD_BACKLIGHT)) #define UP_IS_KBD_BACKLIGHT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_KBD_BACKLIGHT)) #define UP_KBD_BACKLIGHT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_KBD_BACKLIGHT, UpKbdBacklightClass)) typedef struct UpKbdBacklightPrivate UpKbdBacklightPrivate; typedef struct { UpExportedKbdBacklightSkeleton parent; UpKbdBacklightPrivate *priv; } UpKbdBacklight; typedef struct { UpExportedKbdBacklightSkeletonClass parent_class; } UpKbdBacklightClass; UpKbdBacklight *up_kbd_backlight_new (void); GType up_kbd_backlight_get_type (void); void up_kbd_backlight_register (UpKbdBacklight *kbd_backlight, GDBusConnection *connection); G_END_DECLS #endif /* __UP_KBD_BACKLIGHT_H */ 07070100000097000081A400000000000000000000000166EA481400001D44000000000000000000000000000000000000001C00000000upower-1.90.6/src/up-main.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> * * 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 <string.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> #include <gio/gio.h> #include <glib.h> #include <glib-unix.h> #include <glib/gi18n-lib.h> #include <glib-object.h> #include <locale.h> #include "up-daemon.h" #include "up-kbd-backlight.h" #define DEVKIT_POWER_SERVICE_NAME "org.freedesktop.UPower" typedef struct UpState { UpKbdBacklight *kbd_backlight; UpDaemon *daemon; GMainLoop *loop; } UpState; static void up_state_free (UpState *state) { up_daemon_shutdown (state->daemon); g_clear_object (&state->kbd_backlight); g_clear_object (&state->daemon); g_clear_pointer (&state->loop, g_main_loop_unref); g_free (state); } static UpState * up_state_new (void) { UpState *state = g_new0 (UpState, 1); state->kbd_backlight = up_kbd_backlight_new (); state->daemon = up_daemon_new (); state->loop = g_main_loop_new (NULL, FALSE); return state; } /** * up_main_bus_acquired: **/ static void up_main_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { UpState *state = user_data; up_kbd_backlight_register (state->kbd_backlight, connection); if (!up_daemon_startup (state->daemon, connection)) { g_warning ("Could not startup; bailing out"); g_main_loop_quit (state->loop); } } /** * up_main_name_lost: **/ static void up_main_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { UpState *state = user_data; g_debug ("name lost, exiting"); g_main_loop_quit (state->loop); } /** * up_main_sigint_cb: **/ static gboolean up_main_sigint_cb (gpointer user_data) { UpState *state = user_data; g_debug ("Handling SIGINT"); g_main_loop_quit (state->loop); return FALSE; } static gboolean up_main_sigterm_cb (gpointer user_data) { UpState *state = user_data; g_debug ("Handling SIGTERM"); g_main_loop_quit (state->loop); return FALSE; } /** * up_main_timed_exit_cb: * * Exits the main loop, which is helpful for valgrinding. **/ static gboolean up_main_timed_exit_cb (UpState *state) { g_main_loop_quit (state->loop); return FALSE; } /** * up_main_log_ignore_cb: **/ static void up_main_log_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { } /** * up_main_log_handler_cb: **/ static void up_main_log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { gchar str_time[255]; time_t the_time; /* header always in green */ time (&the_time); strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); g_print ("%c[%dmTI:%s\t", 0x1B, 32, str_time); /* critical is also in red */ if (log_level == G_LOG_LEVEL_CRITICAL || log_level == G_LOG_LEVEL_WARNING || log_level == G_LOG_LEVEL_ERROR) { g_print ("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0); } else { /* debug in blue */ g_print ("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0); } } /** * main: **/ gint main (gint argc, gchar **argv) { GError *error = NULL; GOptionContext *context; gboolean timed_exit = FALSE; gboolean immediate_exit = FALSE; guint timer_id = 0; gboolean debug = FALSE; gboolean verbose = FALSE; UpState *state; GBusNameOwnerFlags bus_flags; gboolean replace = FALSE; const GOptionEntry options[] = { { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit, /* TRANSLATORS: exit after we've started up, used for user profiling */ _("Exit after a small delay"), NULL }, { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit, /* TRANSLATORS: exit straight away, used for automatic profiling */ _("Exit after the engine has loaded"), NULL }, { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, _("Replace the old daemon"), NULL}, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, _("Show extra debugging information"), NULL }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, _("Enable debugging (implies --verbose)"), NULL }, { NULL} }; #if !defined(GLIB_VERSION_2_36) g_type_init (); #endif setlocale(LC_ALL, ""); context = g_option_context_new ("upower daemon"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_warning ("Failed to parse command-line options: %s", error->message); g_error_free (error); return 1; } g_option_context_free (context); if (debug) verbose = TRUE; /* verbose? */ if (verbose) { g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_WARNING, up_main_log_handler_cb, NULL); g_log_set_handler ("UPower-Linux", G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_WARNING, up_main_log_handler_cb, NULL); } else { /* hide all debugging */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR); g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, up_main_log_ignore_cb, NULL); g_log_set_handler ("UPower-Linux", G_LOG_LEVEL_DEBUG, up_main_log_ignore_cb, NULL); } /* initialize state */ state = up_state_new (); up_daemon_set_debug (state->daemon, debug); /* do stuff on ctrl-c */ g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGINT, up_main_sigint_cb, state, NULL); /* Clean shutdown on SIGTERM */ g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGTERM, up_main_sigterm_cb, state, NULL); /* acquire name */ bus_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT; if (replace) bus_flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE; g_bus_own_name (G_BUS_TYPE_SYSTEM, DEVKIT_POWER_SERVICE_NAME, bus_flags, up_main_bus_acquired, NULL, up_main_name_lost, state, NULL); g_debug ("Starting upowerd version %s", PACKAGE_VERSION); /* only timeout and close the mainloop if we have specified it on the command line */ if (timed_exit) { timer_id = g_timeout_add_seconds (30, (GSourceFunc) up_main_timed_exit_cb, state); g_source_set_name_by_id (timer_id, "[upower] up_main_timed_exit_cb"); } /* immediatly exit */ if (immediate_exit) { g_timeout_add (50, (GSourceFunc) up_main_timed_exit_cb, state); g_source_set_name_by_id (timer_id, "[upower] up_main_timed_exit_cb"); } /* wait for input or timeout */ g_main_loop_run (state->loop); up_state_free (state); return 0; } 07070100000098000081A400000000000000000000000166EA48140000041C000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-native.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UP_NATIVE_H__ #define __UP_NATIVE_H__ #include <glib-object.h> G_BEGIN_DECLS const gchar *up_native_get_native_path (GObject *object); G_END_DECLS #endif /* __UP_NATIVE_H__ */ 07070100000099000081A400000000000000000000000166EA481400001526000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-polkit.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 <config.h> #endif #include <glib.h> #ifdef HAVE_POLKIT #include <polkit/polkit.h> #endif #include "up-polkit.h" #include "up-daemon.h" #define UP_POLKIT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_POLKIT, UpPolkitPrivate)) struct UpPolkitPrivate { GDBusConnection *connection; #ifdef HAVE_POLKIT PolkitAuthority *authority; #endif }; G_DEFINE_TYPE_WITH_PRIVATE (UpPolkit, up_polkit, G_TYPE_OBJECT) #ifdef HAVE_POLKIT /** * up_polkit_get_subject: **/ PolkitSubject * up_polkit_get_subject (UpPolkit *polkit, GDBusMethodInvocation *invocation) { g_autoptr (GError) error = NULL; const gchar *sender; g_autoptr (PolkitSubject) subject = NULL; sender = g_dbus_method_invocation_get_sender (invocation); subject = polkit_system_bus_name_new (sender); if (subject == NULL) { error = g_error_new (UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "failed to get PolicyKit subject"); g_dbus_method_invocation_return_error (invocation, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "failed to get Polkit subject: %s", error->message); } return g_steal_pointer (&subject); } /** * up_polkit_check_auth: **/ gboolean up_polkit_check_auth (UpPolkit *polkit, PolkitSubject *subject, const gchar *action_id, GDBusMethodInvocation *invocation) { g_autoptr (GError) error = NULL; g_autoptr (GError) error_local = NULL; g_autoptr (PolkitAuthorizationResult) result = NULL; /* check auth */ result = polkit_authority_check_authorization_sync (polkit->priv->authority, subject, action_id, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, &error_local); if (result == NULL) { error = g_error_new (UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "failed to check authorisation: %s", error_local->message); g_dbus_method_invocation_return_gerror (invocation, error); return FALSE; } /* okay? */ if (polkit_authorization_result_get_is_authorized (result)) { return TRUE; } else { error = g_error_new (UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "not authorized"); g_dbus_method_invocation_return_gerror (invocation, error); } return FALSE; } /** * up_polkit_is_allowed: **/ gboolean up_polkit_is_allowed (UpPolkit *polkit, PolkitSubject *subject, const gchar *action_id, GError **error) { gboolean ret = FALSE; g_autoptr (GError) error_local = NULL; g_autoptr (PolkitAuthorizationResult) result = NULL; /* check auth */ result = polkit_authority_check_authorization_sync (polkit->priv->authority, subject, action_id, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, NULL, &error_local); if (result == NULL) { if (error_local != NULL) g_set_error (error, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "%s", error_local->message); else g_set_error (error, UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL, "failed to check authorization"); return FALSE; } ret = polkit_authorization_result_get_is_authorized (result) || polkit_authorization_result_get_is_challenge (result); return ret; } #endif /** * up_polkit_finalize: **/ static void up_polkit_finalize (GObject *object) { #ifdef HAVE_POLKIT g_autoptr (GError) error = NULL; UpPolkit *polkit; g_return_if_fail (UP_IS_POLKIT (object)); polkit = UP_POLKIT (object); if (polkit->priv->connection != NULL) g_object_unref (polkit->priv->connection); g_object_unref (polkit->priv->authority); #endif G_OBJECT_CLASS (up_polkit_parent_class)->finalize (object); } /** * up_polkit_class_init: **/ static void up_polkit_class_init (UpPolkitClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = up_polkit_finalize; } /** * up_polkit_init: * * initializes the polkit class. NOTE: We expect polkit objects * to *NOT* be removed or added during the session. * We only control the first polkit object if there are more than one. **/ static void up_polkit_init (UpPolkit *polkit) { g_autoptr (GError) error = NULL; polkit->priv = up_polkit_get_instance_private (polkit); #ifdef HAVE_POLKIT polkit->priv->authority = polkit_authority_get_sync (NULL, &error); if (polkit->priv->authority == NULL) g_error ("failed to get polkit authority: %s", error->message); #endif } /** * up_polkit_new: * Return value: A new polkit class instance. **/ UpPolkit * up_polkit_new (void) { return UP_POLKIT (g_object_new (UP_TYPE_POLKIT, NULL)); } 0707010000009A000081A400000000000000000000000166EA4814000008E0000000000000000000000000000000000000001E00000000upower-1.90.6/src/up-polkit.h/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 __UP_POLKIT_H #define __UP_POLKIT_H #include "config.h" #include <glib-object.h> #ifdef HAVE_POLKIT #include <polkit/polkit.h> #endif G_BEGIN_DECLS #define UP_TYPE_POLKIT (up_polkit_get_type ()) #define UP_POLKIT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_POLKIT, UpPolkit)) #define UP_POLKIT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_POLKIT, UpPolkitClass)) #define UP_IS_POLKIT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_POLKIT)) #define UP_IS_POLKIT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_POLKIT)) #define UP_POLKIT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_POLKIT, UpPolkitClass)) typedef struct UpPolkitPrivate UpPolkitPrivate; typedef struct { GObject parent; UpPolkitPrivate *priv; } UpPolkit; typedef struct { GObjectClass parent_class; } UpPolkitClass; GType up_polkit_get_type (void); UpPolkit *up_polkit_new (void); #ifdef HAVE_POLKIT PolkitSubject *up_polkit_get_subject (UpPolkit *polkit, GDBusMethodInvocation *context); gboolean up_polkit_check_auth (UpPolkit *polkit, PolkitSubject *subject, const gchar *action_id, GDBusMethodInvocation *context); gboolean up_polkit_is_allowed (UpPolkit *polkit, PolkitSubject *subject, const gchar *action_id, GError **error); #endif G_END_DECLS #endif /* __UP_POLKIT_H */ 0707010000009B000081A400000000000000000000000166EA48140000239D000000000000000000000000000000000000002100000000upower-1.90.6/src/up-self-test.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2009 Richard Hughes <richard@hughsie.com> * * 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 <glib-object.h> #include <glib/gstdio.h> #include <up-history-item.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include "up-backend.h" #include "up-daemon.h" #include "up-device.h" #include "up-device-list.h" #include "up-history.h" #include "up-native.h" #include "up-polkit.h" gchar *history_dir = NULL; #define DBUS_SYSTEM_SOCKET "/var/run/dbus/system_bus_socket" static void up_test_native_func (void) { const gchar *path; path = up_native_get_native_path (NULL); g_assert_cmpstr (path, ==, "/sys/dummy"); } static void up_test_backend_func (void) { UpBackend *backend; backend = up_backend_new (); g_assert (backend != NULL); /* unref */ g_object_unref (backend); } static void up_test_daemon_func (void) { UpDaemon *daemon; /* needs polkit, which only listens to the system bus */ if (!g_file_test (DBUS_SYSTEM_SOCKET, G_FILE_TEST_EXISTS)) { puts("No system D-BUS running, skipping test"); return; } daemon = up_daemon_new (); g_assert (daemon != NULL); /* unref */ g_object_unref (daemon); } static void up_test_device_func (void) { UpDevice *device; device = up_device_new (NULL, NULL); g_assert (device != NULL); /* unref */ g_object_unref (device); } static void up_test_device_list_func (void) { UpDeviceList *list; GObject *native; UpDevice *device; GObject *found; gboolean ret; list = up_device_list_new (); g_assert (list != NULL); /* add device */ native = g_object_new (G_TYPE_OBJECT, NULL); device = up_device_new (NULL, native); ret = up_device_list_insert (list, device); g_assert (ret); /* find device */ found = up_device_list_lookup (list, native); g_assert (found != NULL); g_object_unref (found); /* remove device */ ret = up_device_list_remove (list, device); g_assert (ret); /* unref */ g_object_unref (native); g_object_unref (device); g_object_unref (list); } static void up_test_history_remove_temp_files (void) { gchar *filename; filename = g_build_filename (history_dir, "history-time-full-test.dat", NULL); g_unlink (filename); g_free (filename); filename = g_build_filename (history_dir, "history-time-empty-test.dat", NULL); g_unlink (filename); g_free (filename); filename = g_build_filename (history_dir, "history-charge-test.dat", NULL); g_unlink (filename); g_free (filename); filename = g_build_filename (history_dir, "history-rate-test.dat", NULL); g_unlink (filename); g_free (filename); } static void up_test_history_func (void) { UpHistory *history; gboolean ret; GPtrArray *array; gchar *filename; UpHistoryItem *item, *item2, *item3; history = up_history_new (); g_assert (history != NULL); /* set a temporary directory for the history */ history_dir = g_build_filename (g_get_tmp_dir(), "upower-test.XXXXXX", NULL); if (mkdtemp (history_dir) == NULL) g_error ("Cannot create temporary directory: %s", g_strerror(errno)); up_history_set_directory (history, history_dir); /* remove previous test files */ up_test_history_remove_temp_files (); /* setup fresh environment */ ret = up_history_set_id (history, "test"); g_assert (ret); /* get nonexistant data */ array = up_history_get_data (history, UP_HISTORY_TYPE_CHARGE, 10, 100); g_assert (array != NULL); g_assert_cmpint (array->len, ==, 0); g_ptr_array_unref (array); /* setup some fake device and three data points */ up_history_set_state (history, UP_DEVICE_STATE_CHARGING); up_history_set_charge_data (history, 85); up_history_set_rate_data (history, 0.99f); up_history_set_time_empty_data (history, 12346); up_history_set_time_full_data (history, 54322); g_usleep (2 * G_USEC_PER_SEC); up_history_set_charge_data (history, 90); up_history_set_rate_data (history, 1.00f); up_history_set_time_empty_data (history, 12345); up_history_set_time_full_data (history, 54321); g_usleep (2 * G_USEC_PER_SEC); up_history_set_charge_data (history, 95); up_history_set_rate_data (history, 1.01f); up_history_set_time_empty_data (history, 12344); up_history_set_time_full_data (history, 54320); /* get data for last 10 seconds */ array = up_history_get_data (history, UP_HISTORY_TYPE_CHARGE, 10, 100); g_assert (array != NULL); g_assert_cmpint (array->len, ==, 3); /* get the first item, which should be the most recent */ item = g_ptr_array_index (array, 0); g_assert (item != NULL); g_assert_cmpint (up_history_item_get_value (item), ==, 95); g_assert_cmpint (up_history_item_get_time (item), >, 1000000); /* the second one ought to be older */ item2 = g_ptr_array_index (array, 1); g_assert (item2 != NULL); g_assert_cmpint (up_history_item_get_value (item2), ==, 90); g_assert_cmpint (up_history_item_get_time (item2), <, up_history_item_get_time (item)); /* third one is the oldest */ item3 = g_ptr_array_index (array, 2); g_assert (item3 != NULL); g_assert_cmpint (up_history_item_get_value (item3), ==, 85); g_assert_cmpint (up_history_item_get_time (item3), <, up_history_item_get_time (item2)); g_ptr_array_unref (array); /* request fewer items than we have in our history; should have the * same order: first one is the most recent, and the data gets * interpolated */ array = up_history_get_data (history, UP_HISTORY_TYPE_CHARGE, 10, 2); g_assert (array != NULL); g_assert_cmpint (array->len, ==, 2); item = g_ptr_array_index (array, 0); g_assert (item != NULL); item2 = g_ptr_array_index (array, 1); g_assert (item2 != NULL); g_assert_cmpint (up_history_item_get_time (item), >, 1000000); g_assert_cmpint (up_history_item_get_value (item), ==, 95); g_assert_cmpint (up_history_item_get_value (item2), ==, 87); g_ptr_array_unref (array); /* force a save to disk */ ret = up_history_save_data (history); g_assert (ret); g_object_unref (history); /* ensure the file was created */ filename = g_build_filename (history_dir, "history-charge-test.dat", NULL); g_assert (g_file_test (filename, G_FILE_TEST_EXISTS)); g_free (filename); /* ensure we can load from disk */ history = up_history_new (); up_history_set_directory (history, history_dir); up_history_set_id (history, "test"); /* get data for last 10 seconds */ array = up_history_get_data (history, UP_HISTORY_TYPE_CHARGE, 10, 100); g_assert (array != NULL); g_assert_cmpint (array->len, ==, 4); /* we have inserted an unknown as the first entry */ item = g_ptr_array_index (array, 1); g_assert (item != NULL); g_assert_cmpint (up_history_item_get_value (item), ==, 95); g_assert_cmpint (up_history_item_get_time (item), >, 1000000); g_ptr_array_unref (array); /* ensure old entries are purged */ up_history_set_max_data_age (history, 2); g_usleep (1100 * G_USEC_PER_SEC / 1000); g_object_unref (history); /* ensure only 2 points are returned */ history = up_history_new (); up_history_set_directory (history, history_dir); up_history_set_id (history, "test"); array = up_history_get_data (history, UP_HISTORY_TYPE_CHARGE, 10, 100); g_assert (array != NULL); g_assert_cmpint (array->len, ==, 2); g_ptr_array_unref (array); /* unref */ g_object_unref (history); /* remove these test files */ up_test_history_remove_temp_files (); rmdir (history_dir); } static void up_test_polkit_func (void) { UpPolkit *polkit; /* polkit only listens to the system bus */ if (!g_file_test (DBUS_SYSTEM_SOCKET, G_FILE_TEST_EXISTS)) { puts("No system D-BUS running, skipping test"); return; } polkit = up_polkit_new (); g_assert (polkit != NULL); /* unref */ g_object_unref (polkit); } int main (int argc, char **argv) { #if !defined(GLIB_VERSION_2_36) g_type_init (); #endif g_test_init (&argc, &argv, NULL); g_setenv ("UPOWER_CONF_FILE_NAME", UPOWER_CONF_PATH, TRUE); /* tests go here */ g_test_add_func ("/power/backend", up_test_backend_func); g_test_add_func ("/power/device", up_test_device_func); g_test_add_func ("/power/device_list", up_test_device_list_func); g_test_add_func ("/power/history", up_test_history_func); g_test_add_func ("/power/native", up_test_native_func); g_test_add_func ("/power/polkit", up_test_polkit_func); g_test_add_func ("/power/daemon", up_test_daemon_func); return g_test_run (); } 0707010000009C000081A400000000000000000000000166EA481400000041000000000000000000000000000000000000002D00000000upower-1.90.6/src/upower-integration.test.in[Test] Type=session Exec=@libexecdir@/upower/integration-test.py 0707010000009D000081A400000000000000000000000166EA4814000003DF000000000000000000000000000000000000002400000000upower-1.90.6/src/upower.service.in[Unit] Description=Daemon for power management Documentation=man:upowerd(8) [Service] Type=dbus BusName=org.freedesktop.UPower ExecStart=@libexecdir@/upowerd Restart=on-failure # Filesystem lockdown ProtectSystem=strict # Needed by keyboard backlight support ProtectKernelTunables=false ProtectControlGroups=true ReadWritePaths=@historydir@ StateDirectory=upower ProtectHome=true PrivateTmp=true # Network # PrivateNetwork=true would block udev's netlink socket IPAddressDeny=any RestrictAddressFamilies=AF_UNIX AF_NETLINK # Execute Mappings MemoryDenyWriteExecute=true # Modules ProtectKernelModules=true # Real-time RestrictRealtime=true # Privilege escalation NoNewPrivileges=true # Capabilities CapabilityBoundingSet= # System call interfaces LockPersonality=yes SystemCallArchitectures=native SystemCallFilter=@system-service SystemCallFilter=ioprio_get # Namespaces PrivateUsers=yes RestrictNamespaces=yes # Locked memory LimitMEMLOCK=0 [Install] WantedBy=graphical.target 0707010000009E000041ED00000000000000000000000266EA481400000000000000000000000000000000000000000000001400000000upower-1.90.6/tools0707010000009F000081A400000000000000000000000166EA48140000010D000000000000000000000000000000000000002000000000upower-1.90.6/tools/meson.buildexecutable('upower', sources: [ 'up-tool.c', ], dependencies: [ libupower_glib_dep ], gnu_symbol_visibility: 'hidden', install: true, install_dir: get_option('prefix') / get_option('bindir'), c_args: [ '-DG_LOG_DOMAIN="UPower"' ], ) 070701000000A0000081A400000000000000000000000166EA481400002064000000000000000000000000000000000000001E00000000upower-1.90.6/tools/up-tool.c/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen <davidz@redhat.com> * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/time.h> #include <glib.h> #include <glib/gi18n-lib.h> #include <locale.h> #include "upower.h" static GMainLoop *loop; static gboolean opt_monitor_detail = FALSE; /** * up_tool_get_timestamp: **/ static gchar * up_tool_get_timestamp (void) { gchar *str_time; gchar *timestamp; time_t the_time; struct timeval time_val; time (&the_time); gettimeofday (&time_val, NULL); str_time = g_new0 (gchar, 255); strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); /* generate header text */ timestamp = g_strdup_printf ("%s.%03i", str_time, (gint) time_val.tv_usec / 1000); g_free (str_time); return timestamp; } /** * up_tool_device_added_cb: **/ static void up_tool_device_added_cb (UpClient *client, UpDevice *device, gpointer user_data) { gchar *timestamp; gchar *text = NULL; timestamp = up_tool_get_timestamp (); g_print ("[%s]\tdevice added: %s\n", timestamp, up_device_get_object_path (device)); if (opt_monitor_detail) { text = up_device_to_text (device); g_print ("%s\n", text); } g_free (timestamp); g_free (text); } /** * up_tool_device_changed_cb: **/ static void up_tool_device_changed_cb (UpDevice *device, GParamSpec *pspec, gpointer user_data) { gchar *timestamp; gchar *text = NULL; timestamp = up_tool_get_timestamp (); g_print ("[%s]\tdevice changed: %s\n", timestamp, up_device_get_object_path (device)); if (opt_monitor_detail) { /* TODO: would be nice to just show the diff */ text = up_device_to_text (device); g_print ("%s\n", text); } g_free (timestamp); g_free (text); } /** * up_tool_device_removed_cb: **/ static void up_tool_device_removed_cb (UpClient *client, const char *object_path, gpointer user_data) { gchar *timestamp; timestamp = up_tool_get_timestamp (); g_print ("[%s]\tdevice removed: %s\n", timestamp, object_path); if (opt_monitor_detail) g_print ("\n"); g_free (timestamp); } /** * up_client_print: **/ static void up_client_print (UpClient *client) { gchar *daemon_version; gboolean on_battery; gboolean lid_is_closed; gboolean lid_is_present; char *action; g_object_get (client, "daemon-version", &daemon_version, "on-battery", &on_battery, "lid-is-closed", &lid_is_closed, "lid-is-present", &lid_is_present, NULL); g_print (" daemon-version: %s\n", daemon_version); g_print (" on-battery: %s\n", on_battery ? "yes" : "no"); g_print (" lid-is-closed: %s\n", lid_is_closed ? "yes" : "no"); g_print (" lid-is-present: %s\n", lid_is_present ? "yes" : "no"); action = up_client_get_critical_action (client); g_print (" critical-action: %s\n", action); g_free (action); g_free (daemon_version); } /** * up_tool_changed_cb: **/ static void up_tool_changed_cb (UpClient *client, GParamSpec *pspec, gpointer user_data) { gchar *timestamp; timestamp = up_tool_get_timestamp (); g_print ("[%s]\tdaemon changed:\n", timestamp); if (opt_monitor_detail) { up_client_print (client); g_print ("\n"); } g_free (timestamp); } /** * up_tool_do_monitor: **/ static gboolean up_tool_do_monitor (UpClient *client) { GPtrArray *devices; guint i; g_print ("Monitoring activity from the power daemon. Press Ctrl+C to cancel.\n"); g_signal_connect (client, "device-added", G_CALLBACK (up_tool_device_added_cb), NULL); g_signal_connect (client, "device-removed", G_CALLBACK (up_tool_device_removed_cb), NULL); g_signal_connect (client, "notify", G_CALLBACK (up_tool_changed_cb), NULL); devices = up_client_get_devices2 (client); for (i=0; i < devices->len; i++) { UpDevice *device; device = g_ptr_array_index (devices, i); g_signal_connect (device, "notify", G_CALLBACK (up_tool_device_changed_cb), NULL); } g_main_loop_run (loop); return FALSE; } /** * main: **/ int main (int argc, char **argv) { gint retval = EXIT_FAILURE; guint i; GOptionContext *context; gboolean opt_dump = FALSE; gboolean opt_enumerate = FALSE; gboolean opt_monitor = FALSE; gchar *opt_show_info = FALSE; gboolean opt_version = FALSE; gboolean ret; GError *error = NULL; gchar *text = NULL; UpClient *client; UpDevice *device; const GOptionEntry entries[] = { { "enumerate", 'e', 0, G_OPTION_ARG_NONE, &opt_enumerate, _("Enumerate objects paths for devices"), NULL }, { "dump", 'd', 0, G_OPTION_ARG_NONE, &opt_dump, _("Dump all parameters for all objects"), NULL }, { "monitor", 'm', 0, G_OPTION_ARG_NONE, &opt_monitor, _("Monitor activity from the power daemon"), NULL }, { "monitor-detail", 0, 0, G_OPTION_ARG_NONE, &opt_monitor_detail, _("Monitor with detail"), NULL }, { "show-info", 'i', 0, G_OPTION_ARG_STRING, &opt_show_info, _("Show information about object path"), NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, &opt_version, "Print version of client and daemon", NULL }, { NULL } }; #if !defined(GLIB_VERSION_2_36) g_type_init (); #endif setlocale(LC_ALL, ""); context = g_option_context_new ("UPower tool"); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); loop = g_main_loop_new (NULL, FALSE); client = up_client_new_full (NULL, &error); if (client == NULL) { g_warning ("Cannot connect to upowerd: %s", error->message); g_error_free (error); return EXIT_FAILURE; } if (opt_version) { gchar *daemon_version; g_object_get (client, "daemon-version", &daemon_version, NULL); g_print ("UPower client version %s\n" "UPower daemon version %s\n", PACKAGE_VERSION, daemon_version); g_free (daemon_version); retval = 0; goto out; } if (opt_enumerate || opt_dump) { GPtrArray *devices; devices = up_client_get_devices2 (client); if (!devices) { g_print ("Failed to get device list\n"); goto out; } for (i=0; i < devices->len; i++) { device = (UpDevice*) g_ptr_array_index (devices, i); if (opt_enumerate) { g_print ("%s\n", up_device_get_object_path (device)); } else { g_print ("Device: %s\n", up_device_get_object_path (device)); text = up_device_to_text (device); g_print ("%s\n", text); g_free (text); } } g_ptr_array_unref (devices); device = up_client_get_display_device (client); if (!device) { g_print ("Failed to get display device\n"); goto out; } if (opt_enumerate) { g_print ("%s\n", up_device_get_object_path (device)); } else { g_print ("Device: %s\n", up_device_get_object_path (device)); text = up_device_to_text (device); g_print ("%s\n", text); g_free (text); } g_object_unref (device); if (opt_dump) { g_print ("Daemon:\n"); up_client_print (client); } retval = EXIT_SUCCESS; goto out; } if (opt_monitor || opt_monitor_detail) { if (!up_tool_do_monitor (client)) goto out; retval = EXIT_SUCCESS; goto out; } if (opt_show_info != NULL) { device = up_device_new (); ret = up_device_set_object_path_sync (device, opt_show_info, NULL, &error); if (!ret) { g_print ("failed to set path: %s\n", error->message); g_error_free (error); } else { text = up_device_to_text (device); g_print ("%s\n", text); g_free (text); } g_object_unref (device); retval = EXIT_SUCCESS; goto out; } out: g_object_unref (client); return retval; } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!1952 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor