summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Chudnick <sam@chudnick.com>2021-11-07 06:45:23 -0500
committerSam Chudnick <sam@chudnick.com>2021-11-07 06:45:23 -0500
commitab94e030534305f2bc8fc08a081fd3d5279e49df (patch)
tree64aa1ef45970bc7a0797cb1f31ab3d46868164c9
initial commit
-rw-r--r--.gitignore2
-rw-r--r--Makefile13
-rw-r--r--blocks.h17
-rw-r--r--dwmblocks.c247
4 files changed, 279 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c35e2cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
1patches/
2dwmblocks
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..25da945
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
1PREFIX ?= /usr/local
2CC ?= cc
3LDFLAGS = -lX11
4
5output: dwmblocks.c
6 ${CC} dwmblocks.c $(LDFLAGS) -o dwmblocks
7clean:
8 rm -f *.o *.gch dwmblocks
9install: output
10 mkdir -p $(DESTDIR)$(PREFIX)/bin
11 install -m 0755 dwmblocks $(DESTDIR)$(PREFIX)/bin/dwmblocks
12uninstall:
13 rm -f $(DESTDIR)$(PREFIX)/bin/dwmblocks
diff --git a/blocks.h b/blocks.h
new file mode 100644
index 0000000..a9a79b3
--- /dev/null
+++ b/blocks.h
@@ -0,0 +1,17 @@
1//Modify this file to change what commands output to your statusbar, and recompile using the make command.
2//
3static const Block blocks[] = {
4 /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/
5 { " ", "~/.local/bin/statusbar/bar-cmus", 5, 12},
6 { " ", "~/.local/bin/statusbar/bar-cpu", 2, 13},
7 { " ", "~/.local/bin/statusbar/bar-gpu", 2, 14},
8 { " ", "~/.local/bin/statusbar/bar-volume", 60, 10},
9 { " ", "~/.local/bin/statusbar/bar-memory", 10, 16},
10 { " ", "~/.local/bin/statusbar/bar-storage", 60, 17},
11 { " ", "~/.local/bin/statusbar/bar-ipv4", 60, 18},
12 { " ", "~/.local/bin/statusbar/bar-time", 1, 19},
13};
14
15//Sets delimiter between status commands. NULL character ('\0') means no delimiter.
16static char delim[] = " |";
17static unsigned int delimLen = 5;
diff --git a/dwmblocks.c b/dwmblocks.c
new file mode 100644
index 0000000..78fdeb5
--- /dev/null
+++ b/dwmblocks.c
@@ -0,0 +1,247 @@
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
22typedef struct {
23 char* icon;
24 char* command;
25 unsigned int interval;
26 unsigned int signal;
27} Block;
28#ifndef __OpenBSD__
29void dummysighandler(int num);
30#endif
31void getcmds(int time);
32void getsigcmds(unsigned int signal);
33void setupsignals();
34void sighandler(int signum, siginfo_t *si, void *ucontext);
35int getstatus(char *str, char *last);
36void statusloop();
37void termhandler();
38void chldhandler();
39void pstdout();
40#ifndef NO_X
41void setroot();
42static void (*writestatus) () = setroot;
43static int setupX();
44static Display *dpy;
45static int screen;
46static Window root;
47#else
48static void (*writestatus) () = pstdout;
49#endif
50
51
52#include "blocks.h"
53
54static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
55static char statusstr[2][STATUSLENGTH];
56static int statusContinue = 1;
57static int returnStatus = 0;
58
59//opens process *cmd and stores output in *output
60void 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
86void 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
96void 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
106void 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
124int 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
135void 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
143int 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
156void 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
165void 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 */
181void dummysighandler(int signum)
182{
183 return;
184}
185#endif
186
187void 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
215void termhandler()
216{
217 statusContinue = 0;
218}
219
220void chldhandler()
221{
222 while (0 < waitpid(-1, NULL, WNOHANG));
223}
224
225int 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}