1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Conky, a system monitor, based on torsmo
5 * Any original torsmo code is licensed under the BSD license
7 * All code written since the fork of torsmo is licensed under the GPL
9 * Please see COPYING for details
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14 * All rights reserved.
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * vim: ts=4 sw=4 noet ai cindent syntax=c
33 #include "obj_display.h"
35 //remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat"
36 //string has to end with \0 and it's length should fit in a int
38 void remove_deleted_chars(char *string){
40 while(string[i] != 0){
41 if(string[i] == BACKSPACE){
43 strcpy( &(string[i-1]), &(string[i+1]) );
45 }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string
50 static inline void format_media_player_time(char *buf, const int size,
53 int days, hours, minutes;
55 days = seconds / (24 * 60 * 60);
56 seconds %= (24 * 60 * 60);
57 hours = seconds / (60 * 60);
59 minutes = seconds / 60;
63 snprintf(buf, size, "%i days %i:%02i:%02i", days,
64 hours, minutes, seconds);
65 } else if (hours > 0) {
66 snprintf(buf, size, "%i:%02i:%02i", hours, minutes,
69 snprintf(buf, size, "%i:%02i", minutes, seconds);
73 static inline double get_barnum(char *buf)
85 if (sscanf(buf, "%lf", &barnum) == 0) {
86 NORM_ERR("reading exec value failed (perhaps it's not the "
90 if (barnum > 100.0 || barnum < 0.0) {
91 NORM_ERR("your exec value is not between 0 and 100, "
92 "therefore it will be ignored");
98 char *format_time(unsigned long timeval, const int width)
101 unsigned long nt; // narrow time, for speed on 32-bit
102 unsigned cc; // centiseconds
103 unsigned nn; // multi-purpose whatever
106 cc = nt % 100; // centiseconds past second
107 nt /= 100; // total seconds
108 nn = nt % 60; // seconds past the minute
109 nt /= 60; // total minutes
110 if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
112 return strndup(buf, text_buffer_size);
114 if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
115 return strndup(buf, text_buffer_size);
117 nn = nt % 60; // minutes past the hour
118 nt /= 60; // total hours
119 if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
120 return strndup(buf, text_buffer_size);
122 nn = nt; // now also hours
123 if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
124 return strndup(buf, text_buffer_size);
126 nn /= 24; // now days
127 if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
128 return strndup(buf, text_buffer_size);
130 nn /= 7; // now weeks
131 if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
132 return strndup(buf, text_buffer_size);
134 // well shoot, this outta' fit...
135 return strndup("<inf>", text_buffer_size);
138 /* Prints anything normally printed with snprintf according to the current value
139 * of use_spacer. Actually slightly more flexible than snprintf, as you can
140 * safely specify the destination buffer as one of your inputs. */
141 int spaced_print(char *buf, int size, const char *format, int width, ...)
150 tempbuf = malloc(size * sizeof(char));
152 // Passes the varargs along to vsnprintf
153 va_start(argp, width);
154 vsnprintf(tempbuf, size, format, argp);
157 switch (use_spacer) {
159 len = snprintf(buf, size, "%s", tempbuf);
162 len = snprintf(buf, size, "%*s", width, tempbuf);
165 len = snprintf(buf, size, "%-*s", width, tempbuf);
172 /* print percentage values
174 * - i.e., unsigned values between 0 and 100
175 * - respect the value of pad_percents */
176 static int percent_print(char *buf, int size, unsigned value)
178 return spaced_print(buf, size, "%u", pad_percents, value);
181 static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
183 /* converts from bytes to human readable format (K, M, G, T)
185 * The algorithm always divides by 1024, as unit-conversion of byte
186 * counts suggests. But for output length determination we need to
187 * compare with 1000 here, as we print in decimal form. */
188 static void human_readable(long long num, char *buf, int size)
190 const char **suffix = suffixes;
196 /* Possibly just output as usual, for example for stdout usage */
197 if (!format_human_readable) {
198 spaced_print(buf, size, "%d", 6, round_to_int(num));
209 if (llabs(num) < 1000LL) {
210 spaced_print(buf, size, format, width, 0, (float)num, *suffix);
214 while (llabs(num / 1024) >= 1000LL && **(suffix + 2)) {
222 /* fnum should now be < 1000, so looks like 'AAA.BBBBB'
224 * The goal is to always have a significance of 3, by
225 * adjusting the decimal part of the number. Sample output:
229 * so the point of alignment resides between number and unit. The
230 * upside of this is that there is minimal padding necessary, though
231 * there should be a way to make alignment take place at the decimal
232 * dot (then with fixed width decimal part).
234 * Note the repdigits below: when given a precision value, printf()
235 * rounds the float to it, not just cuts off the remaining digits. So
236 * e.g. 99.95 with a precision of 1 gets 100.0, which again should be
237 * printed with a precision of 0. Yay. */
239 precision = 0; /* print 100-999 without decimal part */
241 precision = 1; /* print 10-99 with one decimal place */
243 precision = 2; /* print 0-9 with two decimal places */
245 spaced_print(buf, size, format, width, precision, fnum, *suffix);
248 /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
249 * multiline objects like $exec work with $align[rc] and friends
251 void substitute_newlines(char *p, long l)
255 while (p && *p && p < s + l) {
257 /* only substitute if it's not the last newline */
258 *p = SECRIT_MULTILINE_CHAR;
264 void evaluate(const char *text, char *buffer)
266 struct information *tmp_info;
267 struct text_object subroot;
269 tmp_info = malloc(sizeof(struct information));
270 memcpy(tmp_info, &ctx->info, sizeof(struct information));
271 parse_conky_vars(&subroot, text, buffer, tmp_info);
272 DBGP("evaluated '%s' to '%s'", text, buffer);
274 free_text_objects(&subroot, 1);
278 void generate_text_internal(char *p, int p_max_size, struct text_object root,
279 struct information *cur)
281 struct text_object *obj;
283 int need_to_load_fonts = 0;
286 /* for the OBJ_top* handler */
287 struct process **needed = 0;
290 char buff_in[p_max_size];
292 set_iconv_converting(0);
293 #endif /* HAVE_ICONV */
297 while (obj && p_max_size > 0) {
298 needed = 0; /* reset for top stuff */
300 /* IFBLOCK jumping algorithm
302 * This is easier as it looks like:
303 * - each IF checks it's condition
304 * - on FALSE: call DO_JUMP
305 * - on TRUE: don't care
306 * - each ELSE calls DO_JUMP unconditionally
307 * - each ENDIF is silently being ignored
310 * DO_JUMP overwrites the "obj" variable of the loop and sets it to the target
311 * (i.e. the corresponding ELSE or ENDIF). After that, processing for the given
312 * object can continue, free()ing stuff e.g., then the for-loop does the rest: as
313 * regularly, "obj" is being updated to point to obj->next, so object parsing
314 * continues right after the corresponding ELSE or ENDIF. This means that if we
315 * find an ELSE, it's corresponding IF must not have jumped, so we need to jump
316 * always. If we encounter an ENDIF, it's corresponding IF or ELSE has not
317 * jumped, and there is nothing to do.
321 obj = obj->data.ifblock.next; \
324 #define OBJ(a) break; case OBJ_##a:
328 NORM_ERR("not implemented obj type %d", obj->type);
331 struct sockaddr_in addr;
332 struct hostent* he = gethostbyname(obj->data.read_tcp.host);
334 sock = socket(he->h_addrtype, SOCK_STREAM, 0);
336 memset(&addr, 0, sizeof(addr));
337 addr.sin_family = AF_INET;
338 addr.sin_port = obj->data.read_tcp.port;
339 memcpy(&addr.sin_addr, he->h_addr, he->h_length);
340 if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == 0) {
344 FD_SET(sock, &readfds);
347 if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
348 received = recv(sock, p, p_max_size, 0);
353 NORM_ERR("read_tcp: Couldn't create a connection");
356 NORM_ERR("read_tcp: Couldn't create a socket");
359 NORM_ERR("read_tcp: Problem with resolving the hostname");
364 temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
366 #endif /* !__OpenBSD__ */
369 obj->a = get_freq(p, p_max_size, "%.0f", 1,
370 obj->data.cpu_index);
376 obj->a = get_freq(p, p_max_size, "%'.2f", 1000,
377 obj->data.cpu_index);
379 /* OpenBSD has no such flag (SUSv2) */
380 obj->a = get_freq(p, p_max_size, "%.2f", 1000,
381 obj->data.cpu_index);
382 #endif /* __OpenBSD */
385 #if defined(__linux__)
388 obj->a = get_voltage(p, p_max_size, "%.0f", 1,
389 obj->data.cpu_index);
394 obj->a = get_voltage(p, p_max_size, "%'.3f", 1000,
395 obj->data.cpu_index);
400 OBJ(wireless_essid) {
401 snprintf(p, p_max_size, "%s", obj->data.net->essid);
404 snprintf(p, p_max_size, "%s", obj->data.net->mode);
406 OBJ(wireless_bitrate) {
407 snprintf(p, p_max_size, "%s", obj->data.net->bitrate);
410 snprintf(p, p_max_size, "%s", obj->data.net->ap);
412 OBJ(wireless_link_qual) {
413 spaced_print(p, p_max_size, "%d", 4,
414 obj->data.net->link_qual);
416 OBJ(wireless_link_qual_max) {
417 spaced_print(p, p_max_size, "%d", 4,
418 obj->data.net->link_qual_max);
420 OBJ(wireless_link_qual_perc) {
421 if (obj->data.net->link_qual_max > 0) {
422 spaced_print(p, p_max_size, "%.0f", 5,
423 (double) obj->data.net->link_qual /
424 obj->data.net->link_qual_max * 100);
426 spaced_print(p, p_max_size, "unk", 5);
429 OBJ(wireless_link_bar) {
431 if(output_methods & TO_X) {
432 new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
433 obj->data.net->link_qual_max) * 255.0);
436 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
437 new_bar_in_shell(p, p_max_size, ((double) obj->data.net->link_qual /
438 obj->data.net->link_qual_max) * 100.0, obj->a);
443 #endif /* HAVE_IWLIB */
445 #endif /* __linux__ */
449 get_adt746x_cpu(p, p_max_size);
452 get_adt746x_fan(p, p_max_size);
455 get_acpi_fan(p, p_max_size);
458 get_acpi_ac_adapter(p, p_max_size);
461 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
464 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
466 OBJ(battery_percent) {
467 percent_print(p, p_max_size, get_battery_perct(obj->data.s));
471 if(output_methods & TO_X) {
472 new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
475 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
476 new_bar_in_shell(p, p_max_size, get_battery_perct_bar(obj->data.s) / 2.55, obj->a);
482 get_battery_short_status(p, p_max_size, obj->data.s);
484 #endif /* __OpenBSD__ */
487 human_readable(cur->buffers * 1024, p, 255);
490 human_readable(cur->cached * 1024, p, 255);
493 if (obj->data.cpu_index > info.cpu_count) {
494 NORM_ERR("obj->data.cpu_index %i info.cpu_count %i",
495 obj->data.cpu_index, info.cpu_count);
496 CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
498 percent_print(p, p_max_size,
499 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
503 new_gauge(p, obj->a, obj->b,
504 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
508 if(output_methods & TO_X) {
509 new_bar(p, obj->a, obj->b,
510 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
513 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
514 new_bar_in_shell(p, p_max_size, round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100), obj->a);
521 new_graph(p, obj->a, obj->b, obj->c, obj->d,
522 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100),
523 100, 1, obj->char_a, obj->char_b);
526 new_graph(p, obj->a, obj->b, obj->c, obj->d, cur->loadavg[0],
527 obj->e, 1, obj->char_a, obj->char_b);
531 new_fg(p, obj->data.l);
566 snprintf(p, p_max_size, "%s", VERSION);
568 OBJ(conky_build_date) {
569 snprintf(p, p_max_size, "%s", BUILD_DATE);
571 OBJ(conky_build_arch) {
572 snprintf(p, p_max_size, "%s", BUILD_ARCH);
574 #if defined(__linux__)
576 snprintf(p, p_max_size, "%s",
577 get_disk_protect_queue(obj->data.s));
580 snprintf(p, p_max_size, "%s", i8k.version);
583 snprintf(p, p_max_size, "%s", i8k.bios);
586 snprintf(p, p_max_size, "%s", i8k.serial);
591 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
592 temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
594 OBJ(i8k_left_fan_status) {
597 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
598 if (left_fan_status == 0) {
599 snprintf(p, p_max_size, "off");
601 if (left_fan_status == 1) {
602 snprintf(p, p_max_size, "low");
604 if (left_fan_status == 2) {
605 snprintf(p, p_max_size, "high");
608 OBJ(i8k_right_fan_status) {
609 int right_fan_status;
611 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
612 if (right_fan_status == 0) {
613 snprintf(p, p_max_size, "off");
615 if (right_fan_status == 1) {
616 snprintf(p, p_max_size, "low");
618 if (right_fan_status == 2) {
619 snprintf(p, p_max_size, "high");
622 OBJ(i8k_left_fan_rpm) {
623 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
625 OBJ(i8k_right_fan_rpm) {
626 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
631 sscanf(i8k.ac_status, "%d", &ac_status);
632 if (ac_status == -1) {
633 snprintf(p, p_max_size, "disabled (read i8k docs)");
635 if (ac_status == 0) {
636 snprintf(p, p_max_size, "off");
638 if (ac_status == 1) {
639 snprintf(p, p_max_size, "on");
642 OBJ(i8k_buttons_status) {
643 snprintf(p, p_max_size, "%s", i8k.buttons_status);
647 get_ibm_acpi_fan(p, p_max_size);
650 get_ibm_acpi_temps();
651 temp_print(p, p_max_size,
652 ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
655 get_ibm_acpi_volume(p, p_max_size);
657 OBJ(ibm_brightness) {
658 get_ibm_acpi_brightness(p, p_max_size);
661 /* information from sony_laptop kernel module
662 * /sys/devices/platform/sony-laptop */
664 get_sony_fanspeed(p, p_max_size);
667 if (!cur->gw_info.count) {
672 snprintf(p, p_max_size, "%s", cur->gw_info.iface);
675 snprintf(p, p_max_size, "%s", cur->gw_info.ip);
678 snprintf(p, p_max_size, "%d", get_laptop_mode());
681 get_powerbook_batt_info(p, p_max_size, obj->data.i);
683 #endif /* __linux__ */
684 #if (defined(__FreeBSD__) || defined(__linux__))
686 if ((obj->data.ifblock.s)
687 && (!interface_up(obj->data.ifblock.s))) {
693 OBJ(obsd_sensors_temp) {
694 obsd_sensors.device = sensor_device;
695 update_obsd_sensors();
696 temp_print(p, p_max_size,
697 obsd_sensors.temp[obsd_sensors.device][obj->data.sensor],
700 OBJ(obsd_sensors_fan) {
701 obsd_sensors.device = sensor_device;
702 update_obsd_sensors();
703 snprintf(p, p_max_size, "%d",
704 obsd_sensors.fan[obsd_sensors.device][obj->data.sensor]);
706 OBJ(obsd_sensors_volt) {
707 obsd_sensors.device = sensor_device;
708 update_obsd_sensors();
709 snprintf(p, p_max_size, "%.2f",
710 obsd_sensors.volt[obsd_sensors.device][obj->data.sensor]);
713 get_obsd_vendor(p, p_max_size);
716 get_obsd_product(p, p_max_size);
718 #endif /* __OpenBSD__ */
721 new_font(p, obj->data.s);
722 need_to_load_fonts = 1;
725 /* TODO: move this correction from kB to kB/s elsewhere
726 * (or get rid of it??) */
728 human_readable((obj->data.diskio->current / update_interval) * 1024LL,
732 human_readable((obj->data.diskio->current_write / update_interval) * 1024LL,
736 human_readable((obj->data.diskio->current_read / update_interval) * 1024LL,
741 new_graph(p, obj->a, obj->b, obj->c, obj->d,
742 obj->data.diskio->current, obj->e, 1, obj->char_a, obj->char_b);
744 OBJ(diskiograph_read) {
745 new_graph(p, obj->a, obj->b, obj->c, obj->d,
746 obj->data.diskio->current_read, obj->e, 1, obj->char_a, obj->char_b);
748 OBJ(diskiograph_write) {
749 new_graph(p, obj->a, obj->b, obj->c, obj->d,
750 obj->data.diskio->current_write, obj->e, 1, obj->char_a, obj->char_b);
754 human_readable(obj->data.net->recv_speed, p, 255);
757 spaced_print(p, p_max_size, "%.1f", 8,
758 obj->data.net->recv_speed / 1024.0);
761 OBJ(downspeedgraph) {
762 new_graph(p, obj->a, obj->b, obj->c, obj->d,
763 obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
767 /* Since we see you, you're if has not jumped.
768 * Do Ninja jump here: without leaving traces.
769 * This is to prevent us from stale jumped flags.
771 obj = obj->data.ifblock.next;
775 /* harmless object, just ignore */
778 if ((obj->data.net->addr.sa_data[2] & 255) == 0
779 && (obj->data.net->addr.sa_data[3] & 255) == 0
780 && (obj->data.net->addr.sa_data[4] & 255) == 0
781 && (obj->data.net->addr.sa_data[5] & 255) == 0) {
782 snprintf(p, p_max_size, "No Address");
784 snprintf(p, p_max_size, "%u.%u.%u.%u",
785 obj->data.net->addr.sa_data[2] & 255,
786 obj->data.net->addr.sa_data[3] & 255,
787 obj->data.net->addr.sa_data[4] & 255,
788 obj->data.net->addr.sa_data[5] & 255);
791 #if defined(__linux__)
793 if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
794 obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
795 strcpy(p, obj->data.net->addrs);
797 strcpy(p, "0.0.0.0");
800 #endif /* __linux__ */
801 #if defined(IMLIB2) && defined(X11)
803 /* doesn't actually draw anything, just queues it omp. the
804 * image will get drawn after the X event loop */
805 cimlib_add_image(obj->data.s);
809 evaluate(obj->data.s, p);
812 read_exec(obj->data.s, p, text_buffer_size);
813 remove_deleted_chars(p);
816 struct information *tmp_info;
817 struct text_object subroot;
819 read_exec(obj->data.s, p, text_buffer_size);
821 tmp_info = malloc(sizeof(struct information));
822 memcpy(tmp_info, cur, sizeof(struct information));
823 parse_conky_vars(&subroot, p, p, tmp_info);
825 free_text_objects(&subroot, 1);
832 read_exec(obj->data.s, p, text_buffer_size);
833 barnum = get_barnum(p); /*using the same function*/
837 new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
844 read_exec(obj->data.s, p, text_buffer_size);
845 barnum = get_barnum(p);
849 if(output_methods & TO_X) {
851 new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
854 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
855 new_bar_in_shell(p, p_max_size, barnum, obj->a);
863 char showaslog = FALSE;
864 char tempgrad = FALSE;
866 char *cmd = obj->data.s;
868 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
870 cmd += strlen(" "TEMPGRAD);
872 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
874 cmd += strlen(" "LOGGRAPH);
876 read_exec(cmd, p, text_buffer_size);
877 barnum = get_barnum(p);
880 new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
881 100, 1, showaslog, tempgrad);
886 if (current_update_time - obj->data.execi.last_update
887 >= obj->data.execi.interval) {
890 read_exec(obj->data.execi.cmd, p, text_buffer_size);
891 barnum = get_barnum(p);
896 obj->data.execi.last_update = current_update_time;
899 if(output_methods & TO_X) {
900 new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
903 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
904 new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a);
911 if (current_update_time - obj->data.execi.last_update
912 >= obj->data.execi.interval) {
914 char showaslog = FALSE;
915 char tempgrad = FALSE;
916 char *cmd = obj->data.execi.cmd;
918 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
920 cmd += strlen(" "TEMPGRAD);
922 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
924 cmd += strlen(" "LOGGRAPH);
926 obj->char_a = showaslog;
927 obj->char_b = tempgrad;
928 read_exec(cmd, p, text_buffer_size);
929 barnum = get_barnum(p);
934 obj->data.execi.last_update = current_update_time;
936 new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b);
939 if (current_update_time - obj->data.execi.last_update
940 >= obj->data.execi.interval) {
943 read_exec(obj->data.execi.cmd, p, text_buffer_size);
944 barnum = get_barnum(p);
947 obj->f = 255 * barnum / 100.0;
949 obj->data.execi.last_update = current_update_time;
951 new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
955 if (current_update_time - obj->data.execi.last_update
956 >= obj->data.execi.interval
957 && obj->data.execi.interval != 0) {
958 read_exec(obj->data.execi.cmd, obj->data.execi.buffer,
960 obj->data.execi.last_update = current_update_time;
962 snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
965 struct text_object subroot;
966 struct information *tmp_info =
967 malloc(sizeof(struct information));
968 memcpy(tmp_info, cur, sizeof(struct information));
970 if (current_update_time - obj->data.execi.last_update
971 < obj->data.execi.interval
972 || obj->data.execi.interval == 0) {
973 parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
975 char *output = obj->data.execi.buffer;
976 FILE *fp = pid_popen(obj->data.execi.cmd, "r", &childpid);
977 int length = fread(output, 1, text_buffer_size, fp);
981 output[length] = '\0';
982 if (length > 0 && output[length - 1] == '\n') {
983 output[length - 1] = '\0';
986 parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
987 obj->data.execi.last_update = current_update_time;
989 free_text_objects(&subroot, 1);
993 if (!obj->data.texeci.p_timed_thread) {
994 obj->data.texeci.p_timed_thread =
995 timed_thread_create(&threaded_exec,
996 (void *) obj, obj->data.texeci.interval * 1000000);
997 if (!obj->data.texeci.p_timed_thread) {
998 NORM_ERR("Error creating texeci timed thread");
1001 * note that we don't register this thread with the
1002 * timed_thread list, because we destroy it manually
1004 if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
1005 NORM_ERR("Error running texeci timed thread");
1008 timed_thread_lock(obj->data.texeci.p_timed_thread);
1009 snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer);
1010 timed_thread_unlock(obj->data.texeci.p_timed_thread);
1014 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1016 if (mail && mail->p_timed_thread) {
1017 timed_thread_lock(mail->p_timed_thread);
1018 snprintf(p, p_max_size, "%lu", mail->unseen);
1019 timed_thread_unlock(mail->p_timed_thread);
1022 OBJ(imap_messages) {
1023 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1025 if (mail && mail->p_timed_thread) {
1026 timed_thread_lock(mail->p_timed_thread);
1027 snprintf(p, p_max_size, "%lu", mail->messages);
1028 timed_thread_unlock(mail->p_timed_thread);
1032 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1034 if (mail && mail->p_timed_thread) {
1035 timed_thread_lock(mail->p_timed_thread);
1036 snprintf(p, p_max_size, "%lu", mail->unseen);
1037 timed_thread_unlock(mail->p_timed_thread);
1041 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1043 if (mail && mail->p_timed_thread) {
1044 timed_thread_lock(mail->p_timed_thread);
1045 snprintf(p, p_max_size, "%.1f",
1046 mail->used / 1024.0 / 1024.0);
1047 timed_thread_unlock(mail->p_timed_thread);
1051 if (obj->data.fs != NULL) {
1052 if (obj->data.fs->size == 0) {
1054 if(output_methods & TO_X) {
1055 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1058 if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1059 new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1065 if(output_methods & TO_X) {
1066 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1067 (int) (255 - obj->data.fsbar.fs->avail * 255 /
1068 obj->data.fs->size));
1071 if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1072 new_bar_in_shell(p, p_max_size,
1073 (int) (100 - obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1081 if (obj->data.fs != NULL) {
1082 human_readable(obj->data.fs->avail, p, 255);
1086 if (obj->data.fs != NULL) {
1089 if (obj->data.fs->size) {
1090 val = obj->data.fs->avail * 100 / obj->data.fs->size;
1093 percent_print(p, p_max_size, val);
1097 if (obj->data.fs != NULL) {
1098 human_readable(obj->data.fs->size, p, 255);
1102 if (obj->data.fs != NULL)
1103 snprintf(p, p_max_size, "%s", obj->data.fs->type);
1106 if (obj->data.fs != NULL) {
1107 human_readable(obj->data.fs->size - obj->data.fs->free, p,
1112 if (obj->data.fs != NULL) {
1113 if (obj->data.fs->size == 0) {
1115 if(output_methods & TO_X) {
1116 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1119 if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1120 new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1126 if(output_methods & TO_X) {
1127 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1128 (int) (obj->data.fsbar.fs->avail * 255 /
1129 obj->data.fs->size));
1132 if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1133 new_bar_in_shell(p, p_max_size,
1134 (int) (obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1142 if (obj->data.fs != NULL) {
1145 if (obj->data.fs->size) {
1146 val = obj->data.fs->free
1151 percent_print(p, p_max_size, 100 - val);
1155 float *v = info.loadavg;
1157 if (obj->data.loadavg[2]) {
1158 snprintf(p, p_max_size, "%.2f %.2f %.2f",
1159 v[obj->data.loadavg[0] - 1],
1160 v[obj->data.loadavg[1] - 1],
1161 v[obj->data.loadavg[2] - 1]);
1162 } else if (obj->data.loadavg[1]) {
1163 snprintf(p, p_max_size, "%.2f %.2f",
1164 v[obj->data.loadavg[0] - 1],
1165 v[obj->data.loadavg[1] - 1]);
1166 } else if (obj->data.loadavg[0]) {
1167 snprintf(p, p_max_size, "%.2f",
1168 v[obj->data.loadavg[0] - 1]);
1172 new_goto(p, obj->data.i);
1175 new_tab(p, obj->data.pair.a, obj->data.pair.b);
1179 new_hr(p, obj->data.i);
1183 if (cur->nameserver_info.nscount > obj->data.i)
1184 snprintf(p, p_max_size, "%s",
1185 cur->nameserver_info.ns_list[obj->data.i]);
1189 char *skill = eve(obj->data.eve.userid, obj->data.eve.apikey, obj->data.eve.charid);
1190 snprintf(p, p_max_size, "%s", skill);
1195 if (obj->data.curl.uri != NULL) {
1196 ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval);
1198 NORM_ERR("error processing Curl data");
1204 if (obj->data.rss.uri != NULL) {
1205 rss_process_info(p, p_max_size, obj->data.rss.uri, obj->data.rss.action, obj->data.rss.act_par, obj->data.rss.interval, obj->data.rss.nrspaces);
1207 NORM_ERR("error processing RSS data");
1213 if (obj->data.weather.uri != NULL) {
1214 weather_process_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
1216 NORM_ERR("error processing weather data, check that you have a valid XOAP key if using XOAP.");
1221 OBJ(weather_forecast) {
1222 if (obj->data.weather_forecast.uri != NULL) {
1223 weather_forecast_process_info(p, p_max_size, obj->data.weather_forecast.uri, obj->data.weather_forecast.day, obj->data.weather_forecast.data_type, obj->data.weather_forecast.interval);
1225 NORM_ERR("error processing weather forecast data, check that you have a valid XOAP key if using XOAP.");
1231 char *str = llua_getstring(obj->data.s);
1233 snprintf(p, p_max_size, "%s", str);
1238 char *str = llua_getstring(obj->data.s);
1246 if (llua_getnumber(obj->data.s, &per)) {
1248 if(output_methods & TO_X) {
1249 new_bar(p, obj->a, obj->b, (per/100.0 * 255));
1252 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1253 new_bar_in_shell(p, p_max_size, per, obj->a);
1262 if (llua_getnumber(obj->data.s, &per)) {
1263 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1264 per, obj->e, 1, obj->char_a, obj->char_b);
1269 if (llua_getnumber(obj->data.s, &per)) {
1270 new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
1274 #endif /* HAVE_LUA */
1279 if (obj->data.hddtemp.update_time < current_update_time - 30) {
1280 if (obj->data.hddtemp.temp)
1281 free(obj->data.hddtemp.temp);
1282 obj->data.hddtemp.temp = get_hddtemp_info(obj->data.hddtemp.dev,
1283 obj->data.hddtemp.addr, obj->data.hddtemp.port);
1284 obj->data.hddtemp.update_time = current_update_time;
1286 if (!obj->data.hddtemp.temp) {
1287 snprintf(p, p_max_size, "N/A");
1289 val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
1290 unit = obj->data.hddtemp.temp[0];
1292 if (*endptr != '\0')
1293 snprintf(p, p_max_size, "N/A");
1294 else if (unit == 'C')
1295 temp_print(p, p_max_size, (double)val, TEMP_CELSIUS);
1296 else if (unit == 'F')
1297 temp_print(p, p_max_size, (double)val, TEMP_FAHRENHEIT);
1299 snprintf(p, p_max_size, "N/A");
1304 new_offset(p, obj->data.i);
1307 new_voffset(p, obj->data.i);
1313 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1314 obj->data.sysfs.devtype, obj->data.sysfs.type);
1316 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1318 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1319 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1320 } else if (r >= 100.0 || r == 0) {
1321 snprintf(p, p_max_size, "%d", (int) r);
1323 snprintf(p, p_max_size, "%.1f", r);
1329 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1330 obj->data.sysfs.devtype, obj->data.sysfs.type);
1332 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1334 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1335 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1336 } else if (r >= 100.0 || r == 0) {
1337 snprintf(p, p_max_size, "%d", (int) r);
1339 snprintf(p, p_max_size, "%.1f", r);
1345 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1346 obj->data.sysfs.devtype, obj->data.sysfs.type);
1348 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1350 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1351 temp_print(p, p_max_size, r, TEMP_CELSIUS);
1352 } else if (r >= 100.0 || r == 0) {
1353 snprintf(p, p_max_size, "%d", (int) r);
1355 snprintf(p, p_max_size, "%.1f", r);
1358 #endif /* __linux__ */
1360 new_alignr(p, obj->data.i);
1363 new_alignc(p, obj->data.i);
1366 char buf[max_user_text];
1367 struct information *tmp_info =
1368 malloc(sizeof(struct information));
1369 memcpy(tmp_info, cur, sizeof(struct information));
1370 generate_text_internal(buf, max_user_text,
1371 *obj->sub, tmp_info);
1373 if (strlen(buf) != 0) {
1379 char expression[max_user_text];
1381 struct information *tmp_info;
1383 tmp_info = malloc(sizeof(struct information));
1384 memcpy(tmp_info, cur, sizeof(struct information));
1385 generate_text_internal(expression, max_user_text,
1386 *obj->sub, tmp_info);
1387 DBGP("parsed arg into '%s'", expression);
1389 val = compare(expression);
1391 NORM_ERR("compare failed for expression '%s'",
1399 if (obj->data.ifblock.str
1400 && !check_contains(obj->data.ifblock.s,
1401 obj->data.ifblock.str)) {
1403 } else if (obj->data.ifblock.s
1404 && access(obj->data.ifblock.s, F_OK)) {
1409 if ((obj->data.ifblock.s)
1410 && (!check_mount(obj->data.ifblock.s))) {
1416 if (!get_process_by_name(obj->data.ifblock.s)) {
1418 if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
1423 #if defined(__linux__)
1425 snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
1429 snprintf(p, p_max_size, "%s", cur->uname_s.release);
1432 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
1437 human_readable(cur->mem * 1024, p, 255);
1440 human_readable(cur->memeasyfree * 1024, p, 255);
1443 human_readable(cur->memfree * 1024, p, 255);
1446 human_readable(cur->memmax * 1024, p, 255);
1450 percent_print(p, p_max_size, cur->mem * 100 / cur->memmax);
1454 new_gauge(p, obj->data.pair.a, obj->data.pair.b,
1455 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
1460 if(output_methods & TO_X) {
1461 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1462 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
1465 if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1466 new_bar_in_shell(p, p_max_size, cur->memmax ? (cur->mem * 100) / (cur->memmax) : 0, obj->data.pair.a);
1473 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1474 cur->memmax ? (cur->mem * 100.0) / (cur->memmax) : 0.0,
1475 100, 1, obj->char_a, obj->char_b);
1480 percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
1483 percent_print(p, p_max_size, mixer_get_left(obj->data.l));
1486 percent_print(p, p_max_size, mixer_get_right(obj->data.l));
1490 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1491 mixer_to_255(obj->data.mixerbar.l,mixer_get_avg(obj->data.mixerbar.l)));
1494 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1495 mixer_to_255(obj->data.mixerbar.l,mixer_get_left(obj->data.mixerbar.l)));
1498 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1499 mixer_to_255(obj->data.mixerbar.l,mixer_get_right(obj->data.mixerbar.l)));
1502 OBJ(if_mixer_mute) {
1503 if (!mixer_is_mute(obj->data.ifblock.i)) {
1508 #define NOT_IN_X "Not running in X"
1510 if(x_initialised != YES) {
1511 strncpy(p, NOT_IN_X, p_max_size);
1513 snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
1516 OBJ(monitor_number) {
1517 if(x_initialised != YES) {
1518 strncpy(p, NOT_IN_X, p_max_size);
1520 snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
1524 if(x_initialised != YES) {
1525 strncpy(p, NOT_IN_X, p_max_size);
1527 snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
1530 OBJ(desktop_number) {
1531 if(x_initialised != YES) {
1532 strncpy(p, NOT_IN_X, p_max_size);
1534 snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
1538 if(x_initialised != YES) {
1539 strncpy(p, NOT_IN_X, p_max_size);
1540 }else if(cur->x11.desktop.name != NULL) {
1541 strncpy(p, cur->x11.desktop.name, p_max_size);
1548 update_mail_count(&obj->data.local_mail);
1549 snprintf(p, p_max_size, "%d", obj->data.local_mail.mail_count);
1552 update_mail_count(&obj->data.local_mail);
1553 snprintf(p, p_max_size, "%d",
1554 obj->data.local_mail.new_mail_count);
1557 update_mail_count(&obj->data.local_mail);
1558 snprintf(p, p_max_size, "%d",
1559 obj->data.local_mail.seen_mail_count);
1562 update_mail_count(&obj->data.local_mail);
1563 snprintf(p, p_max_size, "%d",
1564 obj->data.local_mail.unseen_mail_count);
1566 OBJ(flagged_mails) {
1567 update_mail_count(&obj->data.local_mail);
1568 snprintf(p, p_max_size, "%d",
1569 obj->data.local_mail.flagged_mail_count);
1571 OBJ(unflagged_mails) {
1572 update_mail_count(&obj->data.local_mail);
1573 snprintf(p, p_max_size, "%d",
1574 obj->data.local_mail.unflagged_mail_count);
1576 OBJ(forwarded_mails) {
1577 update_mail_count(&obj->data.local_mail);
1578 snprintf(p, p_max_size, "%d",
1579 obj->data.local_mail.forwarded_mail_count);
1581 OBJ(unforwarded_mails) {
1582 update_mail_count(&obj->data.local_mail);
1583 snprintf(p, p_max_size, "%d",
1584 obj->data.local_mail.unforwarded_mail_count);
1586 OBJ(replied_mails) {
1587 update_mail_count(&obj->data.local_mail);
1588 snprintf(p, p_max_size, "%d",
1589 obj->data.local_mail.replied_mail_count);
1591 OBJ(unreplied_mails) {
1592 update_mail_count(&obj->data.local_mail);
1593 snprintf(p, p_max_size, "%d",
1594 obj->data.local_mail.unreplied_mail_count);
1597 update_mail_count(&obj->data.local_mail);
1598 snprintf(p, p_max_size, "%d",
1599 obj->data.local_mail.draft_mail_count);
1601 OBJ(trashed_mails) {
1602 update_mail_count(&obj->data.local_mail);
1603 snprintf(p, p_max_size, "%d",
1604 obj->data.local_mail.trashed_mail_count);
1607 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
1609 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
1612 snprintf(p, p_max_size, "%s", cur->uname_s.nodename);
1615 new_outline(p, obj->data.l);
1618 spaced_print(p, p_max_size, "%hu", 4, cur->procs);
1620 OBJ(running_processes) {
1621 spaced_print(p, p_max_size, "%hu", 4, cur->run_procs);
1624 snprintf(p, p_max_size, "%s", obj->data.s);
1628 new_bg(p, obj->data.l);
1631 new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
1635 human_readable(cur->swap * 1024, p, 255);
1638 human_readable(cur->swapfree * 1024, p, 255);
1641 human_readable(cur->swapmax * 1024, p, 255);
1644 if (cur->swapmax == 0) {
1645 strncpy(p, "No swap", p_max_size);
1647 percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
1652 if(output_methods & TO_X) {
1653 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1654 cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
1657 if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1658 new_bar_in_shell(p, p_max_size, cur->swapmax ? (cur->swap * 100) / (cur->swapmax) : 0, obj->data.pair.a);
1664 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
1667 time_t t = time(NULL);
1668 struct tm *tm = localtime(&t);
1670 setlocale(LC_TIME, "");
1671 strftime(p, p_max_size, obj->data.s, tm);
1674 time_t t = time(NULL);
1675 struct tm *tm = gmtime(&t);
1677 strftime(p, p_max_size, obj->data.s, tm);
1684 if (obj->data.tztime.tz) {
1685 oldTZ = getenv("TZ");
1686 setenv("TZ", obj->data.tztime.tz, 1);
1692 setlocale(LC_TIME, "");
1693 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
1695 setenv("TZ", oldTZ, 1);
1700 // Needless to free oldTZ since getenv gives ptr to static data
1703 human_readable(obj->data.net->recv, p, 255);
1706 human_readable(obj->data.net->trans, p, 255);
1709 snprintf(p, p_max_size, "%d", total_updates);
1712 if(total_updates % updatereset != obj->data.ifblock.i - 1) {
1717 human_readable(obj->data.net->trans_speed, p, 255);
1720 spaced_print(p, p_max_size, "%.1f", 8,
1721 obj->data.net->trans_speed / 1024.0);
1725 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1726 obj->data.net->trans_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
1730 format_seconds_short(p, p_max_size, (int) cur->uptime);
1733 format_seconds(p, p_max_size, (int) cur->uptime);
1736 snprintf(p, p_max_size, "%s", cur->users.names);
1739 snprintf(p, p_max_size, "%s", cur->users.terms);
1742 snprintf(p, p_max_size, "%s", cur->users.times);
1745 snprintf(p, p_max_size, "%d", cur->users.number);
1747 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
1748 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
1752 msg = get_apm_adapter();
1753 snprintf(p, p_max_size, "%s", msg);
1756 OBJ(apm_battery_life) {
1759 msg = get_apm_battery_life();
1760 snprintf(p, p_max_size, "%s", msg);
1763 OBJ(apm_battery_time) {
1766 msg = get_apm_battery_time();
1767 snprintf(p, p_max_size, "%s", msg);
1770 #endif /* __FreeBSD__ __OpenBSD__ */
1773 #define mpd_printf(fmt, val) \
1774 snprintf(p, p_max_size, fmt, mpd_get_info()->val)
1775 #define mpd_sprintf(val) { \
1776 if (!obj->data.i || obj->data.i > p_max_size) \
1777 mpd_printf("%s", val); \
1779 snprintf(p, obj->data.i, "%s", mpd_get_info()->val); \
1784 mpd_sprintf(artist);
1788 mpd_printf("%s", random);
1790 mpd_printf("%s", repeat);
1798 mpd_printf("%d", volume);
1800 mpd_printf("%d", bitrate);
1802 mpd_printf("%s", status);
1804 format_media_player_time(p, p_max_size, mpd_get_info()->elapsed);
1807 format_media_player_time(p, p_max_size, mpd_get_info()->length);
1810 percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
1814 if(output_methods & TO_X) {
1815 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1816 (int) (mpd_get_info()->progress * 255.0f));
1819 if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1820 new_bar_in_shell(p, p_max_size, (int) (mpd_get_info()->progress * 100.0f), obj->data.pair.a);
1826 struct mpd_s *mpd = mpd_get_info();
1827 int len = obj->data.i;
1828 if (len == 0 || len > p_max_size)
1831 memset(p, 0, p_max_size);
1832 if (mpd->artist && *mpd->artist &&
1833 mpd->title && *mpd->title) {
1834 snprintf(p, len, "%s - %s", mpd->artist,
1836 } else if (mpd->title && *mpd->title) {
1837 snprintf(p, len, "%s", mpd->title);
1838 } else if (mpd->artist && *mpd->artist) {
1839 snprintf(p, len, "%s", mpd->artist);
1840 } else if (mpd->file && *mpd->file) {
1841 snprintf(p, len, "%s", mpd->file);
1846 OBJ(if_mpd_playing) {
1847 if (!mpd_get_info()->is_playing) {
1856 #define MOC_PRINT(t, a) \
1857 snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
1859 MOC_PRINT(state, "??");
1862 MOC_PRINT(file, "no file");
1865 MOC_PRINT(title, "no title");
1868 MOC_PRINT(artist, "no artist");
1871 MOC_PRINT(song, "no song");
1874 MOC_PRINT(album, "no album");
1876 OBJ(moc_totaltime) {
1877 MOC_PRINT(totaltime, "0:00");
1880 MOC_PRINT(timeleft, "0:00");
1883 MOC_PRINT(curtime, "0:00");
1886 MOC_PRINT(bitrate, "0Kbps");
1889 MOC_PRINT(rate, "0KHz");
1895 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
1898 snprintf(p, p_max_size, "%s", cur->xmms2.album);
1901 snprintf(p, p_max_size, "%s", cur->xmms2.title);
1904 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
1906 OBJ(xmms2_comment) {
1907 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
1910 snprintf(p, p_max_size, "%s", cur->xmms2.url);
1913 snprintf(p, p_max_size, "%s", cur->xmms2.status);
1916 snprintf(p, p_max_size, "%s", cur->xmms2.date);
1918 OBJ(xmms2_tracknr) {
1919 if (cur->xmms2.tracknr != -1) {
1920 snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
1923 OBJ(xmms2_bitrate) {
1924 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
1927 snprintf(p, p_max_size, "%u", cur->xmms2.id);
1930 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
1932 OBJ(xmms2_elapsed) {
1933 snprintf(p, p_max_size, "%02d:%02d", cur->xmms2.elapsed / 60000,
1934 (cur->xmms2.elapsed / 1000) % 60);
1936 OBJ(xmms2_duration) {
1937 snprintf(p, p_max_size, "%02d:%02d",
1938 cur->xmms2.duration / 60000,
1939 (cur->xmms2.duration / 1000) % 60);
1941 OBJ(xmms2_percent) {
1942 snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
1946 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1947 (int) (cur->xmms2.progress * 255.0f));
1950 OBJ(xmms2_playlist) {
1951 snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
1953 OBJ(xmms2_timesplayed) {
1954 snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
1957 if (strlen(cur->xmms2.title) < 2
1958 && strlen(cur->xmms2.title) < 2) {
1959 snprintf(p, p_max_size, "%s", cur->xmms2.url);
1961 snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist,
1965 OBJ(if_xmms2_connected) {
1966 if (cur->xmms2.conn_state != 1) {
1972 OBJ(audacious_status) {
1973 snprintf(p, p_max_size, "%s",
1974 cur->audacious.items[AUDACIOUS_STATUS]);
1976 OBJ(audacious_title) {
1977 snprintf(p, cur->audacious.max_title_len > 0
1978 ? cur->audacious.max_title_len : p_max_size, "%s",
1979 cur->audacious.items[AUDACIOUS_TITLE]);
1981 OBJ(audacious_length) {
1982 snprintf(p, p_max_size, "%s",
1983 cur->audacious.items[AUDACIOUS_LENGTH]);
1985 OBJ(audacious_length_seconds) {
1986 snprintf(p, p_max_size, "%s",
1987 cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
1989 OBJ(audacious_position) {
1990 snprintf(p, p_max_size, "%s",
1991 cur->audacious.items[AUDACIOUS_POSITION]);
1993 OBJ(audacious_position_seconds) {
1994 snprintf(p, p_max_size, "%s",
1995 cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
1997 OBJ(audacious_bitrate) {
1998 snprintf(p, p_max_size, "%s",
1999 cur->audacious.items[AUDACIOUS_BITRATE]);
2001 OBJ(audacious_frequency) {
2002 snprintf(p, p_max_size, "%s",
2003 cur->audacious.items[AUDACIOUS_FREQUENCY]);
2005 OBJ(audacious_channels) {
2006 snprintf(p, p_max_size, "%s",
2007 cur->audacious.items[AUDACIOUS_CHANNELS]);
2009 OBJ(audacious_filename) {
2010 snprintf(p, p_max_size, "%s",
2011 cur->audacious.items[AUDACIOUS_FILENAME]);
2013 OBJ(audacious_playlist_length) {
2014 snprintf(p, p_max_size, "%s",
2015 cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
2017 OBJ(audacious_playlist_position) {
2018 snprintf(p, p_max_size, "%s",
2019 cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
2021 OBJ(audacious_main_volume) {
2022 snprintf(p, p_max_size, "%s",
2023 cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
2026 OBJ(audacious_bar) {
2030 atof(cur->audacious.items[AUDACIOUS_POSITION_SECONDS]) /
2031 atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
2032 new_bar(p, obj->a, obj->b, (int) (progress * 255.0f));
2035 #endif /* AUDACIOUS */
2039 snprintf(p, p_max_size, "%s", cur->bmpx.title);
2042 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
2045 snprintf(p, p_max_size, "%s", cur->bmpx.album);
2048 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
2051 snprintf(p, p_max_size, "%i", cur->bmpx.track);
2054 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
2057 /* we have four different types of top (top, top_mem,
2058 * top_time and top_io). To avoid having almost-same code four
2059 * times, we have this special handler. */
2062 parse_top_args("top", obj->data.top.s, obj);
2063 if (!needed) needed = cur->cpu;
2065 parse_top_args("top_mem", obj->data.top.s, obj);
2066 if (!needed) needed = cur->memu;
2068 parse_top_args("top_time", obj->data.top.s, obj);
2069 if (!needed) needed = cur->time;
2072 parse_top_args("top_io", obj->data.top.s, obj);
2073 if (!needed) needed = cur->io;
2076 if (needed[obj->data.top.num]) {
2079 switch (obj->data.top.type) {
2081 snprintf(p, top_name_width + 1, "%-*s", top_name_width,
2082 needed[obj->data.top.num]->name);
2085 snprintf(p, 7, "%6.2f",
2086 needed[obj->data.top.num]->amount);
2089 snprintf(p, 6, "%5i",
2090 needed[obj->data.top.num]->pid);
2093 snprintf(p, 7, "%6.2f",
2094 needed[obj->data.top.num]->totalmem);
2097 timeval = format_time(
2098 needed[obj->data.top.num]->total_cpu_time, 9);
2099 snprintf(p, 10, "%9s", timeval);
2103 human_readable(needed[obj->data.top.num]->rss,
2107 human_readable(needed[obj->data.top.num]->vsize,
2111 case TOP_READ_BYTES:
2112 human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
2115 case TOP_WRITE_BYTES:
2116 human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
2120 snprintf(p, 7, "%6.2f",
2121 needed[obj->data.top.num]->io_perc);
2127 print_tailhead("tail", obj, p, p_max_size);
2130 print_tailhead("head", obj, p, p_max_size);
2133 FILE *fp = open_file(obj->data.s, &obj->a);
2136 /* FIXME: use something more general (see also tail.c, head.c */
2137 #define BUFSZ 0x1000
2142 while(fgets(buf, BUFSZ, fp) != NULL){
2143 for(j = 0; buf[j] != 0; j++) {
2144 if(buf[j] == '\n') {
2149 sprintf(p, "%d", lines);
2152 sprintf(p, "File Unreadable");
2157 FILE *fp = open_file(obj->data.s, &obj->a);
2162 char inword = FALSE;
2165 while(fgets(buf, BUFSZ, fp) != NULL){
2166 for(j = 0; buf[j] != 0; j++) {
2167 if(!isspace(buf[j])) {
2168 if(inword == FALSE) {
2177 sprintf(p, "%d", words);
2180 sprintf(p, "File Unreadable");
2183 #ifdef TCP_PORT_MONITOR
2185 tcp_portmon_action(p, p_max_size,
2186 &obj->data.tcp_port_monitor);
2188 #endif /* TCP_PORT_MONITOR */
2192 set_iconv_converting(1);
2193 set_iconv_selected(obj->a);
2196 set_iconv_converting(0);
2197 set_iconv_selected(0);
2199 #endif /* HAVE_ICONV */
2201 OBJ(entropy_avail) {
2202 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
2205 percent_print(p, p_max_size,
2206 cur->entropy.entropy_avail *
2207 100 / cur->entropy.poolsize);
2209 OBJ(entropy_poolsize) {
2210 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
2213 double entropy_perc;
2215 entropy_perc = (double) cur->entropy.entropy_avail /
2216 (double) cur->entropy.poolsize;
2218 if(output_methods & TO_X) {
2219 new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
2222 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
2223 new_bar_in_shell(p, p_max_size, (int) (entropy_perc * 100.0f), obj->a);
2232 s = smapi_get_val(obj->data.s);
2233 snprintf(p, p_max_size, "%s", s);
2237 OBJ(if_smapi_bat_installed) {
2239 if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
2240 if(!smapi_bat_installed(idx)) {
2244 NORM_ERR("argument to if_smapi_bat_installed must be an integer");
2246 OBJ(smapi_bat_perc) {
2248 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2249 val = smapi_bat_installed(idx) ?
2250 smapi_get_bat_int(idx, "remaining_percent") : 0;
2251 percent_print(p, p_max_size, val);
2253 NORM_ERR("argument to smapi_bat_perc must be an integer");
2255 OBJ(smapi_bat_temp) {
2257 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2258 val = smapi_bat_installed(idx) ?
2259 smapi_get_bat_int(idx, "temperature") : 0;
2260 /* temperature is in milli degree celsius */
2261 temp_print(p, p_max_size, val / 1000, TEMP_CELSIUS);
2263 NORM_ERR("argument to smapi_bat_temp must be an integer");
2265 OBJ(smapi_bat_power) {
2267 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2268 val = smapi_bat_installed(idx) ?
2269 smapi_get_bat_int(idx, "power_now") : 0;
2270 /* power_now is in mW, set to W with one digit precision */
2271 snprintf(p, p_max_size, "%.1f", ((double)val / 1000));
2273 NORM_ERR("argument to smapi_bat_power must be an integer");
2276 OBJ(smapi_bat_bar) {
2277 if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
2278 new_bar(p, obj->a, obj->b, (int)
2279 (255 * smapi_get_bat_int(obj->data.i, "remaining_percent") / 100));
2281 new_bar(p, obj->a, obj->b, 0);
2287 char buf[max_user_text];
2289 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2290 snprintf(p, p_max_size, "%s", buf);
2296 //blinking like this can look a bit ugly if the chars in the font don't have the same width
2297 char buf[max_user_text];
2300 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2301 snprintf(p, p_max_size, "%s", buf);
2302 if(total_updates % 2) {
2303 for(j=0; p[j] != 0; j++) {
2309 char buf[max_user_text];
2311 char unit[16]; // 16 because we can also have long names (like mega-bytes)
2313 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2314 if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
2315 if(strncasecmp("b", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes);
2316 else if(strncasecmp("k", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024);
2317 else if(strncasecmp("m", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024);
2318 else if(strncasecmp("g", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024);
2319 else if(strncasecmp("t", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024 * 1024);
2321 snprintf(p, p_max_size, "%s", buf);
2324 unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
2326 char buf[max_user_text];
2327 generate_text_internal(buf, max_user_text,
2329 for(j = 0; buf[j] != 0; j++) {
2331 case '\n': //place all the lines behind each other with LINESEPARATOR between them
2332 #define LINESEPARATOR '|'
2333 buf[j]=LINESEPARATOR;
2340 //no scrolling necessary if the length of the text to scroll is too short
2341 if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
2342 snprintf(p, p_max_size, "%s", buf);
2345 //make sure a colorchange at the front is not part of the string we are going to show
2346 while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
2347 obj->data.scroll.start++;
2349 //place all chars that should be visible in p, including colorchanges
2350 for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
2351 p[j] = *(buf + obj->data.scroll.start + j);
2352 if(p[j] == SPECIAL_CHAR) {
2353 visibcolorchanges++;
2355 //if there is still room fill it with spaces
2358 for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
2362 //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
2363 for(j = 0; j < obj->data.scroll.start; j++) {
2364 if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
2366 pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
2367 for(j = 0; j < frontcolorchanges; j++) {
2368 pwithcolors[j] = SPECIAL_CHAR;
2371 strcat(pwithcolors,p);
2372 strend = strlen(pwithcolors);
2373 //and place the colorchanges not in front or in the visible part behind the visible part
2374 for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
2375 pwithcolors[strend + j] = SPECIAL_CHAR;
2377 pwithcolors[strend + j] = 0;
2378 strcpy(p, pwithcolors);
2381 obj->data.scroll.start += obj->data.scroll.step;
2382 if(buf[obj->data.scroll.start] == 0){
2383 obj->data.scroll.start = 0;
2386 //reset color when scroll is finished
2387 new_fg(p + strlen(p), obj->data.scroll.resetcolor);
2391 char buf[2][max_user_text];
2398 struct llrows* next;
2400 struct llrows *ll_rows[2], *current[2];
2401 struct text_object * objsub = obj->sub;
2404 for(i=0; i<2; i++) {
2407 ll_rows[i] = malloc(sizeof(struct llrows));
2408 current[i] = ll_rows[i];
2409 for(j=0; j<i; j++) objsub = objsub->sub;
2410 generate_text_internal(buf[i], max_user_text, *objsub, cur);
2411 for(j=0; buf[i][j] != 0; j++) {
2412 if(buf[i][j] == '\t') buf[i][j] = ' ';
2413 if(buf[i][j] == '\n') {
2415 current[i]->row = strdup(buf[i]+nextstart);
2416 if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
2417 current[i]->next = malloc(sizeof(struct llrows));
2418 current[i] = current[i]->next;
2423 current[i]->row = strdup(buf[i]+nextstart);
2424 if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
2425 current[i]->next = NULL;
2426 current[i] = ll_rows[i];
2428 for(j=0; j < (nr_rows[0] > nr_rows[1] ? nr_rows[0] : nr_rows[1] ); j++) {
2430 strcat(p, current[0]->row);
2431 i=strlen(current[0]->row);
2433 while(i < longest) {
2438 strcat(p, obj->data.combine.seperation);
2439 strcat(p, current[1]->row);
2443 #pragma omp parallel for schedule(dynamic,10)
2444 #endif /* HAVE_OPENMP */
2445 for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
2448 #pragma omp parallel for schedule(dynamic,10)
2449 #endif /* HAVE_OPENMP */
2450 for(i=0; i<2; i++) {
2451 while(ll_rows[i] != NULL) {
2452 current[i]=ll_rows[i];
2453 free(current[i]->row);
2454 ll_rows[i]=current[i]->next;
2461 int value = get_nvidia_value(obj->data.nvidia.type, display);
2463 snprintf(p, p_max_size, "N/A");
2464 else if (obj->data.nvidia.type == NV_TEMP)
2465 temp_print(p, p_max_size, (double)value, TEMP_CELSIUS);
2466 else if (obj->data.nvidia.print_as_float &&
2467 value > 0 && value < 100)
2468 snprintf(p, p_max_size, "%.1f", (float)value);
2470 snprintf(p, p_max_size, "%d", value);
2475 /* This is just a meta-object to set host:port */
2478 snprintf(p, p_max_size, "%s",
2479 cur->apcupsd.items[APCUPSD_NAME]);
2481 OBJ(apcupsd_model) {
2482 snprintf(p, p_max_size, "%s",
2483 cur->apcupsd.items[APCUPSD_MODEL]);
2485 OBJ(apcupsd_upsmode) {
2486 snprintf(p, p_max_size, "%s",
2487 cur->apcupsd.items[APCUPSD_UPSMODE]);
2489 OBJ(apcupsd_cable) {
2490 snprintf(p, p_max_size, "%s",
2491 cur->apcupsd.items[APCUPSD_CABLE]);
2493 OBJ(apcupsd_status) {
2494 snprintf(p, p_max_size, "%s",
2495 cur->apcupsd.items[APCUPSD_STATUS]);
2497 OBJ(apcupsd_linev) {
2498 snprintf(p, p_max_size, "%s",
2499 cur->apcupsd.items[APCUPSD_LINEV]);
2502 snprintf(p, p_max_size, "%s",
2503 cur->apcupsd.items[APCUPSD_LOAD]);
2505 OBJ(apcupsd_loadbar) {
2508 if(output_methods & TO_X) {
2509 progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
2510 new_bar(p, obj->a, obj->b, (int) progress);
2513 progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
2514 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
2515 new_bar_in_shell(p, p_max_size, (int) progress, obj->a);
2521 OBJ(apcupsd_loadgraph) {
2523 progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
2524 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2525 (int)progress, 100, 1, obj->char_a, obj->char_b);
2527 OBJ(apcupsd_loadgauge) {
2529 progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
2530 new_gauge(p, obj->a, obj->b,
2534 OBJ(apcupsd_charge) {
2535 snprintf(p, p_max_size, "%s",
2536 cur->apcupsd.items[APCUPSD_CHARGE]);
2538 OBJ(apcupsd_timeleft) {
2539 snprintf(p, p_max_size, "%s",
2540 cur->apcupsd.items[APCUPSD_TIMELEFT]);
2543 snprintf(p, p_max_size, "%s",
2544 cur->apcupsd.items[APCUPSD_TEMP]);
2546 OBJ(apcupsd_lastxfer) {
2547 snprintf(p, p_max_size, "%s",
2548 cur->apcupsd.items[APCUPSD_LASTXFER]);
2550 #endif /* APCUPSD */
2557 size_t a = strlen(p);
2560 iconv_convert(a, buff_in, p, p_max_size);
2561 #endif /* HAVE_ICONV */
2562 if (obj->type != OBJ_text && obj->type != OBJ_execp && obj->type != OBJ_execpi) {
2563 substitute_newlines(p, a - 2);
2571 /* load any new fonts we may have had */
2572 if (need_to_load_fonts) {