" * RSS\n"
#endif /* RSS */
#ifdef WEATHER
- " * Weather (METAR)\n"
+ " * Weather (NOAA)\n"
+#ifdef XOAP
+ " * Weather (XOAP)\n"
+#endif /* XOAP */
#endif /* WEATHER */
#ifdef HAVE_IWLIB
" * wireless\n"
char *current_config;
/* set to 1 if you want all text to be in uppercase */
-static unsigned int stuff_in_upper_case;
+static unsigned int stuff_in_uppercase;
/* Run how many times? */
static unsigned long total_run_times;
}
#ifdef X11
+
+#define SECRIT_MULTILINE_CHAR '\x02'
+
static inline int calc_text_width(const char *s, int l)
{
- if ((output_methods & TO_X) == 0)
+ if ((output_methods & TO_X) == 0) {
return 0;
+ }
#ifdef XFT
if (use_xft) {
XGlyphInfo gi;
static char *text_buffer;
-#ifdef X11
-static unsigned int special_index; /* used when drawing */
-#endif /* X11 */
-
/* quite boring functions */
-static inline void for_each_line(char *b, void f(char *))
+static inline void for_each_line(char *b, int f(char *, int))
{
char *ps, *pe;
+ int special_index = 0; /* specials index */
for (ps = b, pe = b; *pe; pe++) {
if (*pe == '\n') {
*pe = '\0';
- f(ps);
+ special_index = f(ps, special_index);
*pe = '\n';
ps = pe + 1;
}
}
if (ps < pe) {
- f(ps);
+ f(ps, special_index);
}
}
return 1;
}
+long current_text_color;
+
/* construct_text_object() creates a new text_object */
static struct text_object *construct_text_object(const char *s,
const char *arg, long line, char allow_threaded, void **ifblock_opaque, void *free_at_crash)
#ifdef X11
if (output_methods & TO_X) {
obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
+ current_text_color = obj->data.l;
}
#endif /* X11 */
END OBJ(color0, 0)
obj->data.l = color0;
+ current_text_color = obj->data.l;
END OBJ(color1, 0)
obj->data.l = color1;
+ current_text_color = obj->data.l;
END OBJ(color2, 0)
obj->data.l = color2;
+ current_text_color = obj->data.l;
END OBJ(color3, 0)
obj->data.l = color3;
+ current_text_color = obj->data.l;
END OBJ(color4, 0)
obj->data.l = color4;
+ current_text_color = obj->data.l;
END OBJ(color5, 0)
obj->data.l = color5;
+ current_text_color = obj->data.l;
END OBJ(color6, 0)
obj->data.l = color6;
+ current_text_color = obj->data.l;
END OBJ(color7, 0)
obj->data.l = color7;
+ current_text_color = obj->data.l;
END OBJ(color8, 0)
obj->data.l = color8;
+ current_text_color = obj->data.l;
END OBJ(color9, 0)
obj->data.l = color9;
+ current_text_color = obj->data.l;
#ifdef X11
END OBJ(font, 0)
obj->data.s = scan_font(arg);
END OBJ(scroll, 0)
int n1 = 0, n2 = 0;
+ obj->data.scroll.resetcolor = current_text_color;
obj->data.scroll.step = 1;
if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2);
- if(*(arg + n1 + n2)) {
+ if (*(arg + n1 + n2)) {
n1 += n2;
- }else{
+ } else {
obj->data.scroll.step = 1;
}
- obj->data.scroll.text = strndup(arg + n1, text_buffer_size);
+ obj->data.scroll.text = malloc(strlen(arg + n1) + obj->data.scroll.show + 1);
+ for(n2 = 0; (unsigned int) n2 < obj->data.scroll.show; n2++) {
+ obj->data.scroll.text[n2] = ' ';
+ }
+ obj->data.scroll.text[n2] = 0;
+ strcat(obj->data.scroll.text, arg + n1);
obj->data.scroll.start = 0;
obj->sub = malloc(sizeof(struct text_object));
extract_variable_text_internal(obj->sub,
return barnum;
}
+/* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
+ * multiline objects like $exec work with $align[rc] and friends
+ */
+void substitute_newlines(char *p, long l)
+{
+ char *s = p;
+ if (l < 0) return;
+ while (p && *p && p < s + l) {
+ if (*p == '\n') {
+ /* only substitute if it's not the last newline */
+ *p = SECRIT_MULTILINE_CHAR;
+ }
+ p++;
+ }
+}
+
static void generate_text_internal(char *p, int p_max_size,
struct text_object root, struct information *cur)
{
p[0] = 0;
obj = root.next;
while (obj && p_max_size > 0) {
- needed = 0; // reset for top stuff
+ needed = 0; /* reset for top stuff */
/* IFBLOCK jumping algorithm
*
}
#if defined(__linux__)
OBJ(addrs) {
- if(NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2)
- {
+ if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
strcpy(p, obj->data.net->addrs);
+ } else {
+ strcpy(p, "0.0.0.0");
}
- else
- strcpy(p, "0.0.0.0");
- }
+ }
#endif /* __linux__ */
#if defined(IMLIB2) && defined(X11)
OBJ(image) {
if( obj->data.weather.uri != NULL ) {
process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
} else {
- strncpy(p, "invalid xoap keys file", p_max_size);
+ strncpy(p, "either invalid xoap keys file or compiled without xoap support", p_max_size);
}
}
#endif
OBJ(to_bytes) {
char buf[max_user_text];
long long bytes;
- char unit[16]; //16 because we can also have long names (like mega-bytes)
+ char unit[16]; // 16 because we can also have long names (like mega-bytes)
generate_text_internal(buf, max_user_text, *obj->sub, cur);
if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
snprintf(p, p_max_size, "%s", buf);
}
OBJ(scroll) {
- unsigned int j;
- char *tmp, buf[max_user_text];
+ unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
+ char *pwithcolors;
+ char buf[max_user_text];
generate_text_internal(buf, max_user_text,
*obj->sub, cur);
-
- if (strlen(buf) <= obj->data.scroll.show) {
- snprintf(p, p_max_size, "%s", buf);
- break;
- }
-#define LINESEPARATOR '|'
- //place all the lines behind each other with LINESEPARATOR between them
for(j = 0; buf[j] != 0; j++) {
- if(buf[j]=='\n') {
+ 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;
}
}
- //scroll the output obj->data.scroll.start places by copying that many chars from
- //the front of the string to tmp, scrolling the rest to the front and placing tmp
- //at the back of the string
- tmp = calloc(obj->data.scroll.start + 1, sizeof(char));
- strncpy(tmp, buf, obj->data.scroll.start); tmp[obj->data.scroll.start] = 0;
- for(j = obj->data.scroll.start; buf[j] != 0; j++){
- buf[j - obj->data.scroll.start] = buf[j];
- }
- strcpy(&buf[j - obj->data.scroll.start], tmp);
- free(tmp);
- //only show the requested number of chars
- if(obj->data.scroll.show < j) {
- buf[obj->data.scroll.show] = 0;
- }
- //next time, scroll a place more or reset scrolling if we are at the end
+ //no scrolling necessary if the length of the text to scroll is too short
+ if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
+ snprintf(p, p_max_size, "%s", buf);
+ break;
+ }
+ //make sure a colorchange at the front is not part of the string we are going to show
+ while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
+ obj->data.scroll.start++;
+ }
+ //place all chars that should be visible in p, including colorchanges
+ for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
+ p[j] = *(buf + obj->data.scroll.start + j);
+ if(p[j] == SPECIAL_CHAR) {
+ visibcolorchanges++;
+ }
+ //if there is still room fill it with spaces
+ if( ! p[j]) break;
+ }
+ for(; j < obj->data.scroll.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 < obj->data.scroll.start; j++) {
+ if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
+ }
+ pwithcolors=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
obj->data.scroll.start += obj->data.scroll.step;
- if(obj->data.scroll.start >= j){
+ if(buf[obj->data.scroll.start] == 0){
obj->data.scroll.start = 0;
}
- snprintf(p, p_max_size, "%s", buf);
+ //reset color when scroll is finished
+ new_fg(p + strlen(p), obj->data.scroll.resetcolor);
}
OBJ(combine) {
char buf[2][max_user_text];
}
strcat(p, "\n");
#ifdef HAVE_OPENMP
- #pragma omp parallel for
+ #pragma omp parallel for schedule(dynamic,10)
#endif /* HAVE_OPENMP */
for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
}
#ifdef HAVE_OPENMP
- #pragma omp parallel for
+ #pragma omp parallel for schedule(dynamic,10)
#endif /* HAVE_OPENMP */
for(i=0; i<2; i++) {
while(ll_rows[i] != NULL) {
a = outptr - p;
}
#endif /* HAVE_ICONV */
+ if (obj->type != OBJ_text) {
+ substitute_newlines(p, a - 2);
+ }
p += a;
p_max_size -= a;
}
generate_text_internal(p, max_user_text, global_root_object, cur);
- if (stuff_in_upper_case) {
+ if (stuff_in_uppercase) {
char *tmp_p;
tmp_p = text_buffer;
}
last_update_time = current_update_time;
total_updates++;
- // free(p);
}
static inline int get_string_width(const char *s)
return strlen(s);
}
-static inline int get_string_width_special(char *s)
+static int get_string_width_special(char *s, int special_index)
{
#ifdef X11
char *p, *final;
long i;
if ((output_methods & TO_X) == 0) {
-#endif
+#endif /* X11 */
return (s) ? strlen(s) : 0;
#ifdef X11
}
width += specials[special_index + idx].width;
}
idx++;
+ } else if (*p == SECRIT_MULTILINE_CHAR) {
+ *p = 0;
+ break;
} else {
p++;
}
}
#ifdef X11
-static void text_size_updater(char *s);
+static int text_size_updater(char *s, int special_index);
int last_font_height;
static void update_text_area(void)
{
text_width = minimum_width;
text_height = 0;
- special_index = 0;
last_font_height = font_height();
for_each_line(text_buffer, text_size_updater);
text_width += 1;
#ifdef X11
static long current_color;
-static void text_size_updater(char *s)
+static int text_size_updater(char *s, int special_index)
{
int w = 0;
char *p;
if ((output_methods & TO_X) == 0)
- return;
+ return 0;
/* get string widths and skip specials */
p = s;
while (*p) {
special_index++;
s = p + 1;
+ } else if (*p == SECRIT_MULTILINE_CHAR) {
+ int lw;
+ *p = '\0';
+ lw = get_string_width(s);
+ *p = SECRIT_MULTILINE_CHAR;
+ s = p + 1;
+ w = lw > w ? lw : w;
+ text_height += last_font_height;
}
p++;
}
text_height += last_font_height;
last_font_height = font_height();
+ return special_index;
}
static inline void set_foreground_color(long c)
memcpy(tmpstring1, s, text_buffer_size);
}
-static void draw_line(char *s)
-{
#ifdef X11
- char *p;
+int draw_each_line_inner(char *s, int special_index, int last_special_applied)
+{
+ int font_h = font_height();
int cur_y_add = 0;
- int font_h;
- char *tmp_str;
+ char *recurse = 0;
+ char *p = s;
+ int last_special_needed = -1;
+ int orig_special_index = special_index;
- if ((output_methods & TO_X) == 0) {
-#endif /* X11 */
- draw_string(s);
- return;
-#ifdef X11
- }
cur_x = text_start_x;
cur_y += font_ascent();
- font_h = font_height();
- /* find specials and draw stuff */
- p = s;
while (*p) {
- if (*p == SPECIAL_CHAR) {
- int w = 0;
-
- /* draw string before special */
+ if (*p == SECRIT_MULTILINE_CHAR) {
+ /* special newline marker for multiline objects */
+ recurse = p + 1;
*p = '\0';
- draw_string(s);
- *p = SPECIAL_CHAR;
- s = p + 1;
+ break;
+ }
+ if (*p == SPECIAL_CHAR || last_special_applied > -1) {
+ int w = 0;
+ /* draw string before special, unless we're dealing multiline
+ * specials */
+ if (last_special_applied > -1) {
+ special_index = last_special_applied;
+ } else {
+ *p = '\0';
+ draw_string(s);
+ *p = SPECIAL_CHAR;
+ s = p + 1;
+ }
/* draw special */
switch (specials[special_index].type) {
case HORIZONTAL_LINE:
char *tmp_hour_str;
char *tmp_min_str;
char *tmp_sec_str;
+ char *tmp_str;
unsigned short int timeunits;
if (seconds != 0) {
timeunits = seconds / 86400; seconds %= 86400;
if (show_graph_scale && (specials[special_index].show_scale == 1)) {
int tmp_x = cur_x;
int tmp_y = cur_y;
+ char *tmp_str;
cur_x += font_ascent() / 2;
cur_y += font_h / 2;
tmp_str = (char *)
case OFFSET:
w += specials[special_index].arg;
+ last_special_needed = special_index;
break;
case VOFFSET:
if (specials[special_index].arg >= 0) {
cur_x = (int) specials[special_index].arg;
}
+ last_special_needed = special_index;
break;
case TAB:
step = 10;
}
w = step - (cur_x - text_start_x - start) % step;
+ last_special_needed = special_index;
break;
}
/* TODO: add back in "+ window.border_inner_margin" to the end of
* this line? */
int pos_x = text_start_x + text_width -
- get_string_width_special(s);
+ get_string_width_special(s, special_index);
/* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
"get_string_width(p) %i gap_x %i "
if (pos_x > specials[special_index].arg && pos_x > cur_x) {
cur_x = pos_x - specials[special_index].arg;
}
+ last_special_needed = special_index;
break;
}
case ALIGNC:
{
- int pos_x = (text_width) / 2 - get_string_width_special(s) /
- 2 - (cur_x - text_start_x);
+ int pos_x = (text_width) / 2 - get_string_width_special(s,
+ special_index) / 2 - (cur_x -
+ text_start_x);
/* int pos_x = text_start_x + text_width / 2 -
get_string_width_special(s) / 2; */
if (pos_x > specials[special_index].arg) {
w = pos_x - specials[special_index].arg;
}
+ last_special_needed = special_index;
break;
}
}
cur_x += w;
- special_index++;
+ if (special_index != last_special_applied) {
+ special_index++;
+ } else {
+ special_index = orig_special_index;
+ last_special_applied = -1;
+ }
}
-
p++;
}
- if (cur_y_add > 0) {
- cur_y += cur_y_add;
- }
+ cur_y += cur_y_add;
draw_string(s);
cur_y += font_descent();
+ if (recurse && *recurse) {
+ special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
+ *(recurse - 1) = SECRIT_MULTILINE_CHAR;
+ }
+ return special_index;
+}
+#endif /* X11 */
+static int draw_line(char *s, int special_index)
+{
+#ifdef X11
+ if ((output_methods & TO_X) == 0) {
+#endif /* X11 */
+ draw_string(s);
+ return 0;
+#ifdef X11
+ }
+
+ /* find specials and draw stuff */
+ return draw_each_line_inner(s, special_index, -1);
#endif /* X11 */
}
}
/* draw text */
- special_index = 0;
}
setup_fonts();
#endif /* X11 */
color7 = default_fg_color;
color8 = default_fg_color;
color9 = default_fg_color;
+ current_text_color = default_fg_color;
}
#endif /* X11 */
no_buffers = 1;
update_interval = 3.0;
info.music_player_interval = 1.0;
- stuff_in_upper_case = 0;
+ stuff_in_uppercase = 0;
info.users.number = 1;
#ifdef TCP_PORT_MONITOR
}
}
CONF("uppercase") {
- stuff_in_upper_case = string_to_bool(value);
+ stuff_in_uppercase = string_to_bool(value);
}
CONF("max_specials") {
if (value) {
}
#endif
CONF("text") {
- //initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod)
+ /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
if(output_methods & TO_X) {
X11_initialisation();
}
}
#endif /* X11 */
-#ifdef WEATHER
+#if defined(WEATHER) && defined(XOAP)
/*
* TODO: make the xoap keys file readable from the config file
* make the keys directly readable from the config file
free(par);
free(key);
}
-#endif /* WEATHER */
+#endif /* WEATHER && XOAP */
static void print_help(const char *prog_name) {
printf("Usage: %s [OPTION]...\n"
fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
pid);
fflush(stderr);
- return;
+ exit(EXIT_SUCCESS);
}
}
}
}
-#ifdef WEATHER
+#if defined(WEATHER) && defined(XOAP)
/* Load xoap keys, if existing */
load_xoap_keys();
-#endif /* WEATHER */
+#endif /* WEATHER && XOAP */
#ifdef HAVE_SYS_INOTIFY_H
inotify_fd = inotify_init();
* and do any signal processing there, NOT here. */
g_signal_pending = sig;
}
+