Xinqi Bao's Git

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