2 * kmscon - Text Renderer
4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * @short_description: Text Renderer
39 #include "static_misc.h"
43 #define LOG_SUBSYSTEM "text"
46 struct kmscon_dlist list;
47 const struct kmscon_text_ops *ops;
50 static pthread_mutex_t text_mutex = PTHREAD_MUTEX_INITIALIZER;
51 static struct kmscon_dlist text__list = KMSCON_DLIST_INIT(text__list);
53 static void text_lock()
55 pthread_mutex_lock(&text_mutex);
58 static void text_unlock()
60 pthread_mutex_unlock(&text_mutex);
64 * kmscon_text_register:
65 * @ops: Text operations and name for new backend
67 * This register a new text backend with operations set to @ops. The name
68 * @ops->name must be valid.
70 * The first font that is registered automatically becomes the default and
71 * fallback. So make sure you register a safe fallback as first backend.
72 * If this is unregistered, the next in the list becomes the default
75 * Returns: 0 on success, negative error code on failure
77 int kmscon_text_register(const struct kmscon_text_ops *ops)
79 struct kmscon_dlist *iter;
80 struct text_backend *be;
83 if (!ops || !ops->name)
86 log_debug("register text backend %s", ops->name);
90 kmscon_dlist_for_each(iter, &text__list) {
91 be = kmscon_dlist_entry(iter, struct text_backend, list);
92 if (!strcmp(be->ops->name, ops->name)) {
93 log_error("registering already available backend %s",
100 be = malloc(sizeof(*be));
102 log_error("cannot allocate memory for backend");
107 memset(be, 0, sizeof(*be));
109 kmscon_dlist_link(&text__list, &be->list);
119 * kmscon_text_unregister:
120 * @name: Name of backend
122 * This unregisters the text-backend that is registered with name @name. If
123 * @name is not found, a warning is printed but nothing else is done.
125 void kmscon_text_unregister(const char *name)
127 struct kmscon_dlist *iter;
128 struct text_backend *be;
133 log_debug("unregister backend %s", name);
137 kmscon_dlist_for_each(iter, &text__list) {
138 be = kmscon_dlist_entry(iter, struct text_backend, list);
139 if (strcmp(name, be->ops->name))
142 kmscon_dlist_unlink(&be->list);
146 if (iter == &text__list)
152 log_error("cannot unregister backend %s: not found", name);
160 * @out: A pointer to the new text-renderer is stored here
161 * @backend: Backend to use or NULL for default backend
163 * Returns: 0 on success, error code on failure
165 int kmscon_text_new(struct kmscon_text **out,
168 struct kmscon_text *text;
169 struct kmscon_dlist *iter;
170 struct text_backend *be, *def;
178 if (kmscon_dlist_empty(&text__list)) {
179 log_error("no text backend available");
183 def = kmscon_dlist_entry(text__list.prev,
189 kmscon_dlist_for_each(iter, &text__list) {
190 be = kmscon_dlist_entry(iter,
193 if (!strcmp(backend, be->ops->name))
196 if (iter == &text__list) {
197 log_warning("requested backend %s not found",
207 text = malloc(sizeof(*text));
209 log_error("cannot allocate memory for new text-renderer");
213 memset(text, 0, sizeof(*text));
218 ret = text->ops->init(text);
224 log_error("default backend %s cannot create renderer",
229 log_warning("backend %s cannot create renderer; trying default backend %s",
230 be->ops->name, def->ops->name);
232 memset(text, 0, sizeof(*text));
234 text->ops = def->ops;
236 ret = text->ops->init(text);
238 log_error("default backend %s cannot create renderer",
244 log_debug("using: be: %s", text->ops->name);
258 * @text: Valid text-renderer object
260 * This increases the reference count of @text by one.
262 void kmscon_text_ref(struct kmscon_text *text)
264 if (!text || !text->ref)
272 * @text: Valid text-renderer object
274 * This decreases the reference count of @text by one. If it drops to zero, the
277 void kmscon_text_unref(struct kmscon_text *text)
279 if (!text || !text->ref || --text->ref)
282 log_debug("freeing text renderer");
283 kmscon_text_unset(text);
287 if (text->ops->destroy)
288 text->ops->destroy(text);
296 * @txt: Valid text-renderer object
298 * @screen: screen object
300 * This makes the text-renderer @txt use the font @font and screen @screen. You
301 * can drop your reference to both after calling this.
302 * This calls kmscon_text_unset() first to remove all previous associations.
303 * None of the arguments can be NULL!
304 * If this function fails then you must assume that no font/screen will be set
305 * and the object is invalid.
307 * Returns: 0 on success, negative error code on failure.
309 int kmscon_text_set(struct kmscon_text *txt,
310 struct kmscon_font *font,
311 struct uterm_screen *screen)
315 if (!txt || !font || !screen)
318 kmscon_text_unset(txt);
321 txt->screen = screen;
324 ret = txt->ops->set(txt);
332 kmscon_font_ref(txt->font);
333 uterm_screen_ref(txt->screen);
339 * kmscon_text_unset():
340 * @txt: text renderer
342 * This redos kmscon_text_set() by dropping the internal references to the font
343 * and screen and invalidating the object. You need to call kmscon_text_set()
344 * again to make use of this text renderer.
345 * This is automatically called when the text renderer is destroyed.
347 void kmscon_text_unset(struct kmscon_text *txt)
349 if (!txt || !txt->screen || !txt->font)
353 txt->ops->unset(txt);
355 kmscon_font_unref(txt->font);
356 uterm_screen_unref(txt->screen);
361 txt->rendering = false;
365 * kmscon_text_get_cols:
366 * @txt: valid text renderer
368 * After setting the arguments with kmscon_text_set(), the renderer will compute
369 * the number of columns/rows of the console that it can display on the screen.
370 * You can retrieve these values via these functions.
371 * If kmscon_text_set() hasn't been called, this will return 0.
373 * Returns: Number of columns or 0 if @txt is invalid
375 unsigned int kmscon_text_get_cols(struct kmscon_text *txt)
384 * kmscon_text_get_rows:
385 * @txt: valid text renderer
387 * After setting the arguments with kmscon_text_set(), the renderer will compute
388 * the number of columns/rows of the console that it can display on the screen.
389 * You can retrieve these values via these functions.
390 * If kmscon_text_set() hasn't been called, this will return 0.
392 * Returns: Number of rows or 0 if @txt is invalid
394 unsigned int kmscon_text_get_rows(struct kmscon_text *txt)
403 * kmscon_text_prepare:
404 * @txt: valid text renderer
406 * This starts a rendering-round. When rendering a console via a text renderer,
407 * you have to call this first, then render all your glyphs via
408 * kmscon_text_draw() and finally use kmscon_text_render(). If you modify this
409 * renderer during rendering or if you activate different OpenGL contexts in
410 * between, you need to restart rendering by calling kmscon_text_prepare() again
411 * and redoing everything from the beginning.
413 * Returns: 0 on success, negative error code on failure.
415 int kmscon_text_prepare(struct kmscon_text *txt)
419 if (!txt || !txt->font || !txt->screen)
422 txt->rendering = true;
423 if (txt->ops->prepare)
424 ret = txt->ops->prepare(txt);
426 txt->rendering = false;
433 * @txt: valid text renderer
434 * @ch: symbol you want to draw
435 * @posx: X-position of the glyph
436 * @posy: Y-position of the glyph
437 * @attr: glyph attributes
439 * This draws a single glyph at the requested position. The position is a
440 * console position, not a pixel position! You must precede this call with
441 * kmscon_text_prepare(). Use this function to feed all glyphs into the
442 * rendering pipeline and finally call kmscon_text_render().
444 * Returns: 0 on success or negative error code if this glyph couldn't be drawn.
446 int kmscon_text_draw(struct kmscon_text *txt, kmscon_symbol_t ch,
447 unsigned int posx, unsigned int posy,
448 const struct font_char_attr *attr)
450 if (!txt || !txt->rendering)
452 if (posx >= txt->cols || posy >= txt->rows || !attr)
455 return txt->ops->draw(txt, ch, posx, posy, attr);
459 * kmscon_text_render:
460 * @txt: valid text renderer
462 * This does the final rendering round after kmscon_text_prepare() has been
463 * called and all glyphs were sent to the renderer via kmscon_text_draw().
465 * Returns: 0 on success, negative error on failure.
467 int kmscon_text_render(struct kmscon_text *txt)
471 if (!txt || !txt->rendering)
474 if (txt->ops->render)
475 ret = txt->ops->render(txt);
476 txt->rendering = false;
483 * @txt: valid text renderer
485 * If you called kmscon_text_prepare() but you want to abort rendering instead
486 * of finishing it with kmscon_text_render(), you can safely call this to reset
487 * internal state. It is optional to call this or simply restart rendering.
488 * Especially if the other renderers return an error, then they probably already
489 * aborted rendering and it is not required to call this.
491 void kmscon_text_abort(struct kmscon_text *txt)
493 if (!txt || !txt->rendering)
497 txt->ops->abort(txt);
498 txt->rendering = false;