]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/console/consoled-terminal.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 static int terminal_write_fn(term_screen
*screen
, void *userdata
, const void *buf
, size_t size
) {
31 Terminal
*t
= userdata
;
35 r
= pty_write(t
->pty
, buf
, size
);
43 static int terminal_pty_fn(Pty
*pty
, void *userdata
, unsigned int event
, const void *ptr
, size_t size
) {
44 Terminal
*t
= userdata
;
49 log_debug("PTY child exited");
50 t
->pty
= pty_unref(t
->pty
);
53 r
= term_screen_feed_text(t
->screen
, ptr
, size
);
55 log_error_errno(-r
, "Cannot update screen state: %m");
57 workspace_dirty(t
->workspace
);
64 int terminal_new(Terminal
**out
, Workspace
*w
) {
65 _cleanup_(terminal_freep
) Terminal
*t
= NULL
;
70 t
= new0(Terminal
, 1);
75 LIST_PREPEND(terminals_by_workspace
, w
->terminal_list
, t
);
77 r
= term_parser_new(&t
->parser
, true);
81 r
= term_screen_new(&t
->screen
, terminal_write_fn
, t
, NULL
, NULL
);
85 r
= term_screen_set_answerback(t
->screen
, "systemd-console");
95 Terminal
*terminal_free(Terminal
*t
) {
102 (void)pty_signal(t
->pty
, SIGHUP
);
106 term_screen_unref(t
->screen
);
107 term_parser_free(t
->parser
);
108 LIST_REMOVE(terminals_by_workspace
, t
->workspace
->terminal_list
, t
);
114 void terminal_resize(Terminal
*t
) {
115 uint32_t width
, height
, fw
, fh
;
120 width
= t
->workspace
->width
;
121 height
= t
->workspace
->height
;
122 fw
= unifont_get_width(t
->workspace
->manager
->uf
);
123 fh
= unifont_get_height(t
->workspace
->manager
->uf
);
125 width
= (fw
> 0) ? width
/ fw
: 0;
126 height
= (fh
> 0) ? height
/ fh
: 0;
129 r
= pty_resize(t
->pty
, width
, height
);
131 log_error_errno(-r
, "Cannot resize pty: %m");
134 r
= term_screen_resize(t
->screen
, width
, height
);
136 log_error_errno(-r
, "Cannot resize screen: %m");
139 void terminal_run(Terminal
*t
) {
147 pid
= pty_fork(&t
->pty
,
148 t
->workspace
->manager
->event
,
151 term_screen_get_width(t
->screen
),
152 term_screen_get_height(t
->screen
));
154 log_error_errno(-pid
, "Cannot fork PTY: %m");
156 } else if (pid
== 0) {
159 char **argv
= (char*[]){
160 (char*)getenv("SHELL") ? : (char*)_PATH_BSHELL
,
164 setenv("TERM", "xterm-256color", 1);
165 setenv("COLORTERM", "systemd-console", 1);
167 execve(argv
[0], argv
, environ
);
168 log_error("Cannot exec %s (%d): %m", argv
[0], -errno
);
173 static void terminal_feed_keyboard(Terminal
*t
, idev_data
*data
) {
174 idev_data_keyboard
*kdata
= &data
->keyboard
;
177 if (!data
->resync
&& (kdata
->value
== 1 || kdata
->value
== 2)) {
178 assert_cc(TERM_KBDMOD_CNT
== (int)IDEV_KBDMOD_CNT
);
179 assert_cc(TERM_KBDMOD_IDX_SHIFT
== (int)IDEV_KBDMOD_IDX_SHIFT
&&
180 TERM_KBDMOD_IDX_CTRL
== (int)IDEV_KBDMOD_IDX_CTRL
&&
181 TERM_KBDMOD_IDX_ALT
== (int)IDEV_KBDMOD_IDX_ALT
&&
182 TERM_KBDMOD_IDX_LINUX
== (int)IDEV_KBDMOD_IDX_LINUX
&&
183 TERM_KBDMOD_IDX_CAPS
== (int)IDEV_KBDMOD_IDX_CAPS
);
185 r
= term_screen_feed_keyboard(t
->screen
,
192 log_error("Cannot feed keyboard data to screen: %s",
197 void terminal_feed(Terminal
*t
, idev_data
*data
) {
198 switch (data
->type
) {
199 case IDEV_DATA_KEYBOARD
:
200 terminal_feed_keyboard(t
, data
);
205 static void terminal_fill(uint8_t *dst
,
212 for (j
= 0; j
< height
; ++j
) {
215 for (i
= 0; i
< width
; ++i
)
222 static void terminal_blend(uint8_t *dst
,
232 for (j
= 0; j
< height
; ++j
) {
235 for (i
= 0; i
< width
; ++i
) {
236 if (!src
|| src
[i
/ 8] & (1 << (7 - i
% 8)))
250 const grdev_display_target
*target
;
253 uint32_t cell_height
;
255 } TerminalDrawContext
;
257 static int terminal_draw_cell(term_screen
*screen
,
261 const term_attr
*attr
,
264 unsigned int ch_width
) {
265 TerminalDrawContext
*ctx
= userdata
;
266 const grdev_display_target
*target
= ctx
->target
;
267 grdev_fb
*fb
= target
->back
;
268 uint32_t xpos
, ypos
, width
, height
;
275 r
= unifont_lookup(ctx
->uf
, &g
, *ch
);
277 r
= unifont_lookup(ctx
->uf
, &g
, 0xfffd);
279 unifont_fallback(&g
);
282 xpos
= x
* ctx
->cell_width
;
283 ypos
= y
* ctx
->cell_height
;
285 if (xpos
>= fb
->width
|| ypos
>= fb
->height
)
288 width
= MIN(fb
->width
- xpos
, ctx
->cell_width
* ch_width
);
289 height
= MIN(fb
->height
- ypos
, ctx
->cell_height
);
291 term_attr_to_argb32(attr
, &fg
, &bg
, NULL
);
296 dst
+= fb
->strides
[0] * ypos
+ sizeof(uint32_t) * xpos
;
306 terminal_fill(dst
+ sizeof(uint32_t) * g
.width
,
311 if (height
> g
.height
)
312 terminal_fill(dst
+ fb
->strides
[0] * g
.height
,
331 bool terminal_draw(Terminal
*t
, const grdev_display_target
*target
) {
332 TerminalDrawContext ctx
= { };
338 /* start up terminal on first frame */
342 ctx
.uf
= t
->workspace
->manager
->uf
;
343 ctx
.cell_width
= unifont_get_width(ctx
.uf
);
344 ctx
.cell_height
= unifont_get_height(ctx
.uf
);
348 /* if the frontbuffer is new enough, no reason to redraw */
349 age
= term_screen_get_age(t
->screen
);
350 if (age
!= 0 && age
<= target
->front
->data
.u64
)
353 /* force flip if no frontbuffer is set, yet */
357 term_screen_draw(t
->screen
, terminal_draw_cell
, &ctx
, &target
->back
->data
.u64
);