dwmblocks

My build of dwmblocks.
git clone git://git.alex.balgavy.eu/dwmblocks.git
Log | Files | Refs | README | LICENSE

dwmblocks.c (5218B)


      1 #include<stdlib.h>
      2 #include<stdio.h>
      3 #include<string.h>
      4 #include<unistd.h>
      5 #include<signal.h>
      6 #include<sys/wait.h>
      7 #ifndef NO_X
      8 #include<X11/Xlib.h>
      9 #endif
     10 #ifdef __OpenBSD__
     11 #define SIGPLUS			SIGUSR1+1
     12 #define SIGMINUS		SIGUSR1-1
     13 #else
     14 #define SIGPLUS			SIGRTMIN
     15 #define SIGMINUS		SIGRTMIN
     16 #endif
     17 #define LENGTH(X)               (sizeof(X) / sizeof (X[0]))
     18 #define CMDLENGTH		50
     19 #define MIN( a, b ) ( ( a < b) ? a : b )
     20 #define STATUSLENGTH (LENGTH(blocks) * CMDLENGTH + 1)
     21 
     22 typedef struct {
     23 	char* icon;
     24 	char* command;
     25 	unsigned int interval;
     26 	unsigned int signal;
     27 } Block;
     28 #ifndef __OpenBSD__
     29 void dummysighandler(int num);
     30 #endif
     31 void getcmds(int time);
     32 void getsigcmds(unsigned int signal);
     33 void setupsignals();
     34 void sighandler(int signum, siginfo_t *si, void *ucontext);
     35 int getstatus(char *str, char *last);
     36 void statusloop();
     37 void termhandler();
     38 void chldhandler();
     39 void pstdout();
     40 #ifndef NO_X
     41 void setroot();
     42 static void (*writestatus) () = setroot;
     43 static int setupX();
     44 static Display *dpy;
     45 static int screen;
     46 static Window root;
     47 #else
     48 static void (*writestatus) () = pstdout;
     49 #endif
     50 
     51 
     52 #include "blocks.h"
     53 
     54 static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
     55 static char statusstr[2][STATUSLENGTH];
     56 static int statusContinue = 1;
     57 static int returnStatus = 0;
     58 
     59 //opens process *cmd and stores output in *output
     60 void getcmd(const Block *block, char *output)
     61 {
     62 	if (block->signal)
     63 		*output++ = block->signal;
     64 	strcpy(output, block->icon);
     65 	FILE *cmdf = popen(block->command, "r");
     66 	if (!cmdf)
     67 		return;
     68 	int i = strlen(block->icon);
     69 	fgets(output+i, CMDLENGTH-i-delimLen, cmdf);
     70 	i = strlen(output);
     71 	if (i == 0) {
     72 		//return if block and command output are both empty
     73 		pclose(cmdf);
     74 		return;
     75 	}
     76 	if (delim[0] != '\0') {
     77 		//only chop off newline if one is present at the end
     78 		i = output[i-1] == '\n' ? i-1 : i;
     79 		strncpy(output+i, delim, delimLen); 
     80 	}
     81 	else
     82 		output[i++] = '\0';
     83 	pclose(cmdf);
     84 }
     85 
     86 void getcmds(int time)
     87 {
     88 	const Block* current;
     89 	for (unsigned int i = 0; i < LENGTH(blocks); i++) {
     90 		current = blocks + i;
     91 		if ((current->interval != 0 && time % current->interval == 0) || time == -1)
     92 			getcmd(current,statusbar[i]);
     93 	}
     94 }
     95 
     96 void getsigcmds(unsigned int signal)
     97 {
     98 	const Block *current;
     99 	for (unsigned int i = 0; i < LENGTH(blocks); i++) {
    100 		current = blocks + i;
    101 		if (current->signal == signal)
    102 			getcmd(current,statusbar[i]);
    103 	}
    104 }
    105 
    106 void setupsignals()
    107 {
    108 	struct sigaction sa = { .sa_sigaction = sighandler, .sa_flags = SA_SIGINFO };
    109 #ifndef __OpenBSD__
    110 	    /* initialize all real time signals with dummy handler */
    111     for (int i = SIGRTMIN; i <= SIGRTMAX; i++) {
    112         signal(i, dummysighandler);
    113 		sigaddset(&sa.sa_mask, i);
    114 	}
    115 #endif
    116 
    117 	for (unsigned int i = 0; i < LENGTH(blocks); i++) {
    118 		if (blocks[i].signal > 0)
    119 			sigaction(SIGMINUS+blocks[i].signal, &sa, NULL);
    120 	}
    121 
    122 }
    123 
    124 int getstatus(char *str, char *last)
    125 {
    126 	strcpy(last, str);
    127 	str[0] = '\0';
    128 	for (unsigned int i = 0; i < LENGTH(blocks); i++)
    129 		strcat(str, statusbar[i]);
    130 	str[strlen(str)-strlen(delim)] = '\0';
    131 	return strcmp(str, last);//0 if they are the same
    132 }
    133 
    134 #ifndef NO_X
    135 void setroot()
    136 {
    137 	if (!getstatus(statusstr[0], statusstr[1]))//Only set root if text has changed.
    138 		return;
    139 	XStoreName(dpy, root, statusstr[0]);
    140 	XFlush(dpy);
    141 }
    142 
    143 int setupX()
    144 {
    145 	dpy = XOpenDisplay(NULL);
    146 	if (!dpy) {
    147 		fprintf(stderr, "dwmblocks: Failed to open display\n");
    148 		return 0;
    149 	}
    150 	screen = DefaultScreen(dpy);
    151 	root = RootWindow(dpy, screen);
    152 	return 1;
    153 }
    154 #endif
    155 
    156 void pstdout()
    157 {
    158 	if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed.
    159 		return;
    160 	printf("%s\n",statusstr[0]);
    161 	fflush(stdout);
    162 }
    163 
    164 
    165 void statusloop()
    166 {
    167 	setupsignals();
    168 	int i = 0;
    169 	getcmds(-1);
    170 	while (1) {
    171 		getcmds(i++);
    172 		writestatus();
    173 		if (!statusContinue)
    174 			break;
    175 		sleep(1.0);
    176 	}
    177 }
    178 
    179 #ifndef __OpenBSD__
    180 /* this signal handler should do nothing */
    181 void dummysighandler(int signum)
    182 {
    183     return;
    184 }
    185 #endif
    186 
    187 void sighandler(int signum, siginfo_t *si, void *ucontext)
    188 {
    189 	if (si->si_value.sival_int) {
    190 		pid_t parent = getpid();
    191 		if (fork() == 0) {
    192 #ifndef NO_X
    193 			if (dpy)
    194 				close(ConnectionNumber(dpy));
    195 #endif
    196 			int i;
    197 			for (i = 0; i < LENGTH(blocks) && blocks[i].signal != signum-SIGRTMIN; i++);
    198 
    199 			char shcmd[1024];
    200 			sprintf(shcmd, "%s; kill -%d %d", blocks[i].command, SIGRTMIN+blocks[i].signal, parent);
    201 			char *cmd[] = { "/bin/sh", "-c", shcmd, NULL };
    202 			char button[2] = { '0' + si->si_value.sival_int, '\0' };
    203 			setenv("BUTTON", button, 1);
    204 			setsid();
    205 			execvp(cmd[0], cmd);
    206 			perror(cmd[0]);
    207 			exit(EXIT_SUCCESS);
    208 		}
    209 	} else {
    210 		getsigcmds(signum-SIGPLUS);
    211 		writestatus();
    212 	}
    213 }
    214 
    215 void termhandler()
    216 {
    217 	statusContinue = 0;
    218 }
    219 
    220 void chldhandler()
    221 {
    222 	while (0 < waitpid(-1, NULL, WNOHANG));
    223 }
    224 
    225 int main(int argc, char** argv)
    226 {
    227 	for (int i = 0; i < argc; i++) {//Handle command line arguments
    228 		if (!strcmp("-d",argv[i]))
    229 			strncpy(delim, argv[++i], delimLen);
    230 		else if (!strcmp("-p",argv[i]))
    231 			writestatus = pstdout;
    232 	}
    233 #ifndef NO_X
    234 	if (!setupX())
    235 		return 1;
    236 #endif
    237 	delimLen = MIN(delimLen, strlen(delim));
    238 	delim[delimLen++] = '\0';
    239 	signal(SIGTERM, termhandler);
    240 	signal(SIGINT, termhandler);
    241 	signal(SIGCHLD, chldhandler);
    242 	statusloop();
    243 #ifndef NO_X
    244 	XCloseDisplay(dpy);
    245 #endif
    246 	return 0;
    247 }