// 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 #endif #include "bbapm.hh" ToolWindow::ToolWindow(int argc, char **argv): Basewindow(argc, argv) { 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; }