From d0e216b02dcf22ecfb000185420e30c6ca0db794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Sun, 7 Oct 2018 02:25:46 +0200 Subject: [PATCH] WIP: move X11 stuff from conky.cc to display-x11 Still not complete, but seems to work. A lot of variables and calls had to be made non-static. --- src/conky.cc | 440 +++++++++++++++++++---------- src/conky.h | 11 + src/display-ncurses.cc | 3 +- src/display-ncurses.hh | 1 + src/display-output.cc | 27 +- src/display-output.hh | 30 +- src/display-x11.cc | 625 ++++++++++++++++++++++++++++++++++++++++- src/display-x11.hh | 38 +++ src/specials.cc | 42 +-- 9 files changed, 1048 insertions(+), 169 deletions(-) diff --git a/src/conky.cc b/src/conky.cc index 3a9e06f5f1..7d2abb5c45 100644 --- a/src/conky.cc +++ b/src/conky.cc @@ -170,6 +170,35 @@ static char *tmpstring1, *tmpstring2; extern WINDOW *ncurses_window; #endif +/* + * the list of the only current output, when inside draw_text, + * else we iterate over each active outputs. + */ +std::vector current_display_outputs; + +static inline std::vector &display_outputs() { + if (current_display_outputs.size()) + return current_display_outputs; + return conky::active_display_outputs; +} + +static inline conky::display_output_base *display_output() { + if (current_display_outputs.size()) + return current_display_outputs[0]; +//XXX; not really what intended yet... + return conky::active_display_outputs[0]; + //return nullptr; +} + +static inline void unset_display_output() { + current_display_outputs.clear(); +} + +static inline void set_display_output(conky::display_output_base *output) { + current_display_outputs.clear(); + current_display_outputs.push_back(output); +} + enum spacer_state { NO_SPACER = 0, LEFT_SPACER, RIGHT_SPACER }; template <> conky::lua_traits::Map conky::lua_traits::map = { @@ -185,7 +214,7 @@ static conky::simple_config_setting format_human_readable( conky::simple_config_setting out_to_stdout("out_to_console", // Default value is false, unless we are building without X -#ifdef BUILD_X11 +#ifdef BUILD_GUI false, #else true, @@ -419,7 +448,7 @@ static const char *suffixes[] = {_nop("B"), _nop("KiB"), _nop("MiB"), _nop("GiB"), _nop("TiB"), _nop("PiB"), ""}; -#ifdef BUILD_X11 +#ifdef BUILD_X11_ static void X11_create_window(); @@ -432,14 +461,18 @@ struct _x11_stuff_s { #endif } x11_stuff; +#endif /* BUILD_X11_ */ + +#ifdef BUILD_GUI + /* text size */ -static int text_start_x, text_start_y; /* text start position in window */ -static int text_offset_x, text_offset_y; /* offset for start position */ -static int text_width = 1, +int text_start_x, text_start_y; /* text start position in window */ +int text_offset_x, text_offset_y; /* offset for start position */ +int text_width = 1, text_height = 1; /* initially 1 so no zero-sized window is created */ -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* struct that has all info to be shared between * instances of the same text object */ @@ -480,41 +513,41 @@ static conky::simple_config_setting append_file("append_file", true); static FILE *append_fpointer = nullptr; -#ifdef BUILD_X11 +#ifdef BUILD_GUI -static conky::simple_config_setting show_graph_scale("show_graph_scale", +conky::simple_config_setting show_graph_scale("show_graph_scale", false, false); -static conky::simple_config_setting show_graph_range("show_graph_range", +conky::simple_config_setting show_graph_range("show_graph_range", false, false); /* Position on the screen */ -static conky::simple_config_setting gap_x("gap_x", 5, true); -static conky::simple_config_setting gap_y("gap_y", 60, true); +conky::simple_config_setting gap_x("gap_x", 5, true); +conky::simple_config_setting gap_y("gap_y", 60, true); /* border */ -static conky::simple_config_setting draw_borders("draw_borders", false, +conky::simple_config_setting draw_borders("draw_borders", false, false); -static conky::simple_config_setting draw_graph_borders( +conky::simple_config_setting draw_graph_borders( "draw_graph_borders", true, false); conky::range_config_setting stippled_borders( "stippled_borders", 0, std::numeric_limits::max(), 0, true); -static conky::simple_config_setting draw_shades("draw_shades", true, +conky::simple_config_setting draw_shades("draw_shades", true, false); -static conky::simple_config_setting draw_outline("draw_outline", false, +conky::simple_config_setting draw_outline("draw_outline", false, false); #ifdef OWN_WINDOW /* fixed size/pos is set if wm/user changes them */ -static int fixed_size = 0, fixed_pos = 0; +int fixed_size = 0, fixed_pos = 0; #endif -static conky::range_config_setting minimum_height( +conky::range_config_setting minimum_height( "minimum_height", 0, std::numeric_limits::max(), 5, true); -static conky::range_config_setting minimum_width( +conky::range_config_setting minimum_width( "minimum_width", 0, std::numeric_limits::max(), 5, true); -static conky::range_config_setting maximum_width( +conky::range_config_setting maximum_width( "maximum_width", 0, std::numeric_limits::max(), 0, true); static bool isutf8(const char *envvar) { @@ -537,7 +570,7 @@ conky::simple_config_setting utf8_mode("override_utf8_locale", isutf8("LANG"), false); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* maximum size of config TEXT buffer, i.e. below TEXT line. */ conky::range_config_setting max_user_text( @@ -570,13 +603,17 @@ int get_updatereset() { return updatereset; } int get_total_updates() { return total_updates; } int calc_text_width(const char *s) { + if (display_output()) + return display_output()->calc_text_width(s); + size_t slen = strlen(s); + return slen; -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (!out_to_x.get(*state)) { -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ return slen; -#ifdef BUILD_X11 +#ifdef BUILD_X11_ } #ifdef BUILD_XFT if (use_xft.get(*state)) { @@ -595,7 +632,7 @@ int calc_text_width(const char *s) { return XTextWidth(fonts[selected_font].font, s, slen); -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ } /* formatted text to render on screen, generated in generate_text(), @@ -811,10 +848,10 @@ void generate_text_internal(char *p, int p_max_size, struct text_object root) { new_bar(obj, p, p_max_size, (*obj->callbacks.barval)(obj)); } else if (obj->callbacks.gaugeval != nullptr) { new_gauge(obj, p, p_max_size, (*obj->callbacks.gaugeval)(obj)); -#ifdef BUILD_X11 +#ifdef BUILD_GUI } else if (obj->callbacks.graphval != nullptr) { new_graph(obj, p, p_max_size, (*obj->callbacks.graphval)(obj)); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ } else if (obj->callbacks.percentage != nullptr) { percent_print(p, p_max_size, (*obj->callbacks.percentage)(obj)); } @@ -829,10 +866,15 @@ void generate_text_internal(char *p, int p_max_size, struct text_object root) { obj = obj->next; } -#ifdef BUILD_X11 +#ifdef BUILD_X11_ /* load any new fonts we may have had */ load_fonts(utf8_mode.get(*state)); -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ +#ifdef BUILD_GUI + /* load any new fonts we may have had */ + for (auto output : display_outputs()) + output->load_fonts(utf8_mode.get(*state)); +#endif /* BUILD_GUI */ #ifdef BUILD_ICONV free(buff_in); #endif /* BUILD_ICONV */ @@ -914,8 +956,8 @@ static void generate_text() { int get_string_width(const char *s) { return *s != 0 ? calc_text_width(s) : 0; } -#ifdef BUILD_X11 -static inline int get_border_total() { +#ifdef BUILD_GUI +/*static inline*/ int get_border_total() { return border_inner_margin.get(*state) + border_outer_margin.get(*state) + border_width.get(*state); } @@ -929,6 +971,9 @@ static int get_string_width_special(char *s, int special_index) { if (s == nullptr) { return 0; } + if (display_output() == nullptr || !display_output()->graphical()) { + return strlen(s); + } if (!out_to_x.get(*state)) { return strlen(s); } p = strndup(s, text_buffer_size.get(*state)); @@ -1000,7 +1045,7 @@ static int get_string_width_special(char *s, int special_index) { static int text_size_updater(char *s, int special_index); int last_font_height; -static void update_text_area() { +void update_text_area() { int x = 0, y = 0; if (!out_to_x.get(*state)) { return; } @@ -1096,8 +1141,8 @@ static int cur_x, cur_y; /* current x and y for drawing */ // draw_mode also without BUILD_X11 because we only need to print to stdout with // FG static int draw_mode; /* FG, BG or OUTLINE */ -#ifdef BUILD_X11 -static long current_color; +#ifdef BUILD_GUI +/*static*/ long current_color; static int text_size_updater(char *s, int special_index) { int w = 0; @@ -1107,6 +1152,9 @@ static int text_size_updater(char *s, int special_index) { for (int i = 0; i < special_index; i++) { current = current->next; } if (!out_to_x.get(*state)) { return 0; } + if (display_output() == nullptr || !display_output()->graphical()) { + return 0; + } /* get string widths and skip specials */ p = s; while (*p != 0) { @@ -1158,10 +1206,10 @@ static int text_size_updater(char *s, int special_index) { last_font_height = font_height(); return special_index; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ static inline void set_foreground_color(long c) { -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { #ifdef BUILD_ARGB if (have_argb_visual) { @@ -1174,11 +1222,11 @@ static inline void set_foreground_color(long c) { #endif /* BUILD_ARGB */ XSetForeground(display, window.gc, current_color); } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ #ifdef BUILD_NCURSES_ if (out_to_ncurses.get(*state)) { attron(COLOR_PAIR(c)); } -#endif /* BUILD_NCURSES */ - for (auto output : conky::active_display_outputs) +#endif /* BUILD_NCURSES_ */ + for (auto output : display_outputs()) output->set_foreground_color(c); UNUSED(c); } @@ -1208,10 +1256,12 @@ static void draw_string(const char *s) { } #ifdef BUILD_NCURSES_ if (out_to_ncurses.get(*state) && draw_mode == FG) { printw("%s", s); } -#endif /* BUILD_NCURSES */ - if (conky::active_display_outputs.size() && draw_mode == FG) - for (auto output : conky::active_display_outputs) - output->draw_string(s, width_of_s); +#endif /* BUILD_NCURSES_ */ + if (draw_mode == FG) { + for (auto output : display_outputs()) + if (!output->graphical()) + output->draw_string(s, width_of_s); + } int tbs = text_buffer_size.get(*state); memset(tmpstring1, 0, tbs); memset(tmpstring2, 0, tbs); @@ -1219,11 +1269,12 @@ static void draw_string(const char *s) { pos = 0; added = 0; -#ifdef BUILD_X11 - if (out_to_x.get(*state)) { +#ifdef BUILD_GUI +// if (out_to_x.get(*state)) { + if (display_output() && display_output()->graphical()) { max = ((text_width - width_of_s) / get_string_width(" ")); } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* This code looks for tabs in the text and coverts them to spaces. * The trick is getting the correct number of spaces, and not going * over the window's size without forcing the window larger. */ @@ -1242,8 +1293,9 @@ static void draw_string(const char *s) { pos++; } } -#ifdef BUILD_X11 - if (out_to_x.get(*state)) { +#ifdef BUILD_GUI + //if (out_to_x.get(*state)) { + if (display_output() && display_output()->graphical()) { int mw = maximum_width.get(*state); if (text_width == mw) { /* this means the text is probably pushing the limit, @@ -1254,10 +1306,16 @@ static void draw_string(const char *s) { } } } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ s = tmpstring2; -#ifdef BUILD_X11 - if (out_to_x.get(*state)) { +#ifdef BUILD_GUI + //if (out_to_x.get(*state)) { + if (display_output() && display_output()->graphical()) { + display_output()->draw_string_at( + text_offset_x + cur_x, text_offset_y + cur_y, + s, strlen(s)); + +#if BUILD_X11_ #ifdef BUILD_XFT if (use_xft.get(*state)) { XColor c; @@ -1293,37 +1351,39 @@ static void draw_string(const char *s) { text_offset_y + cur_y, s, strlen(s)); } } +#endif cur_x += width_of_s; } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ memcpy(tmpstring1, s, tbs); } int draw_each_line_inner(char *s, int special_index, int last_special_applied) { -#ifndef BUILD_X11 +#ifndef BUILD_GUI static int cur_x, cur_y; /* current x and y for drawing */ #endif -#ifdef BUILD_X11 +#ifdef BUILD_GUI int font_h = 0; int cur_y_add = 0; int mw = maximum_width.get(*state); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ char *p = s; int orig_special_index = special_index; -#ifdef BUILD_X11 - if (out_to_x.get(*state)) { +#ifdef BUILD_GUI + //if (out_to_x.get(*state)) { + if (display_output() && display_output()->graphical()) { font_h = font_height(); cur_y += font_ascent(); } cur_x = text_start_x; -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ while (*p != 0) { if (*p == SPECIAL_CHAR || last_special_applied > -1) { -#ifdef BUILD_X11 +#ifdef BUILD_GUI int w = 0; -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* draw string before special, unless we're dealing multiline * specials */ @@ -1339,16 +1399,22 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { special_t *current = specials; for (int i = 0; i < special_index; i++) { current = current->next; } switch (current->type) { -#ifdef BUILD_X11 +#ifdef BUILD_GUI case HORIZONTAL_LINE: { int h = current->height; int mid = font_ascent() / 2; w = text_start_x + text_width - cur_x; - XSetLineAttributes(display, window.gc, h, LineSolid, CapButt, - JoinMiter); - XDrawLine(display, window.drawable, window.gc, text_offset_x + cur_x, +// XSetLineAttributes(display, window.gc, h, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(h, true); +// XDrawLine(display, window.drawable, window.gc, text_offset_x + cur_x, +// text_offset_y + cur_y - mid / 2, text_offset_x + cur_x + w, +// text_offset_y + cur_y - mid / 2); + if (display_output()) + display_output()->draw_line(text_offset_x + cur_x, text_offset_y + cur_y - mid / 2, text_offset_x + cur_x + w, text_offset_y + cur_y - mid / 2); break; @@ -1361,10 +1427,18 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { char ss[2] = {tmp_s, tmp_s}; w = text_start_x + text_width - cur_x - 1; - XSetLineAttributes(display, window.gc, h, LineOnOffDash, CapButt, - JoinMiter); - XSetDashes(display, window.gc, 0, ss, 2); - XDrawLine(display, window.drawable, window.gc, text_offset_x + cur_x, +// XSetLineAttributes(display, window.gc, h, LineOnOffDash, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(h, false); +// XSetDashes(display, window.gc, 0, ss, 2); + if (display_output()) + display_output()->set_dashes(ss); +/* XDrawLine(display, window.drawable, window.gc, text_offset_x + cur_x, + text_offset_y + cur_y - mid / 2, text_offset_x + cur_x + w, + text_offset_x + cur_y - mid / 2);*/ + if (display_output()) + display_output()->draw_line(text_offset_x + cur_x, text_offset_y + cur_y - mid / 2, text_offset_x + cur_x + w, text_offset_x + cur_y - mid / 2); break; @@ -1384,12 +1458,21 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { if (w == 0) { w = text_start_x + text_width - cur_x - 1; } if (w < 0) { w = 0; } - XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, - JoinMiter); +// XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(1, true); - XDrawRectangle(display, window.drawable, window.gc, +// XDrawRectangle(display, window.drawable, window.gc, +// text_offset_x + cur_x, text_offset_y + by, w, h); + if (display_output()) + display_output()->draw_rect( text_offset_x + cur_x, text_offset_y + by, w, h); - XFillRectangle(display, window.drawable, window.gc, +// XFillRectangle(display, window.drawable, window.gc, +// text_offset_x + cur_x, text_offset_y + by, +// w * bar_usage / scale, h); + if (display_output()) + display_output()->fill_rect( text_offset_x + cur_x, text_offset_y + by, w * bar_usage / scale, h); if (h > cur_y_add && h > font_h) { cur_y_add = h; } @@ -1415,10 +1498,15 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { if (w == 0) { w = text_start_x + text_width - cur_x - 1; } if (w < 0) { w = 0; } - XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, - JoinMiter); +// XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(1, true); - XDrawArc(display, window.drawable, window.gc, text_offset_x + cur_x, +/* XDrawArc(display, window.drawable, window.gc, text_offset_x + cur_x, + text_offset_y + by, w, h * 2, 0, 180 * 64);*/ + if (display_output()) + display_output()->draw_arc(text_offset_x + cur_x, text_offset_y + by, w, h * 2, 0, 180 * 64); #ifdef BUILD_MATH @@ -1430,7 +1518,12 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { py = static_cast(by + (h)) - static_cast(h) * sin(angle); - XDrawLine(display, window.drawable, window.gc, +/* XDrawLine(display, window.drawable, window.gc, + text_offset_x + cur_x + (w / 2.), text_offset_y + by + (h), + text_offset_x + static_cast(px), + text_offset_y + static_cast(py));*/ + if (display_output()) + display_output()->draw_line( text_offset_x + cur_x + (w / 2.), text_offset_y + by + (h), text_offset_x + static_cast(px), text_offset_y + static_cast(py)); @@ -1462,13 +1555,20 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { } if (w < 0) { w = 0; } if (draw_graph_borders.get(*state)) { - XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, - JoinMiter); - XDrawRectangle(display, window.drawable, window.gc, +// XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(1, true); +// XDrawRectangle(display, window.drawable, window.gc, +// text_offset_x + cur_x, text_offset_y + by, w, h); + if (display_output()) + display_output()->draw_rect( text_offset_x + cur_x, text_offset_y + by, w, h); } - XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, - JoinMiter); +// XSetLineAttributes(display, window.gc, 1, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(1, true); /* in case we don't have a graph yet */ if (current->graph != nullptr) { @@ -1504,12 +1604,19 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { } } /* this is mugfugly, but it works */ - XDrawLine( +/* XDrawLine( display, window.drawable, window.gc, text_offset_x + cur_x + i + 1, text_offset_y + by + h, text_offset_x + cur_x + i + 1, text_offset_y + round_to_int(static_cast(by) + h - current->graph[j] * (h - 1) / + current->scale));*/ + if (display_output()) + display_output()->draw_line( + text_offset_x + cur_x + i + 1, text_offset_y + by + h, + text_offset_x + cur_x + i + 1, + text_offset_y + round_to_int(static_cast(by) + h - + current->graph[j] * (h - 1) / current->scale)); ++j; } @@ -1603,12 +1710,12 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { font_h = font_height(); break; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ case FG: if (draw_mode == FG) { set_foreground_color(current->arg); } break; -#ifdef BUILD_X11 +#ifdef BUILD_GUI case BG: if (draw_mode == BG) { set_foreground_color(current->arg); } break; @@ -1668,30 +1775,30 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { if (pos_x > current->arg) { w = pos_x - current->arg; } break; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ case GOTO: if (current->arg >= 0) { -#ifdef BUILD_X11 +#ifdef BUILD_GUI cur_x = static_cast(current->arg); // make sure shades are 1 pixel to the right of the text if (draw_mode == BG) { cur_x++; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ #ifdef BUILD_NCURSES_ if (out_to_ncurses.get(*state)) { int x, y; getyx(ncurses_window, y, x); move(y, cur_x); } -#endif /* BUILD_NCURSES */ - for (auto output : conky::active_display_outputs) +#endif /* BUILD_NCURSES_ */ + for (auto output : display_outputs()) output->gotox(cur_x); } break; } -#ifdef BUILD_X11 +#ifdef BUILD_GUI cur_x += w; -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ if (special_index != last_special_applied) { special_index++; @@ -1703,40 +1810,51 @@ int draw_each_line_inner(char *s, int special_index, int last_special_applied) { p++; } -#ifdef BUILD_X11 +#ifdef BUILD_GUI cur_y += cur_y_add; -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ draw_string(s); #ifdef BUILD_NCURSES if (out_to_ncurses.get(*state)) { printw("\n"); } #endif /* BUILD_NCURSES */ -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { cur_y += font_descent(); } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ +#ifdef BUILD_GUI + if (display_output() && display_output()->graphical()) { + cur_y += font_descent(); + } +#endif /* BUILD_GUI */ return special_index; } static int draw_line(char *s, int special_index) { -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { return draw_each_line_inner(s, special_index, -1); } -#endif /* BUILD_X11 */ -#ifdef BUILD_NCURSES +#endif /* BUILD_X11_ */ +#ifdef BUILD_NCURSES_ if (out_to_ncurses.get(*state)) { return draw_each_line_inner(s, special_index, -1); } #endif /* BUILD_NCURSES */ + + if (display_output() && display_output()->draw_line_inner_required()) { + return draw_each_line_inner(s, special_index, -1); + } draw_string(s); UNUSED(special_index); return 0; } static void draw_text() { - for (auto output : conky::active_display_outputs) + for (auto output : display_outputs()) output->begin_draw_text(); -#ifdef BUILD_X11 - if (out_to_x.get(*state)) { +#ifdef BUILD_GUI + //if (out_to_x.get(*state)) { + //XXX:only works if inside set_display_output() + if (display_output() && display_output()->graphical()) { cur_y = text_start_y; int bw = border_width.get(*state); @@ -1745,16 +1863,24 @@ static void draw_text() { if (stippled_borders.get(*state) != 0) { char ss[2] = {stippled_borders.get(*state), stippled_borders.get(*state)}; - XSetLineAttributes(display, window.gc, bw, LineOnOffDash, CapButt, - JoinMiter); - XSetDashes(display, window.gc, 0, ss, 2); +// XSetLineAttributes(display, window.gc, bw, LineOnOffDash, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(bw, false); +// XSetDashes(display, window.gc, 0, ss, 2); + if (display_output()) + display_output()->set_dashes(ss); } else { - XSetLineAttributes(display, window.gc, bw, LineSolid, CapButt, - JoinMiter); +// XSetLineAttributes(display, window.gc, bw, LineSolid, CapButt, +// JoinMiter); + if (display_output()) + display_output()->set_line_style(bw, true); } int offset = border_inner_margin.get(*state) + bw; - XDrawRectangle(display, window.drawable, window.gc, +// XDrawRectangle(display, window.drawable, window.gc, + if (display_output()) + display_output()->draw_rect( text_offset_x + text_start_x - offset, text_offset_y + text_start_y - offset, text_width + 2 * offset, text_height + 2 * offset); @@ -1763,18 +1889,18 @@ static void draw_text() { /* draw text */ } setup_fonts(); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ #ifdef BUILD_NCURSES_ init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); attron(COLOR_PAIR(COLOR_WHITE)); -#endif /* BUILD_NCURSES */ +#endif /* BUILD_NCURSES_ */ for_each_line(text_buffer, draw_line); - for (auto output : conky::active_display_outputs) + for (auto output : display_outputs()) output->end_draw_text(); } -static void draw_stuff() { -#ifndef BUILD_X11 +void draw_stuff() { +#ifndef BUILD_GUI static int text_offset_x, text_offset_y; /* offset for start position */ #endif text_offset_x = text_offset_y = 0; @@ -1793,9 +1919,15 @@ static void draw_stuff() { NORM_ERR("Cannot append to '%s'", append_file.get(*state).c_str()); } } -#ifdef BUILD_X11 +#ifdef BUILD_GUI llua_draw_pre_hook(); - if (out_to_x.get(*state)) { +// if (out_to_x.get(*state)) { + for (auto output : display_outputs()) { + if (!output->graphical()) + continue; + // XXX: we assume a single graphical display + set_display_output(output); + selected_font = 0; if (draw_shades.get(*state) && !draw_outline.get(*state)) { text_offset_x = text_offset_y = 1; @@ -1821,18 +1953,23 @@ static void draw_stuff() { } set_foreground_color(default_color.get(*state)); + unset_display_output(); } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ draw_mode = FG; draw_text(); -#if defined(BUILD_X11) +#if defined(BUILD_GUI) llua_draw_post_hook(); +/* #if defined(BUILD_XDBE) if (out_to_x.get(*state)) { xdbe_swap_buffers(); } #else if (out_to_x.get(*state)) { xpmdb_swap_buffers(); } #endif -#endif /* BUILD_X11 && BUILD_XDBE */ +*/ + for (auto output : display_outputs()) + output->swap_buffers(); +#endif /* BUILD_GUI */ if (overwrite_fpointer != nullptr) { fclose(overwrite_fpointer); overwrite_fpointer = nullptr; @@ -1843,7 +1980,7 @@ static void draw_stuff() { } } -#ifdef BUILD_X11 +#ifdef BUILD_X11_ static void clear_text(int exposures) { #ifdef BUILD_XDBE if (use_xdbe.get(*state)) { @@ -1865,19 +2002,25 @@ static void clear_text(int exposures) { text_height + 2 * border_total, exposures != 0 ? True : 0); } } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ -static int need_to_update; +int need_to_update; /* update_text() generates new text and clears old text area */ -static void update_text() { +void update_text() { #ifdef BUILD_IMLIB2 cimlib_cleanup(); #endif /* BUILD_IMLIB2 */ generate_text(); -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { clear_text(1); } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ +#ifdef BUILD_GUI + for (auto output : display_outputs()) { + if (output->graphical()) + output->clear_text(1); + } +#endif /* BUILD_GUI */ need_to_update = 1; llua_update_info(&info, active_update_interval()); } @@ -1932,7 +2075,7 @@ static void main_loop() { sigaddset(&newmask, SIGUSR1); #endif -#ifdef BUILD_X11 +#ifdef BUILD_X11_ #ifdef BUILD_XSHAPE if (out_to_x.get(*state)) { /* allow only decorated windows to be given mouse input */ @@ -1950,7 +2093,7 @@ static void main_loop() { } } #endif /* BUILD_XSHAPE */ -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ last_update_time = 0.0; next_update_time = get_time() - fmod(get_time(), active_update_interval()); @@ -1969,7 +2112,7 @@ static void main_loop() { } #endif -#ifdef BUILD_X11 +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { XFlush(display); @@ -2040,7 +2183,10 @@ static void main_loop() { NORM_ERR("Failed to allocate back buffer"); } XSetForeground(display, window.gc, 0); - XFillRectangle(display, window.drawable, window.gc, 0, 0, +/* XFillRectangle(display, window.drawable, window.gc, 0, 0, + window.width, window.height);*/ + if (display_output()) + display_output()->fill_rect(0, 0, window.width, window.height); } #endif @@ -2292,7 +2438,13 @@ static void main_loop() { x11_stuff.region = XCreateRegion(); } } else { -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ +#ifdef BUILD_GUI + if (display_output() && display_output()->graphical()) { + t = next_update_time - get_time(); + display_output()->main_loop_wait(t); + } else { +#endif /* BUILD_GUI */ struct timespec req, rem; auto time_to_sleep = next_update_time - get_time(); auto seconds = (time_t)std::floor(time_to_sleep); @@ -2308,11 +2460,11 @@ static void main_loop() { clear(); } #endif - for (auto output : conky::active_display_outputs) + for (auto output : display_outputs()) output->flush(); -#ifdef BUILD_X11 +#ifdef BUILD_GUI } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ #ifdef SIGNAL_BLOCKING /* unblock signals of interest and let handler fly */ @@ -2340,7 +2492,7 @@ static void main_loop() { clear(); } #endif - for (auto output : conky::active_display_outputs) + for (auto output : display_outputs()) output->flush(); } @@ -2348,7 +2500,9 @@ static void main_loop() { g_sigterm_pending = 0; NORM_ERR("received SIGHUP, SIGINT, or SIGTERM to terminate. bye!"); terminate = 1; -#ifdef BUILD_X11 + for (auto output : display_outputs()) + output->sigterm_cleanup(); +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { XDestroyRegion(x11_stuff.region); x11_stuff.region = nullptr; @@ -2358,7 +2512,7 @@ static void main_loop() { XFixesDestroyRegion(display, x11_stuff.part); #endif /* BUILD_XDAMAGE */ } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ } #ifdef HAVE_SYS_INOTIFY_H if (!disable_auto_reload.get(*state) && inotify_fd != -1 && @@ -2442,7 +2596,7 @@ static void reload_config() { initialisation(argc_copy, argv_copy); } -#ifdef BUILD_X11 +#ifdef BUILD_X11_ void clean_up_x11() { if (window_created == 1) { int border_total = get_border_total(); @@ -2458,7 +2612,7 @@ void clean_up_x11() { x11_stuff.region = nullptr; } } -#endif +#endif /* BUILD_X11_ */ void free_specials(special_t *¤t) { if (current != nullptr) { @@ -2474,14 +2628,16 @@ void clean_up_without_threads(void *memtofree1, void *memtofree2) { free_and_zero(memtofree2); free_and_zero(info.cpu_usage); -#ifdef BUILD_X11 + for (auto output : display_outputs()) + output->cleanup(); +#ifdef BUILD_X11_ if (out_to_x.get(*state)) { clean_up_x11(); } else { fonts.clear(); // in set_default_configurations a font is set but not } // loaded -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ if (info.first_process != nullptr) { free_all_processes(); @@ -2548,7 +2704,7 @@ static void set_default_configurations() { info.users.number = 1; } -#ifdef BUILD_X11 +#ifdef BUILD_X11_ static void X11_create_window() { if (out_to_x.get(*state)) { setup_fonts(); @@ -2587,7 +2743,7 @@ static void X11_create_window() { /* setup lua window globals */ llua_setup_window_table(text_start_x, text_start_y, text_width, text_height); } -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ void load_config_file() { DBGP(_("reading contents from config file '%s'"), current_config.c_str()); @@ -2913,7 +3069,7 @@ void initialisation(int argc, char **argv) { conky::set_config_settings(*state); -#ifdef BUILD_X11 +#ifdef BUILD_GUI if (out_to_x.get(*state)) { current_text_color = default_color.get(*state); } #endif @@ -2957,9 +3113,9 @@ void initialisation(int argc, char **argv) { CRIT_ERR(nullptr, nullptr, "initialize_display_outputs() failed."); } -#ifdef BUILD_X11 +#ifdef BUILD_X11_ X11_create_window(); -#endif /* BUILD_X11 */ +#endif /* BUILD_X11_ */ llua_setup_info(&info, active_update_interval()); /* Set signal handlers */ diff --git a/src/conky.h b/src/conky.h index 417de45a60..27237fd0d4 100644 --- a/src/conky.h +++ b/src/conky.h @@ -302,7 +302,15 @@ extern conky::range_config_setting update_interval; extern conky::range_config_setting update_interval_on_battery; double active_update_interval(); +extern conky::simple_config_setting show_graph_scale; +extern conky::simple_config_setting show_graph_range; +extern conky::simple_config_setting gap_x; +extern conky::simple_config_setting gap_y; +extern conky::simple_config_setting draw_borders; +extern conky::simple_config_setting draw_graph_borders; extern conky::range_config_setting stippled_borders; +extern conky::simple_config_setting draw_shades; +extern conky::simple_config_setting draw_outline; void set_current_text_color(long colour); long get_current_text_color(void); @@ -327,6 +335,9 @@ void extract_object_args_to_sub(struct text_object *, const char *); void generate_text_internal(char *, int, struct text_object); +void update_text_area(); +void draw_stuff(); + int percent_print(char *, int, unsigned); void human_readable(long long, char *, int); diff --git a/src/display-ncurses.cc b/src/display-ncurses.cc index 6f46df7710..bd039eddaa 100644 --- a/src/display-ncurses.cc +++ b/src/display-ncurses.cc @@ -69,7 +69,8 @@ bool display_output_ncurses::detect() { } bool display_output_ncurses::initialize() { - return (ncurses_window != nullptr); + is_active = ncurses_window != nullptr; + return is_active; } bool display_output_ncurses::shutdown() { diff --git a/src/display-ncurses.hh b/src/display-ncurses.hh index db6970436b..30d209e0fe 100644 --- a/src/display-ncurses.hh +++ b/src/display-ncurses.hh @@ -48,6 +48,7 @@ class display_output_ncurses : public display_output_console { // connect to DISPLAY and other stuff virtual bool initialize(); virtual bool shutdown(); + virtual bool draw_line_inner_required() { return true; }; // drawing primitives virtual bool set_foreground_color(long c); diff --git a/src/display-output.cc b/src/display-output.cc index d7e9286019..f5063e16ea 100644 --- a/src/display-output.cc +++ b/src/display-output.cc @@ -93,8 +93,10 @@ bool initialize_display_outputs() { for (auto &output : *display_outputs) { outputs.push_back(output.second); } + // Sort display outputs by descending priority, to try graphical ones first. sort(outputs.begin(), outputs.end(), &display_output_base::priority_compare); + int graphical_count = 0; for (auto output : outputs) { if (output->priority < 0) @@ -104,11 +106,29 @@ bool initialize_display_outputs() { if (output->detect()) { std::cerr << "Detected display output '" << output->name << "'... " << std::endl; + + if (graphical_count && output->graphical()) + continue; + + // X11 init needs to draw, so we must add it to the list first. + active_display_outputs.push_back(output); + if (output->initialize()) { std::cerr << "Initialized display output '" << output->name << "'... " << std::endl; + output->is_active = true; - active_display_outputs.push_back(output); + if (output->graphical()) + graphical_count++; + /* + * We only support a single graphical display for now. + * More than one text display (ncurses + http, ...) should be ok. + */ + //if (graphical_count) + //return true; + } else { + // failed, so remove from list + active_display_outputs.pop_back(); } } } @@ -121,8 +141,11 @@ bool initialize_display_outputs() { bool shutdown_display_outputs() { bool ret = true; - for (auto output : active_display_outputs) + for (auto output : active_display_outputs) { + output->is_active = false; ret = output->shutdown(); + } + active_display_outputs.clear(); return ret; } diff --git a/src/display-output.hh b/src/display-output.hh index ee842c1e9c..f595d454f8 100644 --- a/src/display-output.hh +++ b/src/display-output.hh @@ -26,6 +26,7 @@ #include #include #include +#include #include "luamm.hh" @@ -73,13 +74,41 @@ class display_output_base { virtual bool initialize() { return false; }; virtual bool shutdown() { return false; }; + virtual bool graphical() { return is_graphical; }; + virtual bool draw_line_inner_required() { return is_graphical; }; + + virtual bool main_loop_wait(double t) { return false; }; + + virtual bool sigterm_cleanup() { return false; }; + virtual bool cleanup() { return false; }; + // drawing primitives virtual bool set_foreground_color(long c) { return false; } + virtual int calc_text_width(const char *s) { return strlen(s); }; + virtual bool begin_draw_text() { return false; }; virtual bool end_draw_text() { return false; }; virtual bool draw_string(const char *s, int w) { return false; }; + // GUI interface + virtual bool draw_string_at(int x, int y, const char *s, int w) { return false; }; + // X11 lookalikes + virtual bool set_line_style(int w, bool solid) { return false; }; + virtual bool set_dashes(char *s) { return false; }; + virtual bool draw_line(int x1, int y1, int x2, int y2) { return false; }; + virtual bool draw_rect(int x, int y, int w, int h) { return false; }; + virtual bool fill_rect(int x, int y, int w, int h) { return false; }; + virtual bool draw_arc(int x, int y, int w, int h, int a1, int a2) { return false; }; + virtual bool move_win(int x, int y) { return false; }; + + virtual bool begin_draw_stuff() { return false; }; + virtual bool end_draw_stuff() { return false; }; + virtual bool swap_buffers() { return false; }; + virtual bool clear_text(int exposures) { return false; }; + virtual bool load_fonts(bool utf8) { return false; }; + + // tty interface virtual int getx() { return 0; }; virtual int gety() { return 0; }; virtual bool gotox(int x) { return false; }; @@ -94,7 +123,6 @@ class display_output_base { protected: virtual bool active() { return is_active; }; - virtual bool graphical() { return is_graphical; }; }; /* diff --git a/src/display-x11.cc b/src/display-x11.cc index 6908f26e07..0dabf5169e 100644 --- a/src/display-x11.cc +++ b/src/display-x11.cc @@ -22,12 +22,106 @@ #include -#include "display-x11.hh" +#ifdef BUILD_X11 +#include +#include "x11.h" +#ifdef BUILD_XDAMAGE +#include +#endif +#ifdef BUILD_IMLIB2 +#include "imlib2.h" +#endif /* BUILD_IMLIB2 */ +#ifdef BUILD_XSHAPE +#include +#endif /* BUILD_XSHAPE */ +#endif /* BUILD_X11 */ #include #include #include +#include "conky.h" +#include "llua.h" +#include "display-x11.hh" +#include "x11.h" +#ifdef BUILD_X11 +#include "fonts.h" +#endif + +/* TODO: cleanup global namespace */ +#ifdef BUILD_X11 +//TODO: reindent! + +//TODO: cleanup externs (move to conky.h ?) +#ifdef OWN_WINDOW +extern int fixed_size, fixed_pos; +#endif +extern int text_start_x, text_start_y; /* text start position in window */ +extern int text_offset_x, text_offset_y; /* offset for start position */ +extern int text_width, + text_height; /* initially 1 so no zero-sized window is created */ +extern double current_update_time, next_update_time, last_update_time; +void update_text(); +extern int need_to_update; +int get_border_total(); +extern conky::range_config_setting maximum_width; +extern long current_color; + + +static void X11_create_window(); + +struct _x11_stuff_s { + Region region; +#ifdef BUILD_XDAMAGE + Damage damage; + XserverRegion region2, part; + int event_base, error_base; +#endif +} x11_stuff; + +static void X11_create_window() { + if (out_to_x.get(*state)) { + setup_fonts(); + load_fonts(utf8_mode.get(*state)); + update_text_area(); /* to position text/window on screen */ + +#ifdef OWN_WINDOW + if (own_window.get(*state)) { + if (fixed_pos == 0) { + XMoveWindow(display, window.window, window.x, window.y); + } + + set_transparent_background(window.window); + } +#endif + + create_gc(); + + draw_stuff(); + + x11_stuff.region = XCreateRegion(); +#ifdef BUILD_XDAMAGE + if (XDamageQueryExtension(display, &x11_stuff.event_base, + &x11_stuff.error_base) == 0) { + NORM_ERR("Xdamage extension unavailable"); + } + x11_stuff.damage = + XDamageCreate(display, window.window, XDamageReportNonEmpty); + x11_stuff.region2 = XFixesCreateRegionFromWindow(display, window.window, 0); + x11_stuff.part = XFixesCreateRegionFromWindow(display, window.window, 0); +#endif /* BUILD_XDAMAGE */ + + selected_font = 0; + update_text_area(); /* to get initial size of the window */ + } + /* setup lua window globals */ + llua_setup_window_table(text_start_x, text_start_y, text_width, text_height); +} + + +#endif /* BUILD_X11 */ + + namespace conky { namespace { @@ -48,6 +142,7 @@ namespace priv { display_output_x11::display_output_x11() : display_output_base("x11") { + is_graphical = true; priority = 2; } @@ -60,13 +155,539 @@ bool display_output_x11::detect() { } bool display_output_x11::initialize() { - return false; + X11_create_window(); + //XXX: this was at the top of main_loop() but I don't see any reason + +#ifdef BUILD_XSHAPE + if (true/*out_to_x.get(*state)*/) { + /* allow only decorated windows to be given mouse input */ + int major_version, minor_version; + if (XShapeQueryVersion(display, &major_version, &minor_version) == 0) { + NORM_ERR("Input shapes are not supported"); + } else { + if (own_window.get(*state) && + (own_window_type.get(*state) != TYPE_NORMAL || + ((TEST_HINT(own_window_hints.get(*state), HINT_UNDECORATED)) != + 0))) { + XShapeCombineRectangles(display, window.window, ShapeInput, 0, 0, + nullptr, 0, ShapeSet, Unsorted); + } + } + } +#endif /* BUILD_XSHAPE */ + + return true; } bool display_output_x11::shutdown() { return false; } +bool display_output_x11::main_loop_wait(double t) { + if (true/*out_to_x.get(*state)*/) { + XFlush(display); + + /* wait for X event or timeout */ + + if (XPending(display) == 0) { + fd_set fdsr; + struct timeval tv {}; + int s; + //t = next_update_time - get_time(); + + t = std::min(std::max(t, 0.0), active_update_interval()); + + tv.tv_sec = static_cast(t); + tv.tv_usec = static_cast(t * 1000000) % 1000000; + FD_ZERO(&fdsr); + FD_SET(ConnectionNumber(display), &fdsr); +fprintf(stderr, "select(,,,,%f)\n", t); + + s = select(ConnectionNumber(display) + 1, &fdsr, nullptr, nullptr, &tv); + if (s == -1) { + if (errno != EINTR) { + NORM_ERR("can't select(): %s", strerror(errno)); + } + } else { + /* timeout */ + if (s == 0) { update_text(); } + } + } + + if (need_to_update != 0) { +#ifdef OWN_WINDOW + int wx = window.x, wy = window.y; +#endif + + need_to_update = 0; + selected_font = 0; + update_text_area(); + +#ifdef OWN_WINDOW + if (own_window.get(*state)) { + int changed = 0; + int border_total = get_border_total(); + + /* resize window if it isn't right size */ + if ((fixed_size == 0) && + (text_width + 2 * border_total != window.width || + text_height + 2 * border_total != window.height)) { + window.width = text_width + 2 * border_total; + window.height = text_height + 2 * border_total; + draw_stuff(); /* redraw everything in our newly sized window */ + XResizeWindow(display, window.window, window.width, + window.height); /* resize window */ + set_transparent_background(window.window); +#ifdef BUILD_XDBE + /* swap buffers */ + xdbe_swap_buffers(); +#else + if (use_xpmdb.get(*state)) { + XFreePixmap(display, window.back_buffer); + window.back_buffer = + XCreatePixmap(display, window.window, window.width, + window.height, DefaultDepth(display, screen)); + + if (window.back_buffer != None) { + window.drawable = window.back_buffer; + } else { + // this is probably reallllly bad + NORM_ERR("Failed to allocate back buffer"); + } + XSetForeground(display, window.gc, 0); + XFillRectangle(display, window.drawable, window.gc, 0, 0, + window.width, window.height); + } +#endif + + changed++; + /* update lua window globals */ + llua_update_window_table(text_start_x, text_start_y, text_width, + text_height); + } + + /* move window if it isn't in right position */ + if ((fixed_pos == 0) && (window.x != wx || window.y != wy)) { + XMoveWindow(display, window.window, window.x, window.y); + changed++; + } + + /* update struts */ + if ((changed != 0) && own_window_type.get(*state) == TYPE_PANEL) { + int sidenum = -1; + + fprintf(stderr, "%s", _(PACKAGE_NAME ": defining struts\n")); + fflush(stderr); + + switch (text_alignment.get(*state)) { + case TOP_LEFT: + case TOP_RIGHT: + case TOP_MIDDLE: { + sidenum = 2; + break; + } + case BOTTOM_LEFT: + case BOTTOM_RIGHT: + case BOTTOM_MIDDLE: { + sidenum = 3; + break; + } + case MIDDLE_LEFT: { + sidenum = 0; + break; + } + case MIDDLE_RIGHT: { + sidenum = 1; + break; + } + + case NONE: + case MIDDLE_MIDDLE: /* XXX What about these? */; + } + + set_struts(sidenum); + } + } +#endif + + clear_text(1); + +#if defined(BUILD_XDBE) + if (use_xdbe.get(*state)) { +#else + if (use_xpmdb.get(*state)) { +#endif + XRectangle r; + int border_total = get_border_total(); + + r.x = text_start_x - border_total; + r.y = text_start_y - border_total; + r.width = text_width + 2 * border_total; + r.height = text_height + 2 * border_total; + XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region); + } + } + + /* handle X events */ + while (XPending(display) != 0) { + XEvent ev; + + XNextEvent(display, &ev); + switch (ev.type) { + case Expose: { + XRectangle r; + r.x = ev.xexpose.x; + r.y = ev.xexpose.y; + r.width = ev.xexpose.width; + r.height = ev.xexpose.height; + XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region); + break; + } + + case PropertyNotify: { + if (ev.xproperty.state == PropertyNewValue) { + get_x11_desktop_info(ev.xproperty.display, ev.xproperty.atom); + } +#ifdef USE_ARGB + if (!have_argb_visual) { +#endif + if (ev.xproperty.atom == ATOM(_XROOTPMAP_ID) || + ev.xproperty.atom == ATOM(_XROOTMAP_ID)) { + draw_stuff(); + next_update_time = get_time(); + need_to_update = 1; + } +#ifdef USE_ARGB + } +#endif + break; + } + +#ifdef OWN_WINDOW + case ReparentNotify: + /* make background transparent */ + if (own_window.get(*state)) { + set_transparent_background(window.window); + } + break; + + case ConfigureNotify: + if (own_window.get(*state)) { + /* if window size isn't what expected, set fixed size */ + if (ev.xconfigure.width != window.width || + ev.xconfigure.height != window.height) { + if (window.width != 0 && window.height != 0) { fixed_size = 1; } + + /* clear old stuff before screwing up + * size and pos */ + clear_text(1); + + { + XWindowAttributes attrs; + if (XGetWindowAttributes(display, window.window, &attrs) != + 0) { + window.width = attrs.width; + window.height = attrs.height; + } + } + + int border_total = get_border_total(); + + text_width = window.width - 2 * border_total; + text_height = window.height - 2 * border_total; + int mw = maximum_width.get(*state); + if (text_width > mw && mw > 0) { text_width = mw; } + } + + /* if position isn't what expected, set fixed pos + * total_updates avoids setting fixed_pos when window + * is set to weird locations when started */ + /* // this is broken + if (total_updates >= 2 && !fixed_pos + && (window.x != ev.xconfigure.x + || window.y != ev.xconfigure.y) + && (ev.xconfigure.x != 0 + || ev.xconfigure.y != 0)) { + fixed_pos = 1; + } */ + } + break; + + case ButtonPress: + if (own_window.get(*state)) { + /* if an ordinary window with decorations */ + if ((own_window_type.get(*state) == TYPE_NORMAL && + not TEST_HINT(own_window_hints.get(*state), + HINT_UNDECORATED)) || + own_window_type.get(*state) == TYPE_DESKTOP) { + /* allow conky to hold input focus. */ + break; + } + /* forward the click to the desktop window */ + XUngrabPointer(display, ev.xbutton.time); + ev.xbutton.window = window.desktop; + ev.xbutton.x = ev.xbutton.x_root; + ev.xbutton.y = ev.xbutton.y_root; + XSendEvent(display, ev.xbutton.window, False, ButtonPressMask, + &ev); + XSetInputFocus(display, ev.xbutton.window, RevertToParent, + ev.xbutton.time); + } + break; + + case ButtonRelease: + if (own_window.get(*state)) { + /* if an ordinary window with decorations */ + if ((own_window_type.get(*state) == TYPE_NORMAL) && + not TEST_HINT(own_window_hints.get(*state), + HINT_UNDECORATED)) { + /* allow conky to hold input focus. */ + break; + } + /* forward the release to the desktop window */ + ev.xbutton.window = window.desktop; + ev.xbutton.x = ev.xbutton.x_root; + ev.xbutton.y = ev.xbutton.y_root; + XSendEvent(display, ev.xbutton.window, False, ButtonReleaseMask, + &ev); + } + break; + +#endif + + default: +#ifdef BUILD_XDAMAGE + if (ev.type == x11_stuff.event_base + XDamageNotify) { + auto *dev = reinterpret_cast(&ev); + + XFixesSetRegion(display, x11_stuff.part, &dev->area, 1); + XFixesUnionRegion(display, x11_stuff.region2, x11_stuff.region2, + x11_stuff.part); + } +#endif /* BUILD_XDAMAGE */ + break; + } + } + +#ifdef BUILD_XDAMAGE + XDamageSubtract(display, x11_stuff.damage, x11_stuff.region2, None); + XFixesSetRegion(display, x11_stuff.region2, nullptr, 0); +#endif /* BUILD_XDAMAGE */ + + /* XDBE doesn't seem to provide a way to clear the back buffer + * without interfering with the front buffer, other than passing + * XdbeBackground to XdbeSwapBuffers. That means that if we're + * using XDBE, we need to redraw the text even if it wasn't part of + * the exposed area. OTOH, if we're not going to call draw_stuff at + * all, then no swap happens and we can safely do nothing. */ + + if (XEmptyRegion(x11_stuff.region) == 0) { +#if defined(BUILD_XDBE) + if (use_xdbe.get(*state)) { +#else + if (use_xpmdb.get(*state)) { +#endif + XRectangle r; + int border_total = get_border_total(); + + r.x = text_start_x - border_total; + r.y = text_start_y - border_total; + r.width = text_width + 2 * border_total; + r.height = text_height + 2 * border_total; + XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region); + } + XSetRegion(display, window.gc, x11_stuff.region); +#ifdef BUILD_XFT + if (use_xft.get(*state)) { + XftDrawSetClip(window.xftdraw, x11_stuff.region); + } +#endif + draw_stuff(); + XDestroyRegion(x11_stuff.region); + x11_stuff.region = XCreateRegion(); + } + } + + // handled + return true; +} + +bool display_output_x11::sigterm_cleanup() { + XDestroyRegion(x11_stuff.region); + x11_stuff.region = nullptr; +#ifdef BUILD_XDAMAGE + XDamageDestroy(display, x11_stuff.damage); + XFixesDestroyRegion(display, x11_stuff.region2); + XFixesDestroyRegion(display, x11_stuff.part); +#endif /* BUILD_XDAMAGE */ + return true; +} + +bool display_output_x11::cleanup() { + if (window_created == 1) { + int border_total = get_border_total(); + + XClearArea(display, window.window, text_start_x - border_total, + text_start_y - border_total, text_width + 2 * border_total, + text_height + 2 * border_total, 0); + } + destroy_window(); + free_fonts(utf8_mode.get(*state)); + if (x11_stuff.region != nullptr) { + XDestroyRegion(x11_stuff.region); + x11_stuff.region = nullptr; + } + return false; +} + + +bool display_output_x11::set_foreground_color(long c) { +#ifdef BUILD_ARGB + if (have_argb_visual) { + current_color = c | (own_window_argb_value.get(*state) << 24); + } else { +#endif /* BUILD_ARGB */ + current_color = c; +#ifdef BUILD_ARGB + } +#endif /* BUILD_ARGB */ + XSetForeground(display, window.gc, current_color); + return true; +} + + +int display_output_x11::calc_text_width(const char *s) { + size_t slen = strlen(s); +#ifdef BUILD_XFT + if (use_xft.get(*state)) { + XGlyphInfo gi; + + if (utf8_mode.get(*state)) { + XftTextExtentsUtf8(display, fonts[selected_font].xftfont, + reinterpret_cast(s), slen, &gi); + } else { + XftTextExtents8(display, fonts[selected_font].xftfont, + reinterpret_cast(s), slen, &gi); + } + return gi.xOff; + } +#endif /* BUILD_XFT */ + + return XTextWidth(fonts[selected_font].font, s, slen); +} + +bool display_output_x11::draw_string_at(int x, int y, const char *s, int w) { +#ifdef BUILD_XFT + if (use_xft.get(*state)) { + XColor c; + XftColor c2; + + c.pixel = current_color; + // query color on custom colormap + XQueryColor(display, window.colourmap, &c); + + c2.pixel = c.pixel; + c2.color.red = c.red; + c2.color.green = c.green; + c2.color.blue = c.blue; + c2.color.alpha = fonts[selected_font].font_alpha; + if (utf8_mode.get(*state)) { + XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont, + x, y, + reinterpret_cast(s), w); + } else { + XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont, + x, y, + reinterpret_cast(s), w); + } + } else +#endif + { + if (utf8_mode.get(*state)) { + Xutf8DrawString(display, window.drawable, fonts[selected_font].fontset, + window.gc, x, y, + s, w); + } else { + XDrawString(display, window.drawable, window.gc, x, + y, s, w); + } + } +return true; +} + +bool display_output_x11::set_line_style(int w, bool solid) { + XSetLineAttributes(display, window.gc, w, + solid ? LineSolid : LineOnOffDash, CapButt, JoinMiter); + return true; +} + +bool display_output_x11::set_dashes(char *s) { + XSetDashes(display, window.gc, 0, s, 2); + return true; +} + +bool display_output_x11::draw_line(int x1, int y1, int x2, int y2) { + XDrawLine(display, window.drawable, window.gc, x1, y1, x2, y2); + return true; +} + +bool display_output_x11::draw_rect(int x, int y, int w, int h) { + XDrawRectangle(display, window.drawable, window.gc, x, y, w, h); + return true; +} + +bool display_output_x11::fill_rect(int x, int y, int w, int h) { + XFillRectangle(display, window.drawable, window.gc, x, y, w, h); + return true; +} + +bool display_output_x11::draw_arc(int x, int y, int w, int h, int a1, int a2) { + XDrawArc(display, window.drawable, window.gc, x, y, w, h, a1, a2); + return true; +} + +bool display_output_x11::move_win(int x, int y) { + XMoveWindow(display, window.window, window.x, window.y); + return true; +} + +bool display_output_x11::swap_buffers() { +#if defined(BUILD_XDBE) + xdbe_swap_buffers(); +#else + xpmdb_swap_buffers(); +#endif + return true; +} + +bool display_output_x11::clear_text(int exposures) { +#ifdef BUILD_XDBE + if (use_xdbe.get(*state)) { + /* The swap action is XdbeBackground, which clears */ + return true; + } +#else + if (use_xpmdb.get(*state)) { + return true; + } else +#endif + if ((display != nullptr) && + (window.window != 0u)) { // make sure these are !null + /* there is some extra space for borders and outlines */ + int border_total = get_border_total(); + + XClearArea(display, window.window, text_start_x - border_total, + text_start_y - border_total, text_width + 2 * border_total, + text_height + 2 * border_total, exposures != 0 ? True : 0); + } + return true; +} + +bool display_output_x11::load_fonts(bool utf8) { + ::load_fonts(utf8); + return true; +} + #endif /* BUILD_X11 */ } // namespace conky diff --git a/src/display-x11.hh b/src/display-x11.hh index 3c3c10a9c7..77739810fe 100644 --- a/src/display-x11.hh +++ b/src/display-x11.hh @@ -49,6 +49,44 @@ class display_output_x11 : public display_output_base { virtual bool initialize(); virtual bool shutdown(); + virtual bool main_loop_wait(double t); + + virtual bool sigterm_cleanup(); + virtual bool cleanup(); + + // drawing primitives + virtual bool set_foreground_color(long c); + + virtual int calc_text_width(const char *s); + + virtual bool begin_draw_text() { return false; }; + virtual bool end_draw_text() { return false; }; + virtual bool draw_string(const char *s, int w) { return false; }; + // GUI interface + virtual bool draw_string_at(int x, int y, const char *s, int w); + // X11 lookalikes + virtual bool set_line_style(int w, bool solid); + virtual bool set_dashes(char *s); + virtual bool draw_line(int x1, int y1, int x2, int y2); + virtual bool draw_rect(int x, int y, int w, int h); + virtual bool fill_rect(int x, int y, int w, int h); + virtual bool draw_arc(int x, int y, int w, int h, int a1, int a2); + virtual bool move_win(int x, int y); + + virtual bool begin_draw_stuff() { return false; }; + virtual bool end_draw_stuff() { return false; }; + virtual bool swap_buffers(); + virtual bool clear_text(int exposures); + virtual bool load_fonts(bool utf8); + + virtual int getx() { return 0; }; + virtual int gety() { return 0; }; + virtual bool gotox(int x) { return false; }; + virtual bool gotoy(int y) { return false; }; + virtual bool gotoxy(int x, int y) { return false; }; + + virtual bool flush() { return false; }; + // X11-specific }; diff --git a/src/specials.cc b/src/specials.cc index 774c3b8cb9..9d0436d4b3 100644 --- a/src/specials.cc +++ b/src/specials.cc @@ -53,7 +53,7 @@ conky::range_config_setting default_bar_width( conky::range_config_setting default_bar_height( "default_bar_height", 0, std::numeric_limits::max(), 6, false); -#ifdef BUILD_X11 +#ifdef BUILD_GUI conky::range_config_setting default_graph_width( "default_graph_width", 0, std::numeric_limits::max(), 0, false); conky::range_config_setting default_graph_height( @@ -63,7 +63,7 @@ conky::range_config_setting default_gauge_width( "default_gauge_width", 0, std::numeric_limits::max(), 40, false); conky::range_config_setting default_gauge_height( "default_gauge_height", 0, std::numeric_limits::max(), 25, false); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ conky::simple_config_setting console_graph_ticks( "console_graph_ticks", " ,_,=,#", false); @@ -109,7 +109,7 @@ struct tab { * Scanning arguments to various special text objects */ -#ifdef BUILD_X11 +#ifdef BUILD_GUI const char *scan_gauge(struct text_object *obj, const char *args, double scale) { struct gauge *g; @@ -174,7 +174,7 @@ const char *scan_bar(struct text_object *obj, const char *args, double scale) { return args; } -#ifdef BUILD_X11 +#ifdef BUILD_GUI void scan_font(struct text_object *obj, const char *args) { if ((args != nullptr) && (*args != 0)) { obj->data.s = strndup(args, DEFAULT_TEXT_BUFFER_SIZE); @@ -335,7 +335,7 @@ char *scan_graph(struct text_object *obj, const char *args, double defscale) { return nullptr; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* * Printing various special text objects @@ -385,7 +385,7 @@ void new_gauge_in_shell(struct text_object *obj, char *p, unsigned int p_max_siz snprintf(p, p_max_size, "%s", gaugevals[round_to_int(usage * 4 / g->scale)]); } -#ifdef BUILD_X11 +#ifdef BUILD_GUI void new_gauge_in_x11(struct text_object *obj, char *buf, double usage) { struct special_t *s = nullptr; auto *g = static_cast(obj->special_data); @@ -405,7 +405,7 @@ void new_gauge_in_x11(struct text_object *obj, char *buf, double usage) { s->height = g->height; s->scale = g->scale; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ void new_gauge(struct text_object *obj, char *p, unsigned int p_max_size, double usage) { auto *g = static_cast(obj->special_data); @@ -420,19 +420,19 @@ void new_gauge(struct text_object *obj, char *p, unsigned int p_max_size, double usage = MIN(g->scale, usage); } -#ifdef BUILD_X11 +#ifdef BUILD_GUI if (out_to_x.get(*state)) { new_gauge_in_x11(obj, p, usage); } if (out_to_stdout.get(*state)) { new_gauge_in_shell(obj, p, p_max_size, usage); } -#else /* BUILD_X11 */ +#else /* BUILD_GUI */ new_gauge_in_shell(obj, p, p_max_size, usage); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ } -#ifdef BUILD_X11 +#ifdef BUILD_GUI void new_font(struct text_object *obj, char *p, unsigned int p_max_size) { struct special_t *s; unsigned int tmp = selected_font; @@ -647,14 +647,14 @@ void new_stippled_hr(struct text_object *obj, char *p, unsigned int p_max_size) s->height = sh->height; s->arg = sh->arg; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ void new_fg(struct text_object *obj, char *p, unsigned int p_max_size) { -#ifdef BUILD_X11 +#ifdef BUILD_GUI if (out_to_x.get(*state)) { new_special(p, FG)->arg = obj->data.l; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ #ifdef BUILD_NCURSES if (out_to_ncurses.get(*state)) { new_special(p, FG)->arg = obj->data.l; @@ -665,7 +665,7 @@ void new_fg(struct text_object *obj, char *p, unsigned int p_max_size) { UNUSED(p_max_size); } -#ifdef BUILD_X11 +#ifdef BUILD_GUI void new_bg(struct text_object *obj, char *p, unsigned int p_max_size) { if (not out_to_x.get(*state)) { return; @@ -677,7 +677,7 @@ void new_bg(struct text_object *obj, char *p, unsigned int p_max_size) { new_special(p, BG)->arg = obj->data.l; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ static void new_bar_in_shell(struct text_object *obj, char *buffer, unsigned int buf_max_size, double usage) { @@ -710,7 +710,7 @@ static void new_bar_in_shell(struct text_object *obj, char *buffer, buffer[i] = 0; } -#ifdef BUILD_X11 +#ifdef BUILD_GUI static void new_bar_in_x11(struct text_object *obj, char *buf, double usage) { struct special_t *s = nullptr; auto *b = static_cast(obj->special_data); @@ -730,7 +730,7 @@ static void new_bar_in_x11(struct text_object *obj, char *buf, double usage) { s->height = b->height; s->scale = b->scale; } -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ /* usage is in range [0,255] */ void new_bar(struct text_object *obj, char *p, unsigned int p_max_size, double usage) { @@ -746,16 +746,16 @@ void new_bar(struct text_object *obj, char *p, unsigned int p_max_size, double u usage = MIN(b->scale, usage); } -#ifdef BUILD_X11 +#ifdef BUILD_GUI if (out_to_x.get(*state)) { new_bar_in_x11(obj, p, usage); } if (out_to_stdout.get(*state)) { new_bar_in_shell(obj, p, p_max_size, usage); } -#else /* BUILD_X11 */ +#else /* BUILD_GUI */ new_bar_in_shell(obj, p, p_max_size, usage); -#endif /* BUILD_X11 */ +#endif /* BUILD_GUI */ } void new_outline(struct text_object *obj, char *p, unsigned int p_max_size) {