1 /* $Id: wmwork.c,v 1.67 2005/12/02 07:36:59 godisch Exp $
4 * Copyright (c) 2002-2005 Martin A. Godisch <martin@godisch.de>
31 #include "wmgeneral.h"
41 #define CHAR_SRC_X1(N) ((N - 'A') * 5)
42 #define CHAR_SRC_Y1 (71)
43 #define CHAR_SRC_X2(N) ((N - ' ') * 5)
44 #define CHAR_SRC_Y2 (64)
45 #define CHAR_SRC_X3(N) ((N - '{') * 5 + 65)
46 #define CHAR_SRC_Y3 (57)
47 #define TIMER_SRC_X(N) (N * 5 + 80)
48 #define TIMER_SRC_Y (64)
51 wmwork_mask_bits
[64*64],
68 static void handler(int signo
)
73 static void at_exit(void)
77 if (unlink(lockname
) < 0) {
78 fprintf(stderr
, "%s: cannot unlink '%s'\n", PACKAGE_NAME
, lockname
);
79 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
83 int main(int argc
, char *argv
[])
96 static int signals
[] =
97 {SIGALRM
, SIGHUP
, SIGINT
, SIGPIPE
, SIGTERM
, SIGUSR1
, SIGUSR2
, 0};
100 assert(sizeof(char) == 1);
103 do_opts(argc
, argv
, &show_days
, &xdisplay
, &geometry
, &force
);
105 path_len
= strlen(getenv("HOME")) + strlen("/.wmwork/worklog") + 1;
106 if ((dirName
= malloc(path_len
)) == NULL
|| (logname
= malloc(path_len
)) == NULL
|| (lockname
= malloc(path_len
)) == NULL
) {
107 fprintf(stderr
, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME
);
108 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
111 snprintf(dirName
, path_len
, "%s/.wmwork", getenv("HOME"));
112 snprintf(logname
, path_len
, "%s/worklog", dirName
);
113 snprintf(lockname
, path_len
, "%s/.#LOCK", dirName
);
114 if (chdir(dirName
) < 0) {
115 if (errno
== ENOENT
) {
116 if (mkdir(dirName
, 0777)) {
117 fprintf(stderr
, "%s: cannot mkdir '%s'\n", PACKAGE_NAME
, dirName
);
118 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
123 fprintf(stderr
, "%s: cannot chdir into '%s'\n", PACKAGE_NAME
, dirName
);
124 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
129 for (n
= 0; signals
[n
]; n
++) {
130 if (signal(signals
[n
], handler
) == SIG_ERR
) {
131 fprintf(stderr
, "%s: cannot set handler for signal %d\n", PACKAGE_NAME
, signals
[n
]);
132 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
141 initXwindow(xdisplay
);
142 createXBMfromXPM(wmwork_mask_bits
, wmwork_master_xpm
, 64, 64);
143 openXwindow(argc
, argv
, wmwork_master_xpm
, wmwork_mask_bits
, 64, 64, geometry
, NULL
);
144 AddMouseRegion(BUT_START
, 5, 48, 22, 58);
145 AddMouseRegion(BUT_PAUSE
, 23, 48, 40, 58);
146 AddMouseRegion(BUT_STOP
, 41, 48, 58, 58);
147 AddMouseRegion(BUT_PREV
, 5, 33, 16, 43);
148 AddMouseRegion(BUT_NEXT
, 47, 33, 58, 43);
149 drawTime(current
->time
, sess_time
, microtm
, show_days
, running
);
150 drawProject(current
->name
);
153 last_time
= now
.tv_sec
;
154 gettimeofday(&now
, &tz
);
156 current
->time
+= now
.tv_sec
- last_time
;
157 sess_time
+= now
.tv_sec
- last_time
;
158 microtm
= now
.tv_usec
;
159 drawTime(current
->time
, sess_time
, microtm
, show_days
, running
);
162 while (XPending(display
)) {
163 XNextEvent(display
, &Event
);
164 switch (Event
.type
) {
169 XCloseDisplay(display
);
172 n
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
186 n
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
196 if (but_stat
&& n
== but_stat
) {
211 if (!running
&& sess_time
== 0)
212 current
= current
->prev
;
215 if (!running
&& sess_time
== 0)
216 current
= current
->next
;
219 drawTime(current
->time
, sess_time
, microtm
, show_days
, running
);
220 drawProject(current
->name
);
233 void ButtonDown(int button
)
237 copyXPMArea( 65, 25, 18, 11, 5, 48);
240 copyXPMArea( 84, 25, 18, 11, 23, 48);
243 copyXPMArea(103, 25, 18, 11, 41, 48);
246 copyXPMArea(122, 25, 12, 11, 5, 33);
249 copyXPMArea(135, 25, 12, 11, 47, 33);
254 void ButtonUp(int button
)
258 copyXPMArea( 65, 13, 18, 11, 5, 48);
261 copyXPMArea( 84, 13, 18, 11, 23, 48);
264 copyXPMArea(103, 13, 18, 11, 41, 48);
267 copyXPMArea(122, 13, 12, 11, 5, 33);
270 copyXPMArea(135, 13, 12, 11, 47, 33);
275 void ButtonEnable(int button
)
277 return ButtonUp(button
);
280 void ButtonDisable(int button
)
284 copyXPMArea( 65, 1, 18, 11, 5, 48);
287 copyXPMArea( 84, 1, 18, 11, 23, 48);
290 copyXPMArea(103, 1, 18, 11, 41, 48);
293 copyXPMArea(122, 1, 12, 11, 5, 33);
296 copyXPMArea(135, 1, 12, 11, 47, 33);
301 void do_opts(int argc
, char *argv
[], int *show_days
, char **xdisplay
, char **geometry
, int *force
)
303 static struct option long_opts
[] = {
304 {"days", 0, NULL
, 'd'},
305 {"force", 0, NULL
, 'f'},
306 {"help", 0, NULL
, 'h'},
307 {"version", 0, NULL
, 'v'},
308 {"display", 1, NULL
, 0 },
309 {"geometry", 1, NULL
, 1 },
311 int i
, opt_index
= 0;
314 for (i
= 1; i
< argc
; i
++) {
315 if (*argv
[i
] == '-') {
316 if (argv
[i
][1] == 'd')
318 else if (argv
[i
][1] == 'f')
320 else if (argv
[i
][1] == 'h') {
323 if ((i
= getopt_long(argc
, argv
, "dfhv", long_opts
, &opt_index
)) == -1)
334 printf("usage: %s [options]\n", argv
[0]);
335 printf(" -d, --days display time in ddd.hh:mm instead of hhh:mm:ss,\n");
336 printf(" -f, --force overwrite stale lock files,\n");
337 printf(" -h, --help display this command line summary,\n");
338 printf(" -v, --version display the version number,\n");
339 printf(" --display=<id> open the mini window on display <id>, e.g. ':0.0',\n");
340 printf(" --geometry=<pos> open the mini window at position <pos>, e.g. '+10+10'.\n");
343 } else if (argv
[i
][1] == 'v') {
347 printf("%s %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
348 printf("copyright (c) 2002-2005 Martin A. Godisch <martin@godisch.de>\n");
351 } else if (!strcmp(argv
[i
], "--display"))
353 else if (!strcmp(argv
[i
], "--geometry"))
360 fprintf(stderr
, "%s: invalid argument -- %s\n", PACKAGE_NAME
, argv
[i
]);
375 fprintf(stderr
, "%s: invalid argument -- %s\n", PACKAGE_NAME
, argv
[optind
]);
381 void drawTime(time_t time1
, time_t time2
, int microtm
, int show_days
, const int running
)
383 time_t d1
= 0, d2
= 0, h1
= 0, h2
= 0;
384 short m1
= 0, m2
= 0, s1
= 0, s2
= 0;
386 if (time1
>= 3600000 || time2
>= 3600000)
394 if (d1
>= 1000 || d2
>= 1000) {
409 copyXPMArea(TIMER_SRC_X(d1
/ 100), TIMER_SRC_Y
, 5, 7, 7, 6);
411 copyXPMArea(TIMER_SRC_X(d1
/ 10), TIMER_SRC_Y
, 5, 7, 13, 6);
412 copyXPMArea(TIMER_SRC_X(d1
% 10), TIMER_SRC_Y
, 5, 7, 19, 6);
413 copyXPMArea(TIMER_SRC_X(h1
/ 10), TIMER_SRC_Y
, 5, 7, 29, 6);
414 copyXPMArea(TIMER_SRC_X(h1
% 10), TIMER_SRC_Y
, 5, 7, 35, 6);
415 copyXPMArea(TIMER_SRC_X(m1
/ 10), TIMER_SRC_Y
, 5, 7, 45, 6);
416 copyXPMArea(TIMER_SRC_X(m1
% 10), TIMER_SRC_Y
, 5, 7, 51, 6);
418 copyXPMArea(TIMER_SRC_X(d2
/ 100), TIMER_SRC_Y
, 5, 7, 7, 20);
420 copyXPMArea(TIMER_SRC_X(d2
/ 10), TIMER_SRC_Y
, 5, 7, 13, 20);
421 copyXPMArea(TIMER_SRC_X(d2
% 10), TIMER_SRC_Y
, 5, 7, 19, 20);
422 copyXPMArea(TIMER_SRC_X(h2
/ 10), TIMER_SRC_Y
, 5, 7, 29, 20);
423 copyXPMArea(TIMER_SRC_X(h2
% 10), TIMER_SRC_Y
, 5, 7, 35, 20);
424 copyXPMArea(TIMER_SRC_X(m2
/ 10), TIMER_SRC_Y
, 5, 7, 45, 20);
425 copyXPMArea(TIMER_SRC_X(m2
% 10), TIMER_SRC_Y
, 5, 7, 51, 20);
427 copyXPMArea(TIMER_SRC_X(h1
/ 100), TIMER_SRC_Y
, 5, 7, 7, 6);
429 copyXPMArea(TIMER_SRC_X(h1
/ 10), TIMER_SRC_Y
, 5, 7, 13, 6);
430 copyXPMArea(TIMER_SRC_X(h1
% 10), TIMER_SRC_Y
, 5, 7, 19, 6);
431 copyXPMArea(TIMER_SRC_X(m1
/ 10), TIMER_SRC_Y
, 5, 7, 29, 6);
432 copyXPMArea(TIMER_SRC_X(m1
% 10), TIMER_SRC_Y
, 5, 7, 35, 6);
433 copyXPMArea(TIMER_SRC_X(s1
/ 10), TIMER_SRC_Y
, 5, 7, 45, 6);
434 copyXPMArea(TIMER_SRC_X(s1
% 10), TIMER_SRC_Y
, 5, 7, 51, 6);
436 copyXPMArea(TIMER_SRC_X(h2
/ 100), TIMER_SRC_Y
, 5, 7, 7, 20);
438 copyXPMArea(TIMER_SRC_X(h2
/ 10), TIMER_SRC_Y
, 5, 7, 13, 20);
439 copyXPMArea(TIMER_SRC_X(h2
% 10), TIMER_SRC_Y
, 5, 7, 19, 20);
440 copyXPMArea(TIMER_SRC_X(m2
/ 10), TIMER_SRC_Y
, 5, 7, 29, 20);
441 copyXPMArea(TIMER_SRC_X(m2
% 10), TIMER_SRC_Y
, 5, 7, 35, 20);
442 copyXPMArea(TIMER_SRC_X(s2
/ 10), TIMER_SRC_Y
, 5, 7, 45, 20);
443 copyXPMArea(TIMER_SRC_X(s2
% 10), TIMER_SRC_Y
, 5, 7, 51, 20);
446 if (microtm
< 500000 || !running
) {
448 copyXPMArea(161, CHAR_SRC_Y1
+ 4, 1, 3, 26, 10);
449 copyXPMArea(161, CHAR_SRC_Y1
+ 4, 1, 3, 26, 24);
451 copyXPMArea(161, CHAR_SRC_Y1
, 1, 7, 26, 6);
452 copyXPMArea(161, CHAR_SRC_Y1
, 1, 7, 26, 20);
454 copyXPMArea(161, CHAR_SRC_Y1
, 1, 7, 42, 6);
455 copyXPMArea(161, CHAR_SRC_Y1
, 1, 7, 42, 20);
458 copyXPMArea(163, CHAR_SRC_Y1
, 1, 7, 26, 6);
459 copyXPMArea(163, CHAR_SRC_Y1
, 1, 7, 26, 20);
461 copyXPMArea(163, CHAR_SRC_Y1
, 1, 7, 42, 6);
462 copyXPMArea(163, CHAR_SRC_Y1
, 1, 7, 42, 20);
466 void drawProject(const char *name
)
470 for (i
= 0; i
< 3; i
++) {
471 copyXPMArea(CHAR_SRC_X2(' '), CHAR_SRC_Y2
, 5, 7, 23 + i
* 6, 35);
472 if (i
>= strlen(name
))
474 if (name
[i
] >= 'A' && name
[i
] <= '`')
475 copyXPMArea(CHAR_SRC_X1(name
[i
]), CHAR_SRC_Y1
, 5, 7, 23 + i
* 6, 35);
476 else if (name
[i
] >= ' ' && name
[i
] <= '@')
477 copyXPMArea(CHAR_SRC_X2(name
[i
]), CHAR_SRC_Y2
, 5, 7, 23 + i
* 6, 35);
478 else if (name
[i
] >= '{' && name
[i
] <= '~')
479 copyXPMArea(CHAR_SRC_X3(name
[i
]), CHAR_SRC_Y3
, 5, 7, 23 + i
* 6, 35);
495 if ((first
= malloc(sizeof(struct Project
))) == NULL
) {
496 fprintf(stderr
, "%s: cannot allocate memory for element %d\n", PACKAGE_NAME
, n
);
497 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
500 strcpy(first
->name
, "---");
505 if ((F
= fopen(logname
, "r")) == NULL
) {
506 if (errno
!= ENOENT
) {
507 fprintf(stderr
, "%s: cannot open '%s' for reading\n", PACKAGE_NAME
, logname
);
508 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
513 for (line
= 1;; line
++) {
514 fgets(buffer
, sizeof(buffer
), F
);
520 } else if ((p
= malloc(sizeof(struct Project
))) == NULL
) {
521 fprintf(stderr
, "%s: cannot allocate memory for element %d\n", PACKAGE_NAME
, n
);
522 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
526 if ((s
= index(buffer
, '\n')) != NULL
)
528 if (buffer
[0] == '#' || buffer
[0] == '\0') {
533 if ((colon
= index(buffer
, ':')) == NULL
) {
534 fprintf(stderr
, "%s: missing ':' in '%s' line %d\n", PACKAGE_NAME
, logname
, line
);
539 i
= colon
- buffer
< 3 ? colon
- buffer
: 3;
541 for (i
--; i
>= 0; i
--) {
542 p
->name
[i
] = toupper(buffer
[i
]);
543 if (p
->name
[i
] == '/') {
544 fprintf(stderr
, "%s: '/' is fs delimiter in '%s' line %d\n", PACKAGE_NAME
, logname
, line
);
545 fprintf(stderr
, "%s: converting forbidden '/' in project id into '|'\n", PACKAGE_NAME
);
549 p
->time
= strtol(++colon
, &s
, 10);
550 if (*s
&& *s
!= ':' && *s
!= ' ') {
551 fprintf(stderr
, "%s: error converting timestamp '%s' in '%s' line %d\n", PACKAGE_NAME
, colon
, logname
, line
);
557 if ((p
->comment
= strdup(s
)) == NULL
) {
558 fprintf(stderr
, "%s: ignored error while aquiring memory for comment string '%s' in '%s' line %d\n", PACKAGE_NAME
, s
, logname
, line
);
559 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
564 p
->prev
= first
->prev
;
582 if ((F
= fopen(logname
, "w")) == NULL
) {
583 fprintf(stderr
, "%s: cannot open '%s' for writing\n", PACKAGE_NAME
, logname
);
584 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
587 fprintf(F
, "# wmwork configuration file\n");
588 fprintf(F
, "# do not edit while wmwork is running\n\n");
593 fprintf(F
, "%s: > %s:%li:%s\n", PACKAGE_NAME
, p
->name
, p
->time
, p
->comment
? p
->comment
: "");
595 fprintf(F
, "%s:%li:%s\n", p
->name
, p
->time
, p
->comment
? p
->comment
: "");
597 } while (p
!= first
);
605 int write_record(void)
616 strftime(tbuff
, sizeof(tbuff
), "%a, %d %b %Y %H:%M:%S %z", localtime(&now
.tv_sec
));
617 snprintf(rbuff
, sizeof(rbuff
), "%s %03li:%02li:%02li", tbuff
, sess_time
/ 3600, sess_time
/ 60 % 60, sess_time
% 60);
619 if ((fname
= malloc(path_len
)) == NULL
) {
620 fprintf(stderr
, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME
);
621 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
622 fprintf(stderr
, "%s: > %s\n", PACKAGE_NAME
, rbuff
);
625 snprintf(fname
, path_len
, "%s/.wmwork/%s", getenv("HOME"), current
->name
);
626 if ((F
= fopen(fname
, "a")) == NULL
) {
627 fprintf(stderr
, "%s: cannot open '%s' for writing\n", PACKAGE_NAME
, fname
);
628 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
629 fprintf(stderr
, "%s: > %s\n", PACKAGE_NAME
, rbuff
);
633 fprintf(F
, "%s\n", rbuff
);
639 int make_lock(int force
)
653 if ((fd
= open(lockname
, O_WRONLY
| O_CREAT
| (force
? 0 : O_EXCL
), 0666)) < 0) {
654 if (errno
== EEXIST
) {
655 if ((F
= fopen(lockname
, "r")) != NULL
) {
656 i
= fscanf(F
, PID_T
, &pid
);
658 snprintf(proc
, sizeof(proc
), "/proc/"PID_T
"/exe", pid
);
659 if (i
== 1 && ((i
= readlink(proc
, buffer
, sizeof(buffer
)-1)) >= 0 || errno
== ENOENT
)) {
661 if (i
< 0 || ((c
= rindex(buffer
, '/')) != NULL
&& strcmp(c
+1, "wmwork") != 0)) {
662 fprintf(stderr
, "%s: found stale lock file (pid "PID_T
")\n", PACKAGE_NAME
, pid
);
667 fprintf(stderr
, "%s: already running, --force will overwrite the lock file\n", PACKAGE_NAME
);
670 fprintf(stderr
, "%s: cannot create '%s'\n", PACKAGE_NAME
, lockname
);
671 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
674 if ((F
= fdopen(fd
, "w")) != NULL
) {
675 fprintf(F
, PID_T
"\n", getpid());
691 /* BEGIN compatibility section for wmwork < 0.2.0 */
693 if ((temp1
= malloc(path_len
)) == NULL
|| (temp2
= malloc(path_len
)) == NULL
) {
694 fprintf(stderr
, "%s: cannot allocate memory for path variable\n", PACKAGE_NAME
);
695 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
699 snprintf(temp1
, path_len
, "%s/.wmworklog", getenv("HOME"));
700 if (rename(temp1
, logname
) < 0) {
703 fprintf(stderr
, "%s: cannot rename '%s' to '%s'\n", PACKAGE_NAME
, temp1
, logname
);
704 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
707 fprintf(stderr
, "%s: moving '%s' -> '%s'\n", PACKAGE_NAME
, temp1
, logname
);
709 if ((dir
= opendir(getenv("HOME"))) < 0) {
710 fprintf(stderr
, "%s: cannot read '%s'\n", PACKAGE_NAME
, getenv("HOME"));
711 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
714 while ((entry
= readdir(dir
))) {
715 if (strstr(entry
->d_name
, ".wmwork.") == entry
->d_name
&&
716 strlen(entry
->d_name
) > 8 && strlen(entry
->d_name
) <= 11) {
717 snprintf(temp1
, path_len
, "%s/%s", getenv("HOME"), entry
->d_name
);
718 snprintf(temp2
, path_len
, "%s/%s", dirName
, entry
->d_name
+ 8);
719 if (rename(temp1
, temp2
) < 0) {
720 fprintf(stderr
, "%s: cannot rename '%s' to '%s'\n", PACKAGE_NAME
, temp1
, temp2
);
721 fprintf(stderr
, "%s: %s\n", PACKAGE_NAME
, strerror(errno
));
723 fprintf(stderr
, "%s: moving '%s' to '%s'\n", PACKAGE_NAME
, temp1
, temp2
);
729 /* END compatibility section for wmwork < 0.2.0 */