wmacpi-2.4/0000755000207400020740000000000013653534554012212 5ustar azazelazazelwmacpi-2.4/ChangeLog0000644000207400020740000004040513653534554013767 0ustar azazelazazel2020 May 3 2.4 Fix some resource leaks. Fix a link failure with gcc-10. Fix UAF's and reading of uninitialized buffer. Remove header. Define version once in Makefile. 2014 November 23 2.3 Remove trailing whitespace. Remove deprecated /usr/X11R6/include directory from CFLAGS. Merge clean and clean-all targets in Makefile. Respect DESTDIR variable in Makefile, e.g., for package creation. Fix -Wunused-result and -Wunused-but-set-variable compiler warnings. 2014 August 18 2.2 Remove VCS files from source. Manpage installation location now follows Filesystem Hierarchy Standards. Rename acpi to wmacpi-cli to avoid conflict with the acpi binary that ships with acpiclient (http://sourceforge.net/projects/acpiclient). Allow additional flags to be appended to CFLAGS and/or LDFLAGS during build. Now maintained by the Window Maker Developers Team . Git repository: git clone git://repo.or.cz/dockapps.git 2009 August 10 2.2rc5 Small Makefile fix to allow compiling on newer GCCs, supplied Michael Shigorin of ALT Linux. 2008 November 14 2.2rc4 Change the way that we sleep/wait for activity, to use select rather than a fixed-length sleep, supplied by Julien Blache of Debian: Hi, The attached patch for wmacpi makes it use select() instead of sleeping. It also adjusts the timeout of the select() call depending on the blink & scroll options. If scrolling is not activated, there's no reason to wake up 10x/sec. If blinking is activated, waking up once per second is enough. If blinking is not activated, then we can wake up just to update the data and we're fine. With scrolling and blinking disabled, this saves a number of wakeups and helps battery life. Unfortunately there's another source of wakeups that's probably due to libdockapp that still makes 6 wakeups/seconds (in another thread it seems). With this patch wmacpi makes a best effort to match the sample rate set by the user, but that's hardly an issue I think. I haven't released this patch yet in Debian, so if you like it and want to roll out a release, feel free :) Otherwise I'll add it to the package soon. Thanks, JB. 2008 March 18 2.2rc3 Some fixes for the sysfs interface support, supplied by jblache@debian.org: > Okay, I finally found time to make a new release including this > patch - 2.2rc2. It's up on my website now. I don't remember sending you the updated patch, as it turned out that you can have different attributes in sysfs depending on what the battery reports. The current version is attached. Thanks, JB. 2008 March 14 2.2rc2 Support for the sysfs interface that became mandatory with kernel 2.6.24 (patch supplied by jblache@debian.org). A number of graphics fixes also from jblache@debian.org. Removed support for hardware reported critical battery status. 2007 July 14 2.2rc1 Major changes to command line handling and to the way we use libdockapp, courtesy of Patrice Dumas. This should hopefully fix several long-standing bugs with non-wmaker window managers (in particular Debian bugs #280495 and 293546). Updated to support newer kernels that no longer support /proc/acpi/info - thanks to Samuel Ortiz. Fixed a longstanding issue with redrawing - thanks to Vito Caputo. This version changes a number of command line options (little used ones, but they're still incompatible changes) due to the libdockapp work. In particular, -w becomes -x, -v becomes -V (and takes an argument rather than being repeated), and -V becomes -v (thanks to libdockapp grabbing -h, -v and -w for itself). Also, long options are now supported for everything in wmacpi (but not acpi, since it doesn't use libdockapp for command line parsing). 2007 January 10 2.2a1 Added a patch from Patrice Dumas to support newer versions of libdockapp. Updated email address in AUTHORS and manpages. 2005 February 2 2.1 Finalised libdockapp-0.5.0 port - no changes from 2.1rc1. 2005 Jan 5 2.1rc1 Typo fix in the manpage. Ported to libdockapp-0.5.0 - all this needed was changing the type of the dockapp width and height to unsigned short. 2004 October 24 2.0 Upped version number to 2.0. Small typo fixes. wmacpi 2.0 goes gold . . . 2004 September 28 2.0rc1 Added support for switching to capacity mode automatically, on detecting dodgy reports from the battery. Added support for capacity mode on charging, with automatic enabling as per discharging. Various cleanups. Hopefully last release before the final 2.0. 2004 August 18 1.99r7 Implemented the libdockapp port - this seems to close Debian bug #227819, but it hasn't received sufficient testing. Implemented a capacity mode for calculating time remaining (as opposed to the normal current rate mode) - this mode samples the remaining capacity of the battery and notes the time at which it was sampled, and uses a history of samples to estimate the rate of drain on the battery. From there it calculates a value for time remaining. Also, various cleanups have gone in: * a reworking of the scrolling code * generic battery number support (rather than just using two pixmaps, one for b1 and one for b2) * stopped the battery glyph from blinking when running on AC 2004 July 19 1.99r6 Fix for Debian bug #250792 - the parser for the acpi files was too stupid to deal with error conditions. I've now added some basic checking to make it handle the error that caused the bug report, but I'll need to add more later. 2004 April 23 1.99r5 Collected fixes for the collected fixes below . . . * Manpage fixes, to reflect the reality of the current code. * Code cleanups, to make a few things more sensible. Most notably, the interface for setting the samplerate has changed so that it's no longer inverted and illogical - you now say how many times you want to sample per minute. * Fixed an issue with initialisation - I'd moved the power_init() call below the options parsing code, without dealing with the -m option properly. The end result was that if you told it to monitor a battery number, it would fail saying the battery didn't exist. I moved the check for this out of the options parsing and after the power_init() call. * Fixed a leaking file descriptor in init_ac_adapters. * Implemented a way to handle changing batteries - reinitialise the battery info periodically. I don't know of a better way to do that, since we'd have to do all that parsing anyway to find out if it had changed . . . libdockapp is waiting, but I think that's the only change left without more bug repots . . . 2004 April 15 1.99r4 Collected fixes for various small issues. * Fixed a problem with placement of the window when using the click to place mode - turned out to be a sizehints problem. * Some fixes to the manpage. * Reenabled the CLI build by default - the Debian patches can handle disabling it themselves. * Added a way to disable the scrolling message, since some users find this annoying. I've left the big changes that are needed (like using libdockapp, in the hope that it'll solve the docking problems) until later, so that I can get these smaller fixes out. Hopefully soon . . . 2004 January 12 1.99r3 . . . and a fix for a fix that didn't fix it . . . 2004 January 12 1.99r2 Some cleanups and bugfixes found by the wonderful Debian users. It's finally in testing! 2003 November 23 1.99 Finally claimed the wmacpi name as my own . . . Renamed wmacpi-ng and acpi-ng, renamed the header files, fixed up the makefile. For the Debian package, also made compilation of the command line tool optional, defaulting to not building it. This is because after the renaming, my acpi clashes with the acpi package that's already in Debian. The command line functionality is now accessible via the -w option to wmacpi. This is wmacpi 1.99, so that I can have a release packaged and in Debian before going to 2.0, so that any bugs that are left can be found by all the extra users. 2003 September 26 0.99 Fix the last of the old wmacpi code oddities (specifically, the APMInfo struct, which was a completely inappropriate name given we no longer deal with APM, and because of the various code refactoring). I think this is probably as good as I can make it without getting more feedback and the like, so I'm going to make this version 0.99, preliminary to either wmacpi-ng 1.0 or wmacpi 2.0 (depending which direction I go with that). 2003 September 23 0.92 Fix a few more bugs, and include an option to allow the user to specify how often to sample the ACPI data - some BIOSes disable all interrupts while reading from the battery, which apparently causes some interactivity issues. I have no idea why reading once every three seconds (which is our default), but there've been some complaints. Also fixed acpi-ng to properly handle the -a option. 2003 August 6 0.91 Fix a problem I'm seeing with docking the app - if the window name is set to "acpi" rather than "apm" it doesn't dock . . . 2003 July 16 0.90 Make the time display show '--:--' instead of '00:00' when the time remaining is 0 - I think this is reasonable, since it'll only get into this state when the present rate value is 0. This only happens when the battery is fully charged and neither discharging or charging, or when the battery is completely drained. In any of these states the time remaining is of very little interest, so we don't lose anything. We also get to handle the (sadly, very common) case where the ACPI subsystem doesn't report sane values for the things we depend on. 2003 July 11 0.50a2 Make the time display show nothing (as opposed to 00:00) when the time remaining is unknown, as requested by Emma Jane Hogbin. Respect the critical level specified on the command line, and add a new message to differentiate between the command line critical level and the critical state reported by the battery. Speed up the message scrolling, so that there isn't quite such a painful delay between repeats. Also, up the speed when the battery is low, more when it's critical, and scroll continuously when it's hardware critical. Finally, add support for disabling the blinking power and battery glyphs from the command line, as requested by Sebastian Henschel. We still blink the battery glyph when the battery reports hardware critical level - I think that's worth being a bit annoying about. Also, added an acpi-ng manpage. 2003 July 11 0.50a1 Properly fix the AC adapter issue - it's not much use adding the infrastructure and then forgetting to fix the code that uses it. Fix the time disiplay so that it doesn't try to display values greater than 99:59, since the display area won't fit anything beyond that. 2003 July 10 0.50a Bugfixes, to handle two problems: the case where something like the present rate or some such is "unknown" (reported initially by Emma Jane Hogbin, and where the AC adapter is called something other than "AC" (reported by Sebastian Henschel). This an 'a' release because I can't test these myself . . . 2003 July 6 0.50 Finally got rid of that annoying button - that space now contains a 'B 1' or 'B 2' (only those two at present, since I'm too lazy to fix it so that the number is generic. It should work fine for anyone who doesn't have a freakish system with more than two batteries . . .) A few more code cleanups. 2003 July 1 0.19 libacpi cleanups and reworking - we now handle the charging battery case properly, it seems. Also, some attempts to make error printing a bit cleaner; still a long way to go on that, though . . . 2003 June 24 0.15 Removed process_plugin_timer(), since it was doing nothing useful at all . . . 2003 June 23 0.14 Removed libapm.c - wmacpi-ng is specifically for ACPI, with no APM support. 2003 June 23 0.13 Some more code cleanups, designed to move libacpi to more of a library than something built into wmacpi-ng. This is useful with the seperate programs, though at present it's not used much. 2003 June 21 0.12 Added a command line tool, acpi-ng to query battery status from the command line. 2003 May 30 0.11 Implemented multiple battery support, and averaging of the samples in an attempt to even out the jumpiness of the timer. 2003 May 30 0.10 More major code cleanups: in particular the handling of the power panel and the message has been cleaned up so that it's actually sane and clean. Next step from here is to actually implement handling of multiple batteries, so that if there's a fully charge second battery available it reports the correct time remaining (based on the present rate of power consumption and the sum of the two battery's remaining capacities). 2003 May 29 0.3 Some major reworking of the internals, to help fix the handling of multiple batteries and such things. 2003 May 26 0.2a Code cleanups to fix various problems with corner cases. 2003 May 26 0.2 Added support for multiple batteries: I took the simple route of displaying only one battery per instance - to do more I'd need to hack with the display code, and I'm not ready for that yet. Added a -m option to specify the battery number to monitor. 2003 May 26 0.1 Changed package completely, to support the new ACPI code as of 2.4.21-rc2. Since this code hasn't been touched in more than a year, I figure I might as well have a go at hacking on it . . . -- Simon Fowler, 2002 Feb 17 1.34 Updated ACPI statistics gathering code for the latest ACPI patch from Intel. Now uses/checks for subsystem version 20020214+. Redone the version check a little bit. 2001 Apr 29 1.33 Little fix to ACPI version check so that I don't have to make a new version each time a new kernel comes out 2001 Mar 24 1.32 Split ACPI and APM portions in different source files Added power_init() function - handles checking subsystem presence, version, etc. Enumerates batteries in ACPI implementation ACPI: Beginnings of multiple battery support - not fully implemented ACPI: Get the battery ID from /proc/acpi/battery instead of hard-coding it in - also helps with multi battery stuff Added some stupid command line help Added -c option to set critical battery alarm level. Defaults to 10 percent, and added -b option to make noise when this critical level is reached APM: Updated for critical alarm stuff Made a 20 color "low" quality pixmap for machines running 8bit displays Updated README with some stuff, made separate INSTALL file 2001 Mar 13 1.31 Update for intel ACPI release version 20010313 Minor updates for new /proc layout 2001 Mar 07 1.3 Update for intel ACPI release verion 20010302 Proc format changed a little bit, so updates were necessary. Added a check for specific acpi subsystem version - since each new version seems to have a new interface, better be safe than sorry :) As usual, please test and report to me. This ONLY works with linux acpica 20010302. Download this version from http://developer.intel.com/technology/iapc/acpi/downloads.htm - it's a patch against 2.4.2 2001 Feb 28 1.21 Finally read through the ACPI specification. Hah, they had all my questions answered :) Thus, Confirmed remaining percentage formula (correct) Now calculate "time remaining" according to the spec formula Removed "battery load" hack since we now have "time remaining" Fixed bug in display_percentage (10% didn't display right) Released version 1.21 2001 Feb 23 1.2 Added support for ACPI. This is very untested, and not very clean. This has been tested on machines with only ONE battery, and only with kernel 2.4.2 (that's where ACPI started to work for me) Added some hackery to do with ACPI. Check README. Released 1.2 2001 Jan 16 1.1 Fixed all the stuff so that wmapm works as advertised: Fixed dumb bug where after charging was done new message didn't scroll. Added support for fucked APM bioses that display stuff wrong. (See README to learn how to enable it. Obviously, it's disabled by default) Reorganized apminfo structure and got rid of redundancy. Reorganized acquire_apm_info. All APM data is processed there. Fixed display_state to do the Right Thing. Fixed red blinking button to actually blink on critical battery, and to stop when it isn't critical anymore. I don't think it ever worked right in 1.0. Created ChangeLog. Updated README. Released 1.1. wmacpi-2.4/wmacpi.c0000644000207400020740000006470013653534554013645 0ustar azazelazazel/* apm/acpi dockapp - phear it 1.34 * Copyright (C) 2000, 2001, 2002 timecop@japan.co.jp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "libacpi.h" /* main pixmap */ #ifdef LOW_COLOR #include "master_low.xpm" static char **master_xpm = master_low_xpm; #else #include "master.xpm" #endif static int battery_no; /* Do NOT change the BASE_PERIOD without reading the code ... */ #define BASE_PERIOD 100000 /* base period, 100 ms (in usecs) */ struct dockapp { int x_fd; /* X11 fd */ Display *display; /* display */ Window win; /* main window */ Pixmap pixmap; /* main pixmap */ Pixmap mask; /* mask pixmap */ Pixmap text; /* pixmap for text scroller */ unsigned short width; /* width of pixmap */ unsigned short height; /* height of pixmap */ int screen; /* current screen */ int tw; /* text width inside text pixmap */ int update; /* need to redraw? */ int blink; /* should we blink the LED? (critical battery) */ int bell; /* bell on critical low, or not? */ int scroll; /* scroll message text? */ int scroll_reset; /* reset the scrolling text */ int percent; int period_length; /* length of the polling period, multiple of BASE_PERIOD */ }; /* globals */ struct dockapp *dockapp; /* global_t *globals; */ /* this gives us a variable scroll rate, depending on the importance of the * message . . . */ #define DEFAULT_SCROLL_RESET 150; int scroll_reset = DEFAULT_SCROLL_RESET; /* copy a chunk of pixmap around the app */ static void copy_xpm_area(int x, int y, int w, int h, int dx, int dy) { XCopyArea(DADisplay, dockapp->pixmap, dockapp->pixmap, DAGC, x, y, w, h, dx, dy); dockapp->update = 1; } /* display AC power symbol */ static void display_power_glyph(void) { copy_xpm_area(67, 38, 12, 7, 6, 17); } /* get rid of AC power symbol */ static void kill_power_glyph(void) { copy_xpm_area(67, 48, 12, 7, 6, 17); } /* display battery symbol */ static void display_battery_glyph(void) { copy_xpm_area(82, 38, 12, 7, 20, 17); } /* get rid of battery symbol */ static void kill_battery_glyph(void) { copy_xpm_area(82, 48, 12, 7, 20, 17); } /* clear the time display */ static void clear_time_display(void) { copy_xpm_area(114, 76, 31, 11, 7, 32); } /* set time display to -- -- */ static void invalid_time_display(void) { copy_xpm_area(122, 14, 31, 11, 7, 32); } static void reset_scroll(void) { dockapp->scroll_reset = 1; } static void clear_text_area(void) { copy_xpm_area(66, 9, 52, 7, 6, 50); } static void redraw_window(void) { if (dockapp->update) { XCopyArea(dockapp->display, dockapp->pixmap, dockapp->win, DAGC, 0, 0, 64, 64, 0, 0); dockapp->update = 0; } } static void new_window(char *display, char *name, int argc, char **argv) { XSizeHints *hints; /* Initialise the dockapp window and appicon */ DAOpenDisplay(display, argc, argv); DACreateIcon(name, 64, 64, argc, argv); dockapp->display = DADisplay; dockapp->x_fd = XConnectionNumber(dockapp->display); dockapp->win = DAWindow; XSelectInput(dockapp->display, dockapp->win, ExposureMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); /* create the main pixmap . . . */ DAMakePixmapFromData(master_xpm, &dockapp->pixmap, &dockapp->mask, &dockapp->width, &dockapp->height); DASetPixmap(dockapp->pixmap); DASetShape(dockapp->mask); /* text area is 318x7, or 53 characters long */ dockapp->text = XCreatePixmap(dockapp->display, dockapp->win, 318, 7, DefaultDepth(dockapp->display, dockapp->screen)); if (!dockapp->text) { pfatal("FATAL: Cannot create text scroll pixmap!\n"); exit(1); } /* force the window to stay this size - otherwise the user could * resize us and see our panties^Wmaster pixmap . . . */ hints = XAllocSizeHints(); if(hints) { hints->flags |= PMinSize | PMaxSize; hints->min_width = 64; hints->max_width = 64; hints->min_height = 64; hints->max_height = 64; XSetWMNormalHints(dockapp->display, dockapp->win, hints); XFree(hints); } DAShow(); } static void copy_to_text_buffer(int sx, int sy, int w, int h, int dx, int dy) { XCopyArea(dockapp->display, dockapp->pixmap, dockapp->text, DAGC, sx, sy, w, h, dx, dy); } static void copy_to_text_area(int sx, int sy, int w, int h, int dx, int dy) { XCopyArea(dockapp->display, dockapp->text, dockapp->pixmap, DAGC, sx, sy, w, h, dx, dy); } static void scroll_text(void) { static int start, end, stop; int x = 6; /* x coord of the start of the text area */ int y = 50; /* y coord */ int width = 51; /* width of the text area */ int height = 7; /* height of the text area */ int tw = dockapp->tw; /* width of the rendered text */ int sx, dx, w; if (!dockapp->scroll) return; /* * Conceptually this is viewing the text through a scrolling * window - the window starts out with the end immediately before * the text, and stops when the start of the window is immediately * after the end of the text. * * We begin with the start of the window at pixel (0 - width) and * as we scroll we render only the portion of the window above * pixel 0. The destination of the copy during this period starts * out at the end of the text area and works left as more of the * text is being copied, until a full window is being copied. * * As the end of the window moves out past the end of the text, we * want to keep the destination at the beginning of the text area, * but copy a smaller and smaller chunk of the text. Eventually the * start of the window will scroll past the end of the text, at * which point we stop doing any work and wait to be reset. */ if (dockapp->scroll_reset) { start = 0 - width; end = 0; stop = 0; clear_text_area(); dockapp->scroll_reset = 0; } if (stop) return; w = 52; if (end < 52) w = end; else if (end > tw) w = 52 - (end - tw); dx = x + 52 - w; if (end > tw) dx = x; sx = start; if (start < 0) sx = 0; if (start > tw) stop = 1; clear_text_area(); copy_to_text_area(sx, 0, w, height, dx, y); start += 2; end += 2; dockapp->update = 1; } static void render_text(char *string) { int i, c, k; /* drop out immediately if scrolling is disabled - we don't render * any text at all, since there's not much else we could do * sensibly without scrolling. */ if (!dockapp->scroll) return; if (strlen(string) > 53) return; /* prepare the text area by clearing it */ for (i = 0; i < 54; i++) { copy_to_text_buffer(133, 57, 6, 8, i * 6, 0); } k = 0; for (i = 0; string[i]; i++) { c = toupper(string[i]); if (c >= 'A' && c <= 'Z') { /* letter */ c = c - 'A'; copy_to_text_buffer(c * 6, 67, 6, 7, k, 0); } else if (c >= '0' && c <= '9') { /* number */ c = c - '0'; copy_to_text_buffer(c * 6 + 66, 58, 6, 7, k, 0); } else if (c == '.') { copy_to_text_buffer(140, 58, 6, 7, k, 0); } else if (c == '-') { copy_to_text_buffer(126, 58, 6, 7, k, 0); } k += 6; } dockapp->tw = k; /* length of text segment */ /* re-scroll the message */ reset_scroll(); scroll_text(); } static void clear_percentage(void) { /* clear the number */ copy_xpm_area(95, 47, 21, 9, 37, 16); /* clear the bar */ copy_xpm_area(66, 18, 54, 8, 5, 5); dockapp->percent = -1; } static void display_percentage(int percent) { unsigned int bar; int width = 54; /* width of the bar */ float ratio = 100.0/width; /* ratio between the current percentage * and the number of pixels in the bar */ if (percent == -1) percent = 0; if (dockapp->percent == percent) return; if (percent < 0) percent = 0; if (percent > 100) percent = 100; if (dockapp->percent == -1) copy_xpm_area(127, 28, 5, 7, 52, 17); if (percent < 100) { /* 0 - 99 */ copy_xpm_area(95, 48, 8, 7, 37, 17); if (percent >= 10) copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 40, 17); copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 46, 17); } else copy_xpm_area(95, 37, 21, 9, 37, 16); /* 100% */ dockapp->percent = percent; bar = (int)((float)percent / ratio); copy_xpm_area(66, 0, bar, 8, 5, 5); if (bar < 54) copy_xpm_area(66 + bar, 18, 54 - bar, 8, bar + 5, 5); } static void display_time(int minutes) { static int ohour = -1, omin = -1; int hour, min, tmp; if (minutes <= 0) { /* error - clear the display */ invalid_time_display(); ohour = omin = -1; return; } /* render time on the display */ hour = minutes / 60; /* our display area only fits %2d:%2d, so we need to make sure * what we're displaying will fit in those constraints. I don't * think we're likely to see any batteries that do more than * 100 hours any time soon, so it's fairly safe. */ if (hour >= 100) { hour = 99; min = 59; } else min = minutes % 60; if (hour == ohour && min == omin) return; tmp = hour / 10; copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 7, 32); tmp = hour % 10; copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 14, 32); tmp = min / 10; copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 25, 32); tmp = min % 10; copy_xpm_area(tmp * 7 + 1, 76, 6, 11, 32, 32); copy_xpm_area(71, 76, 3, 11, 21, 32); ohour = hour; omin = min; } /* * The reworked state handling stuff. */ /* set the current state of the power panel */ enum panel_states { PS_AC, PS_BATT, PS_NULL, }; static void really_blink_power_glyph(void) { static int counter = 0; if (counter == 10) display_power_glyph(); else if (counter == 20) kill_power_glyph(); else if (counter > 30) counter = 0; counter += dockapp->period_length; } static void blink_power_glyph(void) { if (dockapp->blink) really_blink_power_glyph(); } static void really_blink_battery_glyph(void) { static int counter = 0; if (counter == 10) display_battery_glyph(); else if (counter == 20) kill_battery_glyph(); else if (counter > 30) counter = 0; counter += dockapp->period_length; } static void blink_battery_glyph(void) { if (dockapp->blink) really_blink_battery_glyph(); } static void set_power_panel(global_t *globals) { static enum panel_states power = PS_NULL; battery_t *binfo = globals->binfo; adapter_t *ap = &globals->adapter; if (ap->power == AC) { if (power != PS_AC) { power = PS_AC; kill_battery_glyph(); display_power_glyph(); } } else if (ap->power == BATT) { if (power != PS_BATT) { power = PS_BATT; kill_power_glyph(); display_battery_glyph(); } } if (globals->battery_count > 0) { if (binfo->charge_state == CHARGE) blink_power_glyph(); if ((binfo->state == CRIT) && (ap->power == BATT)) blink_battery_glyph(); } } void scroll_faster(double factor) { scroll_reset = scroll_reset * factor; } void scroll_slower(double factor) { scroll_reset = scroll_reset * factor; } void reset_scroll_speed(void) { scroll_reset = DEFAULT_SCROLL_RESET; } /* * The message that needs to be displayed needs to be decided * according to a heirarchy: a message like not present needs to take * precedence over a global thing like the current power status, and * something like a low battery warning should take precedence over * the "on battery" message. Likewise, a battery charging message * needs to take precedence over the on ac power message. The other * question is how much of a precedence local messages should take * over global ones . . . * * So, there are three possible sets of messages: not present, on-line * and off-line messages. We need to decide which of those sets is * appropriate right now, and then decide within them. */ enum messages { M_NB, /* no batteries */ M_NP, /* not present */ M_AC, /* on ac power */ M_CH, /* battery charging */ M_BATT, /* on battery */ M_LB, /* low battery */ M_CB, /* critical low battery */ M_HCB, /* battery reported critical capacity state */ M_NULL, /* empty starting state */ }; static void set_message(global_t *globals) { static enum messages state = M_NULL; battery_t *binfo = globals->binfo; adapter_t *ap = &globals->adapter; if (globals->battery_count == 0) { if (state != M_NB) { state = M_NB; reset_scroll_speed(); render_text("no batteries"); } return; } /* battery not present case */ if (!binfo->present) { if (state != M_NP) { state = M_NP; reset_scroll_speed(); render_text("not present"); } } else if (ap->power == AC) { if (binfo->charge_state == CHARGE) { if (state != M_CH) { state = M_CH; reset_scroll_speed(); render_text("battery charging"); } } else { if (state != M_AC) { state = M_AC; reset_scroll_speed(); render_text("on ac power"); } } } else { if (binfo->state == CRIT) { if (state != M_CB) { state = M_CB; scroll_faster(0.75); render_text("critical low battery"); } } else if (binfo->state == LOW) { if (state != M_LB) { state = M_LB; scroll_faster(0.85); render_text("low battery"); } } else { if (state != M_BATT) { state = M_BATT; reset_scroll_speed(); render_text("on battery"); } } } } void set_time_display(global_t *globals) { if (globals->battery_count == 0) { invalid_time_display(); return; } if (globals->binfo->charge_state == CHARGE) display_time(globals->binfo->charge_time); else if (globals->binfo->charge_state == DISCHARGE) display_time(globals->rtime); else invalid_time_display(); } void clear_batt_id_area(void) { copy_xpm_area(125, 40, 7, 11, 51, 32); } void set_batt_id_area(int bno) { int w = 7; /* Width of the number */ int h = 11; /* Height of the number */ int dx = 50; /* x coord of the target area */ int dy = 32; /* y coord of the target area */ int sx = (bno + 1) * 7; /* source x coord */ int sy = 76; /* source y coord */ copy_xpm_area(sx, sy, w, h, dx, dy); } #define VERSION "wmacpi version " WMACPI_VER "\nUsing libacpi version " LIBACPI_VER void cli_wmacpi(global_t *globals, int samples) { int i, j, sleep_time = 0; battery_t *binfo; adapter_t *ap; pdebug("samples: %d\n", samples); if(samples > 1) sleep_time = 1000000/samples; /* we want to acquire samples over some period of time, so . . . */ for(i = 0; i < samples + 2; i++) { for(j = 0; j < globals->battery_count; j++) acquire_batt_info(globals, j); acquire_global_info(globals); usleep(sleep_time); } ap = &globals->adapter; if(ap->power == AC) { printf("On AC Power"); for(i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if(binfo->present && (binfo->charge_state == CHARGE)) { printf("; Battery %s charging", binfo->name); printf(", currently at %2d%%", binfo->percentage); if(binfo->charge_time >= 0) printf(", %2d:%02d remaining", binfo->charge_time/60, binfo->charge_time%60); } } printf("\n"); } else if(ap->power == BATT) { printf("On Battery"); for(i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if(binfo->present && (binfo->percentage >= 0)) printf(", Battery %s at %d%%", binfo->name, binfo->percentage); } if(globals->rtime >= 0) printf("; %d:%02d remaining", globals->rtime/60, globals->rtime%60); printf("\n"); } return; } battery_t *switch_battery(global_t *globals, int battno) { globals->binfo = &batteries[battno]; pinfo("changing to monitor battery %s\n", globals->binfo->name); set_batt_id_area(battno); dockapp->update = 1; return globals->binfo; } int main(int argc, char **argv) { char *display = NULL; int sample_count = 0; int batt_reinit, ac_reinit; int batt_count = 0; int ac_count = 0; int cli = 0, samples = 1, critical = 10; int samplerate = 20; int scroll_count = 0; enum rtime_mode rt_mode = RT_RATE; int rt_forced = 0; battery_t *binfo = NULL; global_t *globals; fd_set fds; struct timeval tv_rate; struct timeval tv = {0, 0}; DAProgramOption options[] = { {"-r", "--no-scroll", "disable scrolling message", DONone, False, {NULL}}, {"-n", "--no-blink", "disable blinking of various UI elements", DONone, False, {NULL}}, {"-x", "--cmdline", "run in command line mode", DONone, False, {NULL}}, {"-f", "--force-capacity-mode", "force the use of capacity mode for calculating time remaining", DONone, False, {NULL}}, {"-d", "--display", "display or remote display", DOString, False, {&display}}, {"-c", "--critical", "set critical low alarm at percent\n (default: 10 percent)", DONatural, False, {&critical}}, {"-m", "--battery", "battery number to monitor", DONatural, False, {&battery_no}}, {"-s", "--sample-rate", "number of times per minute to sample battery information\n default 20 (once every three seconds)", DONatural, False, {&samplerate}}, {"-V", "--verbosity", "Set verbosity", DONatural, False, {&verbosity}}, {"-a", "--samples", "number of samples to average over (cli mode only)", DONatural, False, {&samples}}, }; dockapp = calloc(1, sizeof(struct dockapp)); globals = calloc(1, sizeof(global_t)); dockapp->blink = 1; dockapp->bell = 0; dockapp->scroll = 1; dockapp->scroll_reset = 0; globals->crit_level = 10; battery_no = 1; /* after this many samples, we reinit the battery and AC adapter * information. * XXX: make these configurable . . . */ batt_reinit = 100; ac_reinit = 1000; /* this needs to be up here because we need to know what batteries * are available /before/ we can decide if the battery we want to * monitor is available. */ /* parse command-line options */ DAParseArguments(argc, argv, options, 10, "A battery monitor dockapp for ACPI based systems", VERSION); if (options[0].used) dockapp->scroll = 0; if (options[1].used) dockapp->blink = 0; if (options[2].used) cli = 1; if (options[3].used) { rt_mode = RT_CAP; rt_forced = 1; } if (samplerate == 0) samplerate = 1; if (samplerate > 600) samplerate = 600; /* convert to number of base periods */ samplerate = ((60 * 1000000) / samplerate) / BASE_PERIOD; if (!dockapp->scroll) { if (!dockapp->blink) { /* Adapt the period to the sample rate */ tv_rate.tv_usec = samplerate * BASE_PERIOD; tv_rate.tv_sec = tv_rate.tv_usec / 1000000; tv_rate.tv_usec = tv_rate.tv_usec - (tv_rate.tv_sec * 1000000); dockapp->period_length = samplerate; } else { /* blinking is every second */ tv_rate.tv_sec = 1; /* BASE_PERIOD * 10 = 1 sec */ tv_rate.tv_usec = 0; dockapp->period_length = 10; } } else { /* scrolling is every BASE_PERIOD (100 ms) */ tv_rate.tv_sec = 0; tv_rate.tv_usec = BASE_PERIOD; dockapp->period_length = 1; } if (critical > 100) { fprintf(stderr, "Please use values between 0 and 100%%\n"); fprintf(stderr, "Using default value of 10%%\n"); critical = 10; } globals->crit_level = critical; if (battery_no >= MAXBATT) { fprintf(stderr, "Please specify a battery number below %d\n", MAXBATT); return 1; } pinfo("Monitoring battery %d\n", battery_no); if (power_init(globals)) /* power_init functions handle printing error messages */ exit(1); globals->rt_mode = rt_mode; globals->rt_forced = rt_forced; if (battery_no > globals->battery_count) { pinfo("Battery %d not available for monitoring.\n", battery_no); } /* check for cli mode */ if (cli) { cli_wmacpi(globals, samples); exit(0); } /* check to see if we've got a valid DISPLAY env variable, as a simple check to see if * we're running under X */ if (!getenv("DISPLAY")) { pdebug("Not running under X - using cli mode\n"); cli_wmacpi(globals, samples); exit(0); } battery_no--; /* make new dockapp window */ /* Don't even /think/ of asking me why, but if I set the window name to * "acpi", the app refuses to dock properly - it's just plain /weird/. * So, wmacpi it is . . . */ new_window(display, "wmacpi", argc, argv); /* get initial statistics */ acquire_all_info(globals); if (globals->battery_count > 0) { binfo = &batteries[battery_no]; globals->binfo = binfo; set_batt_id_area(battery_no); pinfo("monitoring battery %s\n", binfo->name); } clear_time_display(); set_power_panel(globals); set_message(globals); /* main loop */ while (1) { Atom atom; Atom wmdelwin; XEvent event; while (XPending(dockapp->display)) { XNextEvent(dockapp->display, &event); switch (event.type) { case Expose: /* update */ dockapp->update = 1; while (XCheckTypedEvent(dockapp->display, Expose, &event)); redraw_window(); break; case DestroyNotify: XCloseDisplay(dockapp->display); exit(0); break; case ButtonPress: break; case ButtonRelease: if (globals->battery_count == 0) break; /* cycle through the known batteries. */ battery_no++; battery_no = battery_no % globals->battery_count; binfo = switch_battery(globals, battery_no); break; case ClientMessage: /* what /is/ this crap? * Turns out that libdockapp adds the WM_DELETE_WINDOW atom to * the WM_PROTOCOLS property for the window, which means that * rather than get a simple DestroyNotify message, we get a * nice little message from the WM saying "hey, can you delete * yourself, pretty please?". So, when running as a window * rather than an icon, we're impossible to kill in a friendly * manner, because we're expecting to die from a DestroyNotify * and thus blithely ignoring the WM knocking on our window * border . . . * * This simply checks for that scenario - it may fail oddly if * something else comes to us via a WM_PROTOCOLS ClientMessage * event, but I suspect it's not going to be an issue. */ wmdelwin = XInternAtom(dockapp->display, "WM_DELETE_WINDOW", 1); atom = event.xclient.data.l[0]; if (atom == wmdelwin) { XCloseDisplay(dockapp->display); exit(0); } break; } } /* XXX: some laptops have problems with sampling the battery * regularly - apparently, the BIOS disables interrupts while * reading from the battery, which is generally on a slow bus * and is a slow device, so you get significant periods without * interrupts. This causes interactivity to suffer . . . * * So, the workaround/fix for this is to sample at a much * lower rate than we may update/refresh/expose/whatever. The * user specifies how many times they want us to sample per * minute; we use select() on our X events fd to wake up when * there's some display work to be done, with the timeout set * to whatever the time between samples is. When we hit our * select() timeout we update our samples, otherwise we update * the display. * * Note that this has a wrinkle when blinking and/or scrolling * is enabled, since we need to update the display more * frequently than we sample (most likely). In that case we * set the timeout based on the display update cycle. */ /* have we completed our timeout, or were we woken up early? */ if ((tv.tv_sec != 0) || (tv.tv_usec != 0)) goto win_update; tv = tv_rate; sample_count += dockapp->period_length; if (sample_count >= samplerate) { if (globals->battery_count == 0) { batt_count = 0; reinit_batteries(globals); /* battery appeared */ if (globals->battery_count > 0) { if (battery_no > globals->battery_count) battery_no = 0; binfo = switch_battery(globals, battery_no); } } acquire_all_info(globals); /* we need to be able to reinitialise batteries and adapters, because * they change - you can hotplug batteries on most laptops these days * and who knows what kind of shit will be happening soon . . . */ if (batt_count++ >= batt_reinit) { if(reinit_batteries(globals)) pfatal("Oh my god, the batteries are gone!\n"); batt_count = 0; } if (ac_count++ >= ac_reinit) { if(reinit_ac_adapters(globals)) pfatal("What happened to our AC adapters?!?\n"); ac_count = 0; } sample_count = 0; } if (scroll_count++ >= scroll_reset) { reset_scroll(); scroll_count = 0; } /* The old code had some kind of weird crap with timers and the like. * As far as I can tell, it's meaningless - the time we want to display * is the time calculated from the remaining capacity, as per the * ACPI spec. The only thing I'd change is the handling of a charging * state: my best guess, based on the behaviour I'm seeing with my * Lifebook, is that the present rate value when charging is the rate * at which the batteries are being charged, which would mean I'd just * need to reverse the rtime calculation to be able to work out how * much time remained until the batteries were fully charged . . . * That would be rather useful, though given it would vary rather a lot * it seems likely that it'd be little more than a rough guesstimate. */ set_time_display(globals); set_power_panel(globals); set_message(globals); if (globals->battery_count == 0) { clear_percentage(); clear_batt_id_area(); } else display_percentage(binfo->percentage); scroll_text(); win_update: /* redraw_window, if anything changed */ redraw_window(); FD_ZERO(&fds); FD_SET(dockapp->x_fd, &fds); select(FD_SETSIZE, &fds, NULL, NULL, &tv); } return 0; } wmacpi-2.4/COPYING0000644000207400020740000004325413653534554013255 0ustar azazelazazel GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. wmacpi-2.4/AUTHORS0000644000207400020740000000124713653534554013266 0ustar azazelazazelSimon Fowler Complete rewriting of the code from wmacpi-1.34. timecop timecop@japan.co.jp all the code Daniel Pittman sent some suggestions and a patch for a broken APM implementations. version 1.1 includes his patch in a modified form Michael G. Henderson some weird dude who generated a lot of random noise about my dockapp and forced me to change the name to wmacpi. general asshole. portions of master.xpm that i was too lazy to draw (the plug and battery icons) came from wmapm-2 by jedgar. the numbers were copied off some other dockapp, too. the button was drawn by ME. PHEAR YES PHEAR IT. wmacpi-2.4/README0000644000207400020740000000473413653534554013102 0ustar azazelazazelFor install instructions, see "INSTALL" file. Usage: +-------------+ |battery graph| <- visual percentage battery remaining |[:][=] [100%]| <- [:] - on AC (blink when charging) [=] - on battery |[00:00] [bX]| <- [00:00] time remaining [bX] battery being monitored. |status area| <- messages scroll here +-------------+ see wmacpi -h for some command line switches ********************************************************************** wmacpi is a dockapp ACPI battery monitor for modern kernels (ie, 2.4.17 or later, and 2.6 kernels). Basically, it opens various files under /proc/acpi, reads status information from them, and then displays summaries. Version 1.99 and later provides full support for multiple batteries. You can tell it to monitor a particular battery with the -m option, which will display the percentage remaining and current status message for that battery. The time remaining and AC/battery status are global - the time remaining is calculated based on all batteries found on the system. When charging, the time displayed is the time remaining until the battery is fully charged - this only works sensibly if your ACPI system is implemented properly (far, far too many laptops have buggered ACPI implementations). The displayed time is averaged over 50 samples, each taken every three seconds (by default). This greatly improves the accuracy of the numbers - on my laptop, the time remaining seems to be overstated by a good hour or so if you only sample once compared to fifty times. Some ACPI implementations are stupid enough to block interrupts while reading status information from the battery over a slow bus - this means that on such b0rken laptops, running an ACPI battery monitor could affect interactivity. To provide a workaround for this, current versions of wmacpi supports setting the sample rate from the command line. The --sample-rate option specifies the number of times the battery is sampled every minute - the default is 20, and the maximum value is 600. Since -s 600 translates to sampling every 0.1 seconds, you really don't want to do that unless you're just having fun . . . Also provided is a command line tool to report the battery status. By default this will only sample once, but with the -a option you can specify a number. Be aware that it will try to take all those samples in the space of one second, so if your ACPI implementation is b0rken this could have adverse effects. Please report bugs to Simon Fowler, 2007-07-13. wmacpi-2.4/INSTALL0000644000207400020740000000145413653534554013247 0ustar azazelazazelThe basic install is very simple: make, make install. You can change the default install prefix (/usr/local) by specifying it in the make install command, eg: make install PREFIX=/usr To build the command line tool, either uncomment the BUILD_CLI=1 line in the Makefile, or specify BUILD_CLI=1 on the make command line. ie, make BUILD_CLI=1 make install BUILD_CLI=1 As of 2.1 wmacpi requires libdockapp-0.5.0 - the tarball is available from the same place as the wmacpi tarball. If you're running Debian testing you just need to install libdockapp-dev. No uninstall is supported, but isn't exactly difficult to delete all the files by hand . . . Files installed (paths relative to PREFIX): bin/wmacpi bin/acpi share/man/man1/wmacpi.1 share/man/man1/acpi.1 Simon Fowler , 2005-01-05wmacpi-2.4/libacpi.c0000644000207400020740000007471213653534554013774 0ustar azazelazazel#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "libacpi.h" extern char *state[]; battery_t batteries[MAXBATT]; int verbosity; #define PROC_DATA_SOURCE 0 #define SYSFS_DATA_SOURCE 1 static int data_source; /* local proto */ int acpi_get_design_cap(int batt); static int cmpstr (const void *va, const void *vb) { const char *a = *(const char **) va; const char *b = *(const char **) vb; return strcmp (a, b); } static int read_sysfs_file(char *node, char *prop, char *buf, size_t buflen) { char tmp[256]; FILE *fp; int ret; ret = snprintf(tmp, sizeof(tmp), "/sys/class/power_supply/%s/%s", node, prop); if (ret >= (int)sizeof(tmp)) { perr("Path too long for %s/%s\n", node, prop); return -1; } fp = fopen(tmp, "r"); if (fp == NULL) { perr("Could not open %s/%s\n", node, prop); return -2; } ret = fread(buf, 1, buflen - 1, fp); fclose(fp); if (ret == 0) { perr("Could not read %s/%s\n", node, prop); return -3; } buf[ret] = '\0'; return 0; } /* initialise the batteries */ static int sysfs_init_batteries(global_t *globals) { DIR *battdir; struct dirent *batt; char *name; char *names[MAXBATT]; char ps_type[16]; int i; /* now enumerate batteries */ globals->battery_count = 0; battdir = opendir("/sys/class/power_supply"); if (battdir == NULL) { pfatal("No batteries or ACPI not supported\n"); return 1; } while ((batt = readdir(battdir))) { /* there's a serious problem with this code when there's * more than one battery: the readdir won't return the * entries in sorted order, so battery one won't * necessarily be the first one returned. So, we need * to sort them ourselves before adding them to the * batteries array. */ name = batt->d_name; /* skip ., .. and dotfiles */ if (name[0] == '.') continue; if (read_sysfs_file(name, "type", ps_type, sizeof(ps_type)) < 0) continue; if (strncmp("Battery", ps_type, 7) != 0) continue; names[globals->battery_count] = strdup(name); globals->battery_count++; } closedir(battdir); qsort(names, globals->battery_count, sizeof *names, cmpstr); for (i = 0; i < globals->battery_count; i++) { snprintf(batteries[i].name, MAX_NAME, "%s", names[i]); pdebug("battery detected at /sys/class/power_supply/%s\n", batteries[i].name); pinfo("found battery %s\n", names[i]); free(names[i]); if (read_sysfs_file(batteries[i].name, "energy_now", ps_type, sizeof(ps_type)) == 0) batteries[i].sysfs_capa_mode = SYSFS_CAPA_ENERGY; else if (read_sysfs_file(batteries[i].name, "charge_now", ps_type, sizeof(ps_type)) == 0) batteries[i].sysfs_capa_mode = SYSFS_CAPA_CHARGE; else if (read_sysfs_file(batteries[i].name, "capacity", ps_type, sizeof(ps_type)) == 0) { batteries[i].sysfs_capa_mode = SYSFS_CAPA_PERCENT; batteries[i].design_cap = 100; batteries[i].last_full_cap = 100; } else batteries[i].sysfs_capa_mode = SYSFS_CAPA_ERR; } /* tell user some info */ pdebug("%d batteries detected\n", globals->battery_count); pinfo("libacpi: found %d batter%s\n", globals->battery_count, (globals->battery_count == 1) ? "y" : "ies"); return 0; } /* initialise the batteries */ static int procfs_init_batteries(global_t *globals) { DIR *battdir; struct dirent *batt; char *name; char *names[MAXBATT]; int i; /* now enumerate batteries */ globals->battery_count = 0; battdir = opendir("/proc/acpi/battery"); if (battdir == NULL) { pfatal("No batteries or ACPI not supported\n"); return 1; } while ((batt = readdir(battdir))) { /* there's a serious problem with this code when there's * more than one battery: the readdir won't return the * entries in sorted order, so battery one won't * necessarily be the first one returned. So, we need * to sort them ourselves before adding them to the * batteries array. */ name = batt->d_name; /* skip . and .. */ if (!strncmp(".", name, 1) || !strncmp("..", name, 2)) continue; names[globals->battery_count] = strdup(name); globals->battery_count++; } closedir(battdir); qsort(names, globals->battery_count, sizeof *names, cmpstr); for (i = 0; i < globals->battery_count; i++) { snprintf(batteries[i].name, MAX_NAME, "%s", names[i]); snprintf(batteries[i].info_file, MAX_NAME, "/proc/acpi/battery/%s/info", names[i]); snprintf(batteries[i].state_file, MAX_NAME, "/proc/acpi/battery/%s/state", names[i]); pdebug("battery detected at %s\n", batteries[i].info_file); pinfo("found battery %s\n", names[i]); free(names[i]); } /* tell user some info */ pdebug("%d batteries detected\n", globals->battery_count); pinfo("libacpi: found %d batter%s\n", globals->battery_count, (globals->battery_count == 1) ? "y" : "ies"); return 0; } int init_batteries(global_t *globals) { if (data_source == SYSFS_DATA_SOURCE) return sysfs_init_batteries(globals); else return procfs_init_batteries(globals); } /* a stub that just calls the current function */ int reinit_batteries(global_t *globals) { pdebug("reinitialising batteries\n"); return init_batteries(globals); } /* the actual name of the subdirectory under power_supply may * be anything, so we need to read the directory and use the * name we find there. */ static int sysfs_init_ac_adapters(global_t *globals) { DIR *acdir; struct dirent *adapter; adapter_t *ap = &globals->adapter; char *name; char ps_type[16]; acdir = opendir("/sys/class/power_supply"); if (acdir == NULL) { pfatal("Unable to open /sys/class/power_supply -" " are you sure this system supports ACPI?\n"); return 1; } name = NULL; while ((adapter = readdir(acdir)) != NULL) { if (adapter->d_name[0] == '.') { continue; } if (read_sysfs_file(adapter->d_name, "type", ps_type, sizeof(ps_type)) < 0) { continue; } if (strncmp("Mains", ps_type, 5) == 0) { pdebug("found adapter %s\n", adapter->d_name); name = strdup(adapter->d_name); break; } } closedir(acdir); if (name == NULL) { perr("No AC adapter found !\n"); return 1; } /* we'll just use the first adapter we find ... */ ap->name = name; pinfo("libacpi: found ac adapter %s\n", ap->name); return 0; } /* the actual name of the subdirectory under ac_adapter may * be anything, so we need to read the directory and use the * name we find there. */ static int procfs_init_ac_adapters(global_t *globals) { DIR *acdir; struct dirent *adapter; adapter_t *ap = &globals->adapter; char *name; acdir = opendir("/proc/acpi/ac_adapter"); if (acdir == NULL) { pfatal("Unable to open /proc/acpi/ac_adapter -" " are you sure this system supports ACPI?\n"); return 1; } name = NULL; while ((adapter = readdir(acdir)) != NULL) { name = adapter->d_name; if (!strncmp(".", name, 1) || !strncmp("..", name, 2)) continue; pdebug("found adapter %s\n", name); } ap->name = strdup(name); closedir(acdir); /* we /should/ only see one filename other than . and .. so * we'll just use the last value name acquires . . . */ snprintf(ap->state_file, MAX_NAME, "/proc/acpi/ac_adapter/%s/state", ap->name); pinfo("libacpi: found ac adapter %s\n", ap->name); return 0; } int init_ac_adapters(global_t *globals) { if (data_source == SYSFS_DATA_SOURCE) return sysfs_init_ac_adapters(globals); else return procfs_init_ac_adapters(globals); } /* stub that does nothing but call the normal init function */ int reinit_ac_adapters(global_t *globals) { pdebug("reinitialising ac adapters\n"); return init_ac_adapters(globals); } /* see if we have ACPI support and check version */ int power_init(global_t *globals) { FILE *acpi; char buf[4096] = ""; int acpi_ver = 0; int retval; size_t buflen; unsigned int version_offset = 0; if (!(acpi = fopen("/sys/module/acpi/parameters/acpica_version", "r"))) { if (!(acpi = fopen("/proc/acpi/info", "r"))) { pfatal("This system does not support ACPI\n"); return 1; } else { version_offset = 25; } } /* okay, now see if we got the right version */ buflen = fread(buf, 4096, 1, acpi); if (buflen != 4096 && ferror(acpi)) { pfatal("Could not read file\n"); return 1; } acpi_ver = strtol(buf + version_offset, NULL, 10); pinfo("ACPI version detected: %d\n", acpi_ver); if (acpi_ver < 20020214) { pfatal("This version requires ACPI subsystem version 20020214\n"); fclose(acpi); return 1; } /* yep, all good */ fclose(acpi); /* determine data source */ if (access("/sys/class/power_supply", R_OK | X_OK) == 0) { data_source = SYSFS_DATA_SOURCE; pinfo("Selecting sysfs as the data source\n"); } else { data_source = PROC_DATA_SOURCE; pinfo("Selecting procfs as the data source\n"); } if (!(retval = init_batteries(globals))) retval = init_ac_adapters(globals); return retval; } /* reinitialise everything, to deal with changing batteries or ac adapters */ int power_reinit(global_t *globals) { FILE *acpi; int retval; if (!(acpi = fopen("/sys/module/acpi/parameters/acpica_version", "r"))) { if (!(acpi = fopen("/proc/acpi/info", "r"))) { pfatal("Could not reopen ACPI info file - does this system support ACPI?\n"); return 1; } } if (!(retval = reinit_batteries(globals))) retval = reinit_ac_adapters(globals); fclose (acpi); return retval; } static char *get_value(char *string) { char *retval; int i; if (string == NULL) return NULL; i = 0; while (string[i] != ':') i++; while (!isalnum(string[i])) i++; retval = (string + i); return retval; } static int check_error(char *buf) { if(strstr(buf, "ERROR") != NULL) return 1; return 0; } static power_state_t sysfs_get_power_status(global_t *globals) { char online[2]; adapter_t *ap = &globals->adapter; if (read_sysfs_file(ap->name, "online", online, sizeof(online)) < 0) return PS_ERR; if (*online == '1') return AC; else return BATT; } static power_state_t procfs_get_power_status(global_t *globals) { FILE *file; char buf[1024]; char *val; adapter_t *ap = &globals->adapter; if ((file = fopen(ap->state_file, "r")) == NULL) { snprintf(buf, 1024, "Could not open state file %s", ap->state_file); perror(buf); return PS_ERR; } if (!fgets(buf, 1024, file)) { pfatal("Could not read file\n"); return PS_ERR; } fclose(file); val = get_value(buf); if ((strncmp(val, "on-line", 7)) == 0) return AC; else return BATT; } power_state_t get_power_status(global_t *globals) { if (data_source == SYSFS_DATA_SOURCE) return sysfs_get_power_status(globals); else return procfs_get_power_status(globals); } static int sysfs_get_battery_info(global_t *globals, int batt_no) { battery_t *info = &batteries[batt_no]; char buf[32]; int ret; /* check to see if battery is present */ ret = read_sysfs_file(info->name, "present", buf, sizeof(buf)); if (ret < 0) { /* interestingly, when the battery is not present, the whole * /sys/class/power_supply/BATn directory does not exist. * Yes, this is broken. */ if (ret == -2) info->present = 0; /* reinit batteries, this one went away and it's very possible there just isn't any other one */ reinit_batteries(globals); return 0; } info->present = (*buf == '1'); if (!info->present) { pinfo("Battery %s not present\n", info->name); return 0; } /* get design capacity * note that all these integer values can also contain the * string 'unknown', so we need to check for this. */ if (info->sysfs_capa_mode == SYSFS_CAPA_ENERGY) { if (read_sysfs_file(info->name, "energy_full_design", buf, sizeof(buf)) < 0) info->design_cap = -1; else info->design_cap = strtoul(buf, NULL, 10) / 1000; /* get last full capacity */ if (read_sysfs_file(info->name, "energy_full", buf, sizeof(buf)) < 0) info->last_full_cap = -1; else info->last_full_cap = strtoul(buf, NULL, 10) / 1000; } else if (info->sysfs_capa_mode == SYSFS_CAPA_CHARGE) { /* get design capacity */ if (read_sysfs_file(info->name, "charge_full_design", buf, sizeof(buf)) < 0) info->design_cap = -1; else info->design_cap = strtoul(buf, NULL, 10) / 1000; /* get last full capacity */ if (read_sysfs_file(info->name, "charge_full", buf, sizeof(buf)) < 0) info->last_full_cap = -1; else info->last_full_cap = strtoul(buf, NULL, 10) / 1000; } else if (info->sysfs_capa_mode != SYSFS_CAPA_PERCENT) { info->design_cap = -1; info->last_full_cap = -1; } /* get design voltage */ if (read_sysfs_file(info->name, "voltage_min_design", buf, sizeof(buf)) < 0) info->design_voltage = -1; else info->design_voltage = strtoul(buf, NULL, 10) / 1000; /* get charging state */ if (read_sysfs_file(info->name, "status", buf, sizeof(buf)) < 0) { info->charge_state = CH_ERR; } else { if (strncmp(buf, "Unknown", 7) == 0) info->charge_state = CH_ERR; else if (strncmp(buf, "Discharging", 11) == 0) info->charge_state = DISCHARGE; else if (strncmp(buf, "Charging", 8) == 0) info->charge_state = CHARGE; else if (strncmp(buf, "Not charging", 12) == 0) info->charge_state = NO_CHARGE; else if (strncmp(buf, "Full", 4) == 0) info->charge_state = FULL; /* DISCHARGE ? as per old comment ... */ } /* get current rate of burn * note that if it's on AC, this will report 0 */ if (read_sysfs_file(info->name, "current_now", buf, sizeof(buf)) < 0) info->present_rate = -1; else { int rate; rate = strtoul(buf, NULL, 10) / 1000; info->present_rate = (rate != 0) ? rate : info->present_rate; } if (info->sysfs_capa_mode == SYSFS_CAPA_ENERGY) { /* get remaining capacity */ if (read_sysfs_file(info->name, "energy_now", buf, sizeof(buf)) < 0) info->remaining_cap = -1; else info->remaining_cap = strtoul(buf, NULL, 10) / 1000; } else if (info->sysfs_capa_mode == SYSFS_CAPA_CHARGE) { /* get remaining capacity */ if (read_sysfs_file(info->name, "charge_now", buf, sizeof(buf)) < 0) info->remaining_cap = -1; else info->remaining_cap = strtoul(buf, NULL, 10) / 1000; } else if (info->sysfs_capa_mode == SYSFS_CAPA_PERCENT) { /* get remaining capacity */ if (read_sysfs_file(info->name, "capacity", buf, sizeof(buf)) < 0) info->remaining_cap = -1; else info->remaining_cap = strtoul(buf, NULL, 10) / 1000; } else { info->remaining_cap = -1; } /* get current voltage */ if (read_sysfs_file(info->name, "voltage_now", buf, sizeof(buf)) < 0) info->present_voltage = -1; else info->present_voltage = strtoul(buf, NULL, 10) / 1000; return 1; } static int procfs_get_battery_info(global_t *globals, int batt_no) { FILE *file; battery_t *info = &batteries[batt_no]; char buf[1024]; char *entry; int buflen; char *val; globals = globals; /* silencing a warning */ if ((file = fopen(info->info_file, "r")) == NULL) { /* this is cheating, but string concatenation should work . . . */ pfatal("Could not open %s:", info->info_file ); perror(NULL); return 0; } /* grab the contents of the file */ buflen = fread(buf, sizeof(buf), 1, file); fclose(file); /* check to see if there were any errors reported in the file */ if(check_error(buf)) { pinfo("Error reported in file %s - discarding data\n", info->info_file); return 0; } /* check to see if battery is present */ entry = strstr(buf, "present:"); val = get_value(entry); if ((strncmp(val, "yes", 3)) == 0) { info->present = 1; } else { pinfo("Battery %s not present\n", info->name); info->present = 0; return 0; } /* get design capacity * note that all these integer values can also contain the * string 'unknown', so we need to check for this. */ entry = strstr(buf, "design capacity:"); val = get_value(entry); if (val[0] == 'u') info->design_cap = -1; else info->design_cap = strtoul(val, NULL, 10); /* get last full capacity */ entry = strstr(buf, "last full capacity:"); val = get_value(entry); if (val[0] == 'u') info->last_full_cap = -1; else info->last_full_cap = strtoul(val, NULL, 10); /* get design voltage */ entry = strstr(buf, "design voltage:"); val = get_value(entry); if (val[0] == 'u') info->design_voltage = -1; else info->design_voltage = strtoul(val, NULL, 10); if ((file = fopen(info->state_file, "r")) == NULL) { perr("Could not open %s:", info->state_file ); perror(NULL); return 0; } /* grab the file contents */ memset(buf, 0, sizeof(buf)); buflen = fread(buf, sizeof(buf), 1, file); if (buflen != sizeof(buf) && ferror(file)) { pfatal("Could not read file\n"); return 1; } fclose(file); /* check to see if there were any errors reported in the file */ if(check_error(buf)) { pinfo("Error reported in file %s - discarding data\n", info->state_file); return 0; } /* check to see if battery is present */ entry = strstr(buf, "present:"); val = get_value(entry); if ((strncmp(val, "yes", 3)) == 0) { info->present = 1; } else { info->present = 0; perr("Battery %s no longer present\n", info->name); return 0; } /* get charging state */ entry = strstr(buf, "charging state:"); val = get_value(entry); if (val[0] == 'u') info->charge_state = CH_ERR; else if ((strncmp(val, "discharging", 10)) == 0) info->charge_state = DISCHARGE; else if ((strncmp(val, "charged", 7)) == 0) /* this is a workaround for machines that report * their charge state as 'charged', rather than * what my laptop does, which is go straight to * 'discharging'. dunno which matches the standard */ info->charge_state = DISCHARGE; else info->charge_state = CHARGE; /* get current rate of burn * note that if it's on AC, this will report 0 */ entry = strstr(buf, "present rate:"); val = get_value(entry); if (val[0] == 'u') { info->present_rate = -1; } else { int rate; rate = strtoul(val, NULL, 10); if (rate != 0) info->present_rate = rate; } /* get remaining capacity */ entry = strstr(buf, "remaining capacity:"); val = get_value(entry); if (val[0] == 'u') info->remaining_cap = -1; else info->remaining_cap = strtoul(val, NULL, 10); /* get current voltage */ entry = strstr(buf, "present voltage:"); val = get_value(entry); if (val[0] == 'u') info->present_voltage = -1; else info->present_voltage = strtoul(val, NULL, 10); return 1; } int get_battery_info(global_t *globals, int batt_no) { if (data_source == SYSFS_DATA_SOURCE) return sysfs_get_battery_info(globals, batt_no); else return procfs_get_battery_info(globals, batt_no); } /* * 2003-7-1. * In order to make this code more convenient for things other than * just plain old wmacpi-ng I'm breaking the basic functionality * up into several chunks: collecting and collating info for a * single battery, calculating the global info (such as rtime), and * some stuff to provide a similar interface to now. */ /* calculate the percentage remaining, using the values of * remaining capacity and last full capacity, as outlined in * the ACPI spec v2.0a, section 3.9.3. */ static int calc_remaining_percentage(int batt) { float rcap, lfcap; battery_t *binfo; int retval; binfo = &batteries[batt]; rcap = (float)binfo->remaining_cap; lfcap = (float)binfo->last_full_cap; /* we use -1 to indicate that the value is unknown . . . */ if (rcap < 0) { perr("unknown percentage value\n"); retval = -1; } else { if (lfcap <= 0) lfcap = 1; retval = (int)((rcap/lfcap) * 100.0); pdebug("percent: %d\n", retval); } return retval; } /* check to see if we've been getting bad data from the batteries - if * we get more than some limit we switch to using the remaining capacity * for the calculations. */ static enum rtime_mode check_rt_mode(global_t *globals) { int i; int bad_limit = 5; battery_t *binfo; /* if we were told what to do, we should keep doing it */ if(globals->rt_forced) return globals->rt_mode; for(i = 0; i < MAXBATT; i++) { binfo = &batteries[i]; if(binfo->present && globals->adapter.power == BATT) { if(binfo->present_rate <= 0) { pdebug("Bad report from %s\n", binfo->name); binfo->bad_count++; } } } for(i = 0; i < MAXBATT; i++) { binfo = &batteries[i]; if(binfo->bad_count > bad_limit) { if(globals->rt_mode != RT_CAP) pinfo("More than %d bad reports from %s; " "Switching to remaining capacity mode\n", bad_limit, binfo->name); return RT_CAP; } } return RT_RATE; } /* calculate remaining time until the battery is charged. * when charging, the battery state file reports the * current being used to charge the battery. We can use * this and the remaining capacity to work out how long * until it reaches the last full capacity of the battery. * XXX: make sure this is actually portable . . . */ static int calc_charge_time_rate(int batt) { float rcap, lfcap; battery_t *binfo; int charge_time = 0; binfo = &batteries[batt]; if (binfo->charge_state == CHARGE) { if (binfo->present_rate == -1) { perr("unknown present rate\n"); charge_time = -1; } else { lfcap = (float)binfo->last_full_cap; rcap = (float)binfo->remaining_cap; charge_time = (int)(((lfcap - rcap)/binfo->present_rate) * 60.0); } } else if (binfo->charge_time) charge_time = 0; return charge_time; } /* we need to calculate the present rate the same way we do in rt_cap * mode, and then use that to estimate charge time. This will * necessarily be even less accurate than it is for remaining time, but * it's just as neessary . . . */ static int calc_charge_time_cap(int batt) { static float cap_samples[CAP_SAMPLES]; static int time_samples[CAP_SAMPLES]; static int sample_count = 0; static int current = 0; static int old = 1; int rtime; int tdiff; float cdiff; float current_rate; battery_t *binfo = &batteries[batt]; cap_samples[current] = (float) binfo->remaining_cap; time_samples[current] = time(NULL); if (sample_count == 0) { /* we can't do much if we don't have any data . . . */ current_rate = 0; } else if (sample_count < CAP_SAMPLES) { /* if we have less than SAMPLES samples so far, we use the first * sample and the current one */ cdiff = cap_samples[current] - cap_samples[0]; tdiff = time_samples[current] - time_samples[0]; current_rate = cdiff/tdiff; } else { /* if we have more than SAMPLES samples, we use the oldest * current one, which at this point is current + 1. This will * wrap the same way that current will wrap, but one cycle * ahead */ cdiff = cap_samples[current] - cap_samples[old]; tdiff = time_samples[current] - time_samples[old]; current_rate = cdiff/(float)tdiff; } if (current_rate == 0) rtime = 0; else { float cap_left = (float)(binfo->last_full_cap - binfo->remaining_cap); rtime = (int)(cap_left/(current_rate * 60.0)); } sample_count++, current++, old++; if (current >= CAP_SAMPLES) current = 0; if (old >= CAP_SAMPLES) old = 0; pdebug("cap charge time rem: %d\n", rtime); return rtime; } static int calc_charge_time(global_t *globals, int batt) { int ctime = 0; globals->rt_mode = check_rt_mode(globals); switch(globals->rt_mode) { case RT_RATE: ctime = calc_charge_time_rate(batt); break; case RT_CAP: ctime = calc_charge_time_cap(batt); break; } return ctime; } void acquire_batt_info(global_t *globals, int batt) { battery_t *binfo; adapter_t *ap = &globals->adapter; get_battery_info(globals, batt); binfo = &batteries[batt]; if (!binfo->present) { binfo->percentage = 0; binfo->valid = 0; binfo->charge_time = 0; globals->rtime = 0; return; } binfo->percentage = calc_remaining_percentage(batt); /* set the battery's capacity state, based (at present) on some * guesstimated values: more than 75% == HIGH, 25% to 75% MED, and * less than 25% is LOW. Less than globals->crit_level is CRIT. */ if (binfo->percentage == -1) binfo->state = BS_ERR; if (binfo->percentage < globals->crit_level) binfo->state = CRIT; else if (binfo->percentage > 75) binfo->state = HIGH; else if (binfo->percentage > 25) binfo->state = MED; else binfo->state = LOW; /* we need to /know/ that we've got a valid state for the * globals->power value . . . .*/ ap->power = get_power_status(globals); binfo->charge_time = calc_charge_time(globals, batt); /* and finally, we tell anyone who wants to use this information * that it's now valid . . .*/ binfo->valid = 1; } void acquire_all_batt_info(global_t *globals) { int i; for(i = 0; i < globals->battery_count; i++) acquire_batt_info(globals, i); } /* * One of the feature requests I've had is for some way to deal with * batteries that are too dumb or too b0rken to report a present rate * value. The way to do this, obviously, is to record the time that * samples were taken and use that information to calculate the rate * at which the battery is draining/charging. This still won't help * systems where the battery doesn't even report the remaining * capacity, but without the present rate or the remaining capacity, I * don't think there's /anything/ we can do to work around it. * * So, what we need to do is provide a way to use a different method * to calculate the time remaining. What seems most sensible is to * split out the code to calculate it into a seperate function, and * then provide multiple implementations . . . */ /* * the default implementation - if present rate and remaining capacity * are both reported correctly, we use them. */ int calc_time_remaining_rate(global_t *globals) { int i; int rtime; float rcap = 0; float rate = 0; battery_t *binfo; static float rate_samples[SAMPLES]; static int sample_count = 0; static int j = 0; static int n = 0; /* calculate the time remaining, using the battery's remaining * capacity and the reported burn rate (3.9.3). * For added accuracy, we average the value over the last * SAMPLES number of calls, or for anything less than this we * simply report the raw number. */ /* XXX: this needs to correctly handle the case where * any of the values used is unknown (which we flag using * -1). */ for (i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if (binfo->present && binfo->valid) { rcap += (float)binfo->remaining_cap; rate += (float)binfo->present_rate; } } rate_samples[j] = rate; j++, sample_count++; if (j >= SAMPLES) j = 0; /* for the first SAMPLES number of calls we calculate the * average based on sample_count, then we use SAMPLES to * calculate the rolling average. */ /* when this fails, n should be equal to SAMPLES. */ if (sample_count < SAMPLES) n++; for (i = 0, rate = 0; i < n; i++) { /* if any of our samples are invalid, we drop * straight out, and flag our unknown values. */ if (rate_samples[i] < 0) { rate = -1; rtime = -1; goto out; } rate += rate_samples[i]; } rate = rate/(float)n; if ((rcap < 1) || (rate < 1)) { rtime = 0; goto out; } if (rate <= 0) rate = 1; /* time remaining in minutes */ rtime = (int)((rcap/rate) * 60.0); if(rtime <= 0) rtime = 0; out: pdebug("discharge time rem: %d\n", rtime); return rtime; } /* * the alternative implementation - record the time at which each * sample was taken, and then use the difference between the latest * sample and the one SAMPLES ago to calculate the difference over * that time, and from there the rate of change of capacity. * * XXX: this code sucks, but largely because batteries aren't exactly * precision instruments - mine only report with about 70mAH * resolution, so they don't report any changes until the difference * is 70mAH. This means that calculating the current rate from the * remaining capacity is very choppy . . . * * To fix this, we should calculate an average over some number of * samples at the old end of the set - this would smooth out the * transitions. */ int calc_time_remaining_cap(global_t *globals) { static float cap_samples[CAP_SAMPLES]; static int time_samples[CAP_SAMPLES]; static int sample_count = 0; static int current = 0; static int old = 1; battery_t *binfo; int i; int rtime; int tdiff; float cdiff; float cap = 0; float current_rate; for (i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if (binfo->present && binfo->valid) cap += binfo->remaining_cap; } cap_samples[current] = cap; time_samples[current] = time(NULL); if (sample_count == 0) { /* we can't do much if we don't have any data . . . */ current_rate = 0; } else if (sample_count < CAP_SAMPLES) { /* if we have less than SAMPLES samples so far, we use the first * sample and the current one */ cdiff = cap_samples[0] - cap_samples[current]; tdiff = time_samples[current] - time_samples[0]; current_rate = cdiff/tdiff; } else { /* if we have more than SAMPLES samples, we use the oldest * current one, which at this point is current + 1. This will * wrap the same way that current will wrap, but one cycle * ahead */ cdiff = cap_samples[old] - cap_samples[current]; tdiff = time_samples[current] - time_samples[old]; current_rate = cdiff/tdiff; } if (current_rate == 0) rtime = 0; else rtime = (int)(cap_samples[current]/(current_rate * 60.0)); sample_count++, current++, old++; if (current >= CAP_SAMPLES) current = 0; if (old >= CAP_SAMPLES) old = 0; pdebug("cap discharge time rem: %d\n", rtime); return rtime; } void acquire_global_info(global_t *globals) { adapter_t *ap = &globals->adapter; globals->rt_mode = check_rt_mode(globals); switch(globals->rt_mode) { case RT_RATE: globals->rtime = calc_time_remaining_rate(globals); break; case RT_CAP: globals->rtime = calc_time_remaining_cap(globals); break; } /* get the power status. * note that this is actually reported seperately from the * battery info, under /proc/acpi/ac_adapter/AC/state */ ap->power = get_power_status(globals); } void acquire_all_info(global_t *globals) { acquire_all_batt_info(globals); acquire_global_info(globals); } wmacpi-2.4/Makefile0000644000207400020740000000324513653534554013656 0ustar azazelazazel# set options. pick one, acpi or apm. comment out the other one. don't # uncomment both, bad things will happen :) WMACPI_VER = 2.4 OPT := -O2 # uncomment this to build the command line acpi tool BUILD_CLI = 1 # uncomment this to make wmacpi use less system colors (looks uglier too) #OPT += -DLOW_COLOR # debugging options (don't bother with these) #OPT = -pg -g CC := gcc CFLAGS += $(OPT) -Wall -W -g -ansi -DWMACPI_VER='"$(WMACPI_VER)"' LDFLAGS += $(OPT) -lX11 -ldockapp WMSRC := wmacpi.c libacpi.c HEADERS := libacpi.h targets := wmacpi doc_targets := wmacpi.1 ifdef BUILD_CLI targets += wmacpi-cli doc_targets += wmacpi-cli.1 endif PREFIX := /usr/local all: $(targets) # build the list of object files WMOBJ := $(patsubst %.c,%.o,$(filter %.c,$(WMSRC))) # include per-file dependencies -include $(WMOBJ:.o=.d) wmacpi: $(WMOBJ) $(CC) -o $@ $^ $(LDFLAGS) # for the Debian package, we want to make building the command line tools # optional. So, we hide all the necessary stuff here . . . ifdef BUILD_CLI CLSRC := wmacpi-cli.c libacpi.c CLOBJ := $(patsubst %.c,%.o,$(filter %.c,$(CLSRC))) -include $(CLOBJ:.o=.d) wmacpi-cli: $(CLOBJ) $(CC) $(LDFLAGS) -o $@ $^ endif # build per-file dependencies - note that -MM may not be supported # in gcc versions older than 2.95.4, but most likely is. %.d: %.c gcc -MM $(CFLAGS) $< > $@ clean: rm -f TAGS *.o *~ trace *.out *.bb *.bbg rm -f *.d $(targets) clean-all: clean install: $(targets) install -d $(DESTDIR)$(PREFIX)/bin/ install -pc $(targets) $(DESTDIR)$(PREFIX)/bin/ install -d $(DESTDIR)$(PREFIX)/share/man/man1/ install -pc $(doc_targets) $(DESTDIR)$(PREFIX)/share/man/man1/ tags: etags $(WMSRC) $(CLSRC) $(HEADERS) wmacpi-2.4/wmacpi.10000644000207400020740000000745113653534554013563 0ustar azazelazazel.TH WMACPI 1 "July 13 2007" .SH NAME wmacpi \- Battery status monitor for systems supporting ACPI .SH NAME wmacpi-cli \- Query battery status for systems supporting ACPI .SH SYNOPSIS .B wmacpi [ .RI -c value ] [ .RI -d display ] [ .RI -m battery no ] [ .RI -s sample rate ] [ .RI -f ] [ .RI -v ] [ .RI -n ] [ .RI -x ] [ .RI -a samples ] [ .RI -v ] [ .RI -h ] .PP .B wmacpi-cli [ .RI -a samples ] [ .RI -V ] [ .RI -v ] ] .RI -b ] [ .RI -r ] [ .RI -h ] .SH DESCRIPTION This manual page documents briefly the .B wmacpi command. .PP .B wmacpi is a program that displays the current battery status in a WindowMaker dock app, on systems that support Intel's Advanced Configuration and Power Interface specification (ACPI). .PP The program monitors a battery, displaying its current percentage charge via a bar and a numeric value. It also displays the current power status for the system, the time remaining (calculated based on the remaining battery capacity and the current rate of power usage), and a scrolling message with some hopefully useful information. .PP Clicking on the window cycles through the batteries that the ACPI system knows about. .PP .B wmacpi-cli queries the battery status from the command line. It prints the power status, the percentage remaining for each battery found, and the time remaining if the system is on battery, or the time remaining for each battery to reach full charge if the batteries are charging. .SH OPTIONS .B wmacpi .TP .B \-c, --critical=percentage Set critical low alarm at % (default: 10%). .TP .B \-d, --display=display Set the X display to open the window on. .TP .B \-m, --battery=battery number Set the battery to monitor initially. .TP .B \-s, --sample-rate=sample rate Set the rate at which to sample the ACPI data, in number of times per minute. Minimum is 1, ie once a minute, default is 20, maximum is 600. .TP .B \-n, --no-blink Disable blinking power glyph when charging. Note that it still blinks when the battery reports its capacity state as critical. .TP .B \-f, --force-capacity-mode Force the use of capacity mode for calculating time remaining. By defalt .B wmacpi will use the reported values of remaining capacity and present rate to calculate the time remaining on battery. This flag will force the use of the remaining capacity and time samples to calculate the present rate of drain, and from there the time remaining. Note that this mode of calculation generally underreports the time remaining. This mode works around certain buggy ACPI BIOSes that fail to report the current rate. .TP .B \-x, --cmdline Run wmacpi in command line mode - this operates identically to .B wmacpi-cli\&. .TP .B \-a, --samples=samples Average the time remaining over num samples. This greatly improves the accuracy of the reported time remaining. .TP .B \-V, --verbosity=num Increase the verbosity of the program. Setting this to 1 will print extra error information; 2 will produce informational output; 3 will produce copious debugging output. .TP .B \-v, --version Print the version information. .TP .B \-r, --no-scroll Disable scrolling message. .TP .B \-h, --help Display help. .TP .B wmacpi-cli .TP .B \-a num Average the time remaining over num samples. This greatly improves the accuracy of the reported time remaining. .TP .B \-V Increase the verbosity of the program. If repeated, the result is the same as setting .B \--verbosity for .B wmacpi to the number of repetitions. .TP .B \-v Print the version information. .TP .B \-h Display help. .SH AUTHOR .B wmacpi was originally written by Tim Copperfield , then completely rewritten after 1.34 by Simon Fowler . .PP This manual page was originally written by Simon Richter for the Debian GNU/Linux system, and then updated by Simon Fowler. .br Last modification by Simon Fowler , 2007-07-13. wmacpi-2.4/libacpi.h0000644000207400020740000000673513653534554014001 0ustar azazelazazel#ifndef _LIBACPI_H_ #define _LIBACPI_H_ #define LIBACPI_VER "0.95" /* Here because we need it for definitions in this file . . . */ #define MAX_NAME 128 #define MAXBATT 8 #define SAMPLES 50 #define CAP_SAMPLES (SAMPLES*10) typedef enum { REMAIN, TIMER } DspMode; typedef enum { AC, BATT, PS_ERR, } power_state_t; typedef enum { HIGH, MED, LOW, CRIT, BS_ERR, } batt_state_t; typedef enum { CHARGE, DISCHARGE, FULL, NO_CHARGE, CH_ERR, } charge_state_t; typedef enum { SYSFS_CAPA_ENERGY, SYSFS_CAPA_CHARGE, SYSFS_CAPA_PERCENT, SYSFS_CAPA_ERR, } sysfs_capa_t; typedef struct { /* general info */ char name[MAX_NAME]; /* these two are conveniences */ char info_file[MAX_NAME]; char state_file[MAX_NAME]; /* sysfs capacity mode */ sysfs_capa_t sysfs_capa_mode; int present; int design_cap; /* assuming mAh */ int last_full_cap; int design_voltage; /* in mV */ /* state info */ charge_state_t charge_state; int present_rate; /* in mAh */ int remaining_cap; /* in mAh */ int present_voltage; /* in mV */ /* calculated states */ batt_state_t state; int percentage; /* stored here because this is a per battery thing */ int charge_time; /* time left to charge this battery */ /* and a flag to indicate that this is valid . . . */ int valid; /* number of times we've gotten bad info on this battery's present rate */ int bad_count; } battery_t; typedef struct { char *name; char state_file[MAX_NAME]; power_state_t power; } adapter_t; /* how to calculate the time remaining */ enum rtime_mode { RT_RATE, /* using the current rate, as per the ACPI spec */ RT_CAP, /* using the remaining capacity over time */ }; typedef struct { int rtime; /* remaining time */ int timer; /* how long been on battery? */ int crit_level; /* anything below this is critical low */ int battery_count; /* number of batteries found */ enum rtime_mode rt_mode; /* remaining time mode */ int rt_forced; /* was our rt_mode forced? if so, we do what we were told */ battery_t *binfo; /* pointer to the battery being monitored */ adapter_t adapter; } global_t; /* * Moving percentage to the battery is right, but I think we need a global * remaining capacity somewhere, too . . . */ /* * To provide a convenient debugging function . . . * * It's a macro because I'm too lazy to deal with varargs. */ #define pdebug(fmt, arg...) \ do { \ if (verbosity > 2) \ fprintf(stderr, fmt, ##arg); \ } while (0) #define pinfo(fmt, arg...) \ do { \ if (verbosity > 1) \ fprintf(stderr, fmt, ##arg); \ } while (0) #define perr(fmt, arg...) \ do { \ if (verbosity > 0) \ fprintf(stderr, fmt, ##arg); \ } while (0) #define pfatal(fmt, arg...) \ fprintf(stderr, fmt, ##arg) \ /* Since these /are/ needed here . . . */ extern battery_t batteries[MAXBATT]; extern int verbosity; /* check if apm/acpi is enabled, etc */ int power_init(global_t *globals); /* reinitialise everything */ int power_reinit(global_t *globals); int reinit_ac_adapters(global_t *globals); int reinit_batteries(global_t *globals); /* fill global_t with data */ void acquire_batt_info(global_t *globals, int batt); void acquire_all_batt_info(global_t *globals); void acquire_global_info(global_t *globals); void acquire_all_info(global_t *globals); #endif /* _WMACPI_H_ */ wmacpi-2.4/wmacpi-cli.10000644000207400020740000000002213653534554014313 0ustar azazelazazel.so man1/wmacpi.1 wmacpi-2.4/master.xpm0000644000207400020740000007170713653534554014247 0ustar azazelazazel/* XPM */ static char * master_xpm[] = { "157 88 100 2", " c None", ". c #000000", "+ c #FF0000", "@ c #FF0900", "# c #FF1200", "$ c #FF1C00", "% c #202020", "& c #FF2F00", "* c #FF3800", "= c #FF4200", "- c #FF4B00", "; c #FF5E00", "> c #FF6700", ", c #FF7100", "' c #FF7A00", ") c #FF8D00", "! c #FF9700", "~ c #FFA000", "{ c #FFA900", "] c #FFBC00", "^ c #FFC600", "/ c #FFCF00", "( c #FFD900", "_ c #FFEC00", ": c #FFF500", "< c #FFFF00", "[ c #F5FF00", "} c #E2FF00", "| c #D9FF00", "1 c #CFFF00", "2 c #C6FF00", "3 c #B3FF00", "4 c #AAFF00", "5 c #A0FF00", "6 c #97FF00", "7 c #84FF00", "8 c #7AFF00", "9 c #71FF00", "0 c #67FF00", "a c #54FF00", "b c #4BFF00", "c c #42FF00", "d c #38FF00", "e c #25FF00", "f c #1CFF00", "g c #12FF00", "h c #09FF00", "i c #400000", "j c #400300", "k c #400500", "l c #400700", "m c #400C00", "n c #400E00", "o c #401100", "p c #401300", "q c #401800", "r c #401A00", "s c #401D00", "t c #401F00", "u c #402400", "v c #402600", "w c #402800", "x c #402B00", "y c #402F00", "z c #403200", "A c #403400", "B c #403700", "C c #403B00", "D c #403E00", "E c #404000", "F c #3E4000", "G c #394000", "H c #374000", "I c #344000", "J c #324000", "K c #2D4000", "L c #2B4000", "M c #284000", "N c #264000", "O c #214000", "P c #1F4000", "Q c #1D4000", "R c #1A4000", "S c #154000", "T c #134000", "U c #114000", "V c #0E4000", "W c #0A4000", "X c #074000", "Y c #054000", "Z c #034000", "` c #C7C7C7", " . c #004941", ".. c #20B2AE", "+. c #303030", "@. c #188A86", "#. c #22B2AE", "$. c #027E72", "%. c #034A40", "&. c #107D79", " . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . + @ # $ % & * = - % ; > , ' % ) ! ~ { % ] ^ / ( % _ : < [ % } | 1 2 % 3 4 5 6 % 7 8 9 0 % a b c d % e f g h ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % ", " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % .% % % % .% .% % % % .% % ..% % .% % % % .% .% % % % .% ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % % % % % % % % % % % % % % % % % % % ` . +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+.% +.+.+.+. % .% % % % .% .% % % % .% % ..% % .% % % % .% .% % % % .% ", " . % % % % % % ..........% % % % ....................% % ` . % % % % % . . .% % % . . .% % % ..% % % % % ` . % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% ", " . % % % % % ..% % % % ......% % ..% % % % % % % % ..% % ` . % % .% .% % % .% .% % % .% ..% ..% ..% % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% ", " . % % % % % ..% % % % ..% % % % ..% % % % % % % % ....% ` . % % .% .% % % .% .% % % .% % ..% ..% % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % % ........% % % ........% % % % % % % ........% % % ........% % ", " . % % % ......% % % % ..% % % % ..% % % % % % % % ....% ` . % % % % % . . .% % % . . .% % % % ..% % % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% ", " . % % ..% % ..% % % % ......% % ..% % % % % % % % ....% ` . % % .% .% % % .% .% % % .% % ..% ..% % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% ", " . % ..% % % % ..........% % % % ..% % % % % % % % ..% % ` . % % .% .% % % .% .% % % .% ..% ..% ..% % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % .% % % % .% .% % % % .% % ..% % .% % % % .% .% % % % .% ", " . % ..% % % % % % % % % % % % % ....................% % ` . % % % % % . . .% % % . . .% % % % % ..% % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % .% % % % .% .% % % % .% % ..% % .% % % % .% .% % % % .% ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % % % % % % % % % % % % % % % % % % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % % % % % % % % % % % % % % % % % % % ` . i j k l % m n o p % q r s t % u v w x % y z A B % C D E F % G H I J % K L M N % O P Q R % S T U V % W X Y Z % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` . ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . % % ......% % % . . .@.% @.......@.% @.......@.% @. . . .@.% @.......@.% @.......@.% @.......@.% @.......@.% @.......@.% % ..% % % % % % % ", " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ` . % ..% % % ..% .% % % ..% .% % % ..% .% % % ..% ..% % % ..% ..% % % .% ..% % % .% .% % % ..% ..% % % ..% ..% % % ..% ..% ..% ..% % ..% ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` % % % % % % % % % % % % % % % % ` . % ..% % % ..% .% % % ..% .% % % ..% .% % % ..% ..% % % ..% ..% % % .% ..% % % .% .% % % ..% ..% % % ..% ..% % % ..% % ..% ..% % % @.% ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` % % % % % % % % % % % % % % % % ` . % @. . . .@.% % . . .@.% @.......@.% % ......@.% @.......@.% @.......@.% @.......@.% % . . .@.% @.......@.% @.......@.% % % ..% % % % % % ", " . % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % ` % % % % % % % % % . . . .% % % ` . % ..% % % ..% .% % % ..% ..% % % .% .% % % ..% .% % % ..% .% % % ..% ..% % % ..% .% % % ..% ..% % % ..% .% % % ..% % ..% ..% % % % % ", " . % % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % ` % % % % % % % % .% % % % .% % ` . % ..% % % ..% .% % % ..% ..% % % .% .% % % ..% .% % % ..% .% % % ..% ..% % % ..% .% % % ..% ..% % % ..% .% % % ..% ..% ..% ..% % ..% ", " . % % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % ` % #.#.#.#.% % % .% % % % .% % ` . % % ......% % % . . .@.% @.......@.% @.......@.% % . . .@.% @.......@.% @.......@.% % . . .@.% @.......@.% @.......@.% % % % ..% % % @.% ", " . % % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % ` % #.% % % #.% % .% % % % .% % ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . % % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % ` % #.% % % #.% % .% % % % .% % ` . ", " . % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % ` % #.% % % #.% % % . . . .% % % ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % . . . . . . . . . . . . . . . . ` ", " . % % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % ` % #.#.#.#.% % % .% % % % .% % ` . % % % % % % ..........% % % % ....................% % % @.% % ......% % % ......% % % ..% % % % % % % % % % % % % % % % % % % % ` ", " . % % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % ` % #.% % % #.% % .% % % % .% % ` . % % % % % ..% % % % ......% % ..% % % % % % % % ..% % % ..% ..% % % ..% ..% % % ..% ..% ..% ..% % % % % % % % % % % % % % % % % ` ", " . % % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % ` % #.% % % #.% % .% % % % .% % ` . % % % % % ..% % % % ..% % % % ..% % % % % % % % ....% % ..% ..% % % ..% ..% % % ..% % ..% ..% % % % % % % % % % % . . . .% % % ` ", " . % % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % ` % #.% % % #.% % .% % % % .% % ` . % % % ......% % % % ..% % % % ..% % % % % % % % ....% % @.% @. . . .@.% @. . . .@.% % % ..% % % % % % % % % % % .% % % % .% % ` ", " . % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % ` % #.#.#.#.% % % % . . . .% % % ` . % % ..% % ..% % % % ......% % ..% % % % % % % % ....% % ..% ..% % % ..% ..% % % ..% % ..% ..% % % #.#.#.#.% % % .% % % % .% % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` % % % % % % % % % % % % % % % % ` . % ..% % % % ..........% % % % ..% % % % % % % % ..% % % ..% ..% % % ..% ..% % % ..% ..% ..% ..% % #.% % % #.% % .% % % % .% % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` % % % % % % % % % % % % % % % % ` . % ..% % % % % % % % % % % % % ....................% % % @.% % ......% % % ......% % % % % ..% % % #.% % % #.% % .% % % % .% % ` ", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % #.% % % #.% % % . . . .% % % ` ", " . % #.#.#.#.% % % .% % % % .% % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % #.% % % #.% % .% % % % .% % ` ", " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . % % % % % % . . . . .% % % % . . . . . . . . . .% % % % % % . . .% % % . . .% % % .% % % % % #.% % % #.% % .% % % % .% % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % .% % % % . . .% % .% % % % % % % % .% % % .% .% % % .% .% % % .% .% .% .% % #.% % % #.% % .% % % % .% % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % .% % % % .% % % % .% % % % % % % % . .% % .% .% % % .% .% % % .% % .% .% % % #.#.#.#.% % % % . . . .% % % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % . . .% % % % .% % % % .% % % % % % % % . .% % % % % . . .% % % . . .% % % % .% % % % % % % % % % % % % % % % % % % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % .% % .% % % % . . .% % .% % % % % % % % . .% % .% .% % % .% .% % % .% % .% .% % % % % % % % % % % % % % % % % % ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % .% % % % . . . . .% % % % .% % % % % % % % .% % % .% .% % % .% .% % % .% .% .% .% ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % .% % % % % % % % % % % % % . . . . . . . . . .% % % % % % . . .% % % . . .% % % % % .% % ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", " . % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ` . % % #.#.#.% % % % % % $.% $.#.#.#.$.% $.#.#.#.$.% $.% % % $.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% % % % % % % % % % % % % % % % % % % ", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` . % #.% % % #.% % % % % #.% % % % % #.% % % % % #.% #.% % % #.% #.% % % % % #.% % % % % % % % % #.% #.% % % #.% #.% % % #.% % % % % % % % % % % % % % % % % % % ", " . % #.% % % #.% % % % % #.% % % % % #.% % % % % #.% #.% % % #.% #.% % % % % #.% % % % % % % % % #.% #.% % % #.% #.% % % #.% % % % % % % % % % % % % % % % % % % ", " . % $.% % % $.% % % % % $.% $.#.#.#.$.% % #.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% % % % % $.% %.#.#.#.%.% $.#.#.#.$.% $.#.#.#.$.% % % % % % % % % % % % % ", " . % #.% % % #.% % % % % #.% #.% % % % % % % % % #.% % % % % #.% % % % % #.% #.% % % #.% % % % % #.% #.% % % #.% % % % % #.% % % % % % % % % % % % % % % % % % % ", " . % #.% % % #.% % % % % #.% #.% % % % % % % % % #.% % % % % #.% % % % % #.% #.% % % #.% % % % % #.% #.% % % #.% % % % % #.% % % % % % % % % % % % % % % % % % % ", ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . % % #.#.#.% % % % % % #.% $.#.#.#.$.% $.#.#.#.$.% % % % % $.% $.#.#.#.$.% $.#.#.#.$.% % % % % $.% $.#.#.#.$.% $.#.#.#.$.% % % % % % % % % % % % % % % % % #.% ", " % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", "% %.#.#.#.%.% $.#.#.#.% % $.#.#.#.$.% $.#.#.#.% % $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.% % % $.% % % $.% % % % % % % $.% $.% % % $.% $.% % % % % #.% % % #.% $.#.#.#.% % $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.#.#.#.$.% $.% % % $.% $.% % % $.% $.% % % $.% $.% % % $.% $.% % % $.% $.#.#.#.$.% ", "% #.% % % #.% #.% % % #.% #.% % % % % #.% % % #.% #.% % % % % #.% % % % % #.% % % % % #.% % % #.% % % #.% % % % % % % #.% #.% % % #.% #.% % % % % #.#.% #.#.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % % % % % #.% % % #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% % % % % #.% ", "% #.% % % #.% #.% % % #.% #.% % % % % #.% % % #.% #.% % % % % #.% % % % % #.% % % % % #.% % % #.% % % #.% % % % % % % #.% #.% % #.%.% #.% % % % % #.% #.% #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % #.% #.% % % % % % % #.% % % #.% % % #.% #.% % % #.% #.% % % #.% %.#.% #.%.% #.% % % #.% % % % #.%.% ", "% $.#.#.#.$.% $.#.#.#.% % $.% % % % % $.% % % $.% $.#.#.#.% % $.#.#.#.% % $.%.#.#.$.% $.#.#.#.$.% % % $.% % % % % % % $.% $.#.#.%.% % $.% % % % % $.% % % $.% $.% % % $.% $.% % % $.% $.#.#.#.$.% $.#.% % $.% $.#.#.#.% % $.#.#.#.$.% % % $.% % % $.% % % $.% $.% % % $.% $.% % % $.% % %.#.%.% % $.#.#.#.$.% % %.#.%.% % ", "% #.% % % #.% #.% % % #.% #.% % % % % #.% % % #.% #.% % % % % #.% % % % % #.% % % #.% #.% % % #.% % % #.% % % % % % % #.% #.% % #.%.% #.% % % % % #.% % % #.% #.% % % #.% #.% % % #.% #.% % % % % #.% #.% #.% #.% % % #.% % % % % #.% % % #.% % % #.% % % #.% #.% % % #.% #.% #.% #.% %.#.% #.%.% % % % % #.% %.#.% % % % ", "% #.% % % #.% #.% % % #.% #.% % % % % #.% % % #.% #.% % % % % #.% % % % % #.% % % #.% #.% % % #.% % % #.% % % % % % % #.% #.% % % #.% #.% % % % % #.% % % #.% #.% % % #.% #.% % % #.% #.% % % % % #.% % #.#.% #.% % % #.% % % % % #.% % % #.% % % #.% % % #.% #.% % % #.% #.#.% #.#.% #.% % % #.% % % % % #.% #.% % % % % ", "% $.% % % $.% $.#.#.#.% % $.#.#.#.$.% #.#.#.#.% % $.#.#.#.$.% #.% % % % % $.#.#.#.$.% $.% % % $.% % % #.% % % $.#.#.#.$.% $.% % % $.% $.#.#.#.%.% $.% % % $.% #.% % % #.% $.#.#.#.$.% $.% % % % % $.#.#.#.$.% $.% % % $.% $.#.#.#.$.% % % $.% % % %.#.#.#.#.% % #.#.#.% % #.% % % #.% $.% % % #.% $.#.#.#.$.% $.#.#.#.$.% ", "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % ", "% % ........% % % . . . .&.% &.........@.% &.........&.% &. . . . .&.% &.........&.% &.........@.% &.........&.% &.........@.% &.........@.% % % % % % % ........% % % ........% % % % % % % ........% % % ........% % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % % #. . . .#.% ", "% ..% % % % ..% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% ..% % % % .% ..% % % % .% .% % % % ..% ..% % % % ..% ..% % % % ..% % ..% % % ..% % % % ..% ..% % % % ..% % ..% % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % #.% #.% #. .% ", "% ..% % % % ..% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% ..% % % % .% ..% % % % .% .% % % % ..% ..% % % % ..% ..% % % % ..% % ..% % % ..% % % % ..% ..% % % % ..% % ..% % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % .#.% #.% .% ", "% ..% % % % ..% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% ..% % % % .% ..% % % % .% .% % % % ..% ..% % % % ..% ..% % % % ..% % % % % % ..% % % % ..% ..% % % % ..% % % % % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % .% #.% #. .% ", "% ..% % % % ..% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% ..% % % % .% ..% % % % .% .% % % % ..% ..% % % % ..% ..% % % % ..% % % % % % ..% % % % ..% ..% % % % ..% % % % % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % .#.% #.% #.% ", "% &. . . . .&.% % . . . .&.% &.........&.% &.........&.% &.........&.% &.........&.% &.........&.% % . . . .&.% &.........&.% &.........&.% % % % % % &. . . . .&.% &. . . . .&.% % % % % &. . . . .&.% &. . . . .&.% % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % #. . . .#.% % ", "% ..% % % % ..% .% % % % ..% ..% % % % .% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% % % % % % ..% % % % ..% ..% % % % ..% % % % % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % .% % % % .% ", "% ..% % % % ..% .% % % % ..% ..% % % % .% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% % % % % % ..% % % % ..% ..% % % % ..% % % % % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % % % % .% % % % .% .% % % % .% % #.#.#.#.#. .% ", "% ..% % % % ..% .% % % % ..% ..% % % % .% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% % ..% % % ..% % % % ..% ..% % % % ..% % ..% % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % #.% % % #.#.% ", "% ..% % % % ..% .% % % % ..% ..% % % % .% .% % % % ..% .% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% ..% % % % ..% .% % % % ..% % ..% % % ..% % % % ..% ..% % % % ..% % ..% % ..% % % % ..% ..% % % % ..% % .% % % % .% .% % % % .% % .% % .% % % % .% .% % % % .% % #.% % % #.#.% ", "% % ........% % % . . . .&.% &.........&.% &.........&.% % . . . .&.% &.........&.% &.........&.% % . . . .&.% &.........&.% &.........&.% % % % % % % ........% % % ........% % % % % % % ........% % % ........% % % % . . . .% % % . . . .% % % % % % % . . . .% % % . . . .% % % #.#.#.#.#.% % ", "% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "}; wmacpi-2.4/wmacpi-cli.c0000644000207400020740000000606113653534554014406 0ustar azazelazazel/* * acpi-ng: command line acpi battery status tool. * * Written by Simon Fowler , 2003-06-20. * Copyright 2003-06-20 Dreamcraft Pty Ltd. * * This file is distributed under the GNU General Public License, * version 2. Please see the COPYING file for details. */ /* * 2003-06-20. * I'm getting sick of not having a convenient way to query battery * status on the command line, so I'm hacking up this - a quick little * command line tool to display current battery status, using the same * libacpi code as wmacpi-ng. */ #define _GNU_SOURCE #include #include #include #include #include #include "libacpi.h" global_t *globals; void usage(char *name) { printf("%s: query battery status on ACPI enabled systems.\n" "Usage:\n" "%s [-h] [-a samples]\n" " h - display this help information\n" " a - average remaining time over some number of samples\n" " much more accurate than using a single sample\n" " V - increase verbosity\n" " v - print version information\n", name, name); } void print_version(void) { printf("wmacpi-cli version %s\n", WMACPI_VER); printf(" Using libacpi version %s\n", LIBACPI_VER); } int main(int argc, char *argv[]) { int i, j, ch; int sleep_time = 0; int samples = 1; battery_t *binfo; adapter_t *ap; while((ch = getopt(argc, argv, "hvVa:")) != EOF) { switch(ch) { case 'h': usage(argv[0]); return 0; case 'V': verbosity++; break; case 'v': print_version(); return 0; case 'a': if(optarg != NULL) { samples = atoi(optarg); if(samples > 1000 || samples <= 0) { fprintf(stderr, "Please specify a reasonable number of samples\n"); exit(1); } } pinfo("samples: %d\n", samples); sleep_time = 1000000/samples; break; default: usage(argv[0]); return 1; } } globals = (global_t *) malloc(sizeof(global_t)); power_init(globals); /* we want to acquire samples over some period of time, so . . . */ for(i = 0; i < samples + 2; i++) { for(j = 0; j < globals->battery_count; j++) acquire_batt_info(globals, j); acquire_global_info(globals); usleep(sleep_time); } ap = &globals->adapter; if(ap->power == AC) { printf("On AC Power"); for(i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if(binfo->present && (binfo->charge_state == CHARGE)) { printf("; Battery %s charging", binfo->name); printf(", currently at %2d%%", binfo->percentage); if(binfo->charge_time >= 0) printf(", %2d:%02d remaining", binfo->charge_time/60, binfo->charge_time%60); } } printf("\n"); } else if(ap->power == BATT) { printf("On Battery"); for(i = 0; i < globals->battery_count; i++) { binfo = &batteries[i]; if(binfo->present && (binfo->percentage >= 0)) printf(", Battery %s at %d%%", binfo->name, binfo->percentage); } if(globals->rtime >= 0) printf("; %d:%02d remaining", globals->rtime/60, globals->rtime%60); printf("\n"); } return 0; } wmacpi-2.4/master_low.xpm0000644000207400020740000003424013653534554015117 0ustar azazelazazel/* XPM */ static char * master_low_xpm[] = { "157 88 18 1", " c None", ". c #000000", "+ c #FF0000", "@ c #202020", "# c #FFF500", "$ c #09FF00", "% c #400000", "& c #403B00", "* c #034000", "= c #AAAFA9", "- c #004941", "; c #20B2AE", "> c #027E72", ", c #188A86", "' c #22B2AE", ") c #C7C7C7", "! c #034A40", "~ c #107D79", " . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " ........................................................ . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . ++++@++++@++++@####@####@####@####@$$$$@$$$$@$$$$@$$$$ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " .%%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@****= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " ======================================================== . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@----@@@----@@@@@@@----@@@----@@ ", " ............................. ......................... . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @-@@@@-@-@@@@-@@;@@-@@@@-@-@@@@-@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@= .@@@@@@@@@@@@@@@@@@@@@@@= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @-@@@@-@-@@@@-@@;@@-@@@@-@-@@@@-@ ", " .@@@@@@;;;;;@@@@;;;;;;;;;;@@= .@@@@@---@@@---@@@;@@@@@= . @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ ", " .@@@@@;@@@@;;;@@;@@@@@@@@;@@= .@@-@-@@@-@-@@@-@;@;@;@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @>;;;;>@>;;;;>@@@@@>;;;;>@>;;;;>@ ", " .@@@@@;@@@@;@@@@;@@@@@@@@;;@= .@@-@-@@@-@-@@@-@@;@;@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " .@@@;;;@@@@;@@@@;@@@@@@@@;;@= .@@@@@---@@@---@@@@;@@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @-@@@@-@-@@@@-@@;@@-@@@@-@-@@@@-@ ", " .@@;@@;@@@@;;;@@;@@@@@@@@;;@= .@@-@-@@@-@-@@@-@@;@;@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @-@@@@-@-@@@@-@@;@@-@@@@-@-@@@@-@ ", " .@;@@@@;;;;;@@@@;@@@@@@@@;@@= .@@-@-@@@-@-@@@-@;@;@;@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ ", " .@;@@@@@@@@@@@@@;;;;;;;;;;@@= .@@@@@---@@@---@@@@@;@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@= .@@@@@@@@@@@@@@@@@@@@@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @@----@@@----@@@@@@@----@@@----@@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@= .@@@@@@@@@@@@@@@@@@@@@@@= . %%%%@%%%%@%%%%@&&&&@&&&&@&&&&@&&&&@****@****@****@**** @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " ============================= ========================= . ", " . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " . @@;;;@@@---,@,;;;,@,;;;,@,---,@,;;;,@,;;;,@,;;;,@,;;;,@,;;;,@@;@@@@@@@ ", " ..................................... ................= . @;@@@;@-@@@;@-@@@;@-@@@;@;@@@;@;@@@-@;@@@-@-@@@;@;@@@;@;@@@;@;@;@;@@;@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= @@@@@@@@@@@@@@@@= . @;@@@;@-@@@;@-@@@;@-@@@;@;@@@;@;@@@-@;@@@-@-@@@;@;@@@;@;@@@;@@;@;@@@,@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= @@@@@@@@@@@@@@@@= . @,---,@@---,@,;;;,@@;;;,@,;;;,@,;;;,@,;;;,@@---,@,;;;,@,;;;,@@@;@@@@@@ ", " .@@@----@@@----@@@@@@@----@@@----@@@= @@@@@@@@@----@@@= . @;@@@;@-@@@;@;@@@-@-@@@;@-@@@;@-@@@;@;@@@;@-@@@;@;@@@;@-@@@;@@;@;@@@@@ ", " .@@-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@@= @@@@@@@@-@@@@-@@= . @;@@@;@-@@@;@;@@@-@-@@@;@-@@@;@-@@@;@;@@@;@-@@@;@;@@@;@-@@@;@;@;@;@@;@ ", " .@@-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@@= @''''@@@-@@@@-@@= . @@;;;@@@---,@,;;;,@,;;;,@@---,@,;;;,@,;;;,@@---,@,;;;,@,;;;,@@@@;@@@,@ ", " .@@-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@@= @'@@@'@@-@@@@-@@= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", " .@@-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@@= @'@@@'@@-@@@@-@@= . ", " .@@@----@@@----@@@@@@@----@@@----@@@= @'@@@'@@@----@@@= . @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ ................) ", " .@@-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@@= @''''@@@-@@@@-@@= . @@@@@@;;;;;@@@ @;;;;;;;;;;@@ @,@@;;;@@@;;;@@@;@@@@ @@@@@@@@@@@@@@@@) ", " .@@-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@@= @'@@@'@@-@@@@-@@= . @@@@@;@@@@;;;@ @;@@@@@@@@;@@ @;@;@@@;@;@@@;@;@;@;@ @@@@@@@@@@@@@@@@) ", " .@@-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@@= @'@@@'@@-@@@@-@@= . @@@@@;@@@@;@@@ @;@@@@@@@@;;@ @;@;@@@;@;@@@;@@;@;@@ @@@@@@@@@----@@@) ", " .@@-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@@= @'@@@'@@-@@@@-@@= . @@@;;;@@@@;@@@ @;@@@@@@@@;;@ @,@,---,@,---,@@@;@@@ @@@@@@@@-@@@@-@@) ", " .@@@----@@@----@@@@@@@----@@@----@@@= @''''@@@@----@@@= . @@;@@;@@@@;;;@ @;@@@@@@@@;;@ @;@;@@@;@;@@@;@@;@;@@ @''''@@@-@@@@-@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= @@@@@@@@@@@@@@@@= . @;@@@@;;;;;@@@ @;@@@@@@@@;@@ @;@;@@@;@;@@@;@;@;@;@ @'@@@'@@-@@@@-@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= @@@@@@@@@@@@@@@@= . @;@@@@@@@@@@@@ @;;;;;;;;;;@@ @,@@;;;@@@;;;@@@@@;@@ @'@@@'@@-@@@@-@@) ", " ===================================== ================= . @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @'@@@'@@@----@@@) ", " . @''''@@@-@@@@-@@) ", " . @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @'@@@'@@-@@@@-@@) ", " ........................................................ . @@@@@@-----@@@ @----------@@ @@@@---@@@---@@@-@@@@ @'@@@'@@-@@@@-@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@@@@-@@@@---@ @-@@@@@@@@-@@ @-@-@@@-@-@@@-@-@-@-@ @'@@@'@@-@@@@-@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@@@@-@@@@-@@@ @-@@@@@@@@--@ @-@-@@@-@-@@@-@@-@-@@ @''''@@@@----@@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@@---@@@@-@@@ @-@@@@@@@@--@ @@@@---@@@---@@@@-@@@ @@@@@@@@@@@@@@@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@-@@-@@@@---@ @-@@@@@@@@--@ @-@-@@@-@-@@@-@@-@-@@ @@@@@@@@@@@@@@@@) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @-@@@@-----@@@ @-@@@@@@@@-@@ @-@-@@@-@-@@@-@-@-@-@ ))))))))))))))))) ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @-@@@@@@@@@@@@ @----------@@ @@@@---@@@---@@@@@-@@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@ ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= . @@'''@@@@@@>@>'''>@>'''>@>@@@>@>'''>@>'''>@>'''>@>'''>@>'''>@@@@@@@@@@@@@ @@@@@@ ", " ======================================================== . @'@@@'@@@@@'@@@@@'@@@@@'@'@@@'@'@@@@@'@@@@@@@@@'@'@@@'@'@@@'@@@@@@@@@@@@@ @@@@@@ ", " . @'@@@'@@@@@'@@@@@'@@@@@'@'@@@'@'@@@@@'@@@@@@@@@'@'@@@'@'@@@'@@@@@@@@@@@@@ @@@@@@ ", " . @>@@@>@@@@@>@>'''>@@'''>@>'''>@>'''>@>'''>@@@@@>@!'''!@>'''>@>'''>@@@@@@@ @@@@@@ ", " . @'@@@'@@@@@'@'@@@@@@@@@'@@@@@'@@@@@'@'@@@'@@@@@'@'@@@'@@@@@'@@@@@@@@@@@@@ @@@@@@ ", " . @'@@@'@@@@@'@'@@@@@@@@@'@@@@@'@@@@@'@'@@@'@@@@@'@'@@@'@@@@@'@@@@@@@@@@@@@ @@@@@@ ", "................................................................. @@'''@@@@@@'@>'''>@>'''>@@@@@>@>'''>@>'''>@@@@@>@>'''>@>'''>@@@@@@@@@@@@@ @@@@'@ ", " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@!'''!@>'''@@>'''>@>'''@@>'''>@>'''>@>'''>@>@@@>@@@>@@@@@@@>@>@@@>@>@@@@@'@@@'@>'''@@>'''>@>'''>@>'''>@>'''>@>'''>@>'''>@>@@@>@>@@@>@>@@@>@>@@@>@>@@@>@>'''>@", "@'@@@'@'@@@'@'@@@@@'@@@'@'@@@@@'@@@@@'@@@@@'@@@'@@@'@@@@@@@'@'@@@'@'@@@@@''@''@'@@@'@'@@@'@'@@@'@'@@@'@'@@@'@'@@@@@@@'@@@'@@@'@'@@@'@'@@@'@'@@@'@'@@@'@@@@@'@", "@'@@@'@'@@@'@'@@@@@'@@@'@'@@@@@'@@@@@'@@@@@'@@@'@@@'@@@@@@@'@'@@'!@'@@@@@'@'@'@'@@@'@'@@@'@'@@@'@'@@@'@'@@@'@'@@@@@@@'@@@'@@@'@'@@@'@'@@@'@!'@'!@'@@@'@@@@'!@", "@>'''>@>'''@@>@@@@@>@@@>@>'''@@>'''@@>!''>@>'''>@@@>@@@@@@@>@>''!@@>@@@@@>@@@>@>@@@>@>@@@>@>'''>@>'@@>@>'''@@>'''>@@@>@@@>@@@>@>@@@>@>@@@>@@!'!@@>'''>@@!'!@@", "@'@@@'@'@@@'@'@@@@@'@@@'@'@@@@@'@@@@@'@@@'@'@@@'@@@'@@@@@@@'@'@@'!@'@@@@@'@@@'@'@@@'@'@@@'@'@@@@@'@'@'@'@@@'@@@@@'@@@'@@@'@@@'@'@@@'@'@'@'@!'@'!@@@@@'@!'@@@@", "@'@@@'@'@@@'@'@@@@@'@@@'@'@@@@@'@@@@@'@@@'@'@@@'@@@'@@@@@@@'@'@@@'@'@@@@@'@@@'@'@@@'@'@@@'@'@@@@@'@@''@'@@@'@@@@@'@@@'@@@'@@@'@'@@@'@''@''@'@@@'@@@@@'@'@@@@@", "@>@@@>@>'''@@>'''>@''''@@>'''>@'@@@@@>'''>@>@@@>@@@'@@@>'''>@>@@@>@>'''!@>@@@>@'@@@'@>'''>@>@@@@@>'''>@>@@@>@>'''>@@@>@@@!''''@@'''@@'@@@'@>@@@'@>'''>@>'''>@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@", "@@;;;;@@@----~@~;;;;,@~;;;;~@~----~@~;;;;~@~;;;;,@~;;;;~@~;;;;,@~;;;;,@@@@@ @@;;;;@@@;;;;@@@@@@@;;;;@@@;;;;@@ @@----@@@----@@@@@@@----@@@----@@ @@'---'@", "@;@@@@;@-@@@@;@-@@@@;@-@@@@;@;@@@@;@;@@@@-@;@@@@-@-@@@@;@;@@@@;@;@@@@;@@;@@ @;@@@@;@;@@@@;@@;@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@ @'@'@'-@", "@;@@@@;@-@@@@;@-@@@@;@-@@@@;@;@@@@;@;@@@@-@;@@@@-@-@@@@;@;@@@@;@;@@@@;@@;@@ @;@@@@;@;@@@@;@@;@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@ @-'@'@-@", "@;@@@@;@-@@@@;@-@@@@;@-@@@@;@;@@@@;@;@@@@-@;@@@@-@-@@@@;@;@@@@;@;@@@@;@@@@@ @;@@@@;@;@@@@;@@@@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ @-@'@'-@", "@;@@@@;@-@@@@;@-@@@@;@-@@@@;@;@@@@;@;@@@@-@;@@@@-@-@@@@;@;@@@@;@;@@@@;@@@@@ @;@@@@;@;@@@@;@@@@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ @-'@'@'@", "@~----~@@----~@~;;;;~@~;;;;~@~;;;;~@~;;;;~@~;;;;~@@----~@~;;;;~@~;;;;~@@@@@ @~----~@~----~@@@@@~----~@~----~@ @@----@@@----@@@@@@@----@@@----@@ @'---'@@", "@;@@@@;@-@@@@;@;@@@@-@-@@@@;@-@@@@;@-@@@@;@;@@@@;@-@@@@;@;@@@@;@-@@@@;@@@@@ @;@@@@;@;@@@@;@@@@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ @-@@@@-@", "@;@@@@;@-@@@@;@;@@@@-@-@@@@;@-@@@@;@-@@@@;@;@@@@;@-@@@@;@;@@@@;@-@@@@;@@@@@ @;@@@@;@;@@@@;@@@@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@@@@-@@@@-@-@@@@-@ @'''''-@", "@;@@@@;@-@@@@;@;@@@@-@-@@@@;@-@@@@;@-@@@@;@;@@@@;@-@@@@;@;@@@@;@-@@@@;@@;@@ @;@@@@;@;@@@@;@@;@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@ @'@@@''@", "@;@@@@;@-@@@@;@;@@@@-@-@@@@;@-@@@@;@-@@@@;@;@@@@;@-@@@@;@;@@@@;@-@@@@;@@;@@ @;@@@@;@;@@@@;@@;@@;@@@@;@;@@@@;@ @-@@@@-@-@@@@-@@-@@-@@@@-@-@@@@-@ @'@@@''@", "@@;;;;@@@----~@~;;;;~@~;;;;~@@----~@~;;;;~@~;;;;~@@----~@~;;;;~@~;;;;~@@@@@ @@;;;;@@@;;;;@@@@@@@;;;;@@@;;;;@@ @@----@@@----@@@@@@@----@@@----@@ @'''''@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@"}; wmacpi-2.4/TODO0000644000207400020740000000276113653534554012710 0ustar azazelazazel2007 July 13 2.2rc1 * Make sure that everything works properly on modern kernels. 2004 January 18 1.99r3 * Correctly handle changing batteries at runtime, if possible. Note the bug reported by Joey Hess against wmacpi 1.33 . . . 2003 November 23 1.99 * Expand libacpi to handle everything else under /proc/acpi. Basically, make it into a full ACPI reporting library. * Make the command line tool a complete replacement for Grahame Bowland's acpi tool, so that wmacpi won't conflict with it. 2003 July 6 0.50 * Fix the non-deb installation - as it stands, it doesn't even try. * Yet more cleanups. 2003 June 24 0.14 * Still more code cleanups - there's a considerable amount of dumb stuff in there still . . . * Display time left for battery charging. But first make sure that this will actually work with other systems. * Turn libacpi into a real library? 2003 May 30 0.10 * More code cleanups, particularly in the various display functions. * Full handling of multiple batteries. * Add some kind of progressive display of power consumption, roughly similar to what wmmon displays for cpu usage (possibly as a completely seperate display mode, or possibly as a replacement for the (completely useless) button). * Drop APM support (maybe?). 2003 May 26 0.2a * Restructure power state handling - split it into a boolean AC on/off and a battery status flag. * Expand the APMInfo struct to be more useful. * Code cleanups . . . -- Simon Fowler,