[vte] widget: Add API to set the operator used to draw the terminal background
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] widget: Add API to set the operator used to draw the terminal background
- Date: Tue, 24 Oct 2017 18:33:34 +0000 (UTC)
commit 91d30f8f678afedd5f8eedbb95b64ec252abb7bd
Author: Christian Persch <chpe src gnome org>
Date: Tue Oct 24 20:33:17 2017 +0200
widget: Add API to set the operator used to draw the terminal background
This is useful only to support a background image.
https://bugzilla.gnome.org/show_bug.cgi?id=767575
configure.ac | 2 +
doc/reference/vte-sections.txt | 1 +
src/app/app.cc | 179 +++++++++++++++++++++++++++++++++++++---
src/vte.cc | 8 ++
src/vte/vteterminal.h | 5 +
src/vtedraw.cc | 3 +-
src/vtedraw.hh | 1 +
src/vtegtk.cc | 26 ++++++
src/vteinternal.hh | 2 +
9 files changed, 213 insertions(+), 14 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3139c96..ad541ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -317,7 +317,9 @@ PKG_CHECK_MODULES([GTK],[gtk+-$GTK_API_VERSION >= $GTK_REQUIRED])
PKG_CHECK_MODULES([APP],[
glib-2.0 >= $GLIB_REQUIRED
gobject-2.0
+ cairo-gobject
pango >= $PANGO_REQUIRED
+ gdk-pixbuf-2.0
gtk+-$GTK_API_VERSION >= $GTK_REQUIRED])
################################################################################
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index 3561bdb..0b6cd47 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -98,6 +98,7 @@ vte_terminal_pty_new_sync
vte_terminal_watch_child
<SUBSECTION>
+vte_terminal_set_background_operator
<SUBSECTION Standard>
VTE_TYPE_CURSOR_BLINK_MODE
diff --git a/src/app/app.cc b/src/app/app.cc
index 4446592..ad4e5bf 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -26,10 +26,14 @@
#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gi18n.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
+#include <cairo/cairo-gobject.h>
#include <vte/vte.h>
#include "vtepcre2.h"
+#include <algorithm>
+
/* options */
class Options {
@@ -53,10 +57,15 @@ public:
gboolean use_gregex{false};
gboolean version{false};
gboolean whole_window_transparent{false};
+ bool bg_color_set{false};
+ bool fg_color_set{false};
bool cursor_bg_color_set{false};
bool cursor_fg_color_set{false};
bool hl_bg_color_set{false};
bool hl_fg_color_set{false};
+ bool background_operator_set{false};
+ cairo_extend_t background_extend{CAIRO_EXTEND_NONE};
+ cairo_operator_t background_operator{CAIRO_OPERATOR_SOURCE};
char* command{nullptr};
char* encoding{nullptr};
char* font_string{nullptr};
@@ -67,6 +76,9 @@ public:
char** dingus{nullptr};
char** exec_argv{nullptr};
char** environment{nullptr};
+ GdkPixbuf* background_pixbuf{nullptr};
+ GdkRGBA bg_color{1.0, 1.0, 1.0, 1.0};
+ GdkRGBA fg_color{0.0, 0.0, 0.0, 1.0};
GdkRGBA cursor_bg_color{};
GdkRGBA cursor_fg_color{};
GdkRGBA hl_bg_color{};
@@ -80,6 +92,7 @@ public:
VteCursorShape cursor_shape{VTE_CURSOR_SHAPE_BLOCK};
~Options() {
+ g_clear_object(&background_pixbuf);
g_free(command);
g_free(encoding);
g_free(font_string);
@@ -96,7 +109,7 @@ private:
bool parse_enum(GType type,
char const* str,
- int* value,
+ int& value,
GError** error)
{
GEnumClass* enum_klass = reinterpret_cast<GEnumClass*>(g_type_class_ref(type));
@@ -110,7 +123,7 @@ private:
return false;
}
- *value = enum_value->value;
+ value = enum_value->value;
g_type_class_unref(enum_klass);
return true;
}
@@ -161,6 +174,39 @@ private:
}
static gboolean
+ parse_background_image(char const* option, char const* value, void* data, GError** error)
+ {
+ Options* that = static_cast<Options*>(data);
+ g_clear_object(&that->background_pixbuf);
+ that->background_pixbuf = gdk_pixbuf_new_from_file(value, error);
+ return that->background_pixbuf != nullptr;
+ }
+
+ static gboolean
+ parse_background_extend(char const* option, char const* value, void* data, GError** error)
+ {
+ Options* that = static_cast<Options*>(data);
+ int v;
+ auto rv = that->parse_enum(CAIRO_GOBJECT_TYPE_EXTEND, value, v, error);
+ if (rv)
+ that->background_extend = cairo_extend_t(v);
+ return rv;
+ }
+
+ static gboolean
+ parse_background_operator(char const* option, char const* value, void* data, GError** error)
+ {
+ Options* that = static_cast<Options*>(data);
+ int v;
+ auto rv = that->parse_enum(CAIRO_GOBJECT_TYPE_OPERATOR, value, v, error);
+ if (rv) {
+ that->background_operator = cairo_operator_t(v);
+ that->background_operator_set = true;
+ }
+ return rv;
+ }
+
+ static gboolean
parse_cjk_width(char const* option, char const* value, void* data, GError** error)
{
Options* that = static_cast<Options*>(data);
@@ -172,7 +218,7 @@ private:
{
Options* that = static_cast<Options*>(data);
int v;
- auto rv = that->parse_enum(VTE_TYPE_CURSOR_BLINK_MODE, value, &v, error);
+ auto rv = that->parse_enum(VTE_TYPE_CURSOR_BLINK_MODE, value, v, error);
if (rv)
that->cursor_blink_mode = VteCursorBlinkMode(v);
return rv;
@@ -183,13 +229,29 @@ private:
{
Options* that = static_cast<Options*>(data);
int v;
- auto rv = that->parse_enum(VTE_TYPE_CURSOR_SHAPE, value, &v, error);
+ auto rv = that->parse_enum(VTE_TYPE_CURSOR_SHAPE, value, v, error);
if (rv)
that->cursor_shape = VteCursorShape(v);
return rv;
}
static gboolean
+ parse_bg_color(char const* option, char const* value, void* data, GError** error)
+ {
+ Options* that = static_cast<Options*>(data);
+ bool set;
+ return that->parse_color(value, &that->bg_color, &set, error);
+ }
+
+ static gboolean
+ parse_fg_color(char const* option, char const* value, void* data, GError** error)
+ {
+ Options* that = static_cast<Options*>(data);
+ bool set;
+ return that->parse_color(value, &that->fg_color, &set, error);
+ }
+
+ static gboolean
parse_cursor_bg_color(char const* option, char const* value, void* data, GError** error)
{
Options* that = static_cast<Options*>(data);
@@ -234,20 +296,22 @@ public:
GdkRGBA get_color_bg() const
{
- double alpha = whole_window_transparent ? 1.0d : get_alpha();
-
- if (reverse)
- return GdkRGBA{1.0, 1.0, 1.0, alpha};
+ double alpha;
+ if (background_pixbuf != nullptr)
+ alpha = 0.0;
+ else if (whole_window_transparent)
+ alpha = 1.0;
else
- return GdkRGBA{0.0, 0.0, 0.0, alpha};
+ alpha = get_alpha();
+
+ GdkRGBA color{bg_color};
+ color.alpha = alpha;
+ return color;
}
GdkRGBA get_color_fg() const
{
- if (reverse)
- return GdkRGBA{0.0, 0.0, 0.0, 1.0};
- else
- return GdkRGBA{1.0, 1.0, 1.0, 1.0};
+ return fg_color;
}
bool parse_argv(int argc,
@@ -261,6 +325,14 @@ public:
"Allow window operations (resize, move, raise/lower, (de)iconify)", nullptr },
{ "audible-bell", 'a', 0, G_OPTION_ARG_NONE, &audible_bell,
"Use audible terminal bell", nullptr },
+ { "background-color", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_bg_color,
+ "Set default background color", nullptr },
+ { "background-image", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_background_image,
+ "Set background image from file", "FILE" },
+ { "background-extend", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_background_extend,
+ "Set background image extend", "EXTEND" },
+ { "background-operator", 0, 0, G_OPTION_ARG_CALLBACK,
(void*)parse_background_operator,
+ "Set background draw operator", "OPERATOR" },
{ "cjk-width", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_cjk_width,
"Specify the cjk ambiguous width to use for UTF-8 encoding", "NARROW|WIDE" },
{ "cursor-blink", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_cursor_blink,
@@ -283,6 +355,8 @@ public:
"Add extra margin around the terminal widget", "MARGIN" },
{ "font", 'f', 0, G_OPTION_ARG_STRING, &font_string,
"Specify a font to use", nullptr },
+ { "foreground-color", 0, 0, G_OPTION_ARG_CALLBACK, (void*)parse_fg_color,
+ "Set default foreground color", nullptr },
{ "gregex", 0, 0, G_OPTION_ARG_NONE, &use_gregex,
"Use GRegex instead of PCRE2", nullptr },
{ "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry,
@@ -383,6 +457,15 @@ public:
g_option_context_free(context);
g_free(dummy_string);
+
+ if (reverse)
+ std::swap(fg_color, bg_color);
+
+ /* Sanity checks */
+ if (background_pixbuf != nullptr &&
+ (!background_operator_set || background_operator == CAIRO_OPERATOR_SOURCE))
+ g_printerr("Background image set but operator is SOURCE; image will not appear.\n");
+
return rv;
}
};
@@ -721,6 +804,8 @@ typedef struct _VteappTerminalClass VteappTerminalClass;
struct _VteappTerminal {
VteTerminal parent;
+
+ cairo_pattern_t* background_pattern;
};
struct _VteappTerminalClass {
@@ -732,13 +817,81 @@ static GType vteapp_terminal_get_type(void);
G_DEFINE_TYPE(VteappTerminal, vteapp_terminal, VTE_TYPE_TERMINAL)
static void
+vteapp_terminal_realize(GtkWidget* widget)
+{
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->realize(widget);
+
+ VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+ if (options.background_pixbuf != nullptr) {
+ auto surface = gdk_cairo_surface_create_from_pixbuf(options.background_pixbuf,
+ 0 /* take scale from window */,
+ gtk_widget_get_window(widget));
+ terminal->background_pattern = cairo_pattern_create_for_surface(surface);
+ cairo_surface_destroy(surface);
+
+ cairo_pattern_set_extend(terminal->background_pattern, options.background_extend);
+ }
+}
+
+static void
+vteapp_terminal_unrealize(GtkWidget* widget)
+{
+ VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+ if (terminal->background_pattern != nullptr) {
+ cairo_pattern_destroy(terminal->background_pattern);
+ terminal->background_pattern = nullptr;
+ }
+
+ GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->unrealize(widget);
+}
+
+static gboolean
+vteapp_terminal_draw(GtkWidget* widget,
+ cairo_t* cr)
+{
+ VteappTerminal* terminal = VTEAPP_TERMINAL(widget);
+ if (terminal->background_pattern != nullptr) {
+ cairo_push_group(cr);
+
+ /* Draw background colour */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0.0, 0.0,
+ gtk_widget_get_allocated_width(widget),
+ gtk_widget_get_allocated_height(widget));
+ auto bg = options.get_color_bg();
+ cairo_set_source_rgba(cr, bg.red, bg.green, bg.blue, 1.0);
+ cairo_paint(cr);
+
+ /* Draw background image */
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source(cr, terminal->background_pattern);
+ cairo_paint(cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint_with_alpha(cr, options.get_alpha());
+
+ }
+
+ return GTK_WIDGET_CLASS(vteapp_terminal_parent_class)->draw(widget, cr);
+}
+
+static void
vteapp_terminal_class_init(VteappTerminalClass *klass)
{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->realize = vteapp_terminal_realize;
+ widget_class->unrealize = vteapp_terminal_unrealize;
+ widget_class->draw = vteapp_terminal_draw;
}
static void
vteapp_terminal_init(VteappTerminal *terminal)
{
+ terminal->background_pattern = nullptr;
+
+ if (options.background_operator_set)
+ vte_terminal_set_background_operator(VTE_TERMINAL(terminal),
+ options.background_operator);
}
static GtkWidget *
diff --git a/src/vte.cc b/src/vte.cc
index 0371d70..6625f11 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -9723,6 +9723,7 @@ VteTerminalPrivate::paint_im_preedit_string()
row_to_pixel(m_screen->cursor.row),
width * columns,
height,
+ m_background_operator,
get_color(VTE_DEFAULT_BG), m_background_alpha);
fore = m_color_defaults.attr.fore;
back = m_color_defaults.attr.back;
@@ -9779,6 +9780,7 @@ VteTerminalPrivate::widget_draw(cairo_t *cr)
_vte_draw_clear (m_draw, 0, 0,
allocated_width, allocated_height,
+ m_background_operator,
get_color(VTE_DEFAULT_BG), m_background_alpha);
/* Clip vertically, for the sake of smooth scrolling. We want the top and bottom paddings to be
unused.
@@ -11428,3 +11430,9 @@ VteTerminalPrivate::set_word_char_exceptions(char const* exceptions)
return true;
}
+
+void
+VteTerminalPrivate::set_background_operator(cairo_operator_t op)
+{
+ m_background_operator = op;
+}
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 1d4a81f..2cb3024 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -458,6 +458,11 @@ void vte_terminal_set_input_enabled (VteTerminal *terminal,
_VTE_PUBLIC
gboolean vte_terminal_get_input_enabled (VteTerminal *terminal) _VTE_GNUC_NONNULL(1);
+/* rarely useful functions */
+_VTE_PUBLIC
+void vte_terminal_set_background_operator(VteTerminal* terminal,
+ cairo_operator_t op) _VTE_GNUC_NONNULL(1);
+
/* Writing contents out */
_VTE_PUBLIC
gboolean vte_terminal_write_contents_sync (VteTerminal *terminal,
diff --git a/src/vtedraw.cc b/src/vtedraw.cc
index bf53a7d..c713d44 100644
--- a/src/vtedraw.cc
+++ b/src/vtedraw.cc
@@ -820,6 +820,7 @@ _vte_draw_set_source_color_alpha (struct _vte_draw *draw,
void
_vte_draw_clear (struct _vte_draw *draw, gint x, gint y, gint width, gint height,
+ cairo_operator_t op,
vte::color::rgb const* color, double alpha)
{
_vte_debug_print (VTE_DEBUG_DRAW, "draw_clear (%d, %d, %d, %d)\n",
@@ -827,7 +828,7 @@ _vte_draw_clear (struct _vte_draw *draw, gint x, gint y, gint width, gint height
g_assert(draw->cr);
cairo_rectangle (draw->cr, x, y, width, height);
- cairo_set_operator (draw->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_operator (draw->cr, op);
_vte_draw_set_source_color_alpha(draw, color, alpha);
cairo_fill (draw->cr);
}
diff --git a/src/vtedraw.hh b/src/vtedraw.hh
index cc17a05..c45cb53 100644
--- a/src/vtedraw.hh
+++ b/src/vtedraw.hh
@@ -58,6 +58,7 @@ void _vte_draw_set_cairo(struct _vte_draw *draw,
void _vte_draw_clear(struct _vte_draw *draw,
gint x, gint y, gint width, gint height,
+ cairo_operator_t op,
vte::color::rgb const* color, double alpha);
void _vte_draw_set_text_font(struct _vte_draw *draw,
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 3dbbc73..3f6ba35 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -4004,3 +4004,29 @@ vte_terminal_write_contents_sync (VteTerminal *terminal,
return IMPL(terminal)->write_contents_sync(stream, flags, cancellable, error);
}
+
+/**
+ * vte_terminal_set_background_operator:
+ * @terminal: a #VteTerminal
+ * @operator: a #cairo_operator_t
+ *
+ * Sets the operator to use to paint the background with the background colour.
+ * The default is %CAIRO_OPERATOR_SOURCE.
+ *
+ * This function is rarely useful. One use for it is to add a background
+ * image to the terminal, in which case %CAIRO_OPERATOR_OVER is most likely
+ * the correct operator to use.
+ *
+ * If the operator is changed while the widget is already shown,
+ * you need to queue a redraw to get it applied.
+ *
+ * Since: 0.52
+ */
+void
+vte_terminal_set_background_operator(VteTerminal* terminal,
+ cairo_operator_t op)
+{
+ g_return_if_fail(VTE_IS_TERMINAL(terminal));
+
+ IMPL(terminal)->set_background_operator(op);
+}
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 0cd686b..a275f2c 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -469,6 +469,7 @@ public:
* and data, which should be dropped when unrealizing and (re)created
* when realizing. */
struct _vte_draw *m_draw;
+ cairo_operator_t m_background_operator{CAIRO_OPERATOR_SOURCE};
VtePaletteColor m_palette[VTE_PALETTE_SIZE];
@@ -1111,6 +1112,7 @@ public:
bool set_scroll_on_keystroke(bool scroll);
bool set_scroll_on_output(bool scroll);
bool set_word_char_exceptions(char const* exceptions);
+ void set_background_operator(cairo_operator_t op);
bool write_contents_sync (GOutputStream *stream,
VteWriteFlags flags,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]