text->ref = 1;
text->ops = be->ops;
- ret = text->ops->init(text);
+ if (text->ops->init)
+ ret = text->ops->init(text);
+ else
+ ret = 0;
+
if (ret) {
if (be == def) {
log_error("default backend %s cannot create renderer",
if (!text || !text->ref || --text->ref)
return;
- text_lock();
log_debug("freeing text renderer");
- text->ops->destroy(text);
- kmscon_font_unref(text->font);
- uterm_screen_unref(text->screen);
+ kmscon_text_unset(text);
+
+ text_lock();
+
+ if (text->ops->destroy)
+ text->ops->destroy(text);
free(text);
+
text_unlock();
}
/**
- * kmscon_text_set_font:
+ * kmscon_text_set:
* @txt: Valid text-renderer object
- * @font: Valid font object
+ * @font: font object
+ * @screen: screen object
*
- * This makes the text-renderer @txt use the font @font. You can drop your
- * reference to @font after calling this.
+ * This makes the text-renderer @txt use the font @font and screen @screen. You
+ * can drop your reference to both after calling this.
+ * This calls kmscon_text_unset() first to remove all previous associations.
+ * None of the arguments can be NULL!
+ * If this function fails then you must assume that no font/screen will be set
+ * and the object is invalid.
+ *
+ * Returns: 0 on success, negative error code on failure.
*/
-void kmscon_text_set_font(struct kmscon_text *txt,
- struct kmscon_font *font)
+int kmscon_text_set(struct kmscon_text *txt,
+ struct kmscon_font *font,
+ struct uterm_screen *screen)
{
- if (!txt || !font)
- return;
+ int ret;
+
+ if (!txt || !font || !screen)
+ return -EINVAL;
+
+ kmscon_text_unset(txt);
- kmscon_font_unref(txt->font);
txt->font = font;
+ txt->screen = screen;
+
+ if (txt->ops->set) {
+ ret = txt->ops->set(txt);
+ if (ret) {
+ txt->font = NULL;
+ txt->screen = NULL;
+ return ret;
+ }
+ }
+
kmscon_font_ref(txt->font);
+ uterm_screen_ref(txt->screen);
- txt->ops->new_font(txt);
+ return 0;
}
/**
- * kmscon_text_set_bgcolor:
- * @txt: Valid text-renderer object
- * @r: red value
- * @g: green value
- * @b: blue value
+ * kmscon_text_unset():
+ * @txt: text renderer
*
- * This sets the background color to r/g/b. The background color is a solid
- * color which is used for the whole background. You should give the same as the
- * default background color of your characters as this will speed up the drawing
- * operations.
+ * This redos kmscon_text_set() by dropping the internal references to the font
+ * and screen and invalidating the object. You need to call kmscon_text_set()
+ * again to make use of this text renderer.
+ * This is automatically called when the text renderer is destroyed.
*/
-void kmscon_text_set_bgcolor(struct kmscon_text *txt,
- uint8_t r, uint8_t g, uint8_t b)
+void kmscon_text_unset(struct kmscon_text *txt)
{
- if (!txt)
+ if (!txt || !txt->screen || !txt->font)
return;
- txt->bg_r = r;
- txt->bg_g = g;
- txt->bg_b = b;
-
- txt->ops->new_bgcolor(txt);
-}
-
-void kmscon_text_set_screen(struct kmscon_text *txt,
- struct uterm_screen *screen)
-{
- if (!txt || !screen)
- return;
+ if (txt->ops->unset)
+ txt->ops->unset(txt);
+ kmscon_font_unref(txt->font);
uterm_screen_unref(txt->screen);
- txt->screen = screen;
- uterm_screen_ref(txt->screen);
-
- txt->ops->new_screen(txt);
+ txt->font = NULL;
+ txt->screen = NULL;
+ txt->cols = 0;
+ txt->rows = 0;
+ txt->rendering = false;
}
+/**
+ * kmscon_text_get_cols:
+ * @txt: valid text renderer
+ *
+ * After setting the arguments with kmscon_text_set(), the renderer will compute
+ * the number of columns/rows of the console that it can display on the screen.
+ * You can retrieve these values via these functions.
+ * If kmscon_text_set() hasn't been called, this will return 0.
+ *
+ * Returns: Number of columns or 0 if @txt is invalid
+ */
unsigned int kmscon_text_get_cols(struct kmscon_text *txt)
{
if (!txt)
return txt->cols;
}
+/**
+ * kmscon_text_get_rows:
+ * @txt: valid text renderer
+ *
+ * After setting the arguments with kmscon_text_set(), the renderer will compute
+ * the number of columns/rows of the console that it can display on the screen.
+ * You can retrieve these values via these functions.
+ * If kmscon_text_set() hasn't been called, this will return 0.
+ *
+ * Returns: Number of rows or 0 if @txt is invalid
+ */
unsigned int kmscon_text_get_rows(struct kmscon_text *txt)
{
if (!txt)
return txt->rows;
}
-void kmscon_text_prepare(struct kmscon_text *txt)
+/**
+ * kmscon_text_prepare:
+ * @txt: valid text renderer
+ *
+ * This starts a rendering-round. When rendering a console via a text renderer,
+ * you have to call this first, then render all your glyphs via
+ * kmscon_text_draw() and finally use kmscon_text_render(). If you modify this
+ * renderer during rendering or if you activate different OpenGL contexts in
+ * between, you need to restart rendering by calling kmscon_text_prepare() again
+ * and redoing everything from the beginning.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int kmscon_text_prepare(struct kmscon_text *txt)
{
+ int ret = 0;
+
if (!txt || !txt->font || !txt->screen)
- return;
+ return -EINVAL;
txt->rendering = true;
- txt->ops->prepare(txt);
+ if (txt->ops->prepare)
+ ret = txt->ops->prepare(txt);
+ if (ret)
+ txt->rendering = false;
+
+ return ret;
}
-void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
+/**
+ * kmscon_text_draw:
+ * @txt: valid text renderer
+ * @ch: symbol you want to draw
+ * @posx: X-position of the glyph
+ * @posy: Y-position of the glyph
+ * @attr: glyph attributes
+ *
+ * This draws a single glyph at the requested position. The position is a
+ * console position, not a pixel position! You must precede this call with
+ * kmscon_text_prepare(). Use this function to feed all glyphs into the
+ * rendering pipeline and finally call kmscon_text_render().
+ *
+ * Returns: 0 on success or negative error code if this glyph couldn't be drawn.
+ */
+int kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
unsigned int posx, unsigned int posy,
const struct font_char_attr *attr)
{
if (!txt || !txt->rendering)
- return;
+ return -EINVAL;
if (posx >= txt->cols || posy >= txt->rows || !attr)
- return;
+ return -EINVAL;
- txt->ops->draw(txt, ch, posx, posy, attr);
+ return txt->ops->draw(txt, ch, posx, posy, attr);
}
-void kmscon_text_render(struct kmscon_text *txt)
+/**
+ * kmscon_text_render:
+ * @txt: valid text renderer
+ *
+ * This does the final rendering round after kmscon_text_prepare() has been
+ * called and all glyphs were sent to the renderer via kmscon_text_draw().
+ *
+ * Returns: 0 on success, negative error on failure.
+ */
+int kmscon_text_render(struct kmscon_text *txt)
+{
+ int ret = 0;
+
+ if (!txt || !txt->rendering)
+ return -EINVAL;
+
+ if (txt->ops->render)
+ ret = txt->ops->render(txt);
+ txt->rendering = false;
+
+ return ret;
+}
+
+/**
+ * kmscon_text_abort:
+ * @txt: valid text renderer
+ *
+ * If you called kmscon_text_prepare() but you want to abort rendering instead
+ * of finishing it with kmscon_text_render(), you can safely call this to reset
+ * internal state. It is optional to call this or simply restart rendering.
+ * Especially if the other renderers return an error, then they probably already
+ * aborted rendering and it is not required to call this.
+ */
+void kmscon_text_abort(struct kmscon_text *txt)
{
if (!txt || !txt->rendering)
return;
- txt->ops->render(txt);
+ if (txt->ops->abort)
+ txt->ops->abort(txt);
txt->rendering = false;
}
struct kmscon_text {
unsigned long ref;
const struct kmscon_text_ops *ops;
+ void *data;
+
struct kmscon_font *font;
struct uterm_screen *screen;
- uint8_t bg_r;
- uint8_t bg_g;
- uint8_t bg_b;
unsigned int cols;
unsigned int rows;
bool rendering;
- void *data;
};
struct kmscon_text_ops {
const char *name;
int (*init) (struct kmscon_text *txt);
void (*destroy) (struct kmscon_text *txt);
- void (*new_font) (struct kmscon_text *txt);
- void (*new_bgcolor) (struct kmscon_text *txt);
- void (*new_screen) (struct kmscon_text *txt);
- void (*prepare) (struct kmscon_text *txt);
- void (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch,
- unsigned int posx, unsigned int posy,
- const struct font_char_attr *attr);
- void (*render) (struct kmscon_text *txt);
+ int (*set) (struct kmscon_text *txt);
+ void (*unset) (struct kmscon_text *txt);
+ int (*prepare) (struct kmscon_text *txt);
+ int (*draw) (struct kmscon_text *txt, kmscon_symbol_t ch,
+ unsigned int posx, unsigned int posy,
+ const struct font_char_attr *attr);
+ int (*render) (struct kmscon_text *txt);
+ void (*abort) (struct kmscon_text *txt);
};
int kmscon_text_register(const struct kmscon_text_ops *ops);
void kmscon_text_ref(struct kmscon_text *txt);
void kmscon_text_unref(struct kmscon_text *txt);
-void kmscon_text_set_font(struct kmscon_text *txt,
- struct kmscon_font *font);
-void kmscon_text_set_bgcolor(struct kmscon_text *txt,
- uint8_t r, uint8_t g, uint8_t b);
-void kmscon_text_set_screen(struct kmscon_text *txt,
- struct uterm_screen *screen);
+int kmscon_text_set(struct kmscon_text *txt,
+ struct kmscon_font *font,
+ struct uterm_screen *screen);
+void kmscon_text_unset(struct kmscon_text *txt);
unsigned int kmscon_text_get_cols(struct kmscon_text *txt);
unsigned int kmscon_text_get_rows(struct kmscon_text *txt);
-void kmscon_text_prepare(struct kmscon_text *txt);
-void kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
+int kmscon_text_prepare(struct kmscon_text *txt);
+int kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
unsigned int posx, unsigned int posy,
const struct font_char_attr *attr);
-void kmscon_text_render(struct kmscon_text *txt);
+int kmscon_text_render(struct kmscon_text *txt);
+void kmscon_text_abort(struct kmscon_text *txt);
/* modularized backends */
#define LOG_SUBSYSTEM "text_bblit"
-static int bblit_init(struct kmscon_text *txt)
-{
- return 0;
-}
-
-static void bblit_destroy(struct kmscon_text *txt)
-{
-}
-
-static void bblit_recalculate_size(struct kmscon_text *txt)
+static int bblit_set(struct kmscon_text *txt)
{
unsigned int sw, sh, fw, fh;
- if (!txt->font || !txt->screen)
- return;
-
fw = txt->font->attr.width;
fh = txt->font->attr.height;
sw = uterm_screen_width(txt->screen);
txt->cols = sw / fw;
txt->rows = sh / fh;
-}
-
-static void bblit_new_font(struct kmscon_text *txt)
-{
- bblit_recalculate_size(txt);
-}
-
-static void bblit_new_bgcolor(struct kmscon_text *txt)
-{
-}
-static void bblit_new_screen(struct kmscon_text *txt)
-{
- bblit_recalculate_size(txt);
-}
-
-static void bblit_prepare(struct kmscon_text *txt)
-{
+ return 0;
}
-static void bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
- unsigned int posx, unsigned int posy,
- const struct font_char_attr *attr)
+static int bblit_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
+ unsigned int posx, unsigned int posy,
+ const struct font_char_attr *attr)
{
const struct kmscon_glyph *glyph;
int ret;
if (ret) {
ret = kmscon_font_render_inval(txt->font, &glyph);
if (ret)
- return;
+ return ret;
}
/* draw glyph */
if (attr->inverse) {
- uterm_screen_blend(txt->screen, &glyph->buf,
- posx * txt->font->attr.width,
- posy * txt->font->attr.height,
- attr->br, attr->bg, attr->bb,
- attr->fr, attr->fg, attr->fb);
+ ret = uterm_screen_blend(txt->screen, &glyph->buf,
+ posx * txt->font->attr.width,
+ posy * txt->font->attr.height,
+ attr->br, attr->bg, attr->bb,
+ attr->fr, attr->fg, attr->fb);
} else {
- uterm_screen_blend(txt->screen, &glyph->buf,
- posx * txt->font->attr.width,
- posy * txt->font->attr.height,
- attr->fr, attr->fg, attr->fb,
- attr->br, attr->bg, attr->bb);
+ ret = uterm_screen_blend(txt->screen, &glyph->buf,
+ posx * txt->font->attr.width,
+ posy * txt->font->attr.height,
+ attr->fr, attr->fg, attr->fb,
+ attr->br, attr->bg, attr->bb);
}
-}
-static void bblit_render(struct kmscon_text *txt)
-{
+ return ret;
}
static const struct kmscon_text_ops kmscon_text_bblit_ops = {
.name = "bblit",
- .init = bblit_init,
- .destroy = bblit_destroy,
- .new_font = bblit_new_font,
- .new_bgcolor = bblit_new_bgcolor,
- .new_screen = bblit_new_screen,
- .prepare = bblit_prepare,
+ .init = NULL,
+ .destroy = NULL,
+ .set = bblit_set,
+ .unset = NULL,
+ .prepare = NULL,
.draw = bblit_draw,
- .render = bblit_render,
+ .render = NULL,
+ .abort = NULL,
};
int kmscon_text_bblit_load(void)