specials: convert graph objects to new style
[monky] / src / specials.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  * vim: ts=4 sw=4 noet ai cindent syntax=c
3  *
4  * Conky, a system monitor, based on torsmo
5  *
6  * Any original torsmo code is licensed under the BSD license
7  *
8  * All code written since the fork of torsmo is licensed under the GPL
9  *
10  * Please see COPYING for details
11  *
12  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14  *      (see AUTHORS)
15  * All rights reserved.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * You should have received a copy of the GNU General Public License
27  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28  *
29  */
30 #include "conky.h"
31 #include "colours.h"
32 #ifdef X11
33 #include "fonts.h"
34 #endif /* X11 */
35 #include "logging.h"
36 #include "specials.h"
37 #include <math.h>
38
39 /* maximum number of special things, e.g. fonts, offsets, aligns, etc. */
40 int max_specials = MAX_SPECIALS_DEFAULT;
41
42 /* create specials array on heap instead of stack with introduction of
43  * max_specials */
44 struct special_t *specials = NULL;
45
46 int special_count;
47
48 int default_bar_width = 0, default_bar_height = 6;
49 #ifdef X11
50 int default_graph_width = 0, default_graph_height = 25;
51 int default_gauge_width = 40, default_gauge_height = 25;
52 #endif /* X11 */
53
54 /*
55  * Special data typedefs
56  */
57
58 struct bar {
59         int width, height;
60 };
61
62 struct graph {
63         int width, height;
64         unsigned int first_colour, last_colour;
65         unsigned int scale, showaslog;
66         char tempgrad;
67 };
68
69 /*
70  * Scanning arguments to various special text objects
71  */
72
73 #ifdef X11
74 const char *scan_gauge(const char *args, int *w, int *h)
75 {
76         /*width and height*/
77         *w = default_gauge_width;
78         *h = default_gauge_height;
79
80         /* gauge's argument is either height or height,width */
81         if (args) {
82                 int n = 0;
83
84                 if (sscanf(args, "%d,%d %n", h, w, &n) <= 1) {
85                         if (sscanf(args, "%d %n", h, &n) == 2) {
86                                 *w = *h; /*square gauge*/
87                         }
88                 }
89                 args += n;
90         }
91
92         return args;
93 }
94 #endif /* X11 */
95
96 const char *scan_bar(struct text_object *obj, const char *args)
97 {
98         struct bar *b;
99
100         b = malloc(sizeof(struct bar));
101         memset(b, 0, sizeof(struct bar));
102
103         /* zero width means all space that is available */
104         b->width = default_bar_width;
105         b->height = default_bar_height;
106         /* bar's argument is either height or height,width */
107         if (args) {
108                 int n = 0;
109
110                 if (sscanf(args, "%d,%d %n", &b->height, &b->width, &n) <= 1) {
111                         sscanf(args, "%d %n", &b->height, &n);
112                 }
113                 args += n;
114         }
115
116         obj->special_data = b;
117         return args;
118 }
119
120 #ifdef X11
121 char *scan_font(const char *args)
122 {
123         if (args && *args) {
124                 return strndup(args, DEFAULT_TEXT_BUFFER_SIZE);
125         }
126
127         return NULL;
128 }
129
130 char *scan_graph(struct text_object *obj, const char *args)
131 {
132         struct graph *g;
133         char buf[1024];
134         memset(buf, 0, 1024);
135
136         g = malloc(sizeof(struct graph));
137         memset(g, 0, sizeof(struct graph));
138         obj->special_data = g;
139
140         /* zero width means all space that is available */
141         g->width = default_graph_width;
142         g->height = default_graph_height;
143         g->first_colour = 0;
144         g->last_colour = 0;
145         g->scale = 0;
146         g->tempgrad = FALSE;
147         g->showaslog = FALSE;
148         if (args) {
149                 if (strstr(args, " "TEMPGRAD) || strncmp(args, TEMPGRAD, strlen(TEMPGRAD)) == 0) {
150                         g->tempgrad = TRUE;
151                 }
152                 if (strstr(args, " "LOGGRAPH) || strncmp(args, LOGGRAPH, strlen(LOGGRAPH)) == 0) {
153                         g->showaslog = TRUE;
154                 }
155                 if (sscanf(args, "%d,%d %x %x %u", &g->height, &g->width, &g->first_colour, &g->last_colour, &g->scale) == 5) {
156                         return NULL;
157                 }
158                 g->scale = 0;
159                 if (sscanf(args, "%d,%d %x %x", &g->height, &g->width, &g->first_colour, &g->last_colour) == 4) {
160                         return NULL;
161                 }
162                 if (sscanf(args, "%1023s %d,%d %x %x %u", buf, &g->height, &g->width, &g->first_colour, &g->last_colour, &g->scale) == 6) {
163                         return strndup(buf, text_buffer_size);
164                 }
165                 g->scale = 0;
166                 if (sscanf(args, "%1023s %d,%d %x %x", buf, &g->height, &g->width, &g->first_colour, &g->last_colour) == 5) {
167                         return strndup(buf, text_buffer_size);
168                 }
169                 buf[0] = '\0';
170                 g->height = 25;
171                 g->width = 0;
172                 if (sscanf(args, "%x %x %u", &g->first_colour, &g->last_colour, &g->scale) == 3) {
173                         return NULL;
174                 }
175                 g->scale = 0;
176                 if (sscanf(args, "%x %x", &g->first_colour, &g->last_colour) == 2) {
177                         return NULL;
178                 }
179                 if (sscanf(args, "%1023s %x %x %u", buf, &g->first_colour, &g->last_colour, &g->scale) == 4) {
180                         return strndup(buf, text_buffer_size);
181                 }
182                 g->scale = 0;
183                 if (sscanf(args, "%1023s %x %x", buf, &g->first_colour, &g->last_colour) == 3) {
184                         return strndup(buf, text_buffer_size);
185                 }
186                 buf[0] = '\0';
187                 g->first_colour = 0;
188                 g->last_colour = 0;
189                 if (sscanf(args, "%d,%d %u", &g->height, &g->width, &g->scale) == 3) {
190                         return NULL;
191                 }
192                 g->scale = 0;
193                 if (sscanf(args, "%d,%d", &g->height, &g->width) == 2) {
194                         return NULL;
195                 }
196                 if (sscanf(args, "%1023s %d,%d %u", buf, &g->height, &g->width, &g->scale) < 4) {
197                         g->scale = 0;
198                         //TODO: check the return value and throw an error?
199                         sscanf(args, "%1023s %d,%d", buf, &g->height, &g->width);
200                 }
201 #undef g
202
203                 return strndup(buf, text_buffer_size);
204         }
205
206         if (buf[0] == '\0') {
207                 return NULL;
208         } else {
209                 return strndup(buf, text_buffer_size);
210         }
211 }
212 #endif /* X11 */
213
214 /*
215  * Printing various special text objects
216  */
217
218 static struct special_t *new_special(char *buf, enum special_types t)
219 {
220         if (special_count >= max_specials) {
221                 CRIT_ERR(NULL, NULL, "too many special things in text");
222         }
223
224         buf[0] = SPECIAL_CHAR;
225         buf[1] = '\0';
226         specials[special_count].type = t;
227         return &specials[special_count++];
228 }
229
230 #ifdef X11
231 void new_gauge(char *buf, int w, int h, int usage)
232 {
233         struct special_t *s = 0;
234         if ((output_methods & TO_X) == 0)
235                 return;
236
237         s = new_special(buf, GAUGE);
238
239         s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
240         s->width = w;
241         s->height = h;
242 }
243
244 void new_bar(struct text_object *obj, char *buf, int usage)
245 {
246         struct special_t *s = 0;
247         struct bar *b = obj->special_data;
248
249         if ((output_methods & TO_X) == 0)
250                 return;
251
252         if (!b)
253                 return;
254
255         s = new_special(buf, BAR);
256
257         s->arg = (usage > 255) ? 255 : ((usage < 0) ? 0 : usage);
258         s->width = b->width;
259         s->height = b->height;
260 }
261
262 void new_font(char *buf, char *args)
263 {
264         if ((output_methods & TO_X) == 0)
265                 return;
266
267         if (args) {
268                 struct special_t *s = new_special(buf, FONT);
269
270                 if (s->font_added > font_count || !s->font_added || (strncmp(args, fonts[s->font_added].name, DEFAULT_TEXT_BUFFER_SIZE) != EQUAL) ) {
271                         int tmp = selected_font;
272
273                         selected_font = s->font_added = add_font(args);
274                         selected_font = tmp;
275                 }
276         } else {
277                 struct special_t *s = new_special(buf, FONT);
278                 int tmp = selected_font;
279
280                 selected_font = s->font_added = 0;
281                 selected_font = tmp;
282         }
283 }
284
285 static void graph_append(struct special_t *graph, double f, char showaslog)
286 {
287         int i;
288
289         if (showaslog) {
290 #ifdef MATH
291                 f = log10(f + 1);
292 #endif
293         }
294
295         if (!graph->scaled && f > graph->graph_scale) {
296                 f = graph->graph_scale;
297         }
298
299         graph->graph[0] = f;    /* add new data */
300         /* shift all the data by 1 */
301         for (i = graph->graph_width - 1; i > 0; i--) {
302                 graph->graph[i] = graph->graph[i - 1];
303                 if (graph->scaled && graph->graph[i - 1] > graph->graph_scale) {
304                         /* check if we need to update the scale */
305                         graph->graph_scale = graph->graph[i - 1];
306                 }
307         }
308         if (graph->scaled && graph->graph[graph->graph_width] > graph->graph_scale) {
309                 /* check if we need to update the scale */
310                 graph->graph_scale = graph->graph[graph->graph_width];
311         }
312 }
313
314 void new_graph(struct text_object *obj, char *buf, double val)
315 {
316         struct special_t *s = 0;
317         struct graph *g = obj->special_data;
318
319         if ((output_methods & TO_X) == 0)
320                 return;
321
322         if (!g)
323                 return;
324
325         s = new_special(buf, GRAPH);
326
327         s->width = g->width;
328         if (s->graph == NULL) {
329                 if (s->width > 0 && s->width < MAX_GRAPH_DEPTH) {
330                         // subtract 2 for the box
331                         s->graph_width = s->width /* - 2 */;
332                 } else {
333                         s->graph_width = MAX_GRAPH_DEPTH - 2;
334                 }
335                 s->graph = malloc(s->graph_width * sizeof(double));
336                 memset(s->graph, 0, s->graph_width * sizeof(double));
337                 s->graph_scale = 100;
338         }
339         s->height = g->height;
340         s->first_colour = adjust_colours(g->first_colour);
341         s->last_colour = adjust_colours(g->last_colour);
342         if (g->scale != 0) {
343                 s->scaled = 0;
344                 s->graph_scale = g->scale;
345                 s->show_scale = 0;
346         } else {
347                 s->scaled = 1;
348                 s->graph_scale = 1;
349                 s->show_scale = 1;
350         }
351         s->tempgrad = g->tempgrad;
352         /* if (s->width) {
353                 s->graph_width = s->width - 2;  // subtract 2 for rectangle around
354         } */
355 #ifdef MATH
356         if (g->showaslog) {
357                 s->graph_scale = log10(s->graph_scale + 1);
358         }
359 #endif
360         graph_append(s, val, g->showaslog);
361 }
362
363 void new_hr(char *buf, int a)
364 {
365         if ((output_methods & TO_X) == 0)
366                 return;
367
368         new_special(buf, HORIZONTAL_LINE)->height = a;
369 }
370
371 void new_stippled_hr(char *buf, int a, int b)
372 {
373         struct special_t *s = 0;
374
375         if ((output_methods & TO_X) == 0)
376                 return;
377
378         s = new_special(buf, STIPPLED_HR);
379
380         s->height = b;
381         s->arg = a;
382 }
383 #endif /* X11 */
384
385 void new_fg(char *buf, long c)
386 {
387 #ifdef X11
388         if (output_methods & TO_X)
389                 new_special(buf, FG)->arg = c;
390 #endif /* X11 */
391 #ifdef NCURSES
392         if (output_methods & TO_NCURSES)
393                 new_special(buf, FG)->arg = c;
394 #endif /* NCURSES */
395         UNUSED(buf);
396         UNUSED(c);
397 }
398
399 #ifdef X11
400 void new_bg(char *buf, long c)
401 {
402         if ((output_methods & TO_X) == 0)
403                 return;
404
405         new_special(buf, BG)->arg = c;
406 }
407 #endif /* X11 */
408
409 void new_bar_in_shell(struct text_object *obj, char* buffer, int buf_max_size, double usage)
410 {
411         struct bar *b = obj->special_data;
412         int width;
413
414         if (!b)
415                 return;
416
417         width = b->width;
418         if (!width)
419                 width = DEFAULT_BAR_WIDTH_NO_X;
420
421         if(width<=buf_max_size){
422                 int i = 0, j = 0, scaledusage = round_to_int( usage * width / 100);
423
424                 #ifdef HAVE_OPENMP
425                 #pragma omp parallel for schedule(dynamic,10)
426                 #endif /* HAVE_OPENMP */
427                 for(i=0; i<(int)scaledusage; i++) {
428                         *(buffer+i)='#';
429                 }
430                 /* gcc seems to think i is not initialized properly :/ */
431                 j = i;
432                 #ifdef HAVE_OPENMP
433                 #pragma omp parallel for schedule(dynamic,10)
434                 #endif /* HAVE_OPENMP */
435                 for(i = j/* cheats */; i < width; i++) {
436                         *(buffer+i)='_';
437                 }
438                 *(buffer+i)=0;
439         }
440 }
441
442 void new_outline(char *buf, long c)
443 {
444         new_special(buf, OUTLINE)->arg = c;
445 }
446
447 void new_offset(char *buf, long c)
448 {
449         new_special(buf, OFFSET)->arg = c;
450 }
451
452 void new_voffset(char *buf, long c)
453 {
454         new_special(buf, VOFFSET)->arg = c;
455 }
456
457 void new_alignr(char *buf, long c)
458 {
459         new_special(buf, ALIGNR)->arg = c;
460 }
461
462 // A postive offset pushes the text further left
463 void new_alignc(char *buf, long c)
464 {
465         new_special(buf, ALIGNC)->arg = c;
466 }
467
468 void new_goto(char *buf, long c)
469 {
470         new_special(buf, GOTO)->arg = c;
471 }
472
473 void new_tab(char *buf, int a, int b)
474 {
475         struct special_t *s = new_special(buf, TAB);
476
477         s->width = a;
478         s->arg = b;
479 }
480