diff options
author | David Zeuthen <davidz@redhat.com> | 2008-05-08 22:29:38 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2008-05-08 22:29:38 -0400 |
commit | 37f9df9b0568f9834452c949336783bf34e02ab9 (patch) | |
tree | 567a010da3aa10870c7f52f1c311a5e36bc9cc0f | |
download | upower-37f9df9b0568f9834452c949336783bf34e02ab9.tar.gz |
initial commit
42 files changed, 4941 insertions, 0 deletions
@@ -0,0 +1 @@ +David Zeuthen <davidz@redhat.com> @@ -0,0 +1,353 @@ +Copyright (C) 2008 David Zeuthen <david@fubar.dk> +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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +-- END GPLv2+ License --- + @@ -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 <joe@coder.org>" + +Coding Style +=== + + - Please follow the coding style already used. + + - Write docs for all functions and structs and so on. We use gtkdoc format. + + - All external interfaces (network protocols, file formats, etc.) + should have documented specifications sufficient to allow an + alternative implementation to be written. Our implementation should + be strict about specification compliance (should not for example + heuristically parse a file and accept not-well-formed + data). Avoiding heuristics is also important for security reasons; + if it looks funny, ignore it (or exit, or disconnect). 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 *~ @@ -0,0 +1,2 @@ +TODO: for now see doc/TODO + @@ -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 "<?xml version=\"1.0\"?>""<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">" > $@ + $(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 "<?xml version=\"1.0\"?>""<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">" > $@ + $(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 @@ +<!-- DTD for D-Bus Introspection Documentation --> + +<!ELEMENT doc (summary?,description?,errors?,permission?,since?,deprecated,seealso?)> + +<!ELEMENT summary (#PCDATA|ref)*> +<!ELEMENT description (#PCDATA|para|example)*> +<!ELEMENT errors (error)*> +<!ELEMENT permission (#PCDATA|ref|para)*> +<!ELEMENT since EMPTY> +<!ATTLIST since version CDATA #REQUIRED> +<!ELEMENT deprecated (#PCDATA|ref)> +<!ATTLIST deprecated version CDATA #REQUIRED> +<!ATTLIST deprecated instead CDATA #REQUIRED> +<!ELEMENT seealso (ref+)> + +<!ELEMENT error (#PCDATA|para)*> +<!ATTLIST error name CDATA #REQUIRED> +<!ELEMENT para (#PCDATA|example|code|list|ref)*> +<!ELEMENT example (#PCDATA|para|code|ref)*> +<!ATTLIST language (c|glib|python|shell) #REQUIRED> +<!ATTLIST title CDATA #IMPLIED> +<!ELEMENT list (item*)> +<!ATTLIST list type (bullet|number) #REQUIRED> +<!ELEMENT item (term|definition)*> +<!ELEMENT term (#PCDATA|ref)*> +<!ELEMENT definition (#PCDATA|para)*> + +<!ELEMENT code (#PCDATA)> +<!ATTLIST code lang CDATA #IMPLIED> +<!ELEMENT ref CDATA> +<!ATTLIST ref type (parameter|arg|signal|method|interface) #REQUIRED> +<!ATTLIST ref to CDATA #REQUIRED> 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 @@ +<?xml version='1.0'?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd" + exclude-result-prefixes="doc"> +<!-- + Convert D-Bus Glib xml into DocBook refentries + Copyright (C) 2007 William Jon McCann + License: GPL +--> +<xsl:output method="xml" indent="yes" encoding="UTF-8"/> + +<xsl:template match="/"> + +<xsl:variable name="interface" select="//interface/@name"/> +<xsl:variable name="basename"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="$interface"/> + </xsl:call-template> +</xsl:variable> + +<refentry><xsl:attribute name="id"><xsl:value-of select="$basename"/></xsl:attribute> + <refmeta> + <refentrytitle role="top_of_page"><xsl:value-of select="//interface/@name"/></refentrytitle> + </refmeta> + + <refnamediv> + <refname><xsl:value-of select="//interface/@name"/></refname> + <refpurpose><xsl:value-of select="$basename"/> interface</refpurpose> + </refnamediv> + + <refsynopsisdiv role="synopsis"> + <title role="synopsis.title">Methods</title> + <synopsis> + <xsl:call-template name="methods-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsynopsisdiv> + + <xsl:choose> + <xsl:when test="count(///signal) > 0"> + <refsect1 role="signal_proto"> + <title role="signal_proto.title">Signals</title> + <synopsis> + <xsl:call-template name="signals-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsect1> + </xsl:when> + </xsl:choose> + + <refsect1 role="impl_interfaces"> + <title role="impl_interfaces.title">Implemented Interfaces</title> + <para> + Objects implementing <xsl:value-of select="$interface"/> also implements + org.freedesktop.DBus.Introspectable, + org.freedesktop.DBus.Properties + </para> + </refsect1> + + <xsl:choose> + <xsl:when test="count(///property) > 0"> + <refsect1 role="properties"> + <title role="properties.title">Properties</title> + <synopsis> + <xsl:call-template name="properties-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsect1> + </xsl:when> + </xsl:choose> + + <refsect1 role="desc"> + <title role="desc.title">Description</title> + <para> + <xsl:apply-templates select="//interface/doc:doc"/> + </para> + </refsect1> + + <refsect1 role="details"> + <title role="details.title">Details</title> + <xsl:call-template name="method-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + + <xsl:choose> + <xsl:when test="count(///signal) > 0"> + <refsect1 role="signals"> + <title role="signals.title">Signal Details</title> + <xsl:call-template name="signal-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(///property) > 0"> + <refsect1 role="property_details"> + <title role="property_details.title">Property Details</title> + <xsl:call-template name="property-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + </xsl:when> + </xsl:choose> + +</refentry> +</xsl:template> + + +<xsl:template name="property-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + <xsl:apply-templates select="doc:doc/doc:permission"/> + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + + +<xsl:template name="property-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///property"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting>'<xsl:value-of select="@name"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="2"/></xsl:call-template> +<xsl:call-template name="property-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/></xsl:call-template></programlisting> + </refsect2> + + <xsl:call-template name="property-doc"/> + + </xsl:for-each> +</xsl:template> + +<xsl:template name="signal-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + <xsl:apply-templates select="doc:doc/doc:permission"/> + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + +<xsl:template name="signal-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///signal"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> + </refsect2> + + <xsl:call-template name="signal-doc"/> + + </xsl:for-each> +</xsl:template> + +<xsl:template match="doc:code"> +<programlisting> +<xsl:apply-templates /> +</programlisting> +</xsl:template> + +<xsl:template match="doc:tt"> + <literal> + <xsl:apply-templates /> + </literal> +</xsl:template> + +<xsl:template match="doc:i"> + <emphasis> + <xsl:apply-templates /> + </emphasis> +</xsl:template> + +<xsl:template match="doc:b"> + <emphasis role="bold"> + <xsl:apply-templates /> + </emphasis> +</xsl:template> + +<xsl:template match="doc:ulink"> + <ulink> + <xsl:attribute name="url"><xsl:value-of select="@url"/></xsl:attribute> + <xsl:value-of select="."/> + </ulink> +</xsl:template> + +<xsl:template match="doc:summary"> + <xsl:apply-templates /> +</xsl:template> + +<xsl:template match="doc:example"> +<informalexample> +<xsl:apply-templates /> +</informalexample> +</xsl:template> + +<xsl:template name="listitems-do-term"> + <xsl:param name="str"/> + <xsl:choose> + <xsl:when test="string-length($str) > 0"> + <emphasis role="bold"><xsl:value-of select="$str"/>: </emphasis> + </xsl:when> + </xsl:choose> +</xsl:template> + +<xsl:template name="do-listitems"> + <xsl:for-each select="doc:item"> + <listitem> + <xsl:call-template name="listitems-do-term"><xsl:with-param name="str" select="doc:term"/></xsl:call-template> + <xsl:apply-templates select="doc:definition"/> + </listitem> + </xsl:for-each> +</xsl:template> + +<xsl:template match="doc:list"> + <para> + <xsl:choose> + <xsl:when test="contains(@type,'number')"> + <orderedlist> + <xsl:call-template name="do-listitems"/> + </orderedlist> + </xsl:when> + <xsl:otherwise> + <itemizedlist> + <xsl:call-template name="do-listitems"/> + </itemizedlist> + </xsl:otherwise> + </xsl:choose> + </para> +</xsl:template> + +<xsl:template match="doc:para"> +<para> +<xsl:apply-templates /> +</para> +</xsl:template> + +<xsl:template match="doc:description"> +<xsl:apply-templates /> +</xsl:template> + +<xsl:template match="doc:since"> +<para role="since">Since <xsl:value-of select="@version"/> +</para> +</xsl:template> + +<xsl:template match="doc:deprecated"> + <xsl:variable name="name" select="../../@name"/> + <xsl:variable name="parent"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="../../../@name"/>/> + </xsl:call-template> + </xsl:variable> + + <xsl:variable name="type" select="name(../..)"/> + + <para role="deprecated"> + <warning><para><literal><xsl:value-of select="$name"/></literal> is deprecated since version <xsl:value-of select="@version"/> and should not be used in newly-written code. Use + + <xsl:variable name="to"> + <xsl:choose> + <xsl:when test="contains($type,'property')"> + <xsl:value-of select="$parent"/>:<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'signal')"> + <xsl:value-of select="$parent"/>::<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'method')"> + <xsl:value-of select="$parent"/>.<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'interface')"> + <xsl:value-of select="@instead"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@instead"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:call-template name="create-link"> + <xsl:with-param name="type" select="$type"/> + <xsl:with-param name="to" select="$to"/> + <xsl:with-param name="val" select="@instead"/> + </xsl:call-template> +instead.</para></warning> +</para> +</xsl:template> + +<xsl:template match="doc:permission"> +<para role="permission"> +<xsl:apply-templates /> +</para> +</xsl:template> + +<xsl:template match="doc:errors"> +<para role="errors"> +<xsl:apply-templates /> +</para> +</xsl:template> + +<xsl:template match="doc:seealso"> +<para> +See also: +<xsl:apply-templates /> + +</para> +</xsl:template> + +<xsl:template name="create-link"> + <xsl:param name="type"/> + <xsl:param name="to"/> + <xsl:param name="val"/> + + <xsl:choose> + <xsl:when test="contains($type,'property')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> + </xsl:when> + <xsl:when test="contains($type,'signal')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> + </xsl:when> + <xsl:when test="contains($type,'method')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><function><xsl:value-of select="$val"/></function></link> + </xsl:when> + <xsl:when test="contains($type,'interface')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link> + </xsl:when> + </xsl:choose> +</xsl:template> + +<xsl:template match="doc:ref"> + <xsl:call-template name="create-link"> + <xsl:with-param name="type" select="@type"/> + <xsl:with-param name="to" select="@to"/> + <xsl:with-param name="val" select="."/> + </xsl:call-template> +</xsl:template> + +<xsl:template name="method-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:apply-templates select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + + <xsl:choose> + <xsl:when test="count(doc:doc/doc:errors) > 0"> + <refsect3> + <title>Errors</title> + <variablelist role="errors"> + <xsl:for-each select="doc:doc/doc:errors/doc:error"> + <varlistentry> + <term><parameter><xsl:value-of select="@name"/></parameter>:</term> + <listitem><simpara><xsl:apply-templates select="."/></simpara></listitem> + </varlistentry> + </xsl:for-each> + </variablelist> + </refsect3> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(doc:doc/doc:permission) > 0"> + <refsect3> + <title>Permissions</title> + <xsl:apply-templates select="doc:doc/doc:permission"/> + </refsect3> + </xsl:when> + </xsl:choose> + + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + +<xsl:template name="method-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///method"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> ()</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="method-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> + </refsect2> + + <xsl:call-template name="method-doc"/> + + </xsl:for-each> +</xsl:template> + + +<xsl:template name="properties-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///property/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///property"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute>'<xsl:value-of select="@name"/>'</link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="$longest + 2"/></xsl:call-template> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="signals-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///signal/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///signal"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///signal"/></xsl:call-template>) +</xsl:for-each> +</xsl:template> + + +<xsl:template name="methods-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///method/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///method"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="method-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///method"/></xsl:call-template>) +</xsl:for-each> +</xsl:template> + + +<xsl:template name="method-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg"><xsl:value-of select="@direction"/> +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="4 - string-length(@direction)"/></xsl:call-template>'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> +<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="signal-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg">'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> +<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="property-args"><xsl:param name="indent"/> +<xsl:value-of select="@access"/><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="9 - string-length(@access) + 1"/></xsl:call-template>'<xsl:value-of select="@type"/>' +</xsl:template> + + +<xsl:template name="pad-spaces"> + <xsl:param name="width"/> + <xsl:variable name="spaces" xml:space="preserve"> </xsl:variable> + <xsl:value-of select="substring($spaces,1,$width)"/> +</xsl:template> + + +<xsl:template name="find-longest"> + <xsl:param name="set"/> + <xsl:param name="index" select="1"/> + <xsl:param name="longest" select="0"/> + + <xsl:choose> + <xsl:when test="$index > count($set)"> + <!--finished looking--> + <xsl:value-of select="$longest"/> + </xsl:when> + <xsl:when test="string-length($set[$index])>$longest"> + <!--found new longest--> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="$set"/> + <xsl:with-param name="index" select="$index + 1"/> + <xsl:with-param name="longest" select="string-length($set[$index])"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!--this isn't any longer--> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="$set"/> + <xsl:with-param name="index" select="$index + 1"/> + <xsl:with-param name="longest" select="$longest"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + + +<xsl:template name="interface-basename"> + <xsl:param name="str"/> + <xsl:choose> + <xsl:when test="contains($str,'.')"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="substring-after($str,'.')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$str"/> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +</xsl:stylesheet> 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 @@ +<?xml version="1.0"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +<!ENTITY version SYSTEM "version.xml"> +]> +<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> + <bookinfo> + <title>DeviceKit-power Reference Manual</title> + <releaseinfo>Version &version;</releaseinfo> + <authorgroup> + <author> + <firstname>David</firstname> + <surname>Zeuthen</surname> + <affiliation> + <address> + <email>david@fubar.dk</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2008</year> + <holder>The DeviceKit-power Authors</holder> + </copyright> + + <legalnotice> + <para> + Permission is granted to copy, distribute and/or modify this + document under the terms of the <citetitle>GNU Free + Documentation License</citetitle>, Version 1.1 or any later + version published by the Free Software Foundation with no + Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. You may obtain a copy of the <citetitle>GNU Free + Documentation License</citetitle> from the Free Software + Foundation by visiting <ulink type="http" + url="http://www.fsf.org">their Web site</ulink> or by writing + to: + + <address> + The Free Software Foundation, Inc., + <street>59 Temple Place</street> - Suite 330, + <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>, + <country>USA</country> + </address> + </para> + + <para> + Many of the names used by companies to distinguish their + products and services are claimed as trademarks. Where those + names appear in any 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. + </para> + </legalnotice> + </bookinfo> + + <reference id="ref-dbus"> + <title>D-Bus API Reference</title> + <partintro> + <para> + This part documents the D-Bus interface used to access the + DeviceKit-power daemon. + </para> + </partintro> + <xi:include href="dbus/org.freedesktop.DeviceKit.Power.ref.xml"/> + <xi:include href="dbus/org.freedesktop.DeviceKit.Power.Source.ref.xml"/> + </reference> + + <reference id="tools-fileformats"> + <title>Manual Pages</title> + <partintro> + <para> + This part contains the manual pages distributed with DeviceKit-power. + </para> + </partintro> + <xi:include href="man/DeviceKit-power.xml"/> + <xi:include href="man/devkit-power-daemon.xml"/> + <xi:include href="man/devkit-power.xml"/> + </reference> + + <index> + <title>Index</title> + </index> + + <!-- License --> + + <appendix id="license"> + <title>License</title> + <para> +<programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../COPYING" parse="text"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting> + </para> + </appendix> +</book> 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 @@ +<refentry id="DeviceKit-power.7"> + <refentryinfo> + <title>DeviceKit-power</title> + <date>March 2008</date> + <productname>DeviceKit-power</productname> + </refentryinfo> + + <refmeta> + <refentrytitle>DeviceKit-power</refentrytitle> + <manvolnum>7</manvolnum> + <refmiscinfo class="version"></refmiscinfo> + </refmeta> + + <refnamediv> + <refname>DeviceKit-power</refname> + <refpurpose>System-wide Power Management</refpurpose> + </refnamediv> + + <refsect1><title>DESCRIPTION</title> + <para> + DeviceKit-power provides an interface to enumerate power sources + on the system and control system-wide power management. Any + application can access + the <emphasis>org.freedesktop.DeviceKit.Power</emphasis> service + on the system message bus. Some operations (such as suspending + the system) is restricted using PolicyKit. + </para> + </refsect1> + + <refsect1><title>AUTHOR</title> + <para> + Written by David Zeuthen <email>david@fubar.dk</email> with + a lot of help from many others. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + <para> + Please send bug reports to either the distribution or the + hal mailing list, + see <ulink url="http://lists.freedesktop.org/mailman/listinfo/hal"/>. + to subscribe. + </para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + <para> + <citerefentry> + <refentrytitle>DeviceKit</refentrytitle><manvolnum>7</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>PolicyKit</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>devkit-power-daemon</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>devkit-power</refentrytitle><manvolnum>1</manvolnum> + </citerefentry> + </para> + </refsect1> +</refentry> 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 @@ +<refentry id="devkit-power-daemon.8"> + <refentryinfo> + <title>devkit-power-daemon</title> + <date>April 2008</date> + <productname>devkit-power-daemon</productname> + </refentryinfo> + + <refmeta> + <refentrytitle>devkit-power-daemon</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo class="version"></refmiscinfo> + </refmeta> + + <refnamediv> + <refname>devkit-power-daemon</refname> + <refpurpose>DeviceKit-power Daemon</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>devkit-power-daemon</command> + <arg><option>--help</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + + + <refsect1><title>DESCRIPTION</title> + <para> + <emphasis><refentrytitle>devkit-power-daemon</refentrytitle></emphasis> provides + the <emphasis>org.freedesktop.DeviceKit.Power</emphasis> service on the + system message bus. Users or administrators should never need to + start this daemon as it will be automatically started by + <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry> + whenever an application calls into the <emphasis>org.freedesktop.DeviceKit.Power</emphasis> + service. + </para> + </refsect1> + + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>--help</option></term> + <listitem> + <para> + Show help options. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1><title>AUTHOR</title> + <para> + Written by David Zeuthen <email>david@fubar.dk</email> with + a lot of help from many others. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + <para> + Please send bug reports to either the distribution or the + hal mailing list, + see <ulink url="http://lists.freedesktop.org/mailman/listinfo/hal"/> + on how to subscribe. + </para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + <para> + <citerefentry> + <refentrytitle>DeviceKit-power</refentrytitle><manvolnum>7</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>devkit-power</refentrytitle><manvolnum>1</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum> + </citerefentry>, + </para> + </refsect1> +</refentry> 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 @@ +<refentry id="devkit-power.1"> + <refentryinfo> + <title>devkit-power</title> + <date>April 2008</date> + <productname>devkit-power</productname> + </refentryinfo> + + <refmeta> + <refentrytitle>devkit-power</refentrytitle> + <manvolnum>1</manvolnum> + <refmiscinfo class="version"></refmiscinfo> + </refmeta> + + <refnamediv> + <refname>devkit-power</refname> + <refpurpose>DeviceKit-power command line tool</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>devkit-power</command> + <arg><option>--enumerate</option></arg> + <arg><option>--monitor</option></arg> + <arg><option>--monitor-detail</option></arg> + <arg><option>--help</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + + + <refsect1><title>DESCRIPTION</title> + <para> + <emphasis><refentrytitle>devkit-power</refentrytitle></emphasis> is a + simple command line client for the + <citerefentry><refentrytitle>DeviceKit-power</refentrytitle><manvolnum>7</manvolnum></citerefentry> + daemon. TODO: not fully documented. + </para> + </refsect1> + + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>--monitor</option></term> + <listitem> + <para> + Connect to the DeviceKit-power daemon and print a line + every time a power source is added, removed or changed. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--monitor-detail</option></term> + <listitem> + <para> + Like <option>--monitor</option> but prints the full + details of the power source whenever an event happens. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>--help</option></term> + <listitem> + <para> + Show help options. + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1><title>AUTHOR</title> + <para> + Written by David Zeuthen <email>david@fubar.dk</email> with + a lot of help from many others. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + <para> + Please send bug reports to either the distribution or the + hal mailing list, + see <ulink url="http://lists.freedesktop.org/mailman/listinfo/hal"/> + on how to subscribe. + </para> + </refsect1> + + <refsect1> + <title>SEE ALSO</title> + <para> + <citerefentry> + <refentrytitle>devkit-power-daemon</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>DeviceKit-power</refentrytitle><manvolnum>7</manvolnum> + </citerefentry>, + </para> + </refsect1> +</refentry> 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 <friedman@prep.ai.mit.edu> +# 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 --- /dev/null +++ b/po/ChangeLog 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 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!DOCTYPE policyconfig PUBLIC + "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" + "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd"> + +<!-- +Policy definitions for DeviceKit-power + +Copyright (c) 2008 David Zeuthen <david@fubar.dk> + +NOTE: If you make changes to this file, make sure to validate the file +using the polkit-policy-file-validate(1) tool. Changes made to this +file are instantly applied. +--> + +<policyconfig> + <vendor>The DeviceKit-power Project</vendor> + <vendor_url>http://hal.freedesktop.org/docs/DeviceKit-power/</vendor_url> + <icon_name>system-suspend</icon_name> + + <action id="org.freedesktop.devicekit.power.suspend"> + <_description>Suspend the system to RAM</_description> + <_message>Authentication is required to suspend to system</_message> + <defaults> + <allow_any>no</allow_any> + <allow_inactive>no</allow_inactive> + <allow_active>yes</allow_active> + </defaults> + </action> + +</policyconfig> 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 <david@fubar.dk> + * + * 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 <string.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <glib-object.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <devkit-gobject.h> + +#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 <david@fubar.dk> + * + * 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 <glib-object.h> +#include <polkit-dbus/polkit-dbus.h> +#include <dbus/dbus-glib.h> + +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 <david@fubar.dk> + * + * 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 <string.h> + +#include <glib.h> +#include <glib/gstdio.h> +#include <glib/gi18n-lib.h> +#include <glib-object.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <devkit-gobject.h> +#include <polkit-dbus/polkit-dbus.h> + +#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 <david@fubar.dk> + * + * 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 <glib-object.h> +#include <polkit-dbus/polkit-dbus.h> +#include <devkit-gobject.h> + +#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 <david@fubar.dk> + * + * 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 <string.h> +#include <math.h> + +#include <glib.h> +#include <glib/gstdio.h> +#include <glib/gi18n-lib.h> +#include <glib-object.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <devkit-gobject.h> +#include <polkit-dbus/polkit-dbus.h> + +#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 <david@fubar.dk> + * + * 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 <glib-object.h> +#include <polkit-dbus/polkit-dbus.h> +#include <devkit-gobject.h> + +#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 <david@fubar.dk> + * + * 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 <string.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <glib-object.h> + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <devkit-gobject.h> + +#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 @@ +<!DOCTYPE node PUBLIC +"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ + <!ENTITY ERROR_GENERAL "org.freedesktop.DeviceKit.Disks.Power.Source.GeneralError"> +]> +<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + <interface name="org.freedesktop.DeviceKit.Power.Source"> + <doc:doc> + <doc:description> + <doc:para> + 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. + </doc:para> + <doc:para> + TODO: do we need to export voltage and other things? Do we need to export raw data? + </doc:para> + <doc:para> + Unless otherwise noted, an empty string or the value 0 in a + property means not set. + </doc:para> + </doc:description> + </doc:doc> + + + <!-- ************************************************************ --> + + <method name="Refresh"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + + <doc:doc> + <doc:description> + <doc:para> + Refreshes the data collected from the power source. + </doc:para> + </doc:description> + <doc:permission>Callers need the org.freedesktop.devicekit.power.refresh-power-source authorization</doc:permission> + <doc:errors> + <doc:error name="&ERROR_GENERAL;">if an error occured while refreshing</doc:error> + </doc:errors> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <signal name="Changed"> + <doc:doc> + <doc:description> + <doc:para> + Some value on the power source changed. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <property name="native-path" type="s" access="read"> + <doc:doc><doc:description><doc:para> + OS specific native path of the power source. On Linux this + is the sysfs path, for + example <doc:tt>/sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT0</doc:tt>. Is + blank if the device is being driven by a user space + driver. + </doc:para></doc:description></doc:doc> + </property> + + <property name="vendor" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Name of the vendor of the battery. + </doc:para></doc:description></doc:doc> + </property> + + <property name="model" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Name of the model of this battery. + </doc:para></doc:description></doc:doc> + </property> + + <property name="serial" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Unique serial number of the battery. + </doc:para></doc:description></doc:doc> + </property> + + <property name="update-time" type="t" access="read"> + <doc:doc><doc:description><doc:para> + The point in time (seconds since the Epoch Jan 1, 1970 + 0:00 UTC) that data was read from the power source. + </doc:para></doc:description></doc:doc> + </property> + + <property name="type" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Type of power source. Known values are "battery" and "line-power". + </doc:para></doc:description></doc:doc> + </property> + + <property name="line-power-online" type="b" access="read"> + <doc:doc><doc:description><doc:para> + Whether power is currently being provided through line power. + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "line-power". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy (measured in Wh) currently available in + the power source. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy-empty" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy (measured in Wh) in the power source when + it's considered to be empty. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy-empty-design" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered to be empty. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy-full" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy (measured in Wh) in the power source when + it's considered full. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy-full-design" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy (measured in Wh) the power source is + designed to hold when it's considered full. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-energy-rate" type="d" access="read"> + <doc:doc><doc:description><doc:para> + Amount of energy being drained from the source, measured + in W. If positive, the source is being discharged, if + negative it's being charged. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-time-to-empty" type="x" access="read"> + <doc:doc><doc:description><doc:para> + Number of seconds until the power source is considered empty. + Is set to -1 if unknown. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-time-to-full" type="x" access="read"> + <doc:doc><doc:description><doc:para> + Number of seconds until the power source is considered full. + Is set to -1 if unknown. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-percentage" type="d" access="read"> + <doc:doc><doc:description><doc:para> + The amount of energy left in the power source expressed as + a percentage between 0 and 100. Typically this is the same as + (<doc:ref type="property" to="Source:battery-energy">battery-energy</doc:ref> - + <doc:ref type="property" to="Source:battery-energy-empty">battery-energy-empty</doc:ref>) / + (<doc:ref type="property" to="Source:battery-energy-full">battery-energy-full</doc:ref> - + <doc:ref type="property" to="Source:battery-energy-empty">battery-energy-empty</doc:ref>). + 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. + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + <property name="battery-technology" type="s" access="read"> + <doc:doc><doc:description><doc:para> + Technology used in the battery; known values are "Li-ion". + </doc:para><doc:para> + This property is only valid if the property + <doc:ref type="property" to="Source:type">type</doc:ref> + has the value "battery". + </doc:para></doc:description></doc:doc> + </property> + + </interface> + +</node> 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 @@ +<!DOCTYPE node PUBLIC +"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + + <interface name="org.freedesktop.DeviceKit.Power"> + + <!-- ************************************************************ --> + + <method name="EnumerateDevices"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <arg name="devices" direction="out" type="ao"> + <doc:doc><doc:summary>An array of object paths for devices.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Enumerate all disks on the system. + </doc:para> + </doc:description> + </doc:doc> + </method> + + <!-- ************************************************************ --> + + <signal name="DeviceAdded"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was added.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device is added. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="DeviceRemoved"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was removed.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device is removed. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + <signal name="DeviceChanged"> + <arg name="device" type="o"> + <doc:doc><doc:summary>Object path of device that was changed.</doc:summary></doc:doc> + </arg> + + <doc:doc> + <doc:description> + <doc:para> + Emitted when a device changed. + </doc:para> + </doc:description> + </doc:doc> + </signal> + + <!-- ************************************************************ --> + + </interface> + +</node> 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 <david@fubar.dk> + * + * 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <fcntl.h> +#include <pwd.h> +#include <grp.h> +#include <linux/fs.h> +#include <sys/ioctl.h> + +#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 <david@fubar.dk> + * + * 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 <glib.h> + +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 <david@fubar.dk> + * + * 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pwd.h> +#include <grp.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <glib-object.h> + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <polkit-dbus/polkit-dbus.h> + +#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; +} |