Xinqi Bao's Git

76df821970b4881dfc2da73701fec6bcb0452f23
[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 get_battery(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 temperature */
99 char *
100 get_cpu_temperature(const char *file)
101 {
102 int temperature;
103 FILE *fp;
104
105 /* open temperature file */
106 if (!(fp = fopen(file, "r"))) {
107 fprintf(stderr, "Could not open temperature file.\n");
108 return smprintf("n/a");
109 }
110
111 /* extract temperature */
112 fscanf(fp, "%d", &temperature);
113
114 /* close temperature file */
115 fclose(fp);
116
117 /* return temperature in degrees */
118 return smprintf("%d°C", temperature / 1000);
119 }
120
121 /* cpu percentage */
122 char *
123 get_cpu_usage(const char *null)
124 {
125 int perc;
126 long double a[4], b[4];
127 FILE *fp;
128
129 /* open stat file */
130 if (!(fp = fopen("/proc/stat","r"))) {
131 fprintf(stderr, "Error opening stat file.");
132 return smprintf("n/a");
133 }
134
135 /* read values */
136 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &a[0], &a[1], &a[2], &a[3]);
137
138 /* close stat file */
139 fclose(fp);
140
141 /* wait a second (for avg values) */
142 sleep(1);
143
144 /* open stat file */
145 if (!(fp = fopen("/proc/stat","r"))) {
146 fprintf(stderr, "Error opening stat file.");
147 return smprintf("n/a");
148 }
149
150 /* read values */
151 fscanf(fp, "%*s %Lf %Lf %Lf %Lf", &b[0], &b[1], &b[2], &b[3]);
152
153 /* close stat file */
154 fclose(fp);
155
156 /* calculate avg in this second */
157 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]));
158
159 /* return perc as string */
160 return smprintf("%d%%", perc);
161 }
162
163 /* date and time */
164 char *
165 get_datetime(const char *timeformat)
166 {
167 time_t tm;
168 size_t bufsize = 64;
169 char *buf = malloc(bufsize);
170
171 /* get time in format */
172 time(&tm);
173 setlocale(LC_TIME, "");
174 if(!strftime(buf, bufsize, timeformat, localtime(&tm))) {
175 setlocale(LC_TIME, "C");
176 fprintf(stderr, "Strftime failed.\n");
177 return smprintf("n/a");
178 }
179
180 setlocale(LC_TIME, "C");
181 /* return time */
182 return smprintf("%s", buf);
183 }
184
185 /* disk usage percentage */
186 char *
187 get_diskusage(const char *mountpoint)
188 {
189 int perc = 0;
190 struct statvfs fs;
191
192 /* try to open mountpoint */
193 if (statvfs(mountpoint, &fs) < 0) {
194 fprintf(stderr, "Could not get filesystem info.\n");
195 return smprintf("n/a");
196 }
197
198 /* calculate percent */
199 perc = 100 * (1.0f - ((float)fs.f_bavail / (float)fs.f_blocks));
200
201 /* return perc */
202 return smprintf("%d%%", perc);
203 }
204
205 /* ram percentage */
206 char *
207 get_ram_usage(const char *null)
208 {
209 int perc;
210 long total, free, buffers, cached;
211 FILE *fp;
212
213 /* open meminfo file */
214 if (!(fp = fopen("/proc/meminfo", "r"))) {
215 fprintf(stderr, "Error opening meminfo file.");
216 return smprintf("n/a");
217 }
218
219 /* read the values */
220 fscanf(fp, "MemTotal: %ld kB\n", &total);
221 fscanf(fp, "MemFree: %ld kB\n", &free);
222 fscanf(fp, "MemAvailable: %ld kB\nBuffers: %ld kB\n", &buffers, &buffers);
223 fscanf(fp, "Cached: %ld kB\n", &cached);
224
225 /* close meminfo file */
226 fclose(fp);
227
228 /* calculate percentage */
229 perc = 100 * ((total - free) - (buffers + cached)) / total;
230
231 /* return perc as string */
232 return smprintf("%d%%", perc);
233 }
234
235 /* alsa volume percentage */
236 char *
237 get_volume(const char *soundcard)
238 {
239 int mute = 0;
240 long vol = 0, max = 0, min = 0;
241
242 /* get volume from alsa */
243 snd_mixer_t *handle;
244 snd_mixer_elem_t *pcm_mixer, *mas_mixer;
245 snd_mixer_selem_id_t *vol_info, *mute_info;
246 snd_mixer_open(&handle, 0);
247 snd_mixer_attach(handle, soundcard);
248 snd_mixer_selem_register(handle, NULL, NULL);
249 snd_mixer_load(handle);
250 snd_mixer_selem_id_malloc(&vol_info);
251 snd_mixer_selem_id_malloc(&mute_info);
252 snd_mixer_selem_id_set_name(vol_info, channel);
253 snd_mixer_selem_id_set_name(mute_info, channel);
254 pcm_mixer = snd_mixer_find_selem(handle, vol_info);
255 mas_mixer = snd_mixer_find_selem(handle, mute_info);
256 snd_mixer_selem_get_playback_volume_range((snd_mixer_elem_t *)pcm_mixer, &min, &max);
257 snd_mixer_selem_get_playback_volume((snd_mixer_elem_t *)pcm_mixer, SND_MIXER_SCHN_MONO, &vol);
258 snd_mixer_selem_get_playback_switch(mas_mixer, SND_MIXER_SCHN_MONO, &mute);
259 if (vol_info)
260 snd_mixer_selem_id_free(vol_info);
261 if (mute_info)
262 snd_mixer_selem_id_free(mute_info);
263 if (handle)
264 snd_mixer_close(handle);
265
266 /* return the string (mute) */
267 if (!mute)
268 return smprintf("mute");
269 else
270 return smprintf("%d%%", (vol * 100) / max);
271 }
272
273 /* wifi percentage */
274 char *
275 get_wifi_signal(const char *wificard)
276 {
277 int bufsize = 255;
278 int strength;
279 char buf[bufsize];
280 char *datastart;
281 char path[64];
282 char status[5];
283 char needle[sizeof wificard + 1];
284 FILE *fp;
285
286 /* generate the path name */
287 memset(path, 0, sizeof path);
288 strcat(path, "/sys/class/net/");
289 strcat(path, wificard);
290 strcat(path, "/operstate");
291
292 /* open wifi file */
293 if(!(fp = fopen(path, "r"))) {
294 fprintf(stderr, "Error opening wifi operstate file.");
295 return smprintf("n/a");
296 }
297
298 /* read the status */
299 fgets(status, 5, fp);
300
301 /* close wifi file */
302 fclose(fp);
303
304 /* check if interface down */
305 if(strcmp(status, "up\n") != 0){
306 return smprintf("n/a");
307 }
308
309 /* open wifi file */
310 if (!(fp = fopen("/proc/net/wireless", "r"))) {
311 fprintf(stderr, "Error opening wireless file.");
312 return smprintf("n/a");
313 }
314
315 /* extract the signal strength */
316 strcpy(needle, wificard);
317 strcat(needle, ":");
318 fgets(buf, bufsize, fp);
319 fgets(buf, bufsize, fp);
320 fgets(buf, bufsize, fp);
321 if ((datastart = strstr(buf, needle)) != NULL) {
322 datastart = strstr(buf, ":");
323 sscanf(datastart + 1, " %*d %d %*d %*d %*d %*d %*d %*d %*d %*d", &strength);
324 }
325
326 /* close wifi file */
327 fclose(fp);
328
329 /* return strength in percent */
330 return smprintf("%d%%", strength);
331 }
332
333 /* main function */
334 int
335 main()
336 {
337 char status_string[1024];
338 struct arg argument;
339
340 /* try to open display */
341 if (!(dpy = XOpenDisplay(0x0))) {
342 fprintf(stderr, "Cannot open display!\n");
343 exit(1);
344 }
345
346 /* return status every interval */
347 for (;;) {
348 /* clear the string */
349 strcpy(status_string, "");
350
351 /* generate status_string */
352 for (size_t i = 0; i < sizeof(args) / sizeof(args[0]); ++i) {
353 argument = args[i];
354 char *res = argument.func(argument.args);
355 char *element = smprintf(argument.format, res);
356 strcat(status_string, element);
357 }
358
359 /* return the statusbar */
360 setstatus(status_string);
361
362 /* wait, "update_interval - 1" because of get_cpu_usage() which uses 1 second */
363 sleep(update_interval -1);
364 }
365
366 /* close display */
367 XCloseDisplay(dpy);
368
369 /* exit successfully */
370 return 0;
371 }