dockapps/wmfu/wmfu.c
Carlos R. Mafra 21625f40b5 Initial dockapps git repo
I tried to get the latest versions from dockapps.org, but I haven't
tested any of them.

More dockapps will be added as time permits.
2011-03-25 19:45:13 +01:00

891 lines
20 KiB
C

/*
* Copyright (c) 2007 Daniel Borca All rights reserved.
*
* 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
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "dockapp.h"
#include "sensors.h"
#include "system.h"
#include "util.h"
#include "font.h"
#include "frame0.xpm"
#include "frame1.xpm"
#include "frame2.xpm"
#include "frame3.xpm"
#include "frame4.xpm"
#include "frame5.xpm"
#define DockApp App.d
#define NELEM(tab) (const int)(sizeof(tab) / sizeof((tab)[0]))
#define INSIDE(x, y, xmin, ymin, xmax, ymax) ((x) >= (xmin) && (x) <= (xmax) && (y) >= (ymin) && (y) <= (ymax))
#define SWITCH_FRAME(a, n) \
do { \
if ((a)->frames[n].v) { \
(a)->page = n; \
(a)->millis = (a)->frames[n].u; \
(a)->handle = handle_frame##n; \
(a)->update = update_frame##n; \
(a)->frames[n].p = 0; \
(a)->update(a, 1); \
} \
} while (0)
#define SCROLL_START(start, num_items, max_items) \
do { \
if ((start) > (num_items) - (max_items)) { \
(start) = (num_items) - (max_items); \
} \
if ((start) < 0) { \
(start) = 0; \
} \
} while (0)
#define MAX_DISPLAY_CPU 2
#define MAX_DISPLAY_NET 2
#define MAX_DISPLAY_TEMP 5
typedef struct {
Pixmap f;
Pixmap m;
int v;
int u;
int p;
} FRAME;
typedef struct {
int row;
int height;
const int *width;
const int *offset;
} FONT;
typedef struct APP {
DOCKAPP d;
FONT fontx9;
FONT fontx8;
FONT fontx7;
FONT fontx6;
FONT meter2;
Pixmap font;
SENSOR *list;
FRAME *frames;
void (*handle) (struct APP *a, XEvent *event);
void (*update) (const struct APP *a, int full);
int page;
int millis;
} APP;
static int
draw_text (const APP *a, const FONT *font, const char *str, int dx, int dy)
{
const DOCKAPP *d = (DOCKAPP *)a;
int ch;
while ((ch = *(unsigned char *)str++)) {
int w = font->width[ch];
dockapp_copy_area(d, a->font, font->offset[ch], font->row, w, font->height, dx, dy);
dx += w;
}
/*printf("dx = %d\n", dx);*/
return dx;
}
static void
draw_meter (const APP *a, const FONT *meter, int num, int den, int dx, int dy)
{
const DOCKAPP *d = (DOCKAPP *)a;
const int w = meter->width[0];
const int h = meter->height;
int col = 1 * w;
if (num) {
int ratio = w * num / den;
XCopyArea(d->display, a->font, a->font, d->gc,
1 * w, meter->row,
w, h,
2 * w, meter->row);
XCopyArea(d->display, a->font, a->font, d->gc,
0 * w, meter->row,
ratio, h,
2 * w, meter->row);
col = 2 * w;
}
dockapp_copy_area(d, a->font, col, meter->row, w, h, dx, dy);
}
static void handle_frame0 (APP *a, XEvent *event);
#define handle_frame1 handle_frameN
#define handle_frame2 handle_frameN
#define handle_frame3 handle_frameN
#define handle_frame4 handle_frameN
#define handle_frame5 handle_frameN
static void handle_frameN (APP *a, XEvent *event);
static void update_frame0 (const APP *a, int full);
static void update_frame1 (const APP *a, int full);
static void update_frame2 (const APP *a, int full);
static void update_frame3 (const APP *a, int full);
static void update_frame4 (const APP *a, int full);
static void update_frame5 (const APP *a, int full);
static void
handle_frame0 (APP *a, XEvent *event)
{
XButtonPressedEvent *bevent;
switch (event->type) {
case ButtonPress:
bevent = (XButtonPressedEvent *)event;
switch (bevent->button & 0xFF) {
case Button1:
/*printf("handle0: b1\n");*/
if (INSIDE(bevent->x, bevent->y, 4, 4, 10, 10)) {
/*printf("next: %d %d\n", bevent->x, bevent->y);*/
break;
}
if (INSIDE(bevent->x, bevent->y, 50, 4, 56, 10)) {
/*printf("quit: %d %d\n", bevent->x, bevent->y);*/
((DOCKAPP *)a)->quit = True;
break;
}
if (INSIDE(bevent->x, bevent->y, 1, 1, 59, 13)) {
/*printf("time: %d %d\n", bevent->x, bevent->y);*/
SWITCH_FRAME(a, 1);
break;
}
if (INSIDE(bevent->x, bevent->y, 1, 16, 59, 27)) {
/*printf("cpu : %d %d\n", bevent->x, bevent->y);*/
SWITCH_FRAME(a, 2);
break;
}
if (INSIDE(bevent->x, bevent->y, 1, 30, 29, 41)) {
/*printf("wifi: %d %d\n", bevent->x, bevent->y);*/
SWITCH_FRAME(a, 3);
break;
}
if (INSIDE(bevent->x, bevent->y, 32, 30, 59, 41)) {
/*printf("temp: %d %d\n", bevent->x, bevent->y);*/
SWITCH_FRAME(a, 4);
break;
}
if (INSIDE(bevent->x, bevent->y, 1, 44, 59, 59)) {
/*printf("batt: %d %d\n", bevent->x, bevent->y);*/
SWITCH_FRAME(a, 5);
break;
}
break;
case Button2:
/*printf("handle0: b2\n");*/
break;
case Button3:
/*printf("handle0: b3\n");*/
break;
}
break;
}
}
static void
handle_frameN (APP *a, XEvent *event)
{
XButtonPressedEvent *bevent;
switch (event->type) {
case ButtonPress:
bevent = (XButtonPressedEvent *)event;
switch (bevent->button & 0xFF) {
case Button1:
/*printf("handleN: b1\n");*/
SWITCH_FRAME(a, 0);
break;
case Button2:
/*printf("handleN: b2\n");*/
break;
case Button3:
/*printf("handleN: b3\n");*/
break;
case Button4:
/*printf("handle0: b4\n");*/
a->frames[a->page].p--;
a->update(a, 0);
break;
case Button5:
/*printf("handle0: b5\n");*/
a->frames[a->page].p++;
a->update(a, 0);
break;
}
break;
}
}
static void
update_frame0 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
const FRAME *frame = &a->frames[0];
char buf[16];
time_t at;
struct tm *bt;
static CPUSTAT avg;
int wifi;
int temp;
int crit;
int on_line;
int battery;
BATSTAT total;
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
at = time(NULL);
bt = localtime(&at);
sprintf(buf, "%2d:%02d", bt->tm_hour, bt->tm_min);
draw_text(a, &a->fontx9, buf, 15, 2);
if (system_get_cpu_load(0, &avg, NULL) > 0) {
sprintf(buf, "__CPU__%3d%%", avg.used);
} else {
strcpy(buf, " _____");
}
draw_text(a, &a->fontx8, buf, 1, 17);
if (system_get_best_wifi(&wifi)) {
sprintf(buf, "%3d\xF7", wifi);
} else {
strcpy(buf, " \xF7");
}
draw_text(a, &a->fontx8, buf, 0, 31);
if (system_get_max_temp(a->list, &temp, &crit)) {
sprintf(buf, "%3d\xF8", temp);
} else {
strcpy(buf, " \xF8");
}
draw_text(a, &a->fontx8, buf, 31, 31);
battery = system_get_battery(a->list, 0, &total, NULL);
on_line = system_get_ac_adapter(a->list);
if (battery) {
int ratio = 100 * total.curr_cap / total.full_cap;
int ch = 0xB0;
if (ratio >= 33) {
ch++;
}
if (ratio >= 66) {
ch++;
}
if (total.rate) {
if (on_line) {
/* charging */
int estimate = 60 * (total.full_cap - total.curr_cap) / total.rate;
int hours = estimate / 60;
if (hours > 99) {
hours = 99;
}
sprintf(buf, "%c__%2d:%02d\xAE\x98", ch, hours, estimate % 60);
} else {
/* discharging */
int estimate = 60 * total.curr_cap / total.rate;
int hours = estimate / 60;
if (hours > 99) {
hours = 99;
}
sprintf(buf, "%c__%2d:%02d__ ", ch, hours, estimate % 60);
}
} else {
if (on_line) {
/* bat + AC */
sprintf(buf, "%c__%3d%%___\x98", ch, ratio);
} else {
/* bat */
sprintf(buf, "%c__%3d%%___ ", ch, ratio);
}
}
draw_meter(a, &a->meter2, total.curr_cap, total.full_cap, 3, 55);
} else {
if (on_line) {
/* only AC */
strcpy(buf, " _____\x98");
} else {
/* nada */
strcpy(buf, " _____ ");
}
draw_meter(a, &a->meter2, 0, 0, 3, 55);
}
draw_text(a, &a->fontx9, buf, 2, 44);
dockapp_update(d);
}
static void
update_frame1 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
const FRAME *frame = &a->frames[1];
char buf[16];
time_t at;
struct tm *bt;
int days, hours, mins;
static const char *dow[] = {
"___SUNDAY___",
"___MONDAY___",
"__TUESDAY__",
"WEDNESDAY",
"_THURSDAY_",
"___FRIDAY___",
"_SATURDAY_"
};
static const char *mon[] = {
"JAN", "FEB", "MAR", "APR",
"MAY", "JUN", "JUL", "AUG",
"SEP", "OCT", "NOV", "DEC"
};
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
at = time(NULL);
bt = localtime(&at);
draw_text(a, &a->fontx9, dow[bt->tm_wday], 3, 2);
sprintf(buf, "%-2d %s", bt->tm_mday, mon[bt->tm_mon]);
draw_text(a, &a->fontx9, buf, 10, 13);
sprintf(buf, "%d", 1900 + bt->tm_year);
draw_text(a, &a->fontx9, buf, 16, 24);
draw_text(a, &a->fontx7, "UPTIME", 15, 39);
strcpy(buf, " _ _ ");
if (system_get_uptime(&days, &hours, &mins)) {
if (days > 999) {
days = 999;
}
sprintf(buf, "%03d_%02d:%02d", days, hours, mins);
}
draw_text(a, &a->fontx8, buf, 2, 48);
dockapp_update(d);
}
static void
update_frame2 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
FRAME *frame = &a->frames[2];
char buf[16];
int speed[8];
static CPUSTAT load[8];
int mem_free, mem_total, swp_free, swp_total;
int i, j, n, k;
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
n = system_get_cpu_speed(NELEM(speed), speed);
system_get_cpu_load(NELEM(load), NULL, load);
SCROLL_START(frame->p, n, MAX_DISPLAY_CPU);
j = frame->p + MAX_DISPLAY_CPU;
if (n < MAX_DISPLAY_CPU) {
while (j > n) {
j--;
draw_text(a, &a->fontx7, " ", 2, 2 + j * 20);
draw_text(a, &a->fontx7, " ", 2, 10 + j * 20);
}
}
for (k = 0, i = 0; k < j; i++, k++) {
int r;
char *gov;
if (speed[i] < 0) {
k--;
continue;
}
r = k - frame->p;
if (r < 0) {
continue;
}
sprintf(buf, "CPU%d %4d M", i, speed[i]);
draw_text(a, &a->fontx7, buf, 2, 2 + r * 20);
strcpy(buf, " ");
if (load[i].used >= 0) {
sprintf(buf, "%3d%%", load[i].used);
}
draw_text(a, &a->fontx7, buf, 2, 10 + r * 20);
gov = " ";
if (system_get_cpu_gov(i, sizeof(buf), buf)) {
if (!strcmp(buf, "performance")) {
gov = "PERFRM";
} else if (!strcmp(buf, "powersave")) {
gov = "PWRSAV";
} else if (!strcmp(buf, "userspace")) {
gov = "USRSPC";
} else if (!strcmp(buf, "ondemand")) {
gov = "ONDMND";
} else if (!strcmp(buf, "conservative")) {
gov = "CONSRV";
}
}
draw_text(a, &a->fontx7, gov, 27, 10 + r * 20);
}
if (system_get_mem_stat(&mem_free, &mem_total, &swp_free, &swp_total)) {
strcpy(buf, " ");
if (mem_total) {
sprintf(buf, "MEM %3d%%", 100 * (mem_total - mem_free) / mem_total);
}
draw_text(a, &a->fontx7, buf, 7, 42);
strcpy(buf, " ");
if (swp_total) {
sprintf(buf, "SWP %3d%%", 100 * (swp_total - swp_free) / swp_total);
}
draw_text(a, &a->fontx7, buf, 7, 50);
}
dockapp_update(d);
}
static void
update_frame3 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
FRAME *frame = &a->frames[3];
char buf[16];
IFSTAT ifs[8];
int i, j, n;
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
n = system_get_netif(NELEM(ifs), ifs);
SCROLL_START(frame->p, n, MAX_DISPLAY_NET);
j = frame->p + MAX_DISPLAY_NET;
if (n < MAX_DISPLAY_NET) {
while (j > n) {
j--;
draw_text(a, &a->fontx7, " ", 2, 2 + j * 30);
draw_text(a, &a->fontx7, " ", 2, 2 + j * 30 + 9);
draw_text(a, &a->fontx6, " _ _ _ ", 2, 2 + j * 30 + 18);
}
}
for (i = frame->p; i < j; i++) {
int r = i - frame->p;
strupr(ifs[i].name, ifs[i].name);
ifs[i].name[6] = '\0';
if (ifs[i].wlink >= 0) {
sprintf(buf, "%-6s_%3d\xF7", ifs[i].name, ifs[i].wlink);
draw_text(a, &a->fontx7, buf, 2, 2 + r * 30);
strupr(buf, ifs[i].essid);
buf[11] = '\0';
} else {
sprintf(buf, "%-6s_ _", ifs[i].name);
draw_text(a, &a->fontx7, buf, 2, 2 + r * 30);
strcpy(buf, " ");
}
draw_text(a, &a->fontx7, buf, 2, 2 + r * 30 + 9);
if (ifs[i].ipv4 != -1) {
int addr = ifs[i].ipv4;
sprintf(buf, "%3d.%3d.%3d.%3d", (addr >> 24) & 0xFF, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF);
} else {
strcpy(buf, " _ _ _ ");
}
draw_text(a, &a->fontx6, buf, 2, 2 + r * 30 + 18);
}
dockapp_update(d);
}
static void
update_frame4 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
FRAME *frame = &a->frames[4];
char buf[16];
TEMPSTAT temp[16];
int i, j, n;
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
n = system_get_temperature(a->list, NELEM(temp), temp);
SCROLL_START(frame->p, n, MAX_DISPLAY_TEMP);
j = frame->p + MAX_DISPLAY_TEMP;
if (n < MAX_DISPLAY_TEMP) {
while (j > n) {
j--;
draw_text(a, &a->fontx7, " _ ", 1, 1 + j * 12);
}
}
for (i = frame->p; i < j; i++) {
int r = i - frame->p;
if (!strncmp(temp[i].name, "Core ", 5) && isdigit(temp[i].name[5]) && !temp[i].name[6]) {
temp[i].name[3] = temp[i].name[5];
}
temp[i].name[4] = '\0';
strupr(temp[i].name, temp[i].name);
sprintf(buf, "%-4s:%3d\xA7%3d", temp[i].name, temp[i].temp, temp[i].max);
if (!temp[i].max) {
int l = strlen(buf);
buf[--l] = ' ';
buf[--l] = ' ';
buf[--l] = ' ';
}
draw_text(a, &a->fontx7, buf, 1, 1 + r * 12);
}
dockapp_update(d);
}
static void
update_frame5 (const APP *a, int full)
{
const DOCKAPP *d = (DOCKAPP *)a;
const FRAME *frame = &a->frames[5];
char buf[16];
int on_line;
int battery;
BATSTAT total, batt[2];
int i;
if (full) {
if (!d->iswindowed) {
dockapp_set_shape(d, frame->m);
}
dockapp_copy_area(d, frame->f, 0, 0, d->width, d->height, 0, 0);
}
on_line = system_get_ac_adapter(a->list);
battery = system_get_battery(a->list, NELEM(batt), &total, batt);
for (i = 0; i < battery; i++) {
char *state;
int ratio = 100 * batt[i].curr_cap / batt[i].full_cap;
if (batt[i].rate) {
int estimate;
int hours;
if (on_line) {
estimate = 60 * (batt[i].full_cap - batt[i].curr_cap) / batt[i].rate;
state = "CHARGING ";
} else {
estimate = 60 * batt[i].curr_cap / batt[i].rate;
state = "DISCHARGING";
}
hours = estimate / 60;
if (hours > 99) {
hours = 99;
}
sprintf(buf, "%3d%% %2d:%02d", ratio, hours, estimate % 60);
} else {
sprintf(buf, "%3d%% _ ", ratio);
state = "STEADY ";
}
draw_text(a, &a->fontx7, batt[i].name, 2, 1 + i * 30);
draw_text(a, &a->fontx7, state, 2, 9 + i * 30);
draw_text(a, &a->fontx7, buf, 2, 17 + i * 30);
draw_meter(a, &a->meter2, batt[i].curr_cap, batt[i].full_cap, 3, 25 + i * 30);
}
for (; i < 2; i++) {
draw_text(a, &a->fontx7, " ", 2, 1 + i * 30);
draw_text(a, &a->fontx7, " ", 2, 9 + i * 30);
draw_text(a, &a->fontx7, " _ ", 2, 17 + i * 30);
draw_text(a, &a->fontx7, " ", 2, 20 + i * 30);
}
dockapp_update(d);
}
static int
update_text (SENSOR *list)
{
(void)list;
/* XXX cool stuff here */
}
static int
run_text (SENSOR *list, unsigned long millis)
{
struct timeval timeout;
fd_set rset;
struct stat buf;
int redir = fstat(STDOUT_FILENO, &buf) == 0 &&
(S_ISREG(buf.st_mode) || S_ISFIFO(buf.st_mode));
for (;;) {
update_text(list);
if (redir) {
break;
}
printf("not yet implemented -- press Enter to quit\n");
timeout.tv_sec = millis / 1000;
timeout.tv_usec = (millis % 1000) * 1000;
FD_ZERO(&rset);
FD_SET(0, &rset);
if (select(0 + 1, &rset, NULL, NULL, &timeout) > 0) {
break;
}
}
return 0;
}
static void
args (int argc, char **argv, int *iswindowed, const char **display_name, int *textmode)
{
const char *myself = argv[0];
*iswindowed = 0;
*display_name = NULL;
*textmode = 0;
while (--argc) {
const char *p = *++argv;
if (!strcmp(p, "-h") || !strcmp(p, "--help")) {
printf("wmfu v1.0 (c) 2007 Daniel Borca\n");
printf("wmfu is distributed under GNU GPL v2\n\n");
printf("usage: %s [OPTIONS]\n", myself);
printf(" -display <name> use specified display\n");
printf(" --windowed run in regular window\n");
printf(" --textmode run in text mode\n");
exit(0);
}
if (!strcmp(p, "-display")) {
if (argc < 2) {
fprintf(stderr, "%s: argument to `%s' is missing\n", myself, p);
exit(1);
}
--argc;
*display_name = *++argv;
}
if (!strcmp(p, "--windowed")) {
*iswindowed = 1;
}
if (!strcmp(p, "--textmode")) {
*textmode = 1;
}
}
}
int
main (int argc, char **argv)
{
int rv;
APP App;
FRAME frames[6];
int iswindowed;
const char *display_name;
int textmode;
args(argc, argv, &iswindowed, &display_name, &textmode);
App.list = sensors_init();
if (App.list == NULL) {
fprintf(stderr, "Error allocating sensor structure\n");
return -1;
}
if (textmode) {
int rv = run_text(App.list, 1000);
sensors_free(App.list);
return rv;
}
rv = dockapp_open_window(&DockApp, display_name, "wmfu", iswindowed, argc, argv);
if (rv != 0) {
fprintf(stderr, "Could not open display `%s'\n", display_name);
sensors_free(App.list);
return rv;
}
frames[0].v = dockapp_xpm2pixmap(&DockApp, frame0_xpm, &frames[0].f, &frames[0].m, NULL, 0);
if (!frames[0].v) {
fprintf(stderr, "Error initializing frame\n");
sensors_free(App.list);
return -1;
}
if (!dockapp_xpm2pixmap(&DockApp, font_xpm, &App.font, NULL, NULL, 0)) {
fprintf(stderr, "Error initializing font\n");
sensors_free(App.list);
return -1;
}
App.fontx9.row = FONTX9_ROW;
App.fontx9.height = 9;
App.fontx9.width = fontx9_width;
App.fontx9.offset = fontx9_offset;
App.fontx8.row = FONTX8_ROW;
App.fontx8.height = 8;
App.fontx8.width = fontx8_width;
App.fontx8.offset = fontx8_offset;
App.fontx7.row = FONTX7_ROW;
App.fontx7.height = 7;
App.fontx7.width = fontx7_width;
App.fontx7.offset = fontx7_offset;
App.fontx6.row = FONTX6_ROW;
App.fontx6.height = 6;
App.fontx6.width = fontx6_width;
App.fontx6.offset = fontx6_offset;
App.meter2.row = METER2_ROW;
App.meter2.height = 2;
App.meter2.width = meter2_width;
App.meter2.offset = NULL;
frames[1].v = dockapp_xpm2pixmap(&DockApp, frame1_xpm, &frames[1].f, &frames[1].m, NULL, 0);
frames[2].v = dockapp_xpm2pixmap(&DockApp, frame2_xpm, &frames[2].f, &frames[2].m, NULL, 0);
frames[3].v = dockapp_xpm2pixmap(&DockApp, frame3_xpm, &frames[3].f, &frames[3].m, NULL, 0);
frames[4].v = dockapp_xpm2pixmap(&DockApp, frame4_xpm, &frames[4].f, &frames[4].m, NULL, 0);
frames[5].v = dockapp_xpm2pixmap(&DockApp, frame5_xpm, &frames[5].f, &frames[5].m, NULL, 0);
frames[0].u = 2000;
frames[1].u = 10000;
frames[2].u = 5000;
frames[3].u = 5000;
frames[4].u = 5000;
frames[5].u = 10000;
App.frames = frames;
SWITCH_FRAME(&App, 0);
dockapp_set_eventmask(&DockApp, ButtonPressMask);
#if 1
while (!DockApp.quit) {
XEvent event;
if (dockapp_nextevent_or_timeout(&DockApp, &event, App.millis)) {
App.handle(&App, &event);
} else {
App.update(&App, 0);
}
}
#else
{
int i;
for (i = 0; i < 1000; i++) {
App.update(&App, 0);
}
}
#endif
XCloseDisplay(DockApp.display);
sensors_free(App.list);
return 0;
}