f78f8078e91941d0adbe9976c604ffec517ab345
[monky] / src / scroll.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
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.
20  *
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/>.
27  *
28  */
29 #include "conky.h"
30 #include "core.h"
31 #include "logging.h"
32 #include "specials.h"
33 #include "text_object.h"
34
35 struct scroll_data {
36         char *text;
37         unsigned int show;
38         unsigned int step;
39         unsigned int start;
40         long resetcolor;
41 };
42
43 void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash)
44 {
45         struct scroll_data *sd;
46         int n1 = 0, n2 = 0;
47
48         sd = malloc(sizeof(struct scroll_data));
49         memset(sd, 0, sizeof(struct scroll_data));
50
51         sd->resetcolor = get_current_text_color();
52         sd->step = 1;
53         if (!arg || sscanf(arg, "%u %n", &sd->show, &n1) <= 0)
54                 CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
55
56         sscanf(arg + n1, "%u %n", &sd->step, &n2);
57         if (*(arg + n1 + n2)) {
58                 n1 += n2;
59         } else {
60                 sd->step = 1;
61         }
62         sd->text = malloc(strlen(arg + n1) + sd->show + 1);
63
64         if (strlen(arg) > sd->show) {
65                 for(n2 = 0; (unsigned int) n2 < sd->show; n2++) {
66                     sd->text[n2] = ' ';
67                 }
68                 sd->text[n2] = 0;
69         }
70         else
71             sd->text[0] = 0;
72
73         strcat(sd->text, arg + n1);
74         sd->start = 0;
75         obj->sub = malloc(sizeof(struct text_object));
76         extract_variable_text_internal(obj->sub, sd->text);
77
78         obj->data.opaque = sd;
79 }
80
81 void print_scroll(struct text_object *obj, char *p, int p_max_size, struct information *cur)
82 {
83         struct scroll_data *sd = obj->data.opaque;
84         unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
85         char *pwithcolors;
86         char buf[max_user_text];
87
88         if (!sd)
89                 return;
90
91         generate_text_internal(buf, max_user_text, *obj->sub, cur);
92         for(j = 0; buf[j] != 0; j++) {
93                 switch(buf[j]) {
94                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
95 #define LINESEPARATOR '|'
96                                 buf[j]=LINESEPARATOR;
97                                 break;
98                         case SPECIAL_CHAR:
99                                 colorchanges++;
100                                 break;
101                 }
102         }
103         //no scrolling necessary if the length of the text to scroll is too short
104         if (strlen(buf) - colorchanges <= sd->show) {
105                 snprintf(p, p_max_size, "%s", buf);
106                 return;
107         }
108         //make sure a colorchange at the front is not part of the string we are going to show
109         while(*(buf + sd->start) == SPECIAL_CHAR) {
110                 sd->start++;
111         }
112         //place all chars that should be visible in p, including colorchanges
113         for(j=0; j < sd->show + visibcolorchanges; j++) {
114                 p[j] = *(buf + sd->start + j);
115                 if(p[j] == SPECIAL_CHAR) {
116                         visibcolorchanges++;
117                 }
118                 //if there is still room fill it with spaces
119                 if( ! p[j]) break;
120         }
121         for(; j < sd->show + visibcolorchanges; j++) {
122                 p[j] = ' ';
123         }
124         p[j] = 0;
125         //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
126         for(j = 0; j < sd->start; j++) {
127                 if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
128         }
129         pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
130         for(j = 0; j < frontcolorchanges; j++) {
131                 pwithcolors[j] = SPECIAL_CHAR;
132         }
133         pwithcolors[j] = 0;
134         strcat(pwithcolors,p);
135         strend = strlen(pwithcolors);
136         //and place the colorchanges not in front or in the visible part behind the visible part
137         for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
138                 pwithcolors[strend + j] = SPECIAL_CHAR;
139         }
140         pwithcolors[strend + j] = 0;
141         strcpy(p, pwithcolors);
142         free(pwithcolors);
143         //scroll
144         sd->start += sd->step;
145         if(buf[sd->start] == 0 || sd->start > strlen(buf)){
146                 sd->start = 0;
147         }
148 #ifdef X11
149         //reset color when scroll is finished
150         new_fg(p + strlen(p), sd->resetcolor);
151 #endif
152 }
153
154 void free_scroll(struct text_object *obj)
155 {
156         struct scroll_data *sd = obj->data.opaque;
157
158         if (!sd)
159                 return;
160
161         if (sd->text)
162                 free(sd->text);
163         if (obj->sub) {
164                 free_text_objects(obj->sub, 1);
165                 free(obj->sub);
166                 obj->sub = NULL;
167         }
168         free(obj->data.opaque);
169         obj->data.opaque = NULL;
170 }