mirror of
https://github.com/Llewellynvdm/conky.git
synced 2024-11-17 10:35:10 +00:00
Fix scrolling of UTF-8 text. (#384)
* Fix scrolling of UTF-8 text. * Fix some out-of-bounds buffer access issues and code style issues.
This commit is contained in:
parent
c93a007a13
commit
cbe403bc51
3
AUTHORS
3
AUTHORS
@ -15,6 +15,9 @@ Adi Zaimi
|
|||||||
Alex <godexsoft at bk dot ru>
|
Alex <godexsoft at bk dot ru>
|
||||||
Iconv patch
|
Iconv patch
|
||||||
|
|
||||||
|
Alexey Bondarenko <alexey.bond.94.55@gmail.com>
|
||||||
|
$scroll fix
|
||||||
|
|
||||||
affinity <affy at users dot sourceforge dot net>
|
affinity <affy at users dot sourceforge dot net>
|
||||||
X-Mozilla-Status support
|
X-Mozilla-Status support
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@ static bool isutf8(const char* envvar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* UTF-8 */
|
/* UTF-8 */
|
||||||
static conky::simple_config_setting<bool> utf8_mode("override_utf8_locale",
|
conky::simple_config_setting<bool> utf8_mode("override_utf8_locale",
|
||||||
isutf8("LC_ALL") || isutf8("LC_CTYPE") || isutf8("LANG"), false);
|
isutf8("LC_ALL") || isutf8("LC_CTYPE") || isutf8("LANG"), false);
|
||||||
|
|
||||||
#endif /* BUILD_X11 */
|
#endif /* BUILD_X11 */
|
||||||
|
@ -298,6 +298,12 @@ void generate_text_internal(char *, int, struct text_object);
|
|||||||
int percent_print(char *, int, unsigned);
|
int percent_print(char *, int, unsigned);
|
||||||
void human_readable(long long, char *, int);
|
void human_readable(long long, char *, int);
|
||||||
|
|
||||||
|
#ifdef BUILD_X11
|
||||||
|
|
||||||
|
/* UTF-8 */
|
||||||
|
extern conky::simple_config_setting<bool> utf8_mode;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* maximum size of config TEXT buffer, i.e. below TEXT line. */
|
/* maximum size of config TEXT buffer, i.e. below TEXT line. */
|
||||||
extern conky::range_config_setting<unsigned int> max_user_text;
|
extern conky::range_config_setting<unsigned int> max_user_text;
|
||||||
|
|
||||||
|
140
src/scroll.cc
140
src/scroll.cc
@ -35,6 +35,48 @@
|
|||||||
#include "x11.h"
|
#include "x11.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of a character in bytes.
|
||||||
|
* @param c first byte of the character
|
||||||
|
*/
|
||||||
|
inline int scroll_character_length(char c) {
|
||||||
|
#ifdef BUILD_X11
|
||||||
|
if (utf8_mode.get(*state)) {
|
||||||
|
unsigned char uc = (unsigned char) c;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if ((uc & 0x80) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (len < 7 && (uc & (0x80 >> len)) != 0)
|
||||||
|
++len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a byte should be skipped when counting characters to scroll text to right.
|
||||||
|
*/
|
||||||
|
inline bool scroll_check_skip_byte(char c) {
|
||||||
|
#ifdef BUILD_X11
|
||||||
|
if (utf8_mode.get(*state)) {
|
||||||
|
// Check if byte matches UTF-8 continuation byte pattern (0b10xxxxxx)
|
||||||
|
if ((c & 0xC0) == 0x80) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return SPECIAL_CHAR == c;
|
||||||
|
}
|
||||||
|
|
||||||
#define SCROLL_LEFT 1
|
#define SCROLL_LEFT 1
|
||||||
#define SCROLL_RIGHT 2
|
#define SCROLL_RIGHT 2
|
||||||
#define SCROLL_WAIT 3
|
#define SCROLL_WAIT 3
|
||||||
@ -50,6 +92,45 @@ struct scroll_data {
|
|||||||
int direction;
|
int direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get count of characters to right from (sd->start) position.
|
||||||
|
*/
|
||||||
|
static unsigned int scroll_count_characters_to_right(struct scroll_data* sd, const std::vector<char>& buf) {
|
||||||
|
unsigned int n = 0;
|
||||||
|
int offset = sd->start;
|
||||||
|
|
||||||
|
while ('\0' != buf[offset] && offset < buf.size()) {
|
||||||
|
offset += scroll_character_length(buf[offset]);
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scroll_scroll_left(struct scroll_data* sd, const std::vector<char>& buf, unsigned int amount) {
|
||||||
|
for (int i = 0; (i < amount) && (buf[sd->start] != '\0') && (sd->start < buf.size()); ++i) {
|
||||||
|
sd->start += scroll_character_length(buf[sd->start]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[sd->start] == 0 || sd->start > strlen(buf.data())) {
|
||||||
|
sd->start = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scroll_scroll_right(struct scroll_data* sd, const std::vector<char>& buf, unsigned int amount) {
|
||||||
|
for (int i = 0; i < amount; ++i) {
|
||||||
|
if (sd->start <= 0) {
|
||||||
|
sd->start = (int) strlen(&(buf[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--(sd->start) >= 0) {
|
||||||
|
if (!scroll_check_skip_byte(buf[sd->start])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash, char *free_at_crash2)
|
void parse_scroll_arg(struct text_object *obj, const char *arg, void *free_at_crash, char *free_at_crash2)
|
||||||
{
|
{
|
||||||
struct scroll_data *sd;
|
struct scroll_data *sd;
|
||||||
@ -122,8 +203,9 @@ void print_scroll(struct text_object *obj, char *p, int p_max_size)
|
|||||||
{
|
{
|
||||||
struct scroll_data *sd = (struct scroll_data *)obj->data.opaque;
|
struct scroll_data *sd = (struct scroll_data *)obj->data.opaque;
|
||||||
unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
|
unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
|
||||||
|
unsigned int visiblechars = 0;
|
||||||
char *pwithcolors;
|
char *pwithcolors;
|
||||||
std::vector<char> buf(max_user_text.get(*state));
|
std::vector<char> buf(max_user_text.get(*state), (char) 0);
|
||||||
|
|
||||||
if (!sd)
|
if (!sd)
|
||||||
return;
|
return;
|
||||||
@ -145,20 +227,38 @@ void print_scroll(struct text_object *obj, char *p, int p_max_size)
|
|||||||
snprintf(p, p_max_size, "%s", &(buf[0]));
|
snprintf(p, p_max_size, "%s", &(buf[0]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//if length of text changed to shorter so the (sd->start) is already
|
||||||
|
//outside of actual text then reset (sd->start)
|
||||||
|
if (sd->start >= strlen(&(buf[0]))) {
|
||||||
|
sd->start = 0;
|
||||||
|
}
|
||||||
//make sure a colorchange at the front is not part of the string we are going to show
|
//make sure a colorchange at the front is not part of the string we are going to show
|
||||||
while(buf[sd->start] == SPECIAL_CHAR) {
|
while(buf[sd->start] == SPECIAL_CHAR) {
|
||||||
sd->start++;
|
sd->start++;
|
||||||
}
|
}
|
||||||
//place all chars that should be visible in p, including colorchanges
|
//place all chars that should be visible in p, including colorchanges
|
||||||
for(j=0; j < sd->show + visibcolorchanges; j++) {
|
for(j=0, visiblechars=0; visiblechars < sd->show;) {
|
||||||
p[j] = buf[sd->start + j];
|
char c = p[j] = buf[sd->start + j];
|
||||||
if(p[j] == SPECIAL_CHAR) {
|
if (0 == c) {
|
||||||
visibcolorchanges++;
|
break;
|
||||||
}
|
}
|
||||||
//if there is still room fill it with spaces
|
|
||||||
if( ! p[j]) break;
|
++j;
|
||||||
|
|
||||||
|
if (SPECIAL_CHAR == c) {
|
||||||
|
++visibcolorchanges;
|
||||||
|
} else {
|
||||||
|
int l = scroll_character_length(c);
|
||||||
|
|
||||||
|
while (--l) {
|
||||||
|
p[j] = buf[sd->start + j];
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
++visiblechars;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(; j < sd->show + visibcolorchanges; j++) {
|
for(; visiblechars < sd->show; j++, visiblechars++) {
|
||||||
p[j] = ' ';
|
p[j] = ' ';
|
||||||
}
|
}
|
||||||
p[j] = 0;
|
p[j] = 0;
|
||||||
@ -182,14 +282,11 @@ void print_scroll(struct text_object *obj, char *p, int p_max_size)
|
|||||||
free(pwithcolors);
|
free(pwithcolors);
|
||||||
//scroll
|
//scroll
|
||||||
if(sd->direction == SCROLL_LEFT) {
|
if(sd->direction == SCROLL_LEFT) {
|
||||||
sd->start += sd->step;
|
scroll_scroll_left(sd, buf, sd->step);
|
||||||
if(buf[sd->start] == 0 || (unsigned) sd->start > strlen(&(buf[0]))) {
|
|
||||||
sd->start = 0;
|
|
||||||
}
|
|
||||||
} else if(sd->direction == SCROLL_WAIT) {
|
} else if(sd->direction == SCROLL_WAIT) {
|
||||||
size_t len = strlen(&buf[0]);
|
unsigned int charsleft = scroll_count_characters_to_right(sd, buf);
|
||||||
|
|
||||||
if(sd->start >= len || sd->show + sd->start >= len) {
|
if(sd->show >= charsleft) {
|
||||||
if (sd->wait_arg && (--sd->wait <= 0 && sd->wait_arg != 1)) {
|
if (sd->wait_arg && (--sd->wait <= 0 && sd->wait_arg != 1)) {
|
||||||
sd->wait = sd->wait_arg;
|
sd->wait = sd->wait_arg;
|
||||||
} else {
|
} else {
|
||||||
@ -199,17 +296,16 @@ void print_scroll(struct text_object *obj, char *p, int p_max_size)
|
|||||||
if(!sd->wait_arg || sd->wait_arg == 1 ||
|
if(!sd->wait_arg || sd->wait_arg == 1 ||
|
||||||
(sd->wait_arg && sd->wait-- <= 0)) {
|
(sd->wait_arg && sd->wait-- <= 0)) {
|
||||||
sd->wait = 0;
|
sd->wait = 0;
|
||||||
sd->start += sd->step;
|
|
||||||
|
|
||||||
if (sd->start + sd->show >= len)
|
if (sd->step < charsleft) {
|
||||||
sd->start = len - sd->show;
|
scroll_scroll_left(sd, buf, sd->step);
|
||||||
|
} else {
|
||||||
|
scroll_scroll_left(sd, buf, charsleft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(sd->start < 1) {
|
scroll_scroll_right(sd, buf, sd->step);
|
||||||
sd->start = strlen(&(buf[0]));
|
|
||||||
}
|
|
||||||
sd->start -= sd->step;
|
|
||||||
}
|
}
|
||||||
#ifdef BUILD_X11
|
#ifdef BUILD_X11
|
||||||
//reset color when scroll is finished
|
//reset color when scroll is finished
|
||||||
|
Loading…
Reference in New Issue
Block a user