/* -*- mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
* vim: ts=4 sw=4 noet ai cindent syntax=cpp
*
* Conky, a system monitor, based on torsmo
*
* Any original torsmo code is licensed under the BSD license
*
* All code written since the fork of torsmo is licensed under the GPL
*
* Please see COPYING for details
*
* Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
* Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
* (see AUTHORS)
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "conky.h"
#include "core.h"
#include "logging.h"
#include "specials.h"
#include "text_object.h"
#include "x11.h"
#include
#define SCROLL_LEFT true
#define SCROLL_RIGHT false
struct scroll_data {
char *text;
unsigned int show;
unsigned int step;
signed int start;
long resetcolor;
bool direction;
};
void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash, char *free_at_crash2)
{
struct scroll_data *sd;
int n1 = 0, n2 = 0;
char dirarg[6];
sd = (struct scroll_data *)malloc(sizeof(struct scroll_data));
memset(sd, 0, sizeof(struct scroll_data));
sd->resetcolor = get_current_text_color();
sd->step = 1;
sd->direction = SCROLL_LEFT;
if (arg && sscanf(arg, "%5s %n", dirarg, &n1) == 1) {
if (strcasecmp(dirarg, "right") == 0 || strcasecmp(dirarg, "r") == 0)
sd->direction = SCROLL_RIGHT;
else if ( strcasecmp(dirarg, "left") != 0 && strcasecmp(dirarg, "l") != 0)
n1 = 0;
}
if (!arg || sscanf(arg + n1, "%u %n", &sd->show, &n2) <= 0) {
free(sd);
#ifdef BUILD_X11
free(obj->next);
#endif
free(free_at_crash2);
CRIT_ERR(obj, free_at_crash, "scroll needs arguments: [left|right] [] ");
}
n1 += n2;
if(sscanf(arg + n1, "%u %n", &sd->step, &n2) == 1) {
n1 += n2;
} else {
sd->step = 1;
}
sd->text = (char*)malloc(strlen(arg + n1) + sd->show + 1);
if (strlen(arg) > sd->show) {
for(n2 = 0; (unsigned int) n2 < sd->show; n2++) {
sd->text[n2] = ' ';
}
sd->text[n2] = 0;
}
else
sd->text[0] = 0;
strcat(sd->text, arg + n1);
sd->start = 0;
obj->sub = (struct text_object *)malloc(sizeof(struct text_object));
extract_variable_text_internal(obj->sub, sd->text);
obj->data.opaque = sd;
#ifdef BUILD_X11
/* add a color object right after scroll to reset any color changes */
#endif /* BUILD_X11 */
}
void print_scroll(struct text_object *obj, char *p, int p_max_size)
{
struct scroll_data *sd = (struct scroll_data *)obj->data.opaque;
unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
char *pwithcolors;
std::vector buf(max_user_text);
if (!sd)
return;
generate_text_internal(&(buf[0]), max_user_text, *obj->sub);
for(j = 0; buf[j] != 0; j++) {
switch(buf[j]) {
case '\n': //place all the lines behind each other with LINESEPARATOR between them
#define LINESEPARATOR '|'
buf[j]=LINESEPARATOR;
break;
case SPECIAL_CHAR:
colorchanges++;
break;
}
}
//no scrolling necessary if the length of the text to scroll is too short
if (strlen(&(buf[0])) - colorchanges <= sd->show) {
snprintf(p, p_max_size, "%s", &(buf[0]));
return;
}
//make sure a colorchange at the front is not part of the string we are going to show
while(buf[sd->start] == SPECIAL_CHAR) {
sd->start++;
}
//place all chars that should be visible in p, including colorchanges
for(j=0; j < sd->show + visibcolorchanges; j++) {
p[j] = buf[sd->start + j];
if(p[j] == SPECIAL_CHAR) {
visibcolorchanges++;
}
//if there is still room fill it with spaces
if( ! p[j]) break;
}
for(; j < sd->show + visibcolorchanges; j++) {
p[j] = ' ';
}
p[j] = 0;
//count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
for(j = 0; j < (unsigned) sd->start; j++) {
if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
}
pwithcolors=(char*)malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
for(j = 0; j < frontcolorchanges; j++) {
pwithcolors[j] = SPECIAL_CHAR;
}
pwithcolors[j] = 0;
strcat(pwithcolors,p);
strend = strlen(pwithcolors);
//and place the colorchanges not in front or in the visible part behind the visible part
for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
pwithcolors[strend + j] = SPECIAL_CHAR;
}
pwithcolors[strend + j] = 0;
strcpy(p, pwithcolors);
free(pwithcolors);
//scroll
if(sd->direction == SCROLL_LEFT) {
sd->start += sd->step;
if(buf[sd->start] == 0 || (unsigned) sd->start > strlen(&(buf[0]))) {
sd->start = 0;
}
} else {
if(sd->start < 1) {
sd->start = strlen(&(buf[0]));
}
sd->start -= sd->step;
}
#ifdef BUILD_X11
//reset color when scroll is finished
if (out_to_x.get(*state))
new_special(p + strlen(p), FG)->arg = sd->resetcolor;
#endif
}
void free_scroll(struct text_object *obj)
{
struct scroll_data *sd = (struct scroll_data *)obj->data.opaque;
if (!sd)
return;
free_and_zero(sd->text);
free_text_objects(obj->sub);
free_and_zero(obj->sub);
free_and_zero(obj->data.opaque);
}