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 }