fixed bugs and added comments to scroll.c; scrolling now works better although i...
[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;//length of scrolling field in # of characters requested by conf file
38         unsigned int step;
39         unsigned int start;//current position of first letter of text?
40         unsigned int junk;//to keep track of any padding we add
41         long resetcolor;
42 };
43
44 void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash)
45 {
46         struct scroll_data *sd;
47         int n1 = 0, n2 = 0;
48
49         sd = malloc(sizeof(struct scroll_data));
50         memset(sd, 0, sizeof(struct scroll_data));
51
52         sd->resetcolor = get_current_text_color();
53         sd->step = 1;
54         if (!arg || sscanf(arg, "%u %n", &sd->show, &n1) <= 0)//get 1st arg: show = field length; n1 =  number of bytes read from the input so far by this call
55                 CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
56
57         sscanf(arg + n1, "%u %n", &sd->step, &n2);//gets step size; n2 is bytes of data required to store that
58         if (*(arg + n1 + n2)) {//trying to read the first byte of text to scroll, i wonder what happens if it's a zero?
59                 n1 += n2;//n1 is now total bytes of all args read, or the number of bytes to skip if you want the text from arg
60         } else {
61                 sd->step = 1;//default step size is 1 if it wasn't specified, although that was set above anyways. 
62         }
63         sd->text = malloc(strlen(arg + n1) + sd->show + 1);//changes the text pointer to point to an array of 2x text + 1; 
64         
65 //i think it's trying to check if there is more text to display than space to fit it.
66 //      if (strlen(arg) > sd->show) {//if the total text and parameters is more than the size to display just the text? why aren't we subtracting n1 from the left side?
67         sd->junk = 0;
68         if (strlen(arg + n1) > sd->show) {//better, we need to skip past the parameters
69                 for(n2 = 0; (unsigned int) n2 < sd->show; n2++) {//i guess this would clear half of the array starting at the beginning, if it was set to 2 x text as above lame code does
70                     sd->text[n2] = ' ';//here we are padding spaces that end up BEFORE the text. 
71                     sd->junk++;
72                 }
73                 sd->text[n2] = 0;//terminates the string
74         }
75         else
76             sd->text[0] = 0;//empty string, strcat probably explodes if you don't do this
77         
78         strcat(sd->text, arg + n1);//copies only the text into sd.text, appending to any existing blank space.
79         sd->start = 0;
80         obj->sub = malloc(sizeof(struct text_object));
81         extract_variable_text_internal(obj->sub, sd->text);
82
83         obj->data.opaque = sd;
84 }
85
86 void print_scroll(struct text_object *obj, char *p, int p_max_size, struct information *cur)
87 {
88         struct scroll_data *sd = obj->data.opaque;
89         unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
90         char *pwithcolors;
91         char buf[max_user_text];
92
93         if (!sd)
94                 return;
95
96         generate_text_internal(buf, max_user_text, *obj->sub, cur);
97         for(j = 0; buf[j] != 0; j++) {
98                 switch(buf[j]) {
99                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
100 #define LINESEPARATOR '|'
101                                 buf[j]=LINESEPARATOR;
102                                 break;
103                         case SPECIAL_CHAR:
104                                 colorchanges++;
105                                 break;
106                 }
107         }
108         //(r)trim any incoming strings. some functions might return data with extra spaces on the end...
109   int k;
110   int len;
111   int junk=0;
112   len=strlen(buf);
113   for
114   (k=len-1;k>=0&&buf[k]==' ';k--)
115   {
116       buf[k]='\0';
117   }
118 //count left padding but don't trim it because it's potentially needed for scrolling... (i commented this out because probably the only spaces on the front of the string
119 //will be ours that we added above, should be more efficient to just keep track of those. but maybe this will be useful some day so i've left it here.
120 //  k=0;
121 //  while (buf[k]==' ') {
122 //      k++;
123 //      junk++;
124 //      }
125   
126         //no scrolling necessary if the length of the text to scroll is shorter than the requested space from the conf
127         //if (strlen(buf) - colorchanges <= sd->show) {
128         if (strlen(buf) - junk - sd->junk - colorchanges <= sd->show) {
129                 //ok we can really trim the left spaces now since we aren't scrolling it...
130                 while ( buf[0] != '\0' && strchr ( &buf[0], ' ' ) != NULL )     {
131                         memmove( &buf[0], &buf[1], strlen(buf) );
132                 }
133                 snprintf(p, p_max_size, "%s", buf);
134                 return;
135         }
136         //make sure a colorchange at the front is not part of the string we are going to show
137         while(*(buf + sd->start) == SPECIAL_CHAR) {
138                 sd->start++;
139         }
140         //place all chars that should be visible in p, including colorchanges
141         for(j=0; j < sd->show + visibcolorchanges; j++) {
142                 p[j] = *(buf + sd->start + j);
143                 if(p[j] == SPECIAL_CHAR) {
144                         visibcolorchanges++;
145                 }
146                 //if there is still room fill it with spaces
147                 if( ! p[j]) break;
148         }
149         for(; j < sd->show + visibcolorchanges; j++) {
150                 p[j] = ' ';
151         }
152         p[j] = 0;
153         //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
154         for(j = 0; j < sd->start; j++) {
155                 if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
156         }
157         pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
158         for(j = 0; j < frontcolorchanges; j++) {
159                 pwithcolors[j] = SPECIAL_CHAR;
160         }
161         pwithcolors[j] = 0;
162         strcat(pwithcolors,p);
163         strend = strlen(pwithcolors);
164         //and place the colorchanges not in front or in the visible part behind the visible part
165         for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
166                 pwithcolors[strend + j] = SPECIAL_CHAR;
167         }
168         pwithcolors[strend + j] = 0;
169         strcpy(p, pwithcolors);
170         free(pwithcolors);
171         //scroll
172         sd->start += sd->step;
173         if(buf[sd->start] == 0 || sd->start > strlen(buf)){
174                 sd->start = 0;
175         }
176 #ifdef X11
177         //reset color when scroll is finished
178         new_fg(p + strlen(p), sd->resetcolor);
179 #endif
180 }
181
182 void free_scroll(struct text_object *obj)
183 {
184         struct scroll_data *sd = obj->data.opaque;
185
186         if (!sd)
187                 return;
188
189         if (sd->text)
190                 free(sd->text);
191         if (obj->sub) {
192                 free_text_objects(obj->sub, 1);
193                 free(obj->sub);
194                 obj->sub = NULL;
195         }
196         free(obj->data.opaque);
197         obj->data.opaque = NULL;
198 }