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.
27 * Wayland Terminal console helpers
34 #include <wayland-client.h>
35 #include <xkbcommon/xkbcommon.h>
42 #include "tsm_unicode.h"
43 #include "tsm_screen.h"
46 #include "wlt_terminal.h"
47 #include "wlt_toolkit.h"
49 #define LOG_SUBSYSTEM "wlt_terminal"
52 struct ev_eloop *eloop;
53 struct wlt_window *wnd;
54 struct wlt_widget *widget;
55 struct wlt_shm_buffer buffer;
57 struct tsm_screen *scr;
59 struct kmscon_pty *pty;
63 struct kmscon_font *font_normal;
71 static int draw_cell(struct tsm_screen *scr,
72 uint32_t id, const uint32_t *ch, size_t len,
73 unsigned int posx, unsigned int posy,
74 const struct tsm_screen_attr *attr, void *data)
76 struct wlt_terminal *term = data;
77 const struct kmscon_glyph *glyph;
79 unsigned int x, y, tmp, width, height, i, r, g, b;
81 const struct uterm_video_buffer *buf;
82 unsigned int fr, fg, fb, br, bg, bb;
86 ret = kmscon_font_render_empty(term->font_normal, &glyph);
88 ret = kmscon_font_render(term->font_normal, id, ch, len,
92 ret = kmscon_font_render_inval(term->font_normal, &glyph);
98 x = posx * term->font_normal->attr.width;
99 y = posy * term->font_normal->attr.height;
117 tmp = x + buf->width;
118 if (tmp < x || x >= term->buffer.width)
120 if (tmp > term->buffer.width)
121 width = term->buffer.width - x;
125 tmp = y + buf->height;
126 if (tmp < y || y >= term->buffer.height)
128 if (tmp > term->buffer.height)
129 height = term->buffer.height - y;
131 height = buf->height;
133 dst = term->buffer.data;
134 dst = &dst[y * term->buffer.stride + x * 4];
137 /* Division by 256 instead of 255 increases
138 * speed by like 20% on slower machines.
139 * Downside is, full white is 254/254/254
140 * instead of 255/255/255. */
142 for (i = 0; i < width; ++i) {
147 } else if (src[i] == 255) {
162 val = (0xff << 24) | (r << 16) | (g << 8) | b;
163 ((uint32_t*)dst)[i] = val;
165 dst += term->buffer.stride;
172 static void widget_redraw(struct wlt_widget *widget, void *data)
174 struct wlt_terminal *term = data;
176 tsm_screen_draw(term->scr, NULL, draw_cell, NULL, term);
179 static void widget_resize(struct wlt_widget *widget, struct wlt_rect *alloc,
182 struct wlt_terminal *term = data;
185 wlt_window_get_buffer(term->wnd, alloc, &term->buffer);
187 /* don't allow children */
191 term->cols = term->buffer.width / term->font_normal->attr.width;
194 term->rows = term->buffer.height / term->font_normal->attr.height;
198 ret = tsm_screen_resize(term->scr, term->cols, term->rows);
200 log_error("cannot resize TSM screen: %d", ret);
201 kmscon_pty_resize(term->pty, term->cols, term->rows);
204 static void widget_prepare_resize(struct wlt_widget *widget,
205 unsigned int width, unsigned int height,
206 unsigned int *min_width,
207 unsigned int *min_height,
208 unsigned int *new_width,
209 unsigned int *new_height,
212 struct wlt_terminal *term = data;
215 if (*new_width >= width) {
216 *new_width += term->font_normal->attr.width;
218 w = width - *new_width;
219 w /= term->font_normal->attr.width;
222 w *= term->font_normal->attr.width;
226 if (*new_width < *min_width) {
227 w = *min_width - *new_width;
228 w /= term->font_normal->attr.width;
230 w *= term->font_normal->attr.width;
234 if (*new_height >= height) {
235 *new_height += term->font_normal->attr.height;
237 h = height - *new_height;
238 h /= term->font_normal->attr.height;
241 h *= term->font_normal->attr.height;
245 if (*new_height < *min_height) {
246 h = *min_height - *new_height;
247 h /= term->font_normal->attr.height;
249 h *= term->font_normal->attr.height;
254 static void widget_key(struct wlt_widget *widget, unsigned int mask,
255 uint32_t sym, uint32_t state, void *data)
257 struct wlt_terminal *term = data;
260 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
263 ucs4 = xkb_keysym_to_utf32(sym) ? : TSM_VTE_INVALID;
265 if (SHL_HAS_BITS(mask, wlt_conf.grab_scroll_up->mods) &&
266 sym == wlt_conf.grab_scroll_up->keysym) {
267 tsm_screen_sb_up(term->scr, 1);
268 wlt_window_schedule_redraw(term->wnd);
271 if (SHL_HAS_BITS(mask, wlt_conf.grab_scroll_down->mods) &&
272 sym == wlt_conf.grab_scroll_down->keysym) {
273 tsm_screen_sb_down(term->scr, 1);
274 wlt_window_schedule_redraw(term->wnd);
277 if (SHL_HAS_BITS(mask, wlt_conf.grab_page_up->mods) &&
278 sym == wlt_conf.grab_page_up->keysym) {
279 tsm_screen_sb_page_up(term->scr, 1);
280 wlt_window_schedule_redraw(term->wnd);
283 if (SHL_HAS_BITS(mask, wlt_conf.grab_page_down->mods) &&
284 sym == wlt_conf.grab_page_down->keysym) {
285 tsm_screen_sb_page_down(term->scr, 1);
286 wlt_window_schedule_redraw(term->wnd);
290 if (tsm_vte_handle_keyboard(term->vte, sym, mask, ucs4))
291 wlt_window_schedule_redraw(term->wnd);
294 static void vte_event(struct tsm_vte *vte, const char *u8, size_t len,
297 struct wlt_terminal *term = data;
299 kmscon_pty_write(term->pty, u8, len);
302 static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len,
305 struct wlt_terminal *term = data;
308 term->pty_open = false;
310 term->cb(term, WLT_TERMINAL_HUP, term->data);
312 tsm_vte_input(term->vte, u8, len);
313 wlt_window_schedule_redraw(term->wnd);
317 static void pty_event(struct ev_fd *fd, int mask, void *data)
319 struct wlt_terminal *term = data;
321 kmscon_pty_dispatch(term->pty);
324 static void widget_destroy(struct wlt_widget *widget, void *data)
326 struct wlt_terminal *term = data;
328 tsm_vte_unref(term->vte);
329 tsm_screen_unref(term->scr);
333 int wlt_terminal_new(struct wlt_terminal **out, struct wlt_window *wnd)
335 struct wlt_terminal *term;
337 struct kmscon_font_attr attr = { "", 0, 20, false, false, 0, 0 };
342 term = malloc(sizeof(*term));
345 memset(term, 0, sizeof(*term));
347 term->eloop = wlt_window_get_eloop(wnd);
351 attr.ppi = wlt_conf.font_ppi;
352 attr.points = wlt_conf.font_size;
353 strncpy(attr.name, wlt_conf.font_name, KMSCON_FONT_MAX_NAME - 1);
354 attr.name[KMSCON_FONT_MAX_NAME - 1] = 0;
356 ret = kmscon_font_find(&term->font_normal, &attr, wlt_conf.font_engine);
358 log_error("cannot create font");
362 ret = tsm_screen_new(&term->scr, log_llog);
364 log_error("cannot create tsm-screen object");
367 tsm_screen_set_max_sb(term->scr, wlt_conf.sb_size);
369 ret = tsm_vte_new(&term->vte, term->scr, vte_event, term, log_llog);
371 log_error("cannot create tsm-vte object");
374 tsm_vte_set_palette(term->vte, wlt_conf.palette);
376 ret = kmscon_pty_new(&term->pty, pty_input, term);
378 log_error("cannot create pty object");
381 kmscon_pty_set_term(term->pty, "xterm-256color");
383 ret = kmscon_pty_set_term(term->pty, wlt_conf.term);
387 ret = kmscon_pty_set_argv(term->pty, wlt_conf.argv);
391 ret = ev_eloop_new_fd(term->eloop, &term->pty_fd,
392 kmscon_pty_get_fd(term->pty),
393 EV_READABLE, pty_event, term);
397 ret = wlt_window_create_widget(wnd, &term->widget, term);
399 log_error("cannot create terminal widget");
403 wlt_widget_set_destroy_cb(term->widget, widget_destroy);
404 wlt_widget_set_redraw_cb(term->widget, widget_redraw);
405 wlt_widget_set_resize_cb(term->widget, widget_prepare_resize,
407 wlt_widget_set_keyboard_cb(term->widget, widget_key);
412 ev_eloop_rm_fd(term->pty_fd);
414 kmscon_pty_unref(term->pty);
416 tsm_vte_unref(term->vte);
418 tsm_screen_unref(term->scr);
420 kmscon_font_unref(term->font_normal);
426 void wlt_terminal_destroy(struct wlt_terminal *term)
431 wlt_widget_destroy(term->widget);
434 int wlt_terminal_open(struct wlt_terminal *term, wlt_terminal_cb cb,
448 kmscon_pty_close(term->pty);
449 ret = kmscon_pty_open(term->pty, term->cols, term->rows);
453 term->pty_open = true;