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