From 37f9df9b0568f9834452c949336783bf34e02ab9 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Thu, 8 May 2008 22:29:38 -0400 Subject: [PATCH] initial commit --- AUTHORS | 1 + COPYING | 353 ++++++++++ HACKING | 93 +++ Makefile.am | 39 ++ NEWS | 2 + README | 2 + acinclude.m4 | 51 ++ autogen.sh | 95 +++ configure.in | 165 +++++ doc/Makefile.am | 81 +++ doc/TODO | 34 + doc/dbus/Makefile.am | 15 + doc/dbus/dbus-introspect-docs.dtd | 32 + doc/dbus/spec-to-docbook.xsl | 543 +++++++++++++++ doc/devkit-power-docs.xml | 94 +++ doc/man/DeviceKit-power.xml | 64 ++ doc/man/Makefile.am | 24 + doc/man/devkit-power-daemon.xml | 84 +++ doc/man/devkit-power.xml | 99 +++ doc/version.xml | 1 + gtk-doc.make | 159 +++++ mkinstalldirs | 111 +++ po/ChangeLog | 0 po/LINGUAS | 4 + po/POTFILES.in | 4 + policy/Makefile.am | 17 + .../org.freedesktop.devicekit.power.policy.in | 32 + src/Makefile.am | 82 +++ src/devkit-power-daemon.c | 631 ++++++++++++++++++ src/devkit-power-daemon.h | 84 +++ src/devkit-power-device.c | 92 +++ src/devkit-power-device.h | 68 ++ src/devkit-power-marshal.list | 2 + src/devkit-power-source.c | 593 ++++++++++++++++ src/devkit-power-source.h | 64 ++ src/main.c | 157 +++++ ...org.freedesktop.DeviceKit.Power.Source.xml | 228 +++++++ src/org.freedesktop.DeviceKit.Power.xml | 77 +++ src/sysfs-utils.c | 203 ++++++ src/sysfs-utils.h | 36 + tools/Makefile.am | 49 ++ tools/devkit-power.c | 376 +++++++++++ 42 files changed, 4941 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 HACKING create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100755 autogen.sh create mode 100644 configure.in create mode 100644 doc/Makefile.am create mode 100644 doc/TODO create mode 100644 doc/dbus/Makefile.am create mode 100644 doc/dbus/dbus-introspect-docs.dtd create mode 100644 doc/dbus/spec-to-docbook.xsl create mode 100644 doc/devkit-power-docs.xml create mode 100644 doc/man/DeviceKit-power.xml create mode 100644 doc/man/Makefile.am create mode 100644 doc/man/devkit-power-daemon.xml create mode 100644 doc/man/devkit-power.xml create mode 100644 doc/version.xml create mode 100644 gtk-doc.make create mode 100755 mkinstalldirs create mode 100644 po/ChangeLog create mode 100644 po/LINGUAS create mode 100644 po/POTFILES.in create mode 100644 policy/Makefile.am create mode 100644 policy/org.freedesktop.devicekit.power.policy.in create mode 100644 src/Makefile.am create mode 100644 src/devkit-power-daemon.c create mode 100644 src/devkit-power-daemon.h create mode 100644 src/devkit-power-device.c create mode 100644 src/devkit-power-device.h create mode 100644 src/devkit-power-marshal.list create mode 100644 src/devkit-power-source.c create mode 100644 src/devkit-power-source.h create mode 100644 src/main.c create mode 100644 src/org.freedesktop.DeviceKit.Power.Source.xml create mode 100644 src/org.freedesktop.DeviceKit.Power.xml create mode 100644 src/sysfs-utils.c create mode 100644 src/sysfs-utils.h create mode 100644 tools/Makefile.am create mode 100644 tools/devkit-power.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..c686966 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +David Zeuthen diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..451efcd --- /dev/null +++ b/COPYING @@ -0,0 +1,353 @@ +Copyright (C) 2008 David Zeuthen +All Rights Reserved. + +The DeviceKit-power 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. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin 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. + + , 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 --- + diff --git a/HACKING b/HACKING new file mode 100644 index 0000000..8d32cc0 --- /dev/null +++ b/HACKING @@ -0,0 +1,93 @@ +SCM +=== + + - anonymous checkouts + + $ git clone git://git.freedesktop.org/git/DeviceKit-disks.git + + - checkouts if you got an ssh account on fd.o (username@ is optional) + + $ git clone ssh://[username@]git.freedesktop.org/git/DeviceKit-disks.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 " + +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). diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..34fc235 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = src doc tools policy po + +# Creating ChangeLog from git log (taken from cairo/Makefile.am): +ChangeLog: $(srcdir)/ChangeLog + +$(srcdir)/ChangeLog: + @if test -d "$(srcdir)/.git"; then \ + (cd "$(srcdir)" && \ + ./missing --run git-log --stat) | fmt --split-only > $@.tmp \ + && mv -f $@.tmp $@ \ + || ($(RM) $@.tmp; \ + echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \ + (test -f $@ || echo git-log is required to generate this file >> $@)); \ + else \ + test -f $@ || \ + (echo A git checkout and git-log is required to generate ChangeLog >&2 && \ + echo A git checkout and git-log is required to generate this file >> $@); \ + fi + +EXTRA_DIST = \ + HACKING \ + mkinstalldirs \ + ChangeLog \ + intltool-extract.in \ + intltool-merge.in \ + intltool-update.in + +DISTCLEANFILES = \ + intltool-extract \ + intltool-merge \ + intltool-update + +# xsltproc barfs on 'make distcheck'; disable for now +DISTCHECK_CONFIGURE_FLAGS=--disable-man-pages --disable-gtk-doc + +clean-local : + rm -f *~ diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..1eb76e2 --- /dev/null +++ b/NEWS @@ -0,0 +1,2 @@ +TODO: for now see doc/TODO + diff --git a/README b/README new file mode 100644 index 0000000..6921cea --- /dev/null +++ b/README @@ -0,0 +1,2 @@ + +TODO diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..18fa66a --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,51 @@ +dnl GTK_DOC_CHECK borrowed from cairo, thanks! + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + dnl for overriding the documentation installation directory + AC_ARG_WITH(html-dir, + AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST(HTML_DIR) + + dnl enable/disable documentation building + AC_ARG_ENABLE(gtk-doc, + AC_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [default=yes]]),, + enable_gtk_doc=yes) + + have_gtk_doc=no + if test x$enable_gtk_doc = xyes; then + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then + have_gtk_doc=yes + fi + + dnl do we want to do a version check? +ifelse([$1],[],, + [gtk_doc_min_version=$1 + if test "$have_gtk_doc" = yes; then + AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) + if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + have_gtk_doc=no + fi + fi +]) + if test "$have_gtk_doc" != yes; then + enable_gtk_doc=no + fi + fi + + AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) + AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") +]) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..05b1526 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +DIE=0 + +(test -f $srcdir/configure.in) || { + echo -n "**Error**: Directory $srcdir does not look like the" + echo " top-level package directory" + exit 1 +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have autoconf installed." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { + (libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have libtool installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have automake installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing aclocal. The version of automake" + echo "installed doesn't appear recent enough." + echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "**Warning**: I am going to run configure with no arguments." + echo "If you wish to pass any to it, please specify them on the" + echo $0 " command line." + echo +fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + + aclocalinclude="$ACLOCAL_FLAGS" + + if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then + if test -z "$NO_LIBTOOLIZE" ; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu -Wno-portability $am_opt ..." + automake --add-missing --gnu -Wno-portability $am_opt + echo "Running autoconf ..." + autoconf + +intltoolize --copy --force --automake || exit 1 + +conf_flags="--enable-maintainer-mode --enable-gtk-doc" + +if test x$NOCONFIGURE = x; then + echo "Running $srcdir/configure $conf_flags $@ ..." + $srcdir/configure $conf_flags "$@" \ + && echo "Now type make to compile." || exit 1 +else + echo "Skipping configure process." +fi diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..f027f8e --- /dev/null +++ b/configure.in @@ -0,0 +1,165 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59c) +AC_INIT(DeviceKit-power, 001, david@fubar.dk) +AM_INIT_AUTOMAKE(DeviceKit-power, 001) +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AM_PROG_LIBTOOL +AC_PROG_MAKE_SET +AC_PROG_LN_S +AC_SYS_LARGEFILE +AM_PROG_CC_C_O + +# Taken from dbus +AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) +AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(man-pages, [ --enable-man-pages build manual pages],enable_man_pages=$enableval,enable_man_pages=yes) + +if test "${enable_man_page}" != no; then +dnl +dnl Check for xsltproc +dnl +AC_PATH_PROG([XSLTPROC], [xsltproc]) + if test -z "$XSLTPROC"; then + enable_man_pages=no + fi +fi +AM_CONDITIONAL(MAN_PAGES_ENABLED, test x$enable_man_pages = xyes) + +GTK_DOC_CHECK([1.3]) + +#### gcc warning flags + +if test "x$GCC" = "xyes"; then + changequote(,)dnl + case " $CFLAGS " in + *[\ \ ]-Wall[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wall" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wchar-subscripts[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wchar-subscripts" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wmissing-declarations[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wmissing-declarations" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wnested-externs[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wnested-externs" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wpointer-arith[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wpointer-arith" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wcast-align[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wcast-align" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wsign-compare[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wsign-compare" ;; + esac + + if test "x$enable_ansi" = "xyes"; then + case " $CFLAGS " in + *[\ \ ]-ansi[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -ansi" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_POSIX_C_SOURCE*) ;; + *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_BSD_SOURCE[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -D_BSD_SOURCE" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-pedantic[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -pedantic" ;; + esac + fi + changequote([,])dnl +fi + +PKG_CHECK_MODULES(DEVKIT, [devkit-gobject >= 002]) +AC_SUBST(DEVKIT_GOBJECT_CFLAGS) +AC_SUBST(DEVKIT_GOBJECT_LIBS) + +PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.6.0]) +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + +PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.0]) +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) + +PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.74]) +AC_SUBST(DBUS_GLIB_CFLAGS) +AC_SUBST(DBUS_GLIB_LIBS) + +PKG_CHECK_MODULES(POLKIT_DBUS, [polkit-dbus >= 0.7]) +AC_SUBST(POLKIT_DBUS_CFLAGS) +AC_SUBST(POLKIT_DBUS_LIBS) + +if test "x$GCC" = "xyes"; then + LDFLAGS="-Wl,--as-needed $LDFLAGS" +fi + +IT_PROG_INTLTOOL([0.36.0]) +GETTEXT_PACKAGE=DeviceKit-power +AC_SUBST([GETTEXT_PACKAGE]) +AM_GLIB_GNU_GETTEXT +AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"],[gettext domain]) + +AC_OUTPUT([ +Makefile +src/Makefile +tools/Makefile +doc/Makefile +doc/version.xml +doc/man/Makefile +doc/dbus/Makefile +policy/Makefile +po/Makefile.in +]) + +dnl ========================================================================== +echo " + DeviceKit-power $VERSION + ======================= + + prefix: ${prefix} + libdir: ${libdir} + libexecdir: ${libexecdir} + bindir: ${bindir} + sbindir: ${sbindir} + datadir: ${datadir} + sysconfdir: ${sysconfdir} + localstatedir: ${localstatedir} + docdir: ${docdir} + + compiler: ${CC} + cflags: ${CFLAGS} + cppflags: ${CPPFLAGS} + xsltproc: ${XSLTPROC} + + Maintainer mode: ${USE_MAINTAINER_MODE} + Building api docs: ${enable_gtk_doc} + Building man pages: ${enable_man_pages} +" diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..9953167 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,81 @@ + +SUBDIRS = man dbus + +NULL = + +AUTOMAKE_OPTIONS = 1.7 + +# The name of the module. +DOC_MODULE=devkit-power + +# The top-level SGML file. +DOC_MAIN_SGML_FILE=devkit-power-docs.xml + +# Extra options to supply to gtkdoc-scan +SCAN_OPTIONS=--ignore-headers=config.h + +# The directory containing the source code. Relative to $(srcdir) +DOC_SOURCE_DIR=../policy + +# Used for dependencies +HFILE_GLOB= +#$(top_srcdir)/policy/*.h +CFILE_GLOB= +#$(top_srcdir)/policy/*.c + +# Headers to ignore +IGNORE_HFILES= \ + $(NULL) + +# CFLAGS and LDFLAGS for compiling scan program. Only needed +# if $(DOC_MODULE).types is non-empty. +INCLUDES = \ + $(DBUS_GLIB_CFLAGS) \ + $(GLIB_CFLAGS) \ + -I$(top_srcdir)/policy \ + -I$(top_builddir)/policy \ + $(NULL) + +GTKDOC_LIBS = \ + $(DBUS_GLIB_LIBS) \ + $(NULL) + +# Extra options to supply to gtkdoc-mkdb +MKDB_OPTIONS=--sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-mktmpl +MKTMPL_OPTIONS= + +# Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE) +content_files = \ + version.xml \ + man/devkit-power.xml \ + man/devkit-power-daemon.xml \ + man/DeviceKit-power.xml \ + dbus/org.freedesktop.DeviceKit.Power.ref.xml \ + dbus/org.freedesktop.DeviceKit.Power.Source.ref.xml \ + $(NULL) + +# Images to copy into HTML directory +HTML_IMAGES = \ + $(NULL) + +# Extra options to supply to gtkdoc-fixref +FIXXREF_OPTIONS= + +MAINTAINERCLEANFILES = \ + *~ \ + Makefile.in \ + devkit-power.types \ + devkit-power-*.txt \ + $(NULL) + +if ENABLE_GTK_DOC +include $(top_srcdir)/gtk-doc.make +else +EXTRA_DIST = +endif + +# Version information for marking the documentation +EXTRA_DIST += version.xml.in + diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..3eb289a --- /dev/null +++ b/doc/TODO @@ -0,0 +1,34 @@ + +------------------------------------------------------------------------ +- Current dependencies +------------------------------------------------------------------------ + + - DeviceKit from git + - http://gitweb.freedesktop.org/?p=users/david/DeviceKit.git + - http://people.freedesktop.org/~david/DK/F9/src/DeviceKit-002-0.git20080506.fc9.src.rpm + + - D-Bus GLib 0.74 with some patches + - necessary changes are already committed upstream + - See Fedora 9 / Rawhide package for the patches needed + + - PolicyKit >= 0.8 + + - D-Bus >= 1.1.20 + +------------------------------------------------------------------------ +- TODO List (TODO: this section is incomplete) +------------------------------------------------------------------------ + +Before (next) release: + + - General project management tasks + - review licenses, NEWS, TODO, HACKING etc. file + +------------------------------------------------------------------------ +- Current features (TODO: this section is incomplete) +------------------------------------------------------------------------ + +------------------------------------------------------------------------ +- Future features (TODO: this section is incomplete) +------------------------------------------------------------------------ + diff --git a/doc/dbus/Makefile.am b/doc/dbus/Makefile.am new file mode 100644 index 0000000..d2685f4 --- /dev/null +++ b/doc/dbus/Makefile.am @@ -0,0 +1,15 @@ + +all : org.freedesktop.DeviceKit.Power.ref.xml org.freedesktop.DeviceKit.Power.Source.ref.xml + +org.freedesktop.DeviceKit.Power.ref.xml : $(top_srcdir)/src/org.freedesktop.DeviceKit.Power.xml $(top_srcdir)/doc/dbus/spec-to-docbook.xsl + echo """" > $@ + $(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@ + +org.freedesktop.DeviceKit.Power.Source.ref.xml : $(top_srcdir)/src/org.freedesktop.DeviceKit.Power.Source.xml $(top_srcdir)/doc/dbus/spec-to-docbook.xsl + echo """" > $@ + $(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@ + +EXTRA_DIST = spec-to-docbook.xsl dbus-introspect-docs.dtd + +clean-local : + rm -f *~ *.ref.xml diff --git a/doc/dbus/dbus-introspect-docs.dtd b/doc/dbus/dbus-introspect-docs.dtd new file mode 100644 index 0000000..ca918fb --- /dev/null +++ b/doc/dbus/dbus-introspect-docs.dtd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/dbus/spec-to-docbook.xsl b/doc/dbus/spec-to-docbook.xsl new file mode 100644 index 0000000..1864414 --- /dev/null +++ b/doc/dbus/spec-to-docbook.xsl @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + interface + + + + Methods + + + + + + + + + + + Signals + + + + + + + + + + + Implemented Interfaces + + Objects implementing also implements + org.freedesktop.DBus.Introspectable, + org.freedesktop.DBus.Properties + + + + + + + Properties + + + + + + + + + + + Description + + + + + + + Details + + + + + + + + + Signal Details + + + + + + + + + + + Property Details + + + + + + + + + + + + + + + + +: + + + + + + + + + + + + + + + + + + + + + + <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 + +'' + + + + + + + + + + + + + +: + + + + + + + + + + + + + + + + + + + + + <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 + + () + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Since + + + + + + + + /> + + + + + + + is deprecated since version and should not be used in newly-written code. Use + + + + + : + + + :: + + + . + + + + + + + + + + + + + + + +instead. + + + + + + + + + + + + + + + + + +See also: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +: + + + + + + + + + + + + Errors + + + + : + + + + + + + + + + + + Permissions + + + + + + + + + + + + + + + + + + <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"/> () + + () + + + + + + + + + + + + + + + + +:'' + + + + + + + + + + + + +::() + + + + + + + + + + + + +.() + + + + + +'' +, + + + + + +'' +, + + + + + + +'' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/devkit-power-docs.xml b/doc/devkit-power-docs.xml new file mode 100644 index 0000000..6af1211 --- /dev/null +++ b/doc/devkit-power-docs.xml @@ -0,0 +1,94 @@ + + +]> + + + DeviceKit-power Reference Manual + Version &version; + + + David + Zeuthen + +
+ david@fubar.dk +
+
+
+
+ + + 2008 + The DeviceKit-power Authors + + + + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free + Documentation License, 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 GNU Free + Documentation License from the Free Software + Foundation by visiting their Web site or by writing + to: + +
+ The Free Software Foundation, Inc., + 59 Temple Place - Suite 330, + Boston, MA 02111-1307, + USA +
+
+ + + Many of the names used by companies to distinguish their + products and services are claimed as trademarks. Where those + names appear in any GNOME documentation, and those trademarks + are made aware to the members of the GNOME Documentation + Project, the names have been printed in caps or initial caps. + +
+
+ + + D-Bus API Reference + + + This part documents the D-Bus interface used to access the + DeviceKit-power daemon. + + + + + + + + Manual Pages + + + This part contains the manual pages distributed with DeviceKit-power. + + + + + + + + + Index + + + + + + License + +FIXME: MISSING XINCLUDE CONTENT + + +
diff --git a/doc/man/DeviceKit-power.xml b/doc/man/DeviceKit-power.xml new file mode 100644 index 0000000..8f5ab6d --- /dev/null +++ b/doc/man/DeviceKit-power.xml @@ -0,0 +1,64 @@ + + + DeviceKit-power + March 2008 + DeviceKit-power + + + + DeviceKit-power + 7 + + + + + DeviceKit-power + System-wide Power Management + + + DESCRIPTION + + DeviceKit-power provides an interface to enumerate power sources + on the system and control system-wide power management. Any + application can access + the org.freedesktop.DeviceKit.Power service + on the system message bus. Some operations (such as suspending + the system) is restricted using PolicyKit. + + + + AUTHOR + + Written by David Zeuthen david@fubar.dk with + a lot of help from many others. + + + + + BUGS + + Please send bug reports to either the distribution or the + hal mailing list, + see . + to subscribe. + + + + + SEE ALSO + + + DeviceKit7 + , + + PolicyKit8 + , + + devkit-power-daemon8 + , + + devkit-power1 + + + + diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am new file mode 100644 index 0000000..f49dde9 --- /dev/null +++ b/doc/man/Makefile.am @@ -0,0 +1,24 @@ + +NULL = + +if MAN_PAGES_ENABLED + +man_MANS = \ + devkit-power.1 \ + devkit-power-daemon.8 \ + DeviceKit-power.7 \ + $(NULL) + +%.1 %.7 %.8 : %.xml + $(XSLTPROC) -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + +endif # MAN_PAGES_ENABLED + +EXTRA_DIST= \ + devkit-power.xml \ + devkit-power-daemon.xml \ + DeviceKit-power.xml \ + $(NULL) + +clean-local: + rm -f *~ *.[178] diff --git a/doc/man/devkit-power-daemon.xml b/doc/man/devkit-power-daemon.xml new file mode 100644 index 0000000..e969586 --- /dev/null +++ b/doc/man/devkit-power-daemon.xml @@ -0,0 +1,84 @@ + + + devkit-power-daemon + April 2008 + devkit-power-daemon + + + + devkit-power-daemon + 8 + + + + + devkit-power-daemon + DeviceKit-power Daemon + + + + + devkit-power-daemon + + + + + + DESCRIPTION + + devkit-power-daemon provides + the org.freedesktop.DeviceKit.Power service on the + system message bus. Users or administrators should never need to + start this daemon as it will be automatically started by + dbus-daemon1 + whenever an application calls into the org.freedesktop.DeviceKit.Power + service. + + + + + OPTIONS + + + + + + Show help options. + + + + + + + AUTHOR + + Written by David Zeuthen david@fubar.dk with + a lot of help from many others. + + + + + BUGS + + Please send bug reports to either the distribution or the + hal mailing list, + see + on how to subscribe. + + + + + SEE ALSO + + + DeviceKit-power7 + , + + devkit-power1 + , + + dbus-daemon1 + , + + + diff --git a/doc/man/devkit-power.xml b/doc/man/devkit-power.xml new file mode 100644 index 0000000..fd25a79 --- /dev/null +++ b/doc/man/devkit-power.xml @@ -0,0 +1,99 @@ + + + devkit-power + April 2008 + devkit-power + + + + devkit-power + 1 + + + + + devkit-power + DeviceKit-power command line tool + + + + + devkit-power + + + + + + + + + DESCRIPTION + + devkit-power is a + simple command line client for the + DeviceKit-power7 + daemon. TODO: not fully documented. + + + + + OPTIONS + + + + + + Connect to the DeviceKit-power daemon and print a line + every time a power source is added, removed or changed. + + + + + + + + Like but prints the full + details of the power source whenever an event happens. + + + + + + + + Show help options. + + + + + + + AUTHOR + + Written by David Zeuthen david@fubar.dk with + a lot of help from many others. + + + + + BUGS + + Please send bug reports to either the distribution or the + hal mailing list, + see + on how to subscribe. + + + + + SEE ALSO + + + devkit-power-daemon8 + , + + DeviceKit-power7 + , + + + diff --git a/doc/version.xml b/doc/version.xml new file mode 100644 index 0000000..5325a8d --- /dev/null +++ b/doc/version.xml @@ -0,0 +1 @@ +001 diff --git a/gtk-doc.make b/gtk-doc.make new file mode 100644 index 0000000..3c3e39a --- /dev/null +++ b/gtk-doc.make @@ -0,0 +1,159 @@ +# -*- mode: makefile -*- + +#################################### +# Everything below here is generic # +#################################### + +if GTK_DOC_USE_LIBTOOL +GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) +else +GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) +endif + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) + +EXTRA_DIST = \ + $(content_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt + +DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \ + $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).signals + +CLEANFILES = $(SCANOBJ_FILES) $(DOC_MODULE)-unused.txt $(DOC_STAMPS) + +if ENABLE_GTK_DOC +all-local: html-build.stamp +else +all-local: +endif + +docs: html-build.stamp + +#### scan #### + +scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) + @echo 'gtk-doc: Scanning header files' + @-chmod -R u+w $(srcdir) + cd $(srcdir) && \ + gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) + if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ + else \ + cd $(srcdir) ; \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp + @true + +#### templates #### + +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt + @echo 'gtk-doc: Rebuilding template files' + @-chmod -R u+w $(srcdir) + cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) $(MKTMPL_OPTIONS) + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +tmpl/*.sgml: + @true + + +#### xml #### + +sgml-build.stamp: tmpl.stamp $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(srcdir)/tmpl/*.sgml $(expand_content_files) + @echo 'gtk-doc: Building XML' + @-chmod -R u+w $(srcdir) + cd $(srcdir) && \ + gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### html #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo 'gtk-doc: Building HTML' + @-chmod -R u+w $(srcdir) + rm -rf $(srcdir)/html + mkdir $(srcdir)/html + cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) + @echo 'gtk-doc: Fixing cross-references' + cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp + +############## + +clean-local: + rm -f *~ *.bak + rm -rf .libs + +maintainer-clean-local: clean + cd $(srcdir) && rm -rf xml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + +install-data-local: + installfiles=`echo $(srcdir)/html/*`; \ + if test "$$installfiles" = '$(srcdir)/html/*'; \ + then echo '-- Nothing to install' ; \ + else \ + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR) || :; \ + fi + +uninstall-local: + rm -f $(DESTDIR)$(TARGET_DIR)/* + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +dist-hook: dist-check-gtkdoc dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/xml/*.xml $(distdir)/xml + cp $(srcdir)/html/* $(distdir)/html + if test -f $(srcdir)/$(DOC_MODULE).types; then \ + cp $(srcdir)/$(DOC_MODULE).types $(distdir)/$(DOC_MODULE).types; \ + fi + +.PHONY : dist-hook-local docs diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..d2d5f21 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,111 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" 1>&2 + exit 0 + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +case $dirmode in + '') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi + ;; + *) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi + ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# End: +# mkinstalldirs ends here diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..b72d517 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,4 @@ +# please keep this list sorted alphabetically +# + + diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..e769d2d --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,4 @@ +# List of source files containing translatable strings. +# Please keep this file sorted alphabetically. +[encoding: UTF-8] +policy/org.freedesktop.devicekit.power.policy.in diff --git a/policy/Makefile.am b/policy/Makefile.am new file mode 100644 index 0000000..e03f095 --- /dev/null +++ b/policy/Makefile.am @@ -0,0 +1,17 @@ + +devkit_policydir = $(datadir)/PolicyKit/policy + +dist_devkit_policy_DATA = \ + org.freedesktop.devicekit.power.policy + +@INTLTOOL_POLICY_RULE@ + +check: + polkit-policy-file-validate $(dist_devkit_policy_DATA) + +clean-local : + rm -f *~ + +DISTCLEANFILES = $(dist_devkit_policy_DATA) + +EXTRA_DIST = $(dist_devkit_policy_DATA:.policy=.policy.in) diff --git a/policy/org.freedesktop.devicekit.power.policy.in b/policy/org.freedesktop.devicekit.power.policy.in new file mode 100644 index 0000000..759b747 --- /dev/null +++ b/policy/org.freedesktop.devicekit.power.policy.in @@ -0,0 +1,32 @@ + + + + + + + + The DeviceKit-power Project + http://hal.freedesktop.org/docs/DeviceKit-power/ + system-suspend + + + <_description>Suspend the system to RAM + <_message>Authentication is required to suspend to system + + no + no + yes + + + + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..1db6572 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,82 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + -I$(top_builddir)/src -I$(top_srcdir)/src \ + -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \ + -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_BIN_DIR=\""$(bindir)"\" \ + -DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ + -DPACKAGE_LIB_DIR=\""$(libdir)"\" \ + -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ + $(DBUS_GLIB_CFLAGS) \ + $(POLKIT_DBUS_CFLAGS) \ + $(DEVKIT_CFLAGS) \ + $(GLIB_CFLAGS) + +BUILT_SOURCES = \ + devkit-power-daemon-glue.h \ + devkit-power-source-glue.h \ + devkit-power-marshal.h devkit-power-marshal.c + +devkit-power-marshal.h: devkit-power-marshal.list + glib-genmarshal $< --prefix=devkit_power_marshal --header > $@ + +devkit-power-marshal.c: devkit-power-marshal.list + echo "#include \"devkit-power-marshal.h\"" > $@ && glib-genmarshal $< --prefix=devkit_power_marshal --body >> $@ + +devkit-power-daemon-glue.h: org.freedesktop.DeviceKit.Power.xml Makefile.am + dbus-binding-tool --prefix=devkit_power_daemon --mode=glib-server --output=devkit-power-daemon-glue.h org.freedesktop.DeviceKit.Power.xml + +devkit-power-source-glue.h: org.freedesktop.DeviceKit.Power.Source.xml Makefile.am + dbus-binding-tool --prefix=devkit_power_source --mode=glib-server --output=devkit-power-source-glue.h org.freedesktop.DeviceKit.Power.Source.xml + +libexec_PROGRAMS = devkit-power-daemon + +dbusifdir = $(datadir)/dbus-1/interfaces +dbusif_DATA = org.freedesktop.DeviceKit.Power.xml org.freedesktop.DeviceKit.Power.Source.xml + +devkit_power_daemon_SOURCES = \ + devkit-power-daemon.h devkit-power-daemon.c \ + devkit-power-device.h devkit-power-device.c \ + devkit-power-source.h devkit-power-source.c \ + sysfs-utils.h sysfs-utils.c \ + main.c \ + $(BUILT_SOURCES) + +devkit_power_daemon_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -DG_LOG_DOMAIN=\"devkit-power-daemon\" \ + $(DISABLE_DEPRECATED) \ + $(AM_CPPFLAGS) + +devkit_power_daemon_LDADD = \ + $(DBUS_GLIB_LIBS) \ + $(POLKIT_DBUS_LIBS) \ + $(DEVKIT_LIBS) + +servicedir = $(datadir)/dbus-1/system-services +service_in_files = org.freedesktop.DeviceKit.Power.service.in +service_DATA = $(service_in_files:.service.in=.service) + +$(service_DATA): $(service_in_files) Makefile + @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ + +dbusconfdir = $(sysconfdir)/dbus-1/system.d +dbusconf_in_files = org.freedesktop.DeviceKit.Power.conf.in +dbusconf_DATA = $(dbusconf_in_files:.conf.in=.conf) + +$(dbusconf_DATA): $(dbusconf_in_files) Makefile + cp $< $@ + +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = org.freedesktop.DeviceKit.Power.xml \ + org.freedesktop.DeviceKit.Power.Source.xml \ + devkit-power-marshal.list \ + $(service_in_files) \ + $(dbusconf_in_files) + +clean-local : + rm -f *~ $(service_DATA) $(dbusconf_DATA) diff --git a/src/devkit-power-daemon.c b/src/devkit-power-daemon.c new file mode 100644 index 0000000..453ff0b --- /dev/null +++ b/src/devkit-power-daemon.c @@ -0,0 +1,631 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#include "devkit-power-daemon.h" +#include "devkit-power-device.h" + +#include "devkit-power-daemon-glue.h" +#include "devkit-power-marshal.h" + +/*--------------------------------------------------------------------------------------------------------------*/ + +enum +{ + DEVICE_ADDED_SIGNAL, + DEVICE_REMOVED_SIGNAL, + DEVICE_CHANGED_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +struct DevkitPowerDaemonPrivate +{ + DBusGConnection *system_bus_connection; + DBusGProxy *system_bus_proxy; + PolKitContext *pk_context; + PolKitTracker *pk_tracker; + + GHashTable *map_native_path_to_device; + + DevkitClient *devkit_client; +}; + +static void devkit_power_daemon_class_init (DevkitPowerDaemonClass *klass); +static void devkit_power_daemon_init (DevkitPowerDaemon *seat); +static void devkit_power_daemon_finalize (GObject *object); + +G_DEFINE_TYPE (DevkitPowerDaemon, devkit_power_daemon, G_TYPE_OBJECT) + +#define DEVKIT_POWER_DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_POWER_DAEMON, DevkitPowerDaemonPrivate)) + +/*--------------------------------------------------------------------------------------------------------------*/ + +GQuark +devkit_power_daemon_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) { + ret = g_quark_from_static_string ("devkit_power_daemon_error"); + } + + return ret; +} + + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +devkit_power_daemon_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + ENUM_ENTRY (DEVKIT_POWER_DAEMON_ERROR_GENERAL, "GeneralError"), + ENUM_ENTRY (DEVKIT_POWER_DAEMON_ERROR_NOT_SUPPORTED, "NotSupported"), + ENUM_ENTRY (DEVKIT_POWER_DAEMON_ERROR_NO_SUCH_DEVICE, "NoSuchDevice"), + { 0, 0, 0 } + }; + g_assert (DEVKIT_POWER_DAEMON_NUM_ERRORS == G_N_ELEMENTS (values) - 1); + etype = g_enum_register_static ("DevkitPowerDaemonError", values); + } + return etype; +} + + +static GObject * +devkit_power_daemon_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + DevkitPowerDaemon *daemon; + DevkitPowerDaemonClass *klass; + + klass = DEVKIT_POWER_DAEMON_CLASS (g_type_class_peek (DEVKIT_TYPE_POWER_DAEMON)); + + daemon = DEVKIT_POWER_DAEMON ( + G_OBJECT_CLASS (devkit_power_daemon_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + return G_OBJECT (daemon); +} + +static void +devkit_power_daemon_class_init (DevkitPowerDaemonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = devkit_power_daemon_constructor; + object_class->finalize = devkit_power_daemon_finalize; + + g_type_class_add_private (klass, sizeof (DevkitPowerDaemonPrivate)); + + signals[DEVICE_ADDED_SIGNAL] = + g_signal_new ("device-added", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[DEVICE_REMOVED_SIGNAL] = + g_signal_new ("device-removed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[DEVICE_CHANGED_SIGNAL] = + g_signal_new ("device-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + dbus_g_object_type_install_info (DEVKIT_TYPE_POWER_DAEMON, &dbus_glib_devkit_power_daemon_object_info); + + dbus_g_error_domain_register (DEVKIT_POWER_DAEMON_ERROR, + NULL, + DEVKIT_POWER_DAEMON_TYPE_ERROR); +} + +static void +devkit_power_daemon_init (DevkitPowerDaemon *daemon) +{ + daemon->priv = DEVKIT_POWER_DAEMON_GET_PRIVATE (daemon); + daemon->priv->map_native_path_to_device = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); +} + +static void +devkit_power_daemon_finalize (GObject *object) +{ + DevkitPowerDaemon *daemon; + + g_return_if_fail (object != NULL); + g_return_if_fail (DEVKIT_IS_POWER_DAEMON (object)); + + daemon = DEVKIT_POWER_DAEMON (object); + + g_return_if_fail (daemon->priv != NULL); + + if (daemon->priv->pk_context != NULL) + polkit_context_unref (daemon->priv->pk_context); + + if (daemon->priv->pk_tracker != NULL) + polkit_tracker_unref (daemon->priv->pk_tracker); + + if (daemon->priv->system_bus_proxy != NULL) + g_object_unref (daemon->priv->system_bus_proxy); + + if (daemon->priv->system_bus_connection != NULL) + dbus_g_connection_unref (daemon->priv->system_bus_connection); + + if (daemon->priv->devkit_client != NULL) { + g_object_unref (daemon->priv->devkit_client); + } + + if (daemon->priv->map_native_path_to_device != NULL) { + g_hash_table_unref (daemon->priv->map_native_path_to_device); + } + + G_OBJECT_CLASS (devkit_power_daemon_parent_class)->finalize (object); +} + +static gboolean +pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data) +{ + int fd; + PolKitContext *pk_context = user_data; + fd = g_io_channel_unix_get_fd (channel); + polkit_context_io_func (pk_context, fd); + return TRUE; +} + +static int +pk_io_add_watch (PolKitContext *pk_context, int fd) +{ + guint id = 0; + GIOChannel *channel; + channel = g_io_channel_unix_new (fd); + if (channel == NULL) + goto out; + id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context); + if (id == 0) { + g_io_channel_unref (channel); + goto out; + } + g_io_channel_unref (channel); +out: + return id; +} + +static void +pk_io_remove_watch (PolKitContext *pk_context, int watch_id) +{ + g_source_remove (watch_id); +} + +static DBusHandlerResult +_filter (DBusConnection *connection, DBusMessage *message, void *user_data) +{ + DevkitPowerDaemon *daemon = DEVKIT_POWER_DAEMON (user_data); + const char *interface; + + interface = dbus_message_get_interface (message); + + if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { + /* pass NameOwnerChanged signals from the bus to PolKitTracker */ + polkit_tracker_dbus_func (daemon->priv->pk_tracker, message); + } + + if (interface != NULL && g_str_has_prefix (interface, "org.freedesktop.ConsoleKit")) { + /* pass ConsoleKit signals to PolKitTracker */ + polkit_tracker_dbus_func (daemon->priv->pk_tracker, message); + } + + /* other filters might want to process this message too */ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void device_add (DevkitPowerDaemon *daemon, DevkitDevice *d, gboolean emit_event); +static void device_remove (DevkitPowerDaemon *daemon, DevkitDevice *d); + +static void +device_changed (DevkitPowerDaemon *daemon, DevkitDevice *d, gboolean synthesized) +{ + DevkitPowerDevice *device; + const char *native_path; + + native_path = devkit_device_get_native_path (d); + device = g_hash_table_lookup (daemon->priv->map_native_path_to_device, native_path); + if (device != NULL) { + if (!devkit_power_device_changed (device, d, synthesized)) { + g_print ("changed triggered remove on %s\n", native_path); + device_remove (daemon, d); + } else { + g_print ("changed %s\n", native_path); + } + } else { + g_print ("treating change event as add on %s\n", native_path); + device_add (daemon, d, TRUE); + } +} + +static gboolean +device_went_away_remove_cb (gpointer key, gpointer value, gpointer user_data) +{ + if (value == user_data) { + g_print ("removed %s\n", (char *) key); + return TRUE; + } + return FALSE; +} + +static void +device_went_away (gpointer user_data, GObject *where_the_object_was) +{ + DevkitPowerDaemon *daemon = DEVKIT_POWER_DAEMON (user_data); + + g_hash_table_foreach_remove (daemon->priv->map_native_path_to_device, + device_went_away_remove_cb, + where_the_object_was); +} + +static void +device_add (DevkitPowerDaemon *daemon, DevkitDevice *d, gboolean emit_event) +{ + DevkitPowerDevice *device; + const char *native_path; + + native_path = devkit_device_get_native_path (d); + device = g_hash_table_lookup (daemon->priv->map_native_path_to_device, native_path); + if (device != NULL) { + /* we already have the device; treat as change event */ + g_print ("treating add event as change event on %s\n", native_path); + device_changed (daemon, d, FALSE); + } else { + device = devkit_power_device_new (daemon, d); + + if (device != NULL) { + /* only take a weak ref; the device will stay on the bus until + * it's unreffed. So if we ref it, it'll never go away. Stupid + * dbus-glib, no cookie for you. + */ + g_object_weak_ref (G_OBJECT (device), device_went_away, daemon); + g_hash_table_insert (daemon->priv->map_native_path_to_device, + g_strdup (native_path), + device); + g_print ("added %s\n", native_path); + if (emit_event) { + g_signal_emit (daemon, signals[DEVICE_ADDED_SIGNAL], 0, + devkit_power_device_get_object_path (device)); + } + } else { + g_print ("ignoring add event on %s\n", native_path); + } + } +} + +static void +device_remove (DevkitPowerDaemon *daemon, DevkitDevice *d) +{ + DevkitPowerDevice *device; + const char *native_path; + + native_path = devkit_device_get_native_path (d); + device = g_hash_table_lookup (daemon->priv->map_native_path_to_device, native_path); + if (device == NULL) { + g_print ("ignoring remove event on %s\n", native_path); + } else { + devkit_power_device_removed (device); + g_signal_emit (daemon, signals[DEVICE_REMOVED_SIGNAL], 0, + devkit_power_device_get_object_path (device)); + g_object_unref (device); + } +} + +static void +device_event_signal_handler (DevkitClient *client, + const char *action, + DevkitDevice *device, + gpointer user_data) +{ + DevkitPowerDaemon *daemon = DEVKIT_POWER_DAEMON (user_data); + + if (strcmp (action, "add") == 0) { + device_add (daemon, device, TRUE); + } else if (strcmp (action, "remove") == 0) { + device_remove (daemon, device); + } else if (strcmp (action, "change") == 0) { + device_changed (daemon, device, FALSE); + } else { + g_warning ("unhandled action '%s' on %s", action, devkit_device_get_native_path (device)); + } +} + +static gboolean +register_power_daemon (DevkitPowerDaemon *daemon) +{ + DBusConnection *connection; + DBusError dbus_error; + GError *error = NULL; + const char *subsystems[] = {"power_supply", NULL}; + + daemon->priv->pk_context = polkit_context_new (); + polkit_context_set_io_watch_functions (daemon->priv->pk_context, pk_io_add_watch, pk_io_remove_watch); + if (!polkit_context_init (daemon->priv->pk_context, NULL)) { + g_critical ("cannot initialize libpolkit"); + goto error; + } + + error = NULL; + daemon->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (daemon->priv->system_bus_connection == NULL) { + if (error != NULL) { + g_critical ("error getting system bus: %s", error->message); + g_error_free (error); + } + goto error; + } + connection = dbus_g_connection_get_connection (daemon->priv->system_bus_connection); + + daemon->priv->pk_tracker = polkit_tracker_new (); + polkit_tracker_set_system_bus_connection (daemon->priv->pk_tracker, connection); + polkit_tracker_init (daemon->priv->pk_tracker); + + dbus_g_connection_register_g_object (daemon->priv->system_bus_connection, "/", + G_OBJECT (daemon)); + + daemon->priv->system_bus_proxy = dbus_g_proxy_new_for_name (daemon->priv->system_bus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + /* TODO FIXME: I'm pretty sure dbus-glib blows in a way that + * we can't say we're interested in all signals from all + * members on all interfaces for a given service... So we do + * this.. + */ + + dbus_error_init (&dbus_error); + + /* need to listen to NameOwnerChanged */ + dbus_bus_add_match (connection, + "type='signal'" + ",interface='"DBUS_INTERFACE_DBUS"'" + ",sender='"DBUS_SERVICE_DBUS"'" + ",member='NameOwnerChanged'", + &dbus_error); + + if (dbus_error_is_set (&dbus_error)) { + g_warning ("Cannot add match rule: %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto error; + } + + /* need to listen to ConsoleKit signals */ + dbus_bus_add_match (connection, + "type='signal',sender='org.freedesktop.ConsoleKit'", + &dbus_error); + + if (dbus_error_is_set (&dbus_error)) { + g_warning ("Cannot add match rule: %s: %s", dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto error; + } + + if (!dbus_connection_add_filter (connection, + _filter, + daemon, + NULL)) { + g_warning ("Cannot add D-Bus filter: %s: %s", dbus_error.name, dbus_error.message); + goto error; + } + + /* connect to the DeviceKit daemon */ + daemon->priv->devkit_client = devkit_client_new (subsystems); + if (!devkit_client_connect (daemon->priv->devkit_client, &error)) { + g_warning ("Couldn't open connection to DeviceKit daemon: %s", error->message); + g_error_free (error); + goto error; + } + g_signal_connect (daemon->priv->devkit_client, "device-event", + G_CALLBACK (device_event_signal_handler), daemon); + + return TRUE; +error: + return FALSE; +} + + +DevkitPowerDaemon * +devkit_power_daemon_new (void) +{ + DevkitPowerDaemon *daemon; + GError *error = NULL; + GList *devices; + GList *l; + const char *subsystems[] = {"power_supply", NULL}; + + daemon = DEVKIT_POWER_DAEMON (g_object_new (DEVKIT_TYPE_POWER_DAEMON, NULL)); + + if (!register_power_daemon (DEVKIT_POWER_DAEMON (daemon))) { + g_object_unref (daemon); + return NULL; + } + + + devices = devkit_client_enumerate_by_subsystem (daemon->priv->devkit_client, + subsystems, + &error); + if (error != NULL) { + g_warning ("Cannot enumerate devices: %s", error->message); + g_error_free (error); + g_object_unref (daemon); + return NULL; + } + for (l = devices; l != NULL; l = l->next) { + DevkitDevice *device = l->data; + device_add (daemon, device, FALSE); + } + g_list_foreach (devices, (GFunc) g_object_unref, NULL); + g_list_free (devices); + + return daemon; +} + +PolKitCaller * +devkit_power_damon_local_get_caller_for_context (DevkitPowerDaemon *daemon, + DBusGMethodInvocation *context) +{ + const char *sender; + GError *error; + DBusError dbus_error; + PolKitCaller *pk_caller; + + sender = dbus_g_method_get_sender (context); + dbus_error_init (&dbus_error); + pk_caller = polkit_tracker_get_caller_from_dbus_name (daemon->priv->pk_tracker, + sender, + &dbus_error); + if (pk_caller == NULL) { + error = g_error_new (DEVKIT_POWER_DAEMON_ERROR, + DEVKIT_POWER_DAEMON_ERROR_GENERAL, + "Error getting information about caller: %s: %s", + dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + dbus_g_method_return_error (context, error); + g_error_free (error); + return NULL; + } + + return pk_caller; +} + +gboolean +devkit_power_damon_local_check_auth (DevkitPowerDaemon *daemon, + PolKitCaller *pk_caller, + const char *action_id, + DBusGMethodInvocation *context) +{ + gboolean ret; + GError *error; + DBusError d_error; + PolKitAction *pk_action; + PolKitResult pk_result; + + ret = FALSE; + + pk_action = polkit_action_new (); + polkit_action_set_action_id (pk_action, action_id); + pk_result = polkit_context_is_caller_authorized (daemon->priv->pk_context, + pk_action, + pk_caller, + TRUE, + NULL); + if (pk_result == POLKIT_RESULT_YES) { + ret = TRUE; + } else { + + dbus_error_init (&d_error); + polkit_dbus_error_generate (pk_action, pk_result, &d_error); + error = NULL; + dbus_set_g_error (&error, &d_error); + dbus_g_method_return_error (context, error); + g_error_free (error); + dbus_error_free (&d_error); + } + polkit_action_unref (pk_action); + return ret; +} + + +/*--------------------------------------------------------------------------------------------------------------*/ + +#if 0 +static gboolean +throw_error (DBusGMethodInvocation *context, int error_code, const char *format, ...) +{ + GError *error; + va_list args; + char *message; + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + error = g_error_new (DEVKIT_POWER_DAEMON_ERROR, + error_code, + message); + dbus_g_method_return_error (context, error); + g_error_free (error); + g_free (message); + return TRUE; +} +#endif + +/*--------------------------------------------------------------------------------------------------------------*/ +/* exported methods */ + +static void +enumerate_cb (gpointer key, gpointer value, gpointer user_data) +{ + DevkitPowerDevice *device = DEVKIT_POWER_DEVICE (value); + GPtrArray *object_paths = user_data; + g_ptr_array_add (object_paths, g_strdup (devkit_power_device_get_object_path (device))); +} + +gboolean +devkit_power_daemon_enumerate_devices (DevkitPowerDaemon *daemon, + DBusGMethodInvocation *context) +{ + GPtrArray *object_paths; + object_paths = g_ptr_array_new (); + g_hash_table_foreach (daemon->priv->map_native_path_to_device, enumerate_cb, object_paths); + dbus_g_method_return (context, object_paths); + g_ptr_array_foreach (object_paths, (GFunc) g_free, NULL); + g_ptr_array_free (object_paths, TRUE); + return TRUE; +} diff --git a/src/devkit-power-daemon.h b/src/devkit-power-daemon.h new file mode 100644 index 0000000..e877730 --- /dev/null +++ b/src/devkit-power-daemon.h @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __DEVKIT_POWER_DAEMON_H__ +#define __DEVKIT_POWER_DAEMON_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_POWER_DAEMON (devkit_power_daemon_get_type ()) +#define DEVKIT_POWER_DAEMON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_POWER_DAEMON, DevkitPowerDaemon)) +#define DEVKIT_POWER_DAEMON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_POWER_DAEMON, DevkitPowerDaemonClass)) +#define DEVKIT_IS_POWER_DAEMON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_POWER_DAEMON)) +#define DEVKIT_IS_POWER_DAEMON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_POWER_DAEMON)) +#define DEVKIT_POWER_DAEMON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_POWER_DAEMON, DevkitPowerDaemonClass)) + +typedef struct DevkitPowerDaemonPrivate DevkitPowerDaemonPrivate; + +typedef struct +{ + GObject parent; + DevkitPowerDaemonPrivate *priv; +} DevkitPowerDaemon; + +typedef struct +{ + GObjectClass parent_class; +} DevkitPowerDaemonClass; + +typedef enum +{ + DEVKIT_POWER_DAEMON_ERROR_GENERAL, + DEVKIT_POWER_DAEMON_ERROR_NOT_SUPPORTED, + DEVKIT_POWER_DAEMON_ERROR_NO_SUCH_DEVICE, + DEVKIT_POWER_DAEMON_NUM_ERRORS +} DevkitPowerDaemonError; + +#define DEVKIT_POWER_DAEMON_ERROR devkit_power_daemon_error_quark () + +GType devkit_power_daemon_error_get_type (void); +#define DEVKIT_POWER_DAEMON_TYPE_ERROR (devkit_power_daemon_error_get_type ()) + +GQuark devkit_power_daemon_error_quark (void); +GType devkit_power_daemon_get_type (void); +DevkitPowerDaemon *devkit_power_daemon_new (void); + +/* local methods */ + +PolKitCaller *devkit_power_damon_local_get_caller_for_context (DevkitPowerDaemon *daemon, + DBusGMethodInvocation *context); + +gboolean devkit_power_damon_local_check_auth (DevkitPowerDaemon *daemon, + PolKitCaller *pk_caller, + const char *action_id, + DBusGMethodInvocation *context); + +/* exported methods */ + +gboolean devkit_power_daemon_enumerate_devices (DevkitPowerDaemon *daemon, + DBusGMethodInvocation *context); + +G_END_DECLS + +#endif /* __DEVKIT_POWER_DAEMON_H__ */ diff --git a/src/devkit-power-device.c b/src/devkit-power-device.c new file mode 100644 index 0000000..0c6742d --- /dev/null +++ b/src/devkit-power-device.c @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysfs-utils.h" +#include "devkit-power-device.h" +#include "devkit-power-source.h" + +static void devkit_power_device_class_init (DevkitPowerDeviceClass *klass); +static void devkit_power_device_init (DevkitPowerDevice *seat); + +G_DEFINE_TYPE (DevkitPowerDevice, devkit_power_device, G_TYPE_OBJECT) + +#define DEVKIT_POWER_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_POWER_DEVICE, DevkitPowerDevicePrivate)) + +static void +devkit_power_device_class_init (DevkitPowerDeviceClass *klass) +{ +} + +static void +devkit_power_device_init (DevkitPowerDevice *device) +{ +} + +void +devkit_power_device_removed (DevkitPowerDevice *device) +{ + DevkitPowerDeviceClass *klass = DEVKIT_POWER_DEVICE_GET_CLASS (device); + klass->removed (device); +} + +DevkitPowerDevice * +devkit_power_device_new (DevkitPowerDaemon *daemon, DevkitDevice *d) +{ + const char *subsys; + DevkitPowerDevice *device; + + device = NULL; + + subsys = devkit_device_get_subsystem (d); + if (strcmp (subsys, "power_supply") == 0) { + device = DEVKIT_POWER_DEVICE (devkit_power_source_new (daemon, d)); + } + + return device; +} + +gboolean +devkit_power_device_changed (DevkitPowerDevice *device, DevkitDevice *d, gboolean synthesized) +{ + DevkitPowerDeviceClass *klass = DEVKIT_POWER_DEVICE_GET_CLASS (device); + return (klass->changed (device, d, synthesized)); +} + +const char * +devkit_power_device_get_object_path (DevkitPowerDevice *device) +{ + DevkitPowerDeviceClass *klass = DEVKIT_POWER_DEVICE_GET_CLASS (device); + return (klass->get_object_path (device)); +} diff --git a/src/devkit-power-device.h b/src/devkit-power-device.h new file mode 100644 index 0000000..3ddb3d3 --- /dev/null +++ b/src/devkit-power-device.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __DEVKIT_POWER_DEVICE_H__ +#define __DEVKIT_POWER_DEVICE_H__ + +#include +#include +#include + +#include "devkit-power-daemon.h" + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_POWER_DEVICE (devkit_power_device_get_type ()) +#define DEVKIT_POWER_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_POWER_DEVICE, DevkitPowerDevice)) +#define DEVKIT_POWER_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_POWER_DEVICE, DevkitPowerDeviceClass)) +#define DEVKIT_IS_POWER_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_POWER_DEVICE)) +#define DEVKIT_IS_POWER_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_POWER_DEVICE)) +#define DEVKIT_POWER_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_POWER_DEVICE, DevkitPowerDeviceClass)) + +typedef struct +{ + GObject parent; +} DevkitPowerDevice; + +typedef struct +{ + GObjectClass parent_class; + + /* vtable */ + gboolean (*changed) (DevkitPowerDevice *device, + DevkitDevice *d, + gboolean synthesized); + void (*removed) (DevkitPowerDevice *device); + const char *(*get_object_path) (DevkitPowerDevice *device); +} DevkitPowerDeviceClass; + +GType devkit_power_device_get_type (void); +DevkitPowerDevice *devkit_power_device_new (DevkitPowerDaemon *daemon, + DevkitDevice *d); +gboolean devkit_power_device_changed (DevkitPowerDevice *device, + DevkitDevice *d, + gboolean synthesized); +void devkit_power_device_removed (DevkitPowerDevice *device); + +const char *devkit_power_device_get_object_path (DevkitPowerDevice *device); + +G_END_DECLS + +#endif /* __DEVKIT_POWER_DEVICE_H__ */ diff --git a/src/devkit-power-marshal.list b/src/devkit-power-marshal.list new file mode 100644 index 0000000..98218d7 --- /dev/null +++ b/src/devkit-power-marshal.list @@ -0,0 +1,2 @@ +VOID:BOOLEAN,STRING,BOOLEAN,INT,INT,STRING,DOUBLE +VOID:STRING,BOOLEAN,STRING,BOOLEAN,INT,INT,STRING,DOUBLE diff --git a/src/devkit-power-source.c b/src/devkit-power-source.c new file mode 100644 index 0000000..9172c59 --- /dev/null +++ b/src/devkit-power-source.c @@ -0,0 +1,593 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysfs-utils.h" +#include "devkit-power-source.h" +#include "devkit-power-marshal.h" + +/*--------------------------------------------------------------------------------------------------------------*/ +#include "devkit-power-source-glue.h" + +typedef enum { + DEVKIT_POWER_SOURCE_TYPE_LINE_POWER, + DEVKIT_POWER_SOURCE_TYPE_BATTERY, +} DevkitPowerSourceType; + +struct DevkitPowerSourcePrivate +{ + DBusGConnection *system_bus_connection; + DBusGProxy *system_bus_proxy; + DevkitPowerDaemon *daemon; + DevkitDevice *d; + + char *object_path; + char *native_path; + + guint poll_timer_id; + + char *vendor; + char *model; + char *serial; + GTimeVal update_time; + DevkitPowerSourceType type; + + gboolean line_power_online; + + double battery_energy; + double battery_energy_empty; + double battery_energy_empty_design; + double battery_energy_full; + double battery_energy_full_design; + double battery_energy_rate; + gint64 battery_time_to_empty; + gint64 battery_time_to_full; + double battery_percentage; + char *battery_technology; +}; + +static void devkit_power_source_class_init (DevkitPowerSourceClass *klass); +static void devkit_power_source_init (DevkitPowerSource *seat); +static void devkit_power_source_finalize (GObject *object); + +static gboolean update (DevkitPowerSource *source); + +enum +{ + PROP_0, + PROP_NATIVE_PATH, + PROP_VENDOR, + PROP_MODEL, + PROP_SERIAL, + PROP_UPDATE_TIME, + PROP_TYPE, + PROP_LINE_POWER_ONLINE, + PROP_BATTERY_ENERGY, + PROP_BATTERY_ENERGY_EMPTY, + PROP_BATTERY_ENERGY_EMPTY_DESIGN, + PROP_BATTERY_ENERGY_FULL, + PROP_BATTERY_ENERGY_FULL_DESIGN, + PROP_BATTERY_ENERGY_RATE, + PROP_BATTERY_TIME_TO_EMPTY, + PROP_BATTERY_TIME_TO_FULL, + PROP_BATTERY_PERCENTAGE, + PROP_BATTERY_TECHNOLOGY, +}; + +enum +{ + CHANGED_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (DevkitPowerSource, devkit_power_source, DEVKIT_TYPE_POWER_DEVICE) +#define DEVKIT_POWER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_POWER_SOURCE, DevkitPowerSourcePrivate)) + +static const char *devkit_power_source_get_object_path (DevkitPowerDevice *device); +static void devkit_power_source_removed (DevkitPowerDevice *device); +static gboolean devkit_power_source_changed (DevkitPowerDevice *device, + DevkitDevice *d, + gboolean synthesized); + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + DevkitPowerSource *source = DEVKIT_POWER_SOURCE (object); + + switch (prop_id) { + case PROP_NATIVE_PATH: + g_value_set_string (value, source->priv->native_path); + break; + case PROP_VENDOR: + g_value_set_string (value, source->priv->vendor); + break; + case PROP_MODEL: + g_value_set_string (value, source->priv->model); + break; + case PROP_SERIAL: + g_value_set_string (value, source->priv->serial); + break; + case PROP_UPDATE_TIME: + g_value_set_uint64 (value, source->priv->update_time.tv_sec); + break; + case PROP_TYPE: + g_value_set_string (value, source->priv->type == DEVKIT_POWER_SOURCE_TYPE_LINE_POWER + ? "line-power" : "battery"); + break; + + case PROP_LINE_POWER_ONLINE: + g_value_set_boolean (value, source->priv->line_power_online); + break; + + case PROP_BATTERY_ENERGY: + g_value_set_double (value, source->priv->battery_energy); + break; + case PROP_BATTERY_ENERGY_EMPTY: + g_value_set_double (value, source->priv->battery_energy_empty); + break; + case PROP_BATTERY_ENERGY_EMPTY_DESIGN: + g_value_set_double (value, source->priv->battery_energy_empty_design); + break; + case PROP_BATTERY_ENERGY_FULL: + g_value_set_double (value, source->priv->battery_energy_full); + break; + case PROP_BATTERY_ENERGY_FULL_DESIGN: + g_value_set_double (value, source->priv->battery_energy_full_design); + break; + case PROP_BATTERY_ENERGY_RATE: + g_value_set_double (value, source->priv->battery_energy_rate); + break; + case PROP_BATTERY_TIME_TO_EMPTY: + g_value_set_int64 (value, source->priv->battery_time_to_empty); + break; + case PROP_BATTERY_TIME_TO_FULL: + g_value_set_int64 (value, source->priv->battery_time_to_full); + break; + case PROP_BATTERY_PERCENTAGE: + g_value_set_double (value, source->priv->battery_percentage); + break; + + case PROP_BATTERY_TECHNOLOGY: + g_value_set_string (value, source->priv->battery_technology); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +devkit_power_source_class_init (DevkitPowerSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + DevkitPowerDeviceClass *device_class = DEVKIT_POWER_DEVICE_CLASS (klass); + + object_class->finalize = devkit_power_source_finalize; + object_class->get_property = get_property; + device_class->changed = devkit_power_source_changed; + device_class->removed = devkit_power_source_removed; + device_class->get_object_path = devkit_power_source_get_object_path; + + g_type_class_add_private (klass, sizeof (DevkitPowerSourcePrivate)); + + signals[CHANGED_SIGNAL] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + dbus_g_object_type_install_info (DEVKIT_TYPE_POWER_SOURCE, &dbus_glib_devkit_power_source_object_info); + + g_object_class_install_property ( + object_class, + PROP_NATIVE_PATH, + g_param_spec_string ("native-path", NULL, NULL, NULL, G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_VENDOR, + g_param_spec_string ("vendor", NULL, NULL, NULL, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_MODEL, + g_param_spec_string ("model", NULL, NULL, NULL, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_SERIAL, + g_param_spec_string ("serial", NULL, NULL, NULL, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_UPDATE_TIME, + g_param_spec_uint64 ("update-time", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_TYPE, + g_param_spec_string ("type", NULL, NULL, NULL, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_LINE_POWER_ONLINE, + g_param_spec_boolean ("line-power-online", NULL, NULL, FALSE, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY, + g_param_spec_double ("battery-energy", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY_EMPTY, + g_param_spec_double ("battery-energy-empty", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY_EMPTY_DESIGN, + g_param_spec_double ("battery-energy-empty-design", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY_FULL, + g_param_spec_double ("battery-energy-full", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY_FULL_DESIGN, + g_param_spec_double ("battery-energy-full-design", NULL, NULL, 0, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_ENERGY_RATE, + g_param_spec_double ("battery-energy-rate", NULL, NULL, -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_TIME_TO_EMPTY, + g_param_spec_int64 ("battery-time-to-empty", NULL, NULL, -1, G_MAXINT64, -1, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_TIME_TO_FULL, + g_param_spec_int64 ("battery-time-to-full", NULL, NULL, -1, G_MAXINT64, -1, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_PERCENTAGE, + g_param_spec_double ("battery-percentage", NULL, NULL, -1, 100, -1, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_BATTERY_TECHNOLOGY, + g_param_spec_string ("battery-technology", NULL, NULL, NULL, G_PARAM_READABLE)); +} + +static void +devkit_power_source_init (DevkitPowerSource *source) +{ + source->priv = DEVKIT_POWER_SOURCE_GET_PRIVATE (source); + source->priv->battery_time_to_empty = -1; + source->priv->battery_time_to_full = -1; +} + +static void +devkit_power_source_finalize (GObject *object) +{ + DevkitPowerSource *source; + + g_return_if_fail (object != NULL); + g_return_if_fail (DEVKIT_IS_POWER_SOURCE (object)); + + source = DEVKIT_POWER_SOURCE (object); + g_return_if_fail (source->priv != NULL); + + g_object_unref (source->priv->d); + g_object_unref (source->priv->daemon); + + g_free (source->priv->native_path); + + g_free (source->priv->vendor); + g_free (source->priv->model); + g_free (source->priv->serial); + + if (source->priv->poll_timer_id > 0) + g_source_remove (source->priv->poll_timer_id); + + G_OBJECT_CLASS (devkit_power_source_parent_class)->finalize (object); +} + +static char * +compute_object_path_from_basename (const char *native_path_basename) +{ + char *basename; + char *object_path; + unsigned int n; + + /* TODO: need to be more thorough with making proper object + * names that won't make D-Bus crash. This is just to cope + * with dm-0... + */ + basename = g_path_get_basename (native_path_basename); + for (n = 0; basename[n] != '\0'; n++) + if (basename[n] == '-') + basename[n] = '_'; + object_path = g_build_filename ("/sources/", basename, NULL); + g_free (basename); + + return object_path; +} + +static char * +compute_object_path (const char *native_path) +{ + char *basename; + char *object_path; + + basename = g_path_get_basename (native_path); + object_path = compute_object_path_from_basename (basename); + g_free (basename); + return object_path; +} + +static gboolean +register_power_source (DevkitPowerSource *source) +{ + DBusConnection *connection; + GError *error = NULL; + + source->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (source->priv->system_bus_connection == NULL) { + if (error != NULL) { + g_critical ("error getting system bus: %s", error->message); + g_error_free (error); + } + goto error; + } + connection = dbus_g_connection_get_connection (source->priv->system_bus_connection); + + source->priv->object_path = compute_object_path (source->priv->native_path); + + dbus_g_connection_register_g_object (source->priv->system_bus_connection, + source->priv->object_path, + G_OBJECT (source)); + + source->priv->system_bus_proxy = dbus_g_proxy_new_for_name (source->priv->system_bus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + return TRUE; + +error: + return FALSE; +} + +DevkitPowerSource * +devkit_power_source_new (DevkitPowerDaemon *daemon, DevkitDevice *d) +{ + DevkitPowerSource *source; + const char *native_path; + + source = NULL; + native_path = devkit_device_get_native_path (d); + + source = DEVKIT_POWER_SOURCE (g_object_new (DEVKIT_TYPE_POWER_SOURCE, NULL)); + source->priv->d = g_object_ref (d); + source->priv->daemon = g_object_ref (daemon); + source->priv->native_path = g_strdup (native_path); + + if (sysfs_file_exists (native_path, "online")) { + source->priv->type = DEVKIT_POWER_SOURCE_TYPE_LINE_POWER; + } else { + source->priv->type = DEVKIT_POWER_SOURCE_TYPE_BATTERY; + } + + if (!update (source)) { + g_object_unref (source); + source = NULL; + goto out; + } + + if (! register_power_source (DEVKIT_POWER_SOURCE (source))) { + g_object_unref (source); + source = NULL; + goto out; + } + +out: + return source; +} + +static void +emit_changed (DevkitPowerSource *source) +{ + g_print ("emitting changed on %s\n", source->priv->native_path); + g_signal_emit_by_name (source->priv->daemon, + "device-changed", + source->priv->object_path, + NULL); + g_signal_emit (source, signals[CHANGED_SIGNAL], 0); +} + +static gboolean +devkit_power_source_changed (DevkitPowerDevice *device, DevkitDevice *d, gboolean synthesized) +{ + DevkitPowerSource *source = DEVKIT_POWER_SOURCE (device); + gboolean keep_source; + + g_object_unref (source->priv->d); + source->priv->d = g_object_ref (d); + + keep_source = update (source); + + /* this 'change' event might prompt us to remove the source */ + if (!keep_source) + goto out; + + /* no, it's good .. keep it */ + emit_changed (source); + +out: + return keep_source; +} + +void +devkit_power_source_removed (DevkitPowerDevice *device) +{ +} + +static const char * +devkit_power_source_get_object_path (DevkitPowerDevice *device) +{ + DevkitPowerSource *source = DEVKIT_POWER_SOURCE (device); + return source->priv->object_path; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +static gboolean +update_line_power (DevkitPowerSource *source) +{ + source->priv->line_power_online = sysfs_get_int (source->priv->native_path, "online"); + return TRUE; +} + +static gboolean +update_battery (DevkitPowerSource *source) +{ + char *status; + gboolean is_charging; + gboolean is_discharging; + + /* TODO: this needs to handle lots of special cases when certain + * files exist, it needs to prefer _avg to _now etc. etc. etc. + * + * This is just a very quick hack for now. + */ + + status = g_strstrip (sysfs_get_string (source->priv->native_path, "status")); + is_charging = strcasecmp (status, "charging") == 0; + is_discharging = strcasecmp (status, "discharging") == 0; + + source->priv->battery_energy = + sysfs_get_double (source->priv->native_path, "energy_now") / 1000000.0; + source->priv->battery_energy_full = + sysfs_get_double (source->priv->native_path, "energy_full") / 1000000.0; + source->priv->battery_energy_full_design = + sysfs_get_double (source->priv->native_path, "energy_full_design") / 1000000.0; + source->priv->battery_energy_rate = + fabs (sysfs_get_double (source->priv->native_path, "current_now") / 1000000.0); + if (is_charging) + source->priv->battery_energy_rate *= -1.0; + + source->priv->battery_percentage = 100.0 * source->priv->battery_energy / source->priv->battery_energy_full; + if (source->priv->battery_percentage < 0) + source->priv->battery_percentage = 0; + if (source->priv->battery_percentage > 100.0) + source->priv->battery_percentage = 100.0; + + g_free (status); + return TRUE; +} + +static gboolean +_poll_battery (DevkitPowerSource *source) +{ + g_warning ("No updates on source %s for 30 seconds; forcing update", source->priv->native_path); + source->priv->poll_timer_id = 0; + update (source); + emit_changed (source); + return FALSE; +} + +static gboolean +update (DevkitPowerSource *source) +{ + gboolean ret; + + if (source->priv->poll_timer_id > 0) { + g_source_remove (source->priv->poll_timer_id); + source->priv->poll_timer_id = 0; + } + + /* initial values */ + if (source->priv->vendor == NULL) { + char *s; + + s = g_strstrip (sysfs_get_string (source->priv->native_path, "technology")); + if (strcmp (s, "Unknown") != 0) + source->priv->battery_technology = s; + else + g_free (s); + + source->priv->vendor = g_strstrip (sysfs_get_string (source->priv->native_path, "manufacturer")); + source->priv->model = g_strstrip (sysfs_get_string (source->priv->native_path, "model_name")); + source->priv->serial = g_strstrip (sysfs_get_string (source->priv->native_path, "serial_number")); + } + + g_get_current_time (&(source->priv->update_time)); + + switch (source->priv->type) { + case DEVKIT_POWER_SOURCE_TYPE_LINE_POWER: + ret = update_line_power (source); + break; + case DEVKIT_POWER_SOURCE_TYPE_BATTERY: + + ret = update_battery (source); + + /* Seems that we don't get change uevents from the + * kernel; set up a timer to poll + * + * TODO: perhaps only do this if running on battery. + */ + source->priv->poll_timer_id = g_timeout_add_seconds (30, (GSourceFunc) _poll_battery, source); + + break; + default: + g_assert_not_reached (); + break; + } + + return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +gboolean +devkit_power_source_refresh (DevkitPowerSource *power_source, + DBusGMethodInvocation *context) +{ + update (power_source); + dbus_g_method_return (context); + return TRUE; +} diff --git a/src/devkit-power-source.h b/src/devkit-power-source.h new file mode 100644 index 0000000..23ea648 --- /dev/null +++ b/src/devkit-power-source.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __DEVKIT_POWER_SOURCE_H__ +#define __DEVKIT_POWER_SOURCE_H__ + +#include +#include +#include + +#include "devkit-power-daemon.h" +#include "devkit-power-device.h" + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_POWER_SOURCE (devkit_power_source_get_type ()) +#define DEVKIT_POWER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_POWER_SOURCE, DevkitPowerSource)) +#define DEVKIT_POWER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_POWER_SOURCE, DevkitPowerSourceClass)) +#define DEVKIT_IS_POWER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_POWER_SOURCE)) +#define DEVKIT_IS_POWER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_POWER_SOURCE)) +#define DEVKIT_POWER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_POWER_SOURCE, DevkitPowerSourceClass)) + +typedef struct DevkitPowerSourcePrivate DevkitPowerSourcePrivate; + +typedef struct +{ + DevkitPowerDevice parent; + DevkitPowerSourcePrivate *priv; +} DevkitPowerSource; + +typedef struct +{ + DevkitPowerDeviceClass parent_class; +} DevkitPowerSourceClass; + +GType devkit_power_source_get_type (void); +DevkitPowerSource *devkit_power_source_new (DevkitPowerDaemon *daemon, + DevkitDevice *d); + +/* exported methods */ + +gboolean devkit_power_source_refresh (DevkitPowerSource *power_source, + DBusGMethodInvocation *context); + +G_END_DECLS + +#endif /* __DEVKIT_POWER_SOURCE_H__ */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ee15b87 --- /dev/null +++ b/src/main.c @@ -0,0 +1,157 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include + +#include +#include +#include + +#include "devkit-power-daemon.h" + +#define NAME_TO_CLAIM "org.freedesktop.DeviceKit.Power" + +static gboolean +acquire_name_on_proxy (DBusGProxy *bus_proxy) +{ + GError *error; + guint result; + gboolean res; + gboolean ret; + + ret = FALSE; + + if (bus_proxy == NULL) { + goto out; + } + + error = NULL; + res = dbus_g_proxy_call (bus_proxy, + "RequestName", + &error, + G_TYPE_STRING, NAME_TO_CLAIM, + G_TYPE_UINT, 0, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message); + g_error_free (error); + } else { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + goto out; + } + + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + if (error != NULL) { + g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message); + g_error_free (error); + } else { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + goto out; + } + + ret = TRUE; + + out: + return ret; +} + +int +main (int argc, char **argv) +{ + GError *error; + GMainLoop *loop; + DevkitPowerDaemon *power_daemon; + GOptionContext *context; + DBusGProxy *bus_proxy; + DBusGConnection *bus; + int ret; + static GOptionEntry entries [] = { + { NULL } + }; + + ret = 1; + + g_type_init (); + + context = g_option_context_new ("DeviceKit Power Daemon"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", error->message); + g_error_free (error); + goto out; + } + + bus_proxy = dbus_g_proxy_new_for_name (bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (bus_proxy == NULL) { + g_warning ("Could not construct bus_proxy object; bailing out"); + goto out; + } + + if (!acquire_name_on_proxy (bus_proxy) ) { + g_warning ("Could not acquire name; bailing out"); + goto out; + } + + g_debug ("Starting devkit-power-daemon version %s", VERSION); + + power_daemon = devkit_power_daemon_new (); + + if (power_daemon == NULL) { + goto out; + } + + loop = g_main_loop_new (NULL, FALSE); + + g_main_loop_run (loop); + + g_object_unref (power_daemon); + g_main_loop_unref (loop); + ret = 0; + +out: + return ret; +} diff --git a/src/org.freedesktop.DeviceKit.Power.Source.xml b/src/org.freedesktop.DeviceKit.Power.Source.xml new file mode 100644 index 0000000..a98dbbd --- /dev/null +++ b/src/org.freedesktop.DeviceKit.Power.Source.xml @@ -0,0 +1,228 @@ + +]> + + + + + + TODO: some explanatory text etc. etc. Mention that we + collect history to provide more precise values of + battery-time-to-empty, battery-time-to-full. Go into detail + with the algorithms. + + + TODO: do we need to export voltage and other things? Do we need to export raw data? + + + Unless otherwise noted, an empty string or the value 0 in a + property means not set. + + + + + + + + + + + + + + Refreshes the data collected from the power source. + + + Callers need the org.freedesktop.devicekit.power.refresh-power-source authorization + + if an error occured while refreshing + + + + + + + + + + + Some value on the power source changed. + + + + + + + + + + OS specific native path of the power source. On Linux this + is the sysfs path, for + example /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0. Is + blank if the device is being driven by a user space + driver. + + + + + + Name of the vendor of the battery. + + + + + + Name of the model of this battery. + + + + + + Unique serial number of the battery. + + + + + + The point in time (seconds since the Epoch Jan 1, 1970 + 0:00 UTC) that data was read from the power source. + + + + + + Type of power source. Known values are "battery" and "line-power". + + + + + + Whether power is currently being provided through line power. + This property is only valid if the property + type + has the value "line-power". + + + + + + Amount of energy (measured in Wh) currently available in + the power source. + + This property is only valid if the property + type + has the value "battery". + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered to be empty. + + This property is only valid if the property + type + has the value "battery". + + + + + + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered to be empty. + + This property is only valid if the property + type + has the value "battery". + + + + + + Amount of energy (measured in Wh) in the power source when + it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered full. + + This property is only valid if the property + type + has the value "battery". + + + + + + Amount of energy being drained from the source, measured + in W. If positive, the source is being discharged, if + negative it's being charged. + + This property is only valid if the property + type + has the value "battery". + + + + + + Number of seconds until the power source is considered empty. + Is set to -1 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + Number of seconds until the power source is considered full. + Is set to -1 if unknown. + + This property is only valid if the property + type + has the value "battery". + + + + + + The amount of energy left in the power source expressed as + a percentage between 0 and 100. Typically this is the same as + (battery-energy - + battery-energy-empty) / + (battery-energy-full - + battery-energy-empty). + However, some primitive power sources are capable of only + reporting percentages and in this case the battery-energy-* + properties will be unset while this property is set. + + This property is only valid if the property + type + has the value "battery". + + + + + + Technology used in the battery; known values are "Li-ion". + + This property is only valid if the property + type + has the value "battery". + + + + + + diff --git a/src/org.freedesktop.DeviceKit.Power.xml b/src/org.freedesktop.DeviceKit.Power.xml new file mode 100644 index 0000000..f206b56 --- /dev/null +++ b/src/org.freedesktop.DeviceKit.Power.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + An array of object paths for devices. + + + + + + Enumerate all disks on the system. + + + + + + + + + + Object path of device that was added. + + + + + + Emitted when a device is added. + + + + + + + + + + Object path of device that was removed. + + + + + + Emitted when a device is removed. + + + + + + + + + + Object path of device that was changed. + + + + + + Emitted when a device changed. + + + + + + + + + + diff --git a/src/sysfs-utils.c b/src/sysfs-utils.c new file mode 100644 index 0000000..0a06c2d --- /dev/null +++ b/src/sysfs-utils.c @@ -0,0 +1,203 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysfs-utils.h" + +double +sysfs_get_double (const char *dir, const char *attribute) +{ + double result; + char *contents; + char *filename; + + result = 0.0; + filename = g_build_filename (dir, attribute, NULL); + if (g_file_get_contents (filename, &contents, NULL, NULL)) { + result = atof (contents); + g_free (contents); + } + g_free (filename); + + + return result; +} + +gboolean +sysfs_file_contains (const char *dir, const char *attribute, const char *string) +{ + gboolean result; + char *filename; + char *s; + + result = FALSE; + + filename = g_build_filename (dir, attribute, NULL); + if (g_file_get_contents (filename, &s, NULL, NULL)) { + result = (strstr(s, string) != NULL); + g_free (s); + } + g_free (filename); + + return result; +} + +char * +sysfs_get_string (const char *dir, const char *attribute) +{ + char *result; + char *filename; + + result = NULL; + filename = g_build_filename (dir, attribute, NULL); + if (!g_file_get_contents (filename, &result, NULL, NULL)) { + result = g_strdup (""); + } + g_free (filename); + + return result; +} + +int +sysfs_get_int (const char *dir, const char *attribute) +{ + int result; + char *contents; + char *filename; + + result = 0; + filename = g_build_filename (dir, attribute, NULL); + if (g_file_get_contents (filename, &contents, NULL, NULL)) { + result = atoi (contents); + g_free (contents); + } + g_free (filename); + + + return result; +} + +guint64 +sysfs_get_uint64 (const char *dir, const char *attribute) +{ + guint64 result; + char *contents; + char *filename; + + result = 0; + filename = g_build_filename (dir, attribute, NULL); + if (g_file_get_contents (filename, &contents, NULL, NULL)) { + result = atoll (contents); + g_free (contents); + } + g_free (filename); + + + return result; +} + +gboolean +sysfs_file_exists (const char *dir, const char *attribute) +{ + gboolean result; + char *filename; + + result = FALSE; + filename = g_build_filename (dir, attribute, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) { + result = TRUE; + } + g_free (filename); + + return result; +} + +char * +_dupv8 (const char *s) +{ + const char *end_valid; + + if (!g_utf8_validate (s, + -1, + &end_valid)) { + g_warning ("The string '%s' is not valid UTF-8. Invalid characters begins at '%s'", s, end_valid); + return g_strndup (s, end_valid - s); + } else { + return g_strdup (s); + } +} + +char * +sysfs_resolve_link (const char *dir, const char *attribute) +{ + char *full_path; + char link_path[PATH_MAX]; + char resolved_path[PATH_MAX]; + ssize_t num; + gboolean found_it; + + found_it = FALSE; + + full_path = g_build_filename (dir, attribute, NULL); + + //g_warning ("attribute='%s'", attribute); + //g_warning ("full_path='%s'", full_path); + num = readlink (full_path, link_path, sizeof (link_path) - 1); + if (num != -1) { + char *absolute_path; + + link_path[num] = '\0'; + + //g_warning ("link_path='%s'", link_path); + absolute_path = g_build_filename (dir, link_path, NULL); + //g_warning ("absolute_path='%s'", absolute_path); + if (realpath (absolute_path, resolved_path) != NULL) { + //g_warning ("resolved_path='%s'", resolved_path); + found_it = TRUE; + } + g_free (absolute_path); + } + g_free (full_path); + + if (found_it) + return g_strdup (resolved_path); + else + return NULL; +} diff --git a/src/sysfs-utils.h b/src/sysfs-utils.h new file mode 100644 index 0000000..fc79137 --- /dev/null +++ b/src/sysfs-utils.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SYSFS_UTILS_H__ +#define __SYSFS_UTILS_H__ + +#include + +double sysfs_get_double (const char *dir, const char *attribute); +gboolean sysfs_file_contains (const char *dir, const char *attribute, const char *string); +char *sysfs_get_string (const char *dir, const char *attribute); +int sysfs_get_int (const char *dir, const char *attribute); +guint64 sysfs_get_uint64 (const char *dir, const char *attribute); +gboolean sysfs_file_exists (const char *dir, const char *attribute); +char *sysfs_resolve_link (const char *dir, const char *attribute); + +char *_dupv8 (const char *s); + +#endif /* __SYSFS_UTILS_H__ */ diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..237c46b --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,49 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + -I$(top_builddir)/src -I$(top_srcdir)/src \ + -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \ + -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_BIN_DIR=\""$(bindir)"\" \ + -DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ + -DPACKAGE_LIB_DIR=\""$(libdir)"\" \ + -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ + $(DBUS_GLIB_CFLAGS) \ + $(POLKIT_DBUS_CFLAGS) \ + $(GLIB_CFLAGS) + +BUILT_SOURCES = \ + devkit-power-daemon-glue.h \ + devkit-power-marshal.h devkit-power-marshal.c + +devkit-power-marshal.h: $(top_srcdir)/src/devkit-power-marshal.list + glib-genmarshal $< --prefix=devkit_power_marshal --header > $@ + +devkit-power-marshal.c: $(top_srcdir)/src/devkit-power-marshal.list + echo "#include \"devkit-power-marshal.h\"" > $@ && glib-genmarshal $< --prefix=devkit_power_marshal --body >> $@ + +devkit-power-daemon-glue.h: $(top_srcdir)/src/org.freedesktop.DeviceKit.Power.xml Makefile.am + dbus-binding-tool --prefix=devkit_power_daemon --mode=glib-client --output=devkit-power-daemon-glue.h $(top_srcdir)/src/org.freedesktop.DeviceKit.Power.xml + +bin_PROGRAMS = devkit-power + +devkit_power_SOURCES = \ + devkit-power.c \ + $(BUILT_SOURCES) + + +devkit_power_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"devkit-power\" \ + $(DISABLE_DEPRECATED) \ + $(AM_CPPFLAGS) + +devkit_power_LDADD = \ + $(DBUS_GLIB_LIBS) \ + $(POLKIT_DBUS_LIBS) + +CLEANFILES = $(BUILT_SOURCES) + +clean-local : + rm -f *~ $(service_DATA) $(dbusconf_DATA) diff --git a/tools/devkit-power.c b/tools/devkit-power.c new file mode 100644 index 0000000..de79957 --- /dev/null +++ b/tools/devkit-power.c @@ -0,0 +1,376 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "devkit-power-daemon-glue.h" +#include "devkit-power-marshal.h" + +static DBusGConnection *bus = NULL; +static DBusGProxy *power_proxy = NULL; +static GMainLoop *loop; + +static gboolean opt_enumerate = FALSE; +static gboolean opt_monitor = FALSE; +static gboolean opt_monitor_detail = FALSE; +static char *opt_show_info = FALSE; + +static gboolean do_monitor (void); +static void do_show_info (const char *object_path); + +static gboolean +polkit_dbus_gerror_parse (GError *error, + PolKitAction **action, + PolKitResult *result) +{ + gboolean ret; + const char *name; + + ret = FALSE; + if (error->domain != DBUS_GERROR || error->code != DBUS_GERROR_REMOTE_EXCEPTION) + goto out; + + name = dbus_g_error_get_name (error); + + ret = polkit_dbus_error_parse_from_strings (name, + error->message, + action, + result); +out: + return ret; +} + +static void +device_added_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data) +{ + g_print ("added: %s\n", object_path); + if (opt_monitor_detail) { + do_show_info (object_path); + g_print ("\n"); + } +} + +static void +device_changed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data) +{ + g_print ("changed: %s\n", object_path); + if (opt_monitor_detail) { + /* TODO: would be nice to just show the diff */ + do_show_info (object_path); + g_print ("\n"); + } +} + +static void +device_removed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data) +{ + g_print ("removed: %s\n", object_path); +} + +/* --- SUCKY CODE BEGIN --- */ + +/* This totally sucks; dbus-bindings-tool and dbus-glib should be able + * to do this for us. + */ + +typedef struct +{ + char *native_path; + char *vendor; + char *model; + char *serial; + guint64 update_time; + char *type; + gboolean line_power_online; + double battery_energy; + double battery_energy_empty; + double battery_energy_empty_design; + double battery_energy_full; + double battery_energy_full_design; + double battery_energy_rate; + gint64 battery_time_to_full; + gint64 battery_time_to_empty; + double battery_percentage; + char *battery_technology; +} DeviceProperties; + +static void +collect_props (const char *key, const GValue *value, DeviceProperties *props) +{ + gboolean handled = TRUE; + + if (strcmp (key, "native-path") == 0) + props->native_path = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "vendor") == 0) + props->vendor = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "model") == 0) + props->model = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "serial") == 0) + props->serial = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "update-time") == 0) + props->update_time = g_value_get_uint64 (value); + else if (strcmp (key, "type") == 0) + props->type = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "line-power-online") == 0) + props->line_power_online = g_value_get_boolean (value); + else if (strcmp (key, "battery-energy") == 0) + props->battery_energy = g_value_get_double (value); + else if (strcmp (key, "battery-energy-empty") == 0) + props->battery_energy_empty = g_value_get_double (value); + else if (strcmp (key, "battery-energy-empty-design") == 0) + props->battery_energy_empty_design = g_value_get_double (value); + else if (strcmp (key, "battery-energy-full") == 0) + props->battery_energy_full = g_value_get_double (value); + else if (strcmp (key, "battery-energy-full-design") == 0) + props->battery_energy_full_design = g_value_get_double (value); + else if (strcmp (key, "battery-energy-rate") == 0) + props->battery_energy_rate = g_value_get_double (value); + else if (strcmp (key, "battery-time-to-full") == 0) + props->battery_time_to_full = g_value_get_int64 (value); + else if (strcmp (key, "battery-time-to-empty") == 0) + props->battery_time_to_empty = g_value_get_int64 (value); + else if (strcmp (key, "battery-percentage") == 0) + props->battery_percentage = g_value_get_double (value); + else if (strcmp (key, "battery-technology") == 0) + props->battery_technology = g_strdup (g_value_get_string (value)); + else + handled = FALSE; + + if (!handled) + g_warning ("unhandled property '%s'", key); +} + +static DeviceProperties * +device_properties_get (DBusGConnection *bus, + const char *object_path) +{ + DeviceProperties *props; + GError *error; + GHashTable *hash_table; + DBusGProxy *prop_proxy; + const char *ifname = "org.freedesktop.DeviceKit.Power.Device"; + + props = g_new0 (DeviceProperties, 1); + + prop_proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.DeviceKit.Power", + object_path, + "org.freedesktop.DBus.Properties"); + error = NULL; + if (!dbus_g_proxy_call (prop_proxy, + "GetAll", + &error, + G_TYPE_STRING, + ifname, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + &hash_table, + G_TYPE_INVALID)) { + g_warning ("Couldn't call GetAll() to get properties for %s: %s", object_path, error->message); + g_error_free (error); + goto out; + } + + g_hash_table_foreach (hash_table, (GHFunc) collect_props, props); + + g_hash_table_unref (hash_table); + +out: + g_object_unref (prop_proxy); + return props; +} + +static void +device_properties_free (DeviceProperties *props) +{ + g_free (props->native_path); + g_free (props->vendor); + g_free (props->model); + g_free (props->serial); + g_free (props->type); + g_free (props->battery_technology); + g_free (props); +} + +/* --- SUCKY CODE END --- */ + +static gboolean +do_monitor (void) +{ + GError *error; + + g_print ("Monitoring activity from the power daemon. Press Ctrl+C to cancel.\n"); + + error = NULL; + + dbus_g_proxy_connect_signal (power_proxy, "DeviceAdded", + G_CALLBACK (device_added_signal_handler), NULL, NULL); + dbus_g_proxy_connect_signal (power_proxy, "DeviceRemoved", + G_CALLBACK (device_removed_signal_handler), NULL, NULL); + dbus_g_proxy_connect_signal (power_proxy, "DeviceChanged", + G_CALLBACK (device_changed_signal_handler), NULL, NULL); + g_main_loop_run (loop); + + return FALSE; +} + +static void +do_show_info (const char *object_path) +{ + DeviceProperties *props; + struct tm *time_tm; + time_t t; + char time_buf[256]; + + props = device_properties_get (bus, object_path); + + t = (time_t) props->update_time; + time_tm = localtime (&t); + strftime (time_buf, sizeof time_buf, "%c", time_tm); + + g_print ("Showing information for %s\n", object_path); + g_print (" native-path: %s\n", props->native_path); + g_print (" vendor: %s\n", props->vendor); + g_print (" model: %s\n", props->model); + g_print (" serial: %s\n", props->serial); + g_print (" updated: %s (%d seconds ago)\n", time_buf, (int) (time (NULL) - props->update_time)); + if (strcmp (props->type, "battery") == 0) { + g_print (" battery\n"); + g_print (" energy: %g Wh\n", props->battery_energy); + g_print (" energy-empty: %g Wh\n", props->battery_energy_empty); + g_print (" energy-empty-design: %g Wh\n", props->battery_energy_empty_design); + g_print (" energy-full: %g Wh\n", props->battery_energy_full); + g_print (" energy-full-design: %g Wh\n", props->battery_energy_full_design); + g_print (" energy-rate: %g W\n", props->battery_energy_rate); + g_print (" time to full: "); + if (props->battery_time_to_full >= 0) + g_print ("%d seconds\n", (int) props->battery_time_to_full); + else + g_print ("unknown\n"); + g_print (" time to empty: "); + if (props->battery_time_to_empty >= 0) + g_print ("%d seconds\n", (int) props->battery_time_to_empty); + else + g_print ("unknown\n"); + g_print (" percentage: %g%%\n", props->battery_percentage); + g_print (" technology: %s\n", props->battery_technology); + } else if (strcmp (props->type, "line-power") == 0) { + g_print (" line-power\n"); + g_print (" online: %s\n", props->line_power_online ? "yes" : "no"); + } else { + g_print (" unknown power source type '%s'\n", props->type); + } + device_properties_free (props); +} + +int +main (int argc, char **argv) +{ + int ret; + GOptionContext *context; + GError *error = NULL; + unsigned int n; + static GOptionEntry entries [] = { + { "enumerate", 0, 0, G_OPTION_ARG_NONE, &opt_enumerate, "Enumerate objects paths for devices", NULL }, + { "monitor", 0, 0, G_OPTION_ARG_NONE, &opt_monitor, "Monitor activity from the disk daemon", NULL }, + { "monitor-detail", 0, 0, G_OPTION_ARG_NONE, &opt_monitor_detail, "Monitor with detail", NULL }, + { "show-info", 0, 0, G_OPTION_ARG_STRING, &opt_show_info, "Show information about object path", NULL }, + { NULL } + }; + + ret = 1; + + g_type_init (); + + context = g_option_context_new ("DeviceKit-power 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); + + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", error->message); + g_error_free (error); + goto out; + } + + power_proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.DeviceKit.Power", + "/", + "org.freedesktop.DeviceKit.Power"); + dbus_g_proxy_add_signal (power_proxy, "DeviceAdded", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal (power_proxy, "DeviceRemoved", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal (power_proxy, "DeviceChanged", G_TYPE_STRING, G_TYPE_INVALID); + + if (opt_enumerate) { + GPtrArray *devices; + if (!org_freedesktop_DeviceKit_Power_enumerate_devices (power_proxy, &devices, &error)) { + g_warning ("Couldn't enumerate devices: %s", error->message); + g_error_free (error); + goto out; + } + for (n = 0; n < devices->len; n++) { + char *object_path = devices->pdata[n]; + g_print ("%s\n", object_path); + } + g_ptr_array_foreach (devices, (GFunc) g_free, NULL); + g_ptr_array_free (devices, TRUE); + } else if (opt_monitor || opt_monitor_detail) { + if (!do_monitor ()) + goto out; + } else if (opt_show_info != NULL) { + do_show_info (opt_show_info); + } + + ret = 0; + +out: + if (power_proxy != NULL) + g_object_unref (power_proxy); + if (bus != NULL) + dbus_g_connection_unref (bus); + + return ret; +}