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