From: Francois Fleuret Date: Mon, 30 Mar 2009 08:59:42 +0000 (+0200) Subject: Initial commit. X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?a=commitdiff_plain;h=8d55f0c774014f7d86424b953f61871b41beb700;p=xacpi.git Initial commit. --- 8d55f0c774014f7d86424b953f61871b41beb700 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..daa750c --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +xacpi: xacpi.c + gcc -g -DNARROWPROTO -o xacpi -L /usr/X11R6/lib/ -lX11 -lXaw xacpi.c diff --git a/xacpi.1 b/xacpi.1 new file mode 100644 index 0000000..17755f0 --- /dev/null +++ b/xacpi.1 @@ -0,0 +1,151 @@ +.\" xacpi.1 -- +.\" Created: Thu Jan 11 16:29:49 1996 by r.faith@ieee.org +.\" Revised: Sun Apr 21 16:37:42 1996 by r.faith@ieee.org +.\" Revised: Sun Jun 13 01:59:58 2004 by francois.fleuret@epfl.ch +.\" Revised: Wed Oct 13 18:33:12 2004 by francois.fleuret@epfl.ch +.\" Revised: Wed Dec 03 08:52:14 2004 by francois.fleuret@epfl.ch +.\" Copyright 1996 Rickard E. Faith (r.faith@ieee.org) +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" manual under the conditions for verbatim copying, provided that the +.\" entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one +.\" +.\" Since the Linux kernel and libraries are constantly changing, this +.\" manual page may be incorrect or out-of-date. The author(s) assume no +.\" responsibility for errors or omissions, or for damages resulting from +.\" the use of the information contained herein. The author(s) may not +.\" have taken the same level of care in the production of this manual, +.\" which is licensed free of charge, as they might when working +.\" professionally. +.\" +.\" Formatted or processed versions of this manual, if unaccompanied by +.\" the source, must acknowledge the copyright and authors of this work. +.\" +.TH XACPI 1 "June 2004" "" "" +.SH NAME +xacpi \- display Advanced Configuration and Power Interface (ACPI) BIOS information +.SH SYNOPSIS +.B xacpi [ ... ] +.SH DESCRIPTION +.B xacpi +puts up an X window that displays, from left to right and optionally: +the time and date, the AC state (L for line and B for battery), the +battery charge (in percentage or remaining time for complete charge or +discharge), a colored bar representing the same, the CPU temperature +and the CPU frequency in Ghz. Clicking on the charge time will toggle +the display between time and percentage, and clicking on the temperature +will toggle between Celsius and Fahrenheit. +.SH "OPTIONS AND RESOURCES" +In addition to standard Xt options, the following options are available: +.TP +.B \-V +Print the program version number and exit. +.TP +.B \-H +Print a short help +.TP +.BI \-highcolor " color" +The color of the bar when the battery percentage is above +.IR highvalue . +Defaults to "green". (*highColor) +.TP +.BI \-lowcolor " color" +The color of the bar when the battery percentage is between +.I lowvalue +and +.IR highvalue . +Defaults to "yellow". (*lowColor) +.TP +.BI \-criticalcolor " color" +The color of the bar when the battery percentage is below +.IR lowvalue +or the color of the temperature when higher then the critical temperature. +Defaults to "red". +This color is also used to flash the alphanumeric part of the display +when the power status is critical. (*criticalColor) +.TP +.BI \-highvalue " highvalue" +Set +.IR highvalue . +The default is 50. (*highValue) +.TP +.BI \-lowvalue " lowvalue" +Set +.IR lowvalue . +The default is 10. (*lowValue) +.TP +.BI \-criticaltemperature " criticaltemperature" +Set +.IR criticaltemperature . +If not set the default is 70C or 158F. (*criticalTemperature) +.TP +.BI \-chargingcolor " color" +The color of the printed display when charging. +The default is "blue". +Use +.B \-foreground +to change the color used when on battery power. (*chargingColor) +.TP +.BI \-delay " delay" +Sets the number of seconds delay between each update. +The default is 1. (*delay) +.TP +.B \-percent +Display percentage on startup, instead of time remaining. (*percent, boolean) +.TP +.B \-percentauto +Swap automatically between displaying percentage and displaying the +time remaining. When on AC power, display percentage, when on battery +power, display the time remaining. (*percentAuto, boolean) +.TP +.B \-showbar +Show the battery colored bar. (*showBar, boolean) +.TP +.B \-showdate +Show the current time and date. (*showDate, boolean) +.TP +.B \-dateformat +Specifies the format for the date (cf. strftime). Default is +.I %a %b %e %H:%M:%S %Z %Y + (*dateFormat). +.TP +.B \-showtemp +Show the temperature (maximum among the sensors). (*showTemperature, boolean) +.TP +.B \-showcpufreq +Show the CPU frequency (in Ghz). (*showCpufreq, boolean) +.TP +.B \-fahrenheit +Display the temperature in Fahrenheit. (*fahrenheit, boolean) +.TP +.B \-acpidir +Specifies the ACPI directory. Default is +.I /proc/acpi + (*acpiDir). +.TP +.B \-cpufreqdir +Specifies the cpu frequency directory. Default is +.I /sys/devices/system/cpu/cpu0/cpufreq + (*cpuFreqDir). +.SH BUGS +When the battery percentage is low, using a bright color to warn you +of impending doom may be futile because the bar is too short. Because +of the form widget's desire to maintain proportions, dynamic resizing +of the window may not do what you want it to do. +.SH FILES +.I /proc/acpi +.SH AUTHOR +This program is an extension of xapm, originally written by Rik Faith +(faith@cs.unc.edu). The changes to xacpi were written by Francois +Fleuret (francois.fleuret@epfl.ch). Xacpi may be freely distributed +under the terms of the GNU General Public License. There is +ABSOLUTELY NO WARRANTY for this program. +.SH "SEE ALSO" +.BR acpi (1), +.BR acpid (8), +.BR strftime (3). diff --git a/xacpi.c b/xacpi.c new file mode 100644 index 0000000..c371296 --- /dev/null +++ b/xacpi.c @@ -0,0 +1,799 @@ +/* xacpi.c -- + * + * This is a patched xapm working with acpi (which does not support + * apm anymore) + * + * xapm was written and (C) by Rickard E. Faith (r.faith@ieee.org) + * + * 2004/06/10 Patch for acpi by Francois Fleuret (francois.fleuret@epfl.ch) + * 2004/07/20 Patch from Bryan Cardillo (dillo@seas.upenn.edu) + * + * To compile: + * + * gcc -DNARROWPROTO -o xacpi -L /usr/X11R6/lib/ -lX11 -lXaw xacpi.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, 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. + * + * $Id: xacpi.c,v 1.40 2004/12/03 07:52:30 fleuret Exp $ + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* The acpi file readings can fail sometime, but we will immediately + retry. We display ERR in the window if we fail more than that + number of times . */ + +#define NB_TOLERATED_FAILURES 1 + +#define XACPI_VERSION "1.3" +#define MIN_BAR_WIDTH 32 + +#define DEFAULT_ACPI_DIR "/proc/acpi" +#define DEFAULT_CPUFREQ_DIR "/sys/devices/system/cpu/cpu0/cpufreq" + +#define BUFFER_LEN 1024 + +#define DEFAULT_DELAY 5 +#define DEFAULT_DATE_FORMAT "%a %b %e %H:%M:%S %Z %Y" + +typedef struct _instance_variables { + Pixel highColor, lowColor, criticalColor, chargingColor; + Pixel foreground; + int highValue, lowValue, criticalTemp; + String geometry; + int delay; + Boolean displayPercent, displayPercentAuto; + Boolean showBar, showTemperature; + Boolean showCpufreq; + String cpuFreqDir; + String dateFormat; + Boolean showDate; + Boolean fahrenheit; + String acpiDir; +} instance_variable_rec; + +struct acpi_info { + int design_capacity, last_full_capacity, remaining_capacity; + int present_rate; + int ac_on_line; + int charging; + int battery_percentage, battery_time; + int temperature; + int cpufreq; +}; + +static XtAppContext app_context; +static Widget scrollbar; +static Widget topLevel; +static Widget form; +static Widget delay; +static Widget temperature; +static Widget cpufreq; +static Widget date; +static XtIntervalId timerId; +static instance_variable_rec iv; +static int debug; + +static int nb_failures; + +char *get_field_name(char *buffer, char *r) { + while(*r && *r != ':') *(buffer++) = *(r++); + while(*r == ' ' || *r == ':') r++; + *(buffer++) = '\0'; + return r; +} + +int get_int(char *r) { + char tmp[BUFFER_LEN]; + char *t = tmp; + while(*r >= '0' && *r <= '9') *(t++) = *(r++); + *t = '\0'; + return atoi(tmp); +} + +char *goto_next_line(char *r) { + while(*r && *r != '\n') r++; + while(*r == '\n') r++; + if(*r) return r; else return 0; +} + +/* We make the assumption that the file is shorter than BUFFER_LEN + bytes. */ + +void read_proc_file(char *path, char *subdir, char *filename, char *content) { + char name[BUFFER_LEN]; + size_t len; + FILE *file; + + snprintf(name, BUFFER_LEN, "%s/%s/%s", path, subdir, filename); + + file = fopen(name, "r"); + if(file) { +#ifdef DEBUG + printf("reading of [%s]\n", name); +#endif + len = fread(content, 1, BUFFER_LEN - 1, file); + fclose(file); + } else { +#ifdef DEBUG + printf("opening of [%s] failed\n", name); +#endif + len = 0; + } + + if(len == 0) { + err(1, "%s", name); +#ifdef DEBUG + printf("reading of [%s] failed\n", name); +#endif + } + else content[len] = '\0'; +} + +void check_acpi(char *acpi_dir) { + DIR *directory; + + directory= opendir(acpi_dir); + if(directory) closedir(directory); + else err(1, "%s", acpi_dir); +} + +void acpi_read(char *acpi_dir, char *cpu_dir, struct acpi_info *acpi) { + DIR *directory; + struct dirent *dir_entry; + char content[BUFFER_LEN], word[BUFFER_LEN], dir_name[BUFFER_LEN]; + + int error = 0; + + memset(acpi, 0, sizeof(*acpi)); + + /* Read the battery information */ + + snprintf(dir_name, BUFFER_LEN, "%s/battery", acpi_dir); + directory = opendir(dir_name); + if (!(directory)) err(1, "%s", dir_name); + + while((dir_entry = readdir(directory))) { + if(dir_entry->d_name[0] != '.') { + char *s; + + read_proc_file(dir_name, dir_entry->d_name, "info", content); + + s = content; + while(s) { + s = get_field_name(word, s); + + if(strcmp(word, "ERROR") == 0) { +#ifdef DEBUG + printf("Read \"ERROR\"\n"); +#endif + error = 1; + } + + else if(strcmp(word, "design capacity") == 0 && s) acpi->design_capacity += get_int(s); + else if(strcmp(word, "last full capacity") == 0 && s) acpi->last_full_capacity += get_int(s); + s = goto_next_line(s); + } + + read_proc_file(dir_name, dir_entry->d_name, "state", content); + s = content; + while(s) { + s = get_field_name(word, s); + if(strcmp(word, "ERROR") == 0) { +#ifdef DEBUG + printf("Read \"ERROR\"\n"); +#endif + error = 1; + } + + else if(strcmp(word, "present rate") == 0 && s) acpi->present_rate += get_int(s); + else if(strcmp(word, "remaining capacity") == 0 && s) acpi->remaining_capacity += get_int(s); + else if(strcmp(word, "charging state") == 0 && s) { + if(strncmp(s, "charging", 8) == 0) acpi->charging = 1; + else if(strncmp(s, "charged", 7) == 0) acpi->charging = 0; + else if(strncmp(s, "discharging", 11) == 0) acpi->charging = -1; + } + s = goto_next_line(s); + } + } + } + + closedir(directory); + + /* Read the AC line information */ + + snprintf(dir_name, BUFFER_LEN, "%s/ac_adapter", acpi_dir); + directory = opendir(dir_name); + if (!(directory)) err(1, "%s", dir_name); + + while((dir_entry = readdir(directory))) { + if(dir_entry->d_name[0] != '.') { + char *s; + read_proc_file(dir_name, dir_entry->d_name, "state", content); + s = content; + while(s) { + s = get_field_name(word, s); + if(strcmp(word, "ERROR") == 0) { +#ifdef DEBUG + printf("Read \"ERROR\"\n"); +#endif + error = 1; + } + + else if(strcmp(word, "state") == 0 && s) + acpi->ac_on_line = (strncmp(s, "on-line", 7) == 0); + s = goto_next_line(s); + } + } + } + + closedir(directory); + + /* When required, read the temperature information */ + + if(temperature) { + snprintf(dir_name, BUFFER_LEN, "%s/thermal_zone", acpi_dir); + directory = opendir(dir_name); + if (!(directory)) err(1, "%s", dir_name); + + acpi->temperature = -1; + + while((dir_entry = readdir(directory))) { + if(dir_entry->d_name[0] != '.') { + char *s; + read_proc_file(dir_name, dir_entry->d_name, "temperature", content); + s = content; + while(s) { + s = get_field_name(word, s); + if(strcmp(word, "ERROR") == 0) { +#ifdef DEBUG + printf("Read \"ERROR\"\n"); +#endif + error = 1; + } + + else if(strcmp(word, "temperature") == 0 && s) { + int temp = get_int(s); + if(temp > acpi->temperature) acpi->temperature = temp; + } + s = goto_next_line(s); + } + } + } + + closedir(directory); + } + + /* When required, read the frequency information */ + + if(cpufreq) { + read_proc_file(cpu_dir, "", "scaling_cur_freq", content); + char *s = content; + acpi->cpufreq = get_int(s)/1000; + } + + if(error) nb_failures++; else nb_failures = 0; + + if(nb_failures == 0) { + + // Bryan Cardillo preferes to see the percentage of the design + // capacity. I think it's kind of depressive to see that the + // battery gets worst and worst ... + + /* if (acpi->charging == 0) { */ + /* acpi->battery_percentage = (acpi->remaining_capacity * 100) / acpi->design_capacity; */ + /* } else { */ + acpi->battery_percentage = (acpi->remaining_capacity * 100) / acpi->last_full_capacity; + /* } */ + + if(acpi->present_rate) { + if(acpi->charging > 0) + acpi->battery_time = ((acpi->last_full_capacity - acpi->remaining_capacity) * 3600) / acpi->present_rate; + else if(acpi->charging < 0) + acpi->battery_time = (acpi->remaining_capacity * 3600) / acpi->present_rate; + } + } else if(nb_failures > NB_TOLERATED_FAILURES) { + acpi->battery_time = -1; + } +} + +void put_date(char *buf, char *format) { + time_t t; + time(&t); + strftime(buf, BUFFER_LEN, format, localtime(&t)); +} + +static void update(XtPointer client_data, XtIntervalId * id) { + struct acpi_info acpi; + char buf[128]; + + static int current_bar_color = -1; + static int current_charging_color = -1; + static int current_temperature_color = -1; + static int blink_counter = 0; + + static int lastPercentage = -1; + static int lastMinutes = -1; + static int lastDisplay = -1; + static int lastACStatus = -1; + static int lastTemperature = -1; + static int lastCpufreq = -1; + + acpi_read(iv.acpiDir, iv.cpuFreqDir, &acpi); + + if(nb_failures > NB_TOLERATED_FAILURES) { + + XtVaSetValues(delay, XtNlabel, "ERR", NULL); + + if(scrollbar && current_bar_color != iv.criticalColor) { + current_bar_color = iv.criticalColor; + XtVaSetValues(scrollbar, XtNforeground, current_bar_color, NULL); + XtVaSetValues(scrollbar, XtNborderColor, current_bar_color, NULL); + } + + /* All this will have to be refreshed */ + + lastPercentage = -1; + lastMinutes = -1; + lastDisplay = -1; + blink_counter = 0; + lastACStatus = -1; + lastTemperature = -1; + lastCpufreq = -1; + + } + + /* We refresh only if there were no error during updating */ + + else if(nb_failures == 0) { + + if(iv.displayPercentAuto && acpi.ac_on_line != lastACStatus){ + lastDisplay = -1; + iv.displayPercent = acpi.ac_on_line; + } + + if (iv.displayPercent) { + if (lastDisplay != iv.displayPercent + || acpi.battery_percentage != lastPercentage + || acpi.ac_on_line != lastACStatus) { + + /* lastPercentage updated at end */ + + snprintf(buf, BUFFER_LEN, "%s%d%%", acpi.ac_on_line ? "L" : "B", acpi.battery_percentage); + XtVaSetValues(delay, XtNlabel, buf, NULL); + } + } else { + + /* Negative value means we could not estimate it in acpi_read + because the charging speed was 0 */ + + if(acpi.battery_time < 0) { + snprintf(buf, BUFFER_LEN, "%s", acpi.ac_on_line ? "L" : "B???"); + XtVaSetValues(delay, XtNlabel, buf, NULL); + + } else { + + int minutes = acpi.battery_time / 60; + if (lastDisplay != iv.displayPercent || lastMinutes != minutes + || acpi.ac_on_line != lastACStatus + ) { + lastMinutes = minutes; + snprintf(buf, BUFFER_LEN, "%s%lu:%02lu", acpi.ac_on_line ? "L" : "B", minutes/60, minutes%60); + XtVaSetValues(delay, XtNlabel, buf, NULL); + } + + } + } + + lastDisplay = iv.displayPercent; + lastACStatus = acpi.ac_on_line; + + if(scrollbar) { + if (acpi.battery_percentage <= iv.lowValue) { + if (current_bar_color != iv.criticalColor) { + current_bar_color = iv.criticalColor; + XtVaSetValues(scrollbar, XtNforeground, current_bar_color, NULL); + XtVaSetValues(scrollbar, XtNborderColor, current_bar_color, NULL); + } + } else if (acpi.battery_percentage <= iv.highValue) { + if (current_bar_color != iv.lowColor) { + current_bar_color = iv.lowColor; + XtVaSetValues(scrollbar, XtNforeground, current_bar_color, NULL); + XtVaSetValues(scrollbar, XtNborderColor, current_bar_color, NULL); + } + } else { + if (current_bar_color != iv.highColor) { + current_bar_color = iv.highColor; + XtVaSetValues(scrollbar, XtNforeground, current_bar_color, NULL); + XtVaSetValues(scrollbar, XtNborderColor, current_bar_color, NULL); + } + } + } + + if(temperature) { + int degrees = (iv.fahrenheit) ? + 32 + (acpi.temperature * 18) / 10 : acpi.temperature; + + if (degrees != lastTemperature) { + if(iv.fahrenheit) { + snprintf(buf, BUFFER_LEN, "%dF", degrees); + } else { + snprintf(buf, BUFFER_LEN, "%dC", degrees); + } + XtVaSetValues(temperature, XtNlabel, buf, NULL); + } + + if(degrees >= iv.criticalTemp) { + if (current_temperature_color != iv.criticalColor) { + current_temperature_color = iv.criticalColor; + XtVaSetValues(temperature, XtNforeground, current_temperature_color, NULL); + } + } else { + if (current_temperature_color != iv.foreground) { + current_temperature_color = iv.foreground; + XtVaSetValues(temperature, XtNforeground, current_temperature_color, NULL); + } + } + + lastTemperature = degrees; + } + + if(cpufreq && acpi.cpufreq != lastCpufreq) { + snprintf(buf, BUFFER_LEN, "%.1fGhz", ((float) acpi.cpufreq)/1000.0); + XtVaSetValues(cpufreq, XtNlabel, buf, NULL); + } + + if(date) { + put_date(buf, iv.dateFormat); + XtVaSetValues(date, XtNlabel, buf, NULL); + } + + if (acpi.charging > 0) { + if (current_charging_color != iv.chargingColor) + XtVaSetValues(delay, XtNforeground, + current_charging_color = iv.chargingColor, NULL); + } else { + if (acpi.battery_percentage < iv.lowValue && blink_counter++ % 2) { + if (current_charging_color != iv.criticalColor) + XtVaSetValues(delay, + XtNforeground, current_charging_color = iv.criticalColor, NULL); + } else { + if (current_charging_color != iv.foreground) + XtVaSetValues(delay, + XtNforeground, current_charging_color = iv.foreground, NULL); + } + } + + if (scrollbar && acpi.battery_percentage != lastPercentage) { + XawScrollbarSetThumb(scrollbar, 0.0, + acpi.battery_percentage < 0 ? 0.0 : acpi.battery_percentage / 100.0); + lastPercentage = acpi.battery_percentage; + } + } + + /* We come back in 0.5s if there was an error */ + + timerId = XtAppAddTimeOut(app_context, + ((nb_failures > 0 && nb_failures <= NB_TOLERATED_FAILURES)) ? 250 : (1000 * iv.delay + 500), + update, app_context); +} + +static void press(Widget w, XtPointer client_data, XtPointer call_data){ + if (w == delay) { + iv.displayPercent = !iv.displayPercent; + } else if (w == temperature) { + iv.fahrenheit = !iv.fahrenheit; + } + XtRemoveTimeOut(timerId); + timerId = XtAppAddTimeOut(app_context, 0, update, app_context); +} + +static XrmOptionDescRec options[] = { + {"-highcolor", "*highColor", XrmoptionSepArg, NULL}, + {"-lowcolor", "*lowColor", XrmoptionSepArg, NULL}, + {"-criticalcolor", "*criticalColor", XrmoptionSepArg, NULL}, + {"-criticaltemperature", "*criticalTemperature", XrmoptionSepArg, NULL}, + {"-chargingcolor", "*chargingColor", XrmoptionSepArg, NULL}, + {"-highvalue", "*highValue", XrmoptionSepArg, NULL}, + {"-lowvalue", "*lowValue", XrmoptionSepArg, NULL}, + {"-delay", "*delay", XrmoptionSepArg, NULL}, + {"-percent", "*percent", XrmoptionNoArg, (XtPointer) "true"}, + {"-percentauto", "*percentAuto", XrmoptionNoArg, (XtPointer) "true"}, + {"-showbar", "*showBar", XrmoptionNoArg, (XtPointer) "true"}, + {"-showtemp", "*showTemperature", XrmoptionNoArg, (XtPointer) "true"}, + {"-showcpufreq", "*showCpuFreq", XrmoptionNoArg, (XtPointer) "true"}, + {"-showdate", "*showDate", XrmoptionNoArg, (XtPointer) "true"}, + {"-fahrenheit", "*fahrenheit", XrmoptionNoArg, (XtPointer) "true"}, + {"-dateformat", "*dateFormat", XrmoptionSepArg, NULL}, + {"-acpidir", "*acpiDir", XrmoptionSepArg, NULL}, + {"-cpufreqdir", "*cpuFreqDir", XrmoptionSepArg, NULL}, +}; + +#define offset(field) XtOffsetOf( instance_variable_rec, field ) + +static XtResource resources[] = { + + {"highColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(highColor), XtRString, "green"}, + {"lowColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(lowColor), XtRString, "yellow"}, + {"criticalColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(criticalColor), XtRString, "red"}, + {"chargingColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(chargingColor), XtRString, "blue"}, + + {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), + offset(foreground), XtRString, XtDefaultForeground}, + {"highValue", XtCValue, XtRInt, sizeof(int), + offset(highValue), XtRImmediate, (XtPointer) 50}, + {"lowValue", XtCValue, XtRInt, sizeof(int), + offset(lowValue), XtRImmediate, (XtPointer) 10}, + {"criticalTemperature", XtCValue, XtRInt, sizeof(int), + offset(criticalTemp), XtRImmediate, (XtPointer) 0}, + {"geometry", XtCString, XtRString, sizeof(String), + offset(geometry), XtRString, (XtPointer) "170x10"}, + {"delay", XtCValue, XtRInt, sizeof(int), + offset(delay), XtRImmediate, (XtPointer) DEFAULT_DELAY}, + {"percent", XtCValue, XtRBoolean, sizeof(Boolean), + offset(displayPercent), XtRImmediate, (XtPointer) FALSE}, + {"percentAuto", XtCValue, XtRBoolean, sizeof(Boolean), + offset(displayPercentAuto), XtRImmediate, (XtPointer) FALSE}, + {"showBar", XtCValue, XtRBoolean, sizeof(Boolean), + offset(showBar), XtRImmediate, (XtPointer) FALSE}, + {"showTemperature", XtCValue, XtRBoolean, sizeof(Boolean), + offset(showTemperature), XtRImmediate, (XtPointer) FALSE}, + {"showCpuFreq", XtCValue, XtRBoolean, sizeof(Boolean), + offset(showCpufreq), XtRImmediate, (XtPointer) FALSE}, + {"showDate", XtCValue, XtRBoolean, sizeof(Boolean), + offset(showDate), XtRImmediate, (XtPointer) FALSE}, + {"fahrenheit", XtCValue, XtRBoolean, sizeof(Boolean), + offset(fahrenheit), XtRImmediate, (XtPointer) FALSE}, + {"dateFormat", XtCString, XtRString, sizeof(String), + offset(dateFormat), XtRString, (XtPointer) DEFAULT_DATE_FORMAT}, + {"acpiDir", XtCString, XtRString, sizeof(String), + offset(acpiDir), XtRString, (XtPointer) DEFAULT_ACPI_DIR}, + {"cpuFreqDir", XtCString, XtRString, sizeof(String), + offset(cpuFreqDir), XtRString, (XtPointer) DEFAULT_CPUFREQ_DIR}, +}; + +static void quit(Widget w, XtPointer client_data, XtPointer call_data){ + exit (0); +} + +static XtActionsRec main_actions[] = { {"Quit", (XtActionProc) quit}, +}; + +static String main_translations = "WM_PROTOCOLS:Quit()\n"; + +int main(int argc, char **argv){ + char c; + + int x = 0, y = 0, height = 0, width = 0; + int current_width = 0, own_width; + XFontStruct *fs; + Atom wm_protocols[1]; + Widget last; + + nb_failures = 0; + + topLevel = XtVaAppInitialize(&app_context, "XAcpi", + options, XtNumber(options), + &argc, argv, NULL, NULL); + + XtGetApplicationResources(topLevel, + &iv, + resources, + XtNumber(resources), + NULL, 0); + + if(iv.criticalTemp <= 0) { + if(iv.fahrenheit) iv.criticalTemp = 158; + else iv.criticalTemp = 70; + } + + check_acpi(iv.acpiDir); + + if (iv.delay < 1) iv.delay = DEFAULT_DELAY; + + XParseGeometry(iv.geometry, &x, &y, &width, &height); + + while ((c = getopt(argc, argv, "DVH")) != -1) + switch (c) { + case 'D': + ++debug; + break; + case 'V': + fprintf(stderr, "xacpi version " XACPI_VERSION ".\n"); + fprintf(stderr, "$Id: xacpi.c,v 1.40 2004/12/03 07:52:30 fleuret Exp $.\n"); + exit(0); + case 'H': + printf("Options:\n" + " -D\n" + " -V\n" + " -H\n" + " -highcolor \n" + " -lowcolor \n" + " -criticalcolor \n" + " -chargingcolor \n" + " -highvalue \n" + " -lowvalue \n" + " -delay \n" + " -percent\n" + " -percentauto\n" + " -showbar\n" + " -showtemp\n" + " -showcpufreq\n" + " -showdate\n" + " -dateformat \n" + " -fahrenheit\n" + " -acpidir \n" + " -cpufreqdir \n" + "\n" + "See man xacpi for more detailed information.\n"); + exit(0); + break; + } + + form = XtVaCreateManagedWidget("form", + formWidgetClass, topLevel, + XtNorientation, XtorientHorizontal, + XtNborderWidth, 0, + XtNdefaultDistance, 0, + NULL); + + /* Add the date */ + + if(iv.showDate) { + date = XtVaCreateManagedWidget("date", + labelWidgetClass, form, + XtNinternalHeight, 0, + XtNinternalWidth, 0, + XtNborderWidth, 0, + XtNlabel, "", + XtNresize, FALSE, + NULL); + + char buf[BUFFER_LEN]; + put_date(buf, iv.dateFormat); + last = date; + XtVaGetValues(last, XtNfont, &fs, NULL); + own_width = ((strlen(buf) + 2) * fs->max_bounds.width); + XtVaSetValues(last, XtNwidth, own_width, NULL); + current_width += own_width; + } else date = 0; + + /* Add the widget to display the remaining battery time */ + + delay = XtVaCreateManagedWidget("delay", + commandWidgetClass, form, + XtNleft, XtChainLeft, + XtNhighlightThickness, 0, + XtNinternalHeight, 0, + XtNinternalWidth, 0, + XtNborderWidth, 0, + XtNlabel, "", + XtNresize, FALSE, + NULL); + + + if(date) XtVaSetValues(delay, XtNfromHoriz, last, 0); + XtAddCallback(delay, XtNcallback, press, NULL); + + last = delay; + XtVaGetValues(last, XtNfont, &fs, NULL); + own_width = 6 * fs->max_bounds.width; + XtVaSetValues(last, XtNwidth, own_width, NULL); + current_width += own_width; + + /* Add the widget to display the colored bar */ + + if(iv.showBar) { + + scrollbar = XtVaCreateManagedWidget("scrollbar", + scrollbarWidgetClass, form, + XtNhorizDistance, 3, + XtNfromHoriz, last, + XtNorientation, XtorientHorizontal, + NULL); + + XawScrollbarSetThumb(scrollbar, 0.0, 0.0); + + XtVaSetValues(scrollbar, + XtNtranslations, XtParseTranslationTable(""), + NULL); + + last = scrollbar; + } else scrollbar = 0; + + /* Add the widget to display the temperature */ + + if(iv.showTemperature) { + temperature = XtVaCreateManagedWidget("temperature", + commandWidgetClass, form, + XtNhorizDistance, 6, + XtNfromHoriz, last, + XtNhighlightThickness, 0, + XtNinternalHeight, 0, + XtNinternalWidth, 0, + XtNborderWidth, 0, + XtNlabel, iv.fahrenheit ? "000F " : "00C ", + XtNresize, FALSE, + NULL); + last = temperature; + XtVaGetValues(last, XtNfont, &fs, NULL); + own_width = (iv. fahrenheit ? 5 : 4) * fs->max_bounds.width; + XtVaSetValues(last, XtNwidth, own_width, NULL); + current_width += own_width; + XtAddCallback(temperature, XtNcallback, press, NULL); + } else temperature = 0; + + /* Add the widget to display the cpu frequency */ + + if(iv.showCpufreq) { + cpufreq = XtVaCreateManagedWidget("cpufreq", + labelWidgetClass, form, + XtNhorizDistance, 6, + XtNfromHoriz, last, + XtNinternalHeight, 0, + XtNinternalWidth, 0, + XtNborderWidth, 0, + XtNlabel, "?.?Ghz", + XtNresize, FALSE, + NULL); + last = cpufreq; + XtVaGetValues(last, XtNfont, &fs, NULL); + own_width = 7 * fs->max_bounds.width; + XtVaSetValues(last, XtNwidth, own_width, NULL); + current_width += own_width; + } else cpufreq = 0; + + /* Changed the bar length to the unused width */ + + if(scrollbar) { + if(width > current_width + MIN_BAR_WIDTH) + XtVaSetValues(scrollbar, XtNwidth, width - current_width, 0); + else { + XtVaSetValues(scrollbar, XtNwidth, MIN_BAR_WIDTH, 0); + } + } + + XtRealizeWidget(topLevel); + + /* Add code to handle WM_DELETE_WINDOW cleanly. */ + + XtAppAddActions(app_context, main_actions, XtNumber(main_actions)); + XtOverrideTranslations(topLevel, XtParseTranslationTable(main_translations)); + wm_protocols[0] + = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW", False); + XSetWMProtocols(XtDisplay(topLevel), XtWindow(topLevel), wm_protocols, 1); + + timerId = XtAppAddTimeOut(app_context, 0, update, app_context); + XtAppMainLoop(app_context); + + return 0; +}