#include #include #include #include #include #include #include #include #ifndef NO_X #include #endif #ifdef __OpenBSD__ #define SIGPLUS (SIGUSR1 + 1) #define SIGMINUS (SIGUSR1 - 1) #else #define SIGPLUS SIGRTMIN #define SIGMINUS SIGRTMIN #endif #define LENGTH(X) (sizeof(X) / sizeof(X[0])) #define CMDLENGTH 50 #define SDIRLENGTH 256 #define MIN( a, b ) (a < b ? a : b) #define STATUSLENGTH (LENGTH(blocks) * CMDLENGTH + 1) typedef struct { char* icon; char* command; unsigned int interval; unsigned int signal; } Block; typedef void(*ThreadCallback)(pthread_t *); void getcmd(const Block *block, char *output); void getcmds(int time); void getsigcmds(unsigned int signal); #ifndef __OpenBSD__ void dummysighandler(int signum); #endif void sighandler(int signum); void setupsignals(void); int getstatus(char *str, char *last); void pstdout(void); int gcd(int n1, int n2); void startthreads(void); void statusloop(void); void stopthreads(void); void termhandler(void); #ifndef NO_X void setroot(void); static void (*writestatus) (void) = setroot; static int setupx(void); static Display *dpy; static int screen; static Window root; #else static void (*writestatus) (void) = pstdout; #endif #include "blocks.h" static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; static char statusstr[2][STATUSLENGTH]; static int statuscontinue = 1; static pthread_t main_thread; static pthread_t threads[LENGTH(thread_callbacks)]; static int initdone = 0; //opens process *cmd and stores output in *output void getcmd(const Block *block, char *output) { strcpy(output, block->icon); FILE *cmdf = popen(block->command, "r"); if (!cmdf) { return; } int i = strlen(block->icon); fgets(output + i, CMDLENGTH - i - delimLen, cmdf); i = strlen(output); if (i == 0) { //return if block and command output are both empty pclose(cmdf); return; } //only chop off newline if one is present at the end i = output[i - 1] == '\n' ? i - 1 : i; if (delim[0] != '\0') { strncpy(output + i, delim, delimLen); } else { output[i++] = '\0'; } pclose(cmdf); } void getcmds(int time) { const Block* current; for (unsigned int i = 0; i < LENGTH(blocks); ++i) { current = blocks + i; if ((current->interval != 0 && time % current->interval == 0) || time == -1) { getcmd(current, statusbar[i]); } } } void getsigcmds(unsigned int signal) { const Block *current; for (unsigned int i = 0; i < LENGTH(blocks); ++i) { current = blocks + i; if (current->signal == signal) { getcmd(current, statusbar[i]); } } } #ifndef __OpenBSD__ /* this signal handler should do nothing */ void dummysighandler(int signum) { return; } #endif void sighandler(int signum) { getsigcmds(signum-SIGPLUS); writestatus(); } void setupsignals() { #ifndef __OpenBSD__ /* initialize all real time signals with dummy handler */ for (int i = SIGRTMIN; i <= SIGRTMAX; ++i) { signal(i, dummysighandler); } #endif for (unsigned int i = 0; i < LENGTH(blocks); ++i) { if (blocks[i].signal > 0) { signal(SIGMINUS + blocks[i].signal, sighandler); } } } int getstatus(char *str, char *last) { strcpy(last, str); str[0] = '\0'; for (unsigned int i = 0; i < LENGTH(blocks); ++i) { strcat(str, statusbar[i]); } str[strlen(str)-strlen(delim)] = '\0'; return strcmp(str, last); //0 if they are the same } void pstdout() { if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only write out if text has changed. return; } printf("%s\n", statusstr[0]); fflush(stdout); } void somebar_pstdout() { if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only write out if text has changed. return; } printf("status %s\n", statusstr[0]); fflush(stdout); } int gcd(int n1, int n2) { int temp; while (n2 > 0){ temp = n1 % n2; n1 = n2; n2 = temp; } return n1; } void startthreads() { main_thread = pthread_self(); for (int i = 0; i < LENGTH(thread_callbacks); ++i) { pthread_create(&threads[i], NULL, (void *(*)(void *)) thread_callbacks[i], &main_thread); } } void statusloop() { setupsignals(); unsigned int interval = -1; for (int i = 0; i < LENGTH(blocks); ++i){ if (blocks[i].interval){ interval = gcd(blocks[i].interval, interval); } } startthreads(); int i = 0; getcmds(-1); long nsec_part = interval * 1000000; time_t sec_part = floor(nsec_part / 1000000000.0); nsec_part -= sec_part * 1000000000l; const struct timespec sleeptime = { sec_part, nsec_part }; struct timespec tosleep = sleeptime; while (statuscontinue) { initdone = 1; if (nanosleep(&tosleep, &tosleep) < 0) { continue; } getcmds((i++) * interval); writestatus(); tosleep = sleeptime; } } void stopthreads() { for (int i = 0; i < LENGTH(thread_callbacks); ++i) { pthread_cancel(threads[i]); pthread_join(threads[i], NULL); } } void termhandler() { statuscontinue = 0; } #ifndef NO_X void setroot() { if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only set root if text has changed. return; } XStoreName(dpy, root, statusstr[0]); XFlush(dpy); } int setupx() { dpy = XOpenDisplay(NULL); if (!dpy) { fprintf(stderr, "dwmblocks: Failed to open display\n"); return 0; } screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); return 1; } #endif int main(int argc, char** argv) { for (int i = 0; i < argc; ++i) { //Handle command line arguments if (strcmp("-d", argv[i]) == 0) { strncpy(delim, argv[++i], delimLen); } else if (strcmp("-p", argv[i]) == 0) { writestatus = pstdout; } else if (strcmp("-s", argv[i]) == 0) { writestatus = somebar_pstdout; } } #ifndef NO_X if (!setupx()) { return 1; } #endif delimLen = MIN(delimLen, strlen(delim)); delim[delimLen++] = '\0'; signal(SIGTERM, (void(*)(int))termhandler); signal(SIGINT, (void(*)(int))termhandler); statusloop(); #ifndef NO_X XCloseDisplay(dpy); #endif stopthreads(); return 0; }