// bbapm.cc for bbapm - an tool for display the battery status in X11.
//
// Copyright (c) 1998 by John Kennis, j.m.b.m.kennis@ele.tue.nl
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// (See the included file COPYING / GPL-2.0)
//
#ifdef DEBUG
#include <iostream>
#endif
#include "bbapm.hh"
ToolWindow::ToolWindow(int argc, char **argv):
Basewindow(argc, argv)
{
resource = NULL;
load = NULL;
close_app = False;
broken = False;
/*
* initialize xrm database
*/
XrmInitialize();
resource = new Resource(this);
load = new GEOM[resource->loadbar.number_of_bars];
MakeWindow(False);
ReadAPM();
Redraw();
}
ToolWindow::~ToolWindow()
{
XUnmapWindow(dpy, framewin);
/*
* destroy pixmaps
*/
if (pixmap.frame)
image_control->removeImage(pixmap.frame);
if (pixmap.label)
image_control->removeImage(pixmap.label);
if (pixmap.loadbar_active)
image_control->removeImage(pixmap.loadbar_active);
if (pixmap.loadbar_inactive)
image_control->removeImage(pixmap.loadbar_inactive);
if (frameGC)
XFreeGC(dpy, frameGC);
XDestroyWindow(dpy, labelwin);
XDestroyWindow(dpy, framewin);
delete resource;
}
void
ToolWindow::Reconfigure(void)
{
/*
* destroy pixmaps
*/
image_control->removeImage(pixmap.frame);
image_control->removeImage(pixmap.label);
image_control->removeImage(pixmap.loadbar_active);
image_control->removeImage(pixmap.loadbar_inactive);
delete[]load;
resource->Reload();
load = new GEOM[resource->loadbar.number_of_bars];
memset(load, 0, sizeof(GEOM) * resource->loadbar.number_of_bars);
MakeWindow(True);
if (resource->show.label)
XClearWindow(dpy, labelwin);
XClearWindow(dpy, framewin);
ReadAPM();
Redraw();
}
void
ToolWindow::MakeWindow(bool reconfigure)
{
XSetWindowAttributes
attrib;
XWMHints
wmhints;
int
i;
int
number_of_loadbars = 0;
int
extra_space = 0;
int
label_counter = 0;
unsigned long
create_mask = CWBackPixmap | // CWBackPixel|CWBorderPixel|
CWOverrideRedirect | CWCursor | CWEventMask;
frame.height =
resource->frame.font->ascent + resource->frame.font->descent +
4 * resource->frame.bevelWidth;
if (resource->show.percentage)
number_of_loadbars ++;
label.seperator_width = label.space_width = 0;
memset(label.width, 0, 8);
if (resource->show.label) {
if (resource->show.label_percentage) {
label.width[0] = XTextWidth(resource->label.font, "100%",
strlen("100%"));
label_counter++;
}
if (resource->show.label_time) {
label.width[1] = XTextWidth(resource->label.font,
"00:00", strlen("00:00"));
label_counter++;
}
label.seperator_width =
XTextWidth(resource->label.font, "/", strlen("/"));
label.space_width =
XTextWidth(resource->label.font, " ",
strlen(" ")) + resource->frame.bevelWidth;
label.height = frame.height - 2 * resource->frame.bevelWidth;
extra_space = resource->frame.bevelWidth;
}
label.total_width = (label_counter - 1) * label.seperator_width +
2 * label.space_width;
for (i = 0; i < 8; i++) {
label.total_width += label.width[i];
}
#ifdef DEBUG
cerr << "MakeWindow: computing width " << endl;
#endif
frame.width = label.total_width + extra_space +
+resource->frame.bevelWidth * 2 +
(resource->frame.bevelWidth + resource->loadbar.width) *
number_of_loadbars;
#ifdef DEBUG
cerr << "\tframe.width = " << frame.width << endl;
cerr << "\tnumber_of_loadbars = " << number_of_loadbars << endl;
cerr << "\tresource.loadbar.width = " << resource->loadbar.width << endl;
#endif
int
label_x_position = 0;
if (number_of_loadbars!=0)
label_x_position = 2*resource->frame.bevelWidth+
(resource->frame.bevelWidth+
resource->loadbar.width)*number_of_loadbars;
else
label_x_position = resource->frame.bevelWidth+extra_space/2+
(resource->frame.bevelWidth+
resource->loadbar.width)*number_of_loadbars;
if (resource->position.mask & XNegative) {
resource->position.x =
display_width + resource->position.x - frame.width;
}
if (resource->position.mask & YNegative) {
resource->position.y =
display_height + resource->position.y - frame.height;
}
attrib.background_pixmap = ParentRelative;
pixmap.frame =
image_control->renderImage(frame.width, frame.height,
&resource->frame.texture);
if (withdrawn) {
attrib.override_redirect = False;
wmhints.initial_state = WithdrawnState;
} else {
attrib.override_redirect = True;
wmhints.initial_state = NormalState;
}
attrib.cursor = cursor;
attrib.event_mask =
ButtonPressMask | ButtonReleaseMask | ExposureMask |
FocusChangeMask | KeyPressMask | StructureNotifyMask;
if (!reconfigure) {
framewin = XCreateWindow(dpy, root, resource->position.x,
resource->position.y, frame.width,
frame.height, 0, depth, InputOutput,
v, create_mask, &attrib);
} else if (!withdrawn) {
XMoveResizeWindow(dpy, framewin, resource->position.x,
resource->position.y, frame.width, frame.height);
} else {
XResizeWindow(dpy, framewin, frame.width, frame.height);
}
wmhints.flags = IconWindowHint | StateHint;
wmhints.icon_window = framewin;
XSetWMHints(dpy, framewin, &wmhints);
if (!shape) {
XSetWindowBackgroundPixmap(dpy, framewin, pixmap.frame);
}
if (resource->show.label) {
pixmap.label =
image_control->renderImage(label.total_width, label.height,
&resource->label.texture);
if (!reconfigure) {
labelwin = XCreateWindow(dpy, framewin, label_x_position,
resource->frame.bevelWidth,
label.total_width, label.height, 0,
depth, InputOutput, v, create_mask,
&attrib);
} else {
XMoveResizeWindow(dpy, labelwin,
label_x_position,
resource->frame.bevelWidth,
label.total_width, label.height);
}
if (!resource->label.transparent)
XSetWindowBackgroundPixmap(dpy, labelwin, pixmap.label);
}
pixmap.loadbar_active =
image_control->renderImage(resource->loadbar.width + 4,
frame.height + 4,
&resource->loadbar.active_texture);
pixmap.loadbar_inactive =
image_control->renderImage(resource->loadbar.width + 4,
frame.height + 4,
&resource->loadbar.inactive_texture);
int
height = 0;
if (resource->loadbar.number_of_bars != 0)
height = (int) ceil((frame.height - 2.0 *
resource->frame.bevelWidth) /
resource->loadbar.number_of_bars);
for (i = 0; i < resource->loadbar.number_of_bars; i++) {
load[i].x = (int) (resource->loadbar.left_step_width * i
+ resource->frame.bevelWidth);
load[i].y = frame.height - resource->frame.bevelWidth - height * i;
load[i].width = (int) (resource->loadbar.width -
(resource->loadbar.left_step_width +
resource->loadbar.right_step_width) * i);
load[i].height = (int) (height * resource->loadbar.ratio);
load[i].level = (i + 1) * (resource->loadbar.max_time /
resource->loadbar.number_of_bars);
}
if (!reconfigure) {
if (resource->show.label) {
gcv.font = resource->label.font->fid;
frameGC = XCreateGC(dpy, framewin, GCFont, &gcv);
} else
frameGC = XCreateGC(dpy, framewin, 0, &gcv);
} else {
if (resource->show.label) {
gcv.font = resource->label.font->fid;
XChangeGC(dpy, frameGC, GCFont, &gcv);
} else
XChangeGC(dpy, frameGC, 0, &gcv);
}
if (!reconfigure) {
XClearWindow(dpy, framewin);
XMapSubwindows(dpy, framewin);
XMapWindow(dpy, framewin);
mapped = true;
}
}
void
ToolWindow::ReadAPM()
{
bool
redraw = True;
if (!broken) {
// if (apm_exists() < 0)
// broken = True;
// else {
if ((apm_read(&apm))<0)
broken = True;
// }
}
if (redraw)
Redraw();
}
void
ToolWindow::Redraw()
{
int
i;
int
offset = 0;
static int noLoadBarFilled = -1; // the number of the loadbar that was drawn last
#ifdef DEBUG
cerr << "Toolwindow::Redraw called" << endl;
#endif
// If the battery is loading, reuse the resource.show.percentage
// loadbar to show that the battery is loading. A bit like GSM. But
// in this case the label will show how far the loading is done.
if ((resource->show.loading) &&
(apm.ai_acline==1) &&
(resource->show.percentage)) {
for (i=0; i < resource->loadbar.number_of_bars; i++) {
if (noLoadBarFilled>=i) {
XCopyArea(dpy, pixmap.loadbar_active, framewin, frameGC,
2, load[i].y - 1,
load[i].width, load[i].height, load[i].x,
load[i].y - 1);
} else {
XCopyArea(dpy, pixmap.loadbar_inactive, framewin, frameGC,
2, load[i].y - 1, load[i].width, load[i].height,
load[i].x, load[i].y - 1);
}
}
noLoadBarFilled++;
if (noLoadBarFilled>resource->loadbar.number_of_bars)
noLoadBarFilled = -1;
} else {
if (resource->show.percentage) {
#ifdef DEBUG
cerr << "Toolwindow::Redraw: drawing percentage " <<
apm.ai_batt_life << " " <<
resource->loadbar.number_of_bars << endl;
#endif
for (i = 0; i < resource->loadbar.number_of_bars; i++) {
if (apm.ai_batt_life >= load[i].level)
XCopyArea(dpy, pixmap.loadbar_active, framewin, frameGC,
2, load[i].y - 1,
load[i].width, load[i].height, load[i].x,
load[i].y - 1);
else
XCopyArea(dpy, pixmap.loadbar_inactive, framewin, frameGC,
2, load[i].y - 1, load[i].width, load[i].height,
load[i].x, load[i].y - 1);
}
offset++;
}
}
if (resource->show.label) {
char
t[6];
int
labelnr = 0;
int
xposition = label.space_width;
XClearWindow(dpy, labelwin);
if (resource->show.label_percentage) {
labelnr++;
XSetForeground(dpy, frameGC,
resource->label.percentage_textColor.pixel);
sprintf(t, "%03d%%", apm.ai_batt_life);
XDrawString(dpy, labelwin, frameGC, label.space_width,
(label.height + resource->label.font->ascent -
resource->label.font->descent) / 2,
t, strlen(t));
xposition += label.width[0];
}
if (resource->show.label_time) {
if (labelnr != 0) {
XSetForeground(dpy, frameGC,
resource->label.seperator_textColor.pixel);
sprintf(t, "/");
XDrawString(dpy, labelwin, frameGC, xposition,
(label.height + resource->label.font->ascent
- resource->label.font->descent) / 2,
t, strlen(t));
xposition += label.seperator_width;
}
labelnr++;
XSetForeground(dpy, frameGC,
resource->label.time_textColor.pixel);
sprintf(t, "%02d:%02d", apm.ai_batt_time/3600, (apm.ai_batt_time/60)%60);
XDrawString(dpy, labelwin, frameGC, xposition,
(label.height + resource->label.font->ascent -
resource->label.font->descent) / 2, t, strlen(t));
xposition += label.width[1];
}
}
if (broken) {
/*
* show broken
*/
}
}
void
ToolWindow::CheckConfig()
{
struct stat
file_status;
if (stat(config_filename, &file_status) != 0) {
fprintf(stderr, "Could not config file %s\n", config_filename);
} else if (file_status.st_mtime != resource->style.mtime) {
resource->style.mtime = file_status.st_mtime;
Reconfigure();
}
}
void
ToolWindow::EventLoop(void)
{
int
xfd = ConnectionNumber(dpy);
time_t
lastTime = time(NULL);
time_t
lastLoadingTime = time(NULL);
while (!close_app) {
if (XPending(dpy)) {
XEvent
Event;
XNextEvent(dpy, &Event);
/*
* process events
*/
switch (Event.type) {
case Expose:
{
Redraw();
}
break;
case ButtonPress:
{
if (Event.xbutton.button == LEFT_BUTTON) {
if (!(raised)) {
XRaiseWindow(dpy, framewin);
raised = True;
}
} else if (Event.xbutton.button == MIDDLE_BUTTON) {
if (raised) {
XLowerWindow(dpy, framewin);
raised = False;
}
}
}
break;
case ButtonRelease:
{
if (Event.xbutton.button == RIGHT_BUTTON) {
if (Event.xbutton.window == labelwin) {
Reconfigure();
}
}
}
break;
case ConfigureNotify:
{
if (Event.xconfigure.window == framewin
&& Event.xconfigure.send_event) {
Reconfigure();
int
parent_x,
parent_y;
Window
parent_root;
unsigned int
parent_width;
unsigned int
parent_height;
unsigned int
parent_border_width;
unsigned int
parent_depth;
XGetGeometry(dpy, Event.xconfigure.above,
&parent_root, &parent_x, &parent_y,
&parent_width, &parent_height,
&parent_border_width, &parent_depth);
frame.x = Event.xconfigure.x + parent_x;
frame.y = Event.xconfigure.y + parent_y;
}
}
}
if (apm.ai_acline==1) {
if (time(NULL) - lastLoadingTime > resource->show.loadingTime) {
ReadAPM();
lastLoadingTime = time(NULL);
}
}
if (time(NULL) - lastTime > resource->report.check_delay - 1) {
ReadAPM();
if (resource->style.auto_config && !withdrawn) {
CheckConfig();
}
lastTime = time(NULL);
}
} else {
// put a wait on the network file descriptor for the X
// connection...
// this saves blackbox from eating all available cpu
if (time(NULL) - lastTime < resource->show.loadingTime) {
fd_set
rfds;
FD_ZERO(&rfds);
FD_SET(xfd, &rfds);
struct timeval
tv;
tv.tv_sec =
resource->show.loadingTime - (time(NULL) - lastTime);
tv.tv_usec = 0;
select(xfd + 1, &rfds, 0, 0, &tv);
} else {
// this will be done every check_delay seconds
ReadAPM();
if (resource->style.auto_config) {
CheckConfig();
}
lastTime = time(NULL);
}
}
}
}
int
main(int argc, char **argv)
{
/* APM initialization */
apm_exists();
ToolWindow *
AppWindow = new ToolWindow(argc, argv);
AppWindow->EventLoop();
delete
AppWindow;
}
syntax highlighted by Code2HTML, v. 0.9.1