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