Xinqi Bao's Git

completely new system: only values in config file get updated + cleaner code
[slstatus.git] / slstatus.c
1 /* See LICENSE file for copyright and license details. */
2
3 /* global libraries */
4 #include <alsa/asoundlib.h>
5 #include <fcntl.h>
6 #include <locale.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/statvfs.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <X11/Xlib.h>
17
18 /* global variables */
19 static Display *dpy;
20
21 /* statusbar configuration type and struct */
22 typedef char *(*op_fun) (const char *);
23 struct arg {
24 op_fun func;
25 const char *format;
26 const char *args;
27 };
28
29 /* functions */
30 void setstatus(const char *);
31 char *smprintf(const char *, ...);
32 char *get_battery(const char *);
33 char *get_cpu_temperature(const char *);
34 char *get_cpu_usage(const char *);
35 char *get_datetime(const char *);
36 char *get_diskusage(const char *);
37 char *get_ram_usage(const char *);
38 char *get_volume(const char *);
39 char *get_wifi_signal(const char *);
40
41 /* include config header */
42 #include "config.h"
43
44 /* set statusbar */
45 void
46 setstatus(const char *str)
47 {
48 /* set WM_NAME via X11 */
49 XStoreName(dpy, DefaultRootWindow(dpy), str);
50 XSync(dpy, False);
51 }
52
53 /* smprintf function */
54 char *
55 smprintf(const char *fmt, ...)
56 {
57 va_list fmtargs;
58 char *ret = NULL;
59
60 va_start(fmtargs, fmt);
61 if (vasprintf(&ret, fmt, fmtargs) < 0)
62 return NULL;
63 va_end(fmtargs);
64
65 return ret;
66 }
67
68 /* battery percentage */
69 char *
70 get_battery(const char *battery)
71 {
72 int now, full, perc;
73 char batterynowfile[64] = "";
74 char batteryfullfile[64] = "";
75 FILE *fp;
76
77 /* generate battery nowfile path */
78 strcat(batterynowfile, batterypath);
79 strcat(batterynowfile, battery);
80 strcat(batterynowfile, "/");
81 strcat(batterynowfile, batterynow);
82
83 /* generate battery fullfile path */
84 strcat(batteryfullfile, batterypath);
85 strcat(batteryfullfile, battery);
86 strcat(batteryfullfile, "/");
87 strcat(batteryfullfile, batteryfull);
88
89 /* open battery now file */
90 if (!(fp = fopen(batterynowfile, "r"))) {
91 fprintf(stderr, "Error opening battery file.%s",batterynowfile);
92 return smprintf("n/a");
93 }
94
95 /* read value */
96 fscanf(fp, "%i", &now);
97
98 /* close battery now file */
99 fclose(fp);
100
101 /* open battery full file */
102 if (!(fp = fopen(batteryfullfile, "r"))) {
103 fprintf(stderr, "Error opening battery file.");
104 return smprintf("n/a");
105 }
106
107 /* read value */
108 fscanf(fp, "%i", &full);
109
110 /* close battery full file */
111 fclose(fp);
112
113 /* calculate percent */
114 perc = now / (full / 100);
115
116 /* return perc as string */
117 return smprintf("%d%%", perc);
118 }
119
120 /* cpu temperature */
121 char *
122 get_cpu_temperature(const char *file)
123 {
124 int temperature;
125 FILE *fp;
126
127 /* open temperature file */
128 if (!(fp = fopen(file, "r"))) {
129 fprintf(stderr, "Could not open temperature file.\n");
130 return smprintf("n/a");
131 }
132
133 /* extract temperature */
134 fscanf(fp, "%d", &temperature);
135
136 /* close temperature file */
137 fclose(fp);
138
139 /* return temperature in degrees */
140 return smprintf("%d°C", temperature / 1000);
141 }
142
143 /* cpu percentage */
144 char *
145 get_cpu_usage(const char *null)
146 {
147 int perc;
148 long double a[4], b[4];
149 FILE *fp;
150
151 /* open stat file */
152 if (!(fp = fopen("/proc/stat","r"))) {
153 fprintf(stderr, "Error opening stat file.");
154 return smprintf("n/a");
155 }
156
157 /* read values */
158 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
159
160 /* close stat file */
161 fclose(fp);
162
163 /* wait a second (for avg values) */
164 sleep(1);
165
166 /* open stat file */
167 if (!(fp = fopen("/proc/stat","r"))) {
168 fprintf(stderr, "Error opening stat file.");
169 return smprintf("n/a");
170 }
171
172 /* read values */
173 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
174
175 /* close stat file */
176 fclose(fp);
177
178 /* calculate avg in this second */
179 perc = 100 * ((b[0]+b[1]+b[2]) - (a[0]+a[1]+a[2])) / ((b[0]+b[1]+b[2]+b[3]) - (a[0]+a[1]+a[2]+a[3]));
180
181 /* return perc as string */
182 return smprintf("%d%%", perc);
183 }
184
185 /* date and time */
186 char *
187 get_datetime(const char *timeformat)
188 {
189 time_t tm;
190 size_t bufsize = 64;
191 char *buf = malloc(bufsize);
192
193 /* get time in format */
194 time(&tm);
195 setlocale(LC_TIME, "");
196 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
197 setlocale(LC_TIME, "C");
198 fprintf(stderr, "Strftime failed.\n");
199 return smprintf("n/a");
200 }
201
202 setlocale(LC_TIME, "C");
203 /* return time */
204 return smprintf("%s", buf);
205 }
206
207 /* disk usage percentage */
208 char *
209 get_diskusage(const char *mountpoint)
210 {
211 int perc = 0;
212 struct statvfs fs;
213
214 /* try to open mountpoint */
215 if (statvfs(mountpoint, &fs) < 0) {
216 fprintf(stderr, "Could not get filesystem info.\n");
217 return smprintf("n/a");
218 }
219
220 /* calculate percent */
221 perc = 100 * (1.0f - ((float)fs.f_bavail / (float)fs.f_blocks));
222
223 /* return perc */
224 return smprintf("%d%%", perc);
225 }
226
227 /* ram percentage */
228 char *
229 get_ram_usage(const char *null)
230 {
231 int perc;
232 long total, free, buffers, cached;
233 FILE *fp;
234
235 /* open meminfo file */
236 if (!(fp = fopen("/proc/meminfo", "r"))) {
237 fprintf(stderr, "Error opening meminfo file.");
238 return smprintf("n/a");
239 }
240
241 /* read the values */
242 fscanf(fp, "MemTotal: %ld kB\n", &total);
243 fscanf(fp, "MemFree: %ld kB\n", &free);
244 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
245 fscanf(fp, "Cached: %ld kB\n", &cached);
246
247 /* close meminfo file */
248 fclose(fp);
249
250 /* calculate percentage */
251 perc = 100 * ((total - free) - (buffers + cached)) / total;
252
253 /* return perc as string */
254 return smprintf("%d%%", perc);
255 }
256
257 /* alsa volume percentage */
258 char *
259 get_volume(const char *soundcard)
260 {
261 int mute = 0;
262 long vol = 0, max = 0, min = 0;
263
264 /* get volume from alsa */
265 snd_mixer_t *handle;
266 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
267 snd_mixer_selem_id_t *vol_info, *mute_info;
268 snd_mixer_open(&handle, 0);
269 snd_mixer_attach(handle, soundcard);
270 snd_mixer_selem_register(handle, NULL, NULL);
271 snd_mixer_load(handle);
272 snd_mixer_selem_id_malloc(&vol_info);
273 snd_mixer_selem_id_malloc(&mute_info);
274 snd_mixer_selem_id_set_name(vol_info, channel);
275 snd_mixer_selem_id_set_name(mute_info, channel);
276 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
277 mas_mixer = snd_mixer_find_selem(handle, mute_info);
278 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
279 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
280 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
281 if (vol_info)
282 snd_mixer_selem_id_free(vol_info);
283 if (mute_info)
284 snd_mixer_selem_id_free(mute_info);
285 if (handle)
286 snd_mixer_close(handle);
287
288 /* return the string (mute) */
289 if (!mute)
290 return smprintf("mute");
291 else
292 return smprintf("%d%%", (vol * 100) / max);
293 }
294
295 /* wifi percentage */
296 char *
297 get_wifi_signal(const char *wificard)
298 {
299 int bufsize = 255;
300 int strength;
301 char buf[bufsize];
302 char *datastart;
303 char path[64];
304 char status[5];
305 char needle[sizeof wificard + 1];
306 FILE *fp;
307
308 /* generate the path name */
309 memset(path, 0, sizeof path);
310 strcat(path, "/sys/class/net/");
311 strcat(path, wificard);
312 strcat(path, "/operstate");
313
314 /* open wifi file */
315 if(!(fp = fopen(path, "r"))) {
316 fprintf(stderr, "Error opening wifi operstate file.");
317 return smprintf("n/a");
318 }
319
320 /* read the status */
321 fgets(status, 5, fp);
322
323 /* close wifi file */
324 fclose(fp);
325
326 /* check if interface down */
327 if(strcmp(status, "up\n") != 0){
328 return smprintf("n/a");
329 }
330
331 /* open wifi file */
332 if (!(fp = fopen("/proc/net/wireless", "r"))) {
333 fprintf(stderr, "Error opening wireless file.");
334 return smprintf("n/a");
335 }
336
337 /* extract the signal strength */
338 strcpy(needle, wificard);
339 strcat(needle, ":");
340 fgets(buf, bufsize, fp);
341 fgets(buf, bufsize, fp);
342 fgets(buf, bufsize, fp);
343 if ((datastart = strstr(buf, needle)) != NULL) {
344 datastart = strstr(buf, ":");
345 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
346 }
347
348 /* close wifi file */
349 fclose(fp);
350
351 /* return strength in percent */
352 return smprintf("%d%%", strength);
353 }
354
355 /* main function */
356 int
357 main()
358 {
359 char status_string[1024];
360 struct arg argument;
361
362 /* try to open display */
363 if (!(dpy = XOpenDisplay(0x0))) {
364 fprintf(stderr, "Cannot open display!\n");
365 exit(1);
366 }
367
368 /* return status every interval */
369 for (;;) {
370 /* clear the string */
371 strcpy(status_string, "");
372
373 /* generate status_string */
374 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
375 argument = args[i];
376 char *res = argument.func(argument.args);
377 char *element = smprintf(argument.format, res);
378 strcat(status_string, element);
379 }
380
381 /* return the statusbar */
382 setstatus(status_string);
383
384 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
385 sleep(update_interval -1);
386 }
387
388 /* close display */
389 XCloseDisplay(dpy);
390
391 /* exit successfully */
392 return 0;
393 }