From 622f3c72e23382b7b6e2809077bffa9c5627bdd0 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 27 Mar 2012 16:11:38 +0200 Subject: [PATCH] terminal: rework API We now use the new input/video hooks to avoid waking up the UI all the time. This reduces the code in the generic UI subsystem and makes the terminal handle all the stuff. Signed-off-by: David Herrmann --- src/terminal.c | 271 ++++++++++++++++++++++++++++++++----------------- src/terminal.h | 25 +++-- src/ui.c | 28 ++--- 3 files changed, 202 insertions(+), 122 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 0f62569..cd9743b 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1,7 +1,7 @@ /* * kmscon - Terminal * - * Copyright (c) 2011 David Herrmann + * Copyright (c) 2011-2012 David Herrmann * Copyright (c) 2011 University of Tuebingen * * Permission is hereby granted, free of charge, to any person obtaining @@ -30,10 +30,13 @@ * runs a fully functional terminal emulation on it. */ +#define GL_GLEXT_PROTOTYPES + #include +#include +#include #include #include - #include "console.h" #include "eloop.h" #include "font.h" @@ -46,8 +49,12 @@ #include "uterm.h" #include "vte.h" -struct term_out { - struct term_out *next; +#define LOG_SUBSYSTEM "terminal" + +struct screen { + struct screen *next; + struct screen *prev; + struct uterm_display *disp; struct uterm_screen *screen; }; @@ -55,9 +62,12 @@ struct kmscon_terminal { unsigned long ref; struct ev_eloop *eloop; struct uterm_video *video; + struct kmscon_input *input; struct gl_shader *shader; + bool opened; - struct term_out *outputs; + struct screen *screens; + unsigned int max_width; unsigned int max_height; struct kmscon_console *console; @@ -65,20 +75,20 @@ struct kmscon_terminal { struct kmscon_vte *vte; struct kmscon_pty *pty; - kmscon_terminal_closed_cb closed_cb; - void *closed_data; + kmscon_terminal_event_cb cb; + void *data; }; static void draw_all(struct ev_idle *idle, void *data) { struct kmscon_terminal *term = data; - struct term_out *iter; + struct screen *iter; struct uterm_screen *screen; int ret; ev_eloop_rm_idle(idle); - iter = term->outputs; + iter = term->screens; for (; iter; iter = iter->next) { screen = iter->screen; @@ -87,6 +97,8 @@ static void draw_all(struct ev_idle *idle, void *data) continue; gl_viewport(screen); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); kmscon_console_map(term->console, term->shader); uterm_screen_swap(screen); } @@ -96,12 +108,96 @@ static void schedule_redraw(struct kmscon_terminal *term) { int ret; - if (!term || !term->eloop) - return; - ret = ev_eloop_add_idle(term->eloop, term->redraw, draw_all, term); if (ret && ret != -EALREADY) - log_warn("terminal: cannot schedule redraw\n"); + log_warn("terminal: cannot schedule redraw"); +} + +static int add_display(struct kmscon_terminal *term, struct uterm_display *disp) +{ + struct screen *scr; + int ret; + unsigned int width, height; + bool resize; + + scr = malloc(sizeof(*scr)); + if (!scr) + return -ENOMEM; + memset(scr, 0, sizeof(*scr)); + scr->disp = disp; + + ret = uterm_screen_new_single(&scr->screen, disp); + if (ret) { + free(scr); + return ret; + } + + scr->next = term->screens; + if (scr->next) + scr->next->prev = scr; + term->screens = scr; + + resize = false; + width = uterm_screen_width(scr->screen); + height = uterm_screen_height(scr->screen); + if (term->max_width < width) { + term->max_width = width; + resize = true; + } + if (term->max_height < height) { + term->max_height = height; + resize = true; + } + + if (resize) + kmscon_console_resize(term->console, 0, 0, term->max_height); + + log_debug("added display %p to terminal %p", disp, term); + schedule_redraw(term); + uterm_display_ref(scr->disp); + return 0; +} + +static void free_screen(struct screen *scr) +{ + uterm_screen_unref(scr->screen); + uterm_display_unref(scr->disp); + free(scr); +} + +static void rm_display(struct kmscon_terminal *term, struct uterm_display *disp) +{ + struct screen *scr; + + for (scr = term->screens; scr; scr = scr->next) { + if (scr->disp == disp) { + if (scr->prev) + scr->prev->next = scr->next; + if (scr->next) + scr->next->prev = scr->prev; + if (term->screens == scr) + term->screens = scr->next; + break; + } + } + + if (!scr) + return; + + log_debug("removed display %p from terminal %p", disp, term); + free_screen(scr); + if (!term->screens && term->cb) + term->cb(term, KMSCON_TERMINAL_NO_DISPLAY, term->data); +} + +static void rm_all_screens(struct kmscon_terminal *term) +{ + struct screen *scr; + + while ((scr = term->screens)) { + term->screens = scr->next; + free_screen(scr); + } } static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len, @@ -110,28 +206,60 @@ static void pty_input(struct kmscon_pty *pty, const char *u8, size_t len, struct kmscon_terminal *term = data; if (!len) { - if (term->closed_cb) - term->closed_cb(term, term->closed_data); + if (term->cb) + term->cb(term, KMSCON_TERMINAL_HUP, term->data); } else { kmscon_vte_input(term->vte, u8, len); schedule_redraw(term); } } +static void video_event(struct uterm_video *video, + struct uterm_video_hotplug *ev, + void *data) +{ + struct kmscon_terminal *term = data; + + if (ev->action == UTERM_GONE) + rm_display(term, ev->display); +} + +static void input_event(struct kmscon_input *input, + struct kmscon_input_event *ev, + void *data) +{ + struct kmscon_terminal *term = data; + int ret; + const char *u8; + size_t len; + + if (!term->opened) + return; + + ret = kmscon_vte_handle_keyboard(term->vte, ev, &u8, &len); + switch (ret) { + case KMSCON_VTE_SEND: + kmscon_pty_write(term->pty, u8, len); + break; + case KMSCON_VTE_DROP: + default: + break; + } +} + int kmscon_terminal_new(struct kmscon_terminal **out, struct ev_eloop *loop, + struct kmscon_symbol_table *st, struct kmscon_font_factory *ff, struct uterm_video *video, - struct kmscon_symbol_table *st) + struct kmscon_input *input) { struct kmscon_terminal *term; int ret; - if (!out) + if (!out || !loop || !st || !ff || !video || !input) return -EINVAL; - log_debug("terminal: new terminal object\n"); - term = malloc(sizeof(*term)); if (!term) return -ENOMEM; @@ -140,6 +268,7 @@ int kmscon_terminal_new(struct kmscon_terminal **out, term->ref = 1; term->eloop = loop; term->video = video; + term->input = input; ret = ev_idle_new(&term->redraw); if (ret) @@ -162,12 +291,26 @@ int kmscon_terminal_new(struct kmscon_terminal **out, if (ret) goto err_pty; + ret = uterm_video_register_cb(term->video, video_event, term); + if (ret) + goto err_shader; + + ret = kmscon_input_register_cb(term->input, input_event, term); + if (ret) + goto err_video; + ev_eloop_ref(term->eloop); uterm_video_ref(term->video); + kmscon_input_ref(term->input); *out = term; + log_debug("new terminal object %p", term); return 0; +err_video: + uterm_video_unregister_cb(term->video, video_event, term); +err_shader: + gl_shader_unref(term->shader); err_pty: kmscon_pty_unref(term->pty); err_vte: @@ -197,21 +340,25 @@ void kmscon_terminal_unref(struct kmscon_terminal *term) if (--term->ref) return; + log_debug("free terminal object %p", term); kmscon_terminal_close(term); - kmscon_terminal_rm_all_outputs(term); + rm_all_screens(term); + kmscon_input_unregister_cb(term->input, input_event, term); + uterm_video_unregister_cb(term->video, video_event, term); gl_shader_unref(term->shader); kmscon_pty_unref(term->pty); kmscon_vte_unref(term->vte); kmscon_console_unref(term->console); + ev_eloop_rm_idle(term->redraw); ev_idle_unref(term->redraw); + kmscon_input_unref(term->input); uterm_video_unref(term->video); ev_eloop_unref(term->eloop); free(term); - log_debug("terminal: destroying terminal object\n"); } int kmscon_terminal_open(struct kmscon_terminal *term, - kmscon_terminal_closed_cb closed_cb, void *data) + kmscon_terminal_event_cb cb, void *data) { int ret; unsigned short width, height; @@ -225,8 +372,9 @@ int kmscon_terminal_open(struct kmscon_terminal *term, if (ret) return ret; - term->closed_cb = closed_cb; - term->closed_data = data; + term->opened = true; + term->cb = cb; + term->data = data; return 0; } @@ -236,81 +384,16 @@ void kmscon_terminal_close(struct kmscon_terminal *term) return; kmscon_pty_close(term->pty); - term->closed_data = NULL; - term->closed_cb = NULL; + term->data = NULL; + term->cb = NULL; + term->opened = false; } -int kmscon_terminal_add_output(struct kmscon_terminal *term, +int kmscon_terminal_add_display(struct kmscon_terminal *term, struct uterm_display *disp) { - struct term_out *out; - unsigned int height; - int ret; - if (!term || !disp) return -EINVAL; - out = malloc(sizeof(*out)); - if (!out) - return -ENOMEM; - - memset(out, 0, sizeof(*out)); - ret = uterm_screen_new_single(&out->screen, disp); - if (ret) { - free(out); - return ret; - } - - out->next = term->outputs; - term->outputs = out; - - height = uterm_screen_height(out->screen); - if (term->max_height < height) { - term->max_height = height; - kmscon_console_resize(term->console, 0, 0, term->max_height); - } - - schedule_redraw(term); - - return 0; -} - -void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term) -{ - struct term_out *tmp; - - if (!term) - return; - - while (term->outputs) { - tmp = term->outputs; - term->outputs = tmp->next; - uterm_screen_unref(tmp->screen); - free(tmp); - } -} - -int kmscon_terminal_input(struct kmscon_terminal *term, - const struct kmscon_input_event *ev) -{ - int ret; - const char *u8; - size_t len; - - if (!term || !ev) - return -EINVAL; - - ret = kmscon_vte_handle_keyboard(term->vte, ev, &u8, &len); - switch (ret) { - case KMSCON_VTE_SEND: - ret = kmscon_pty_write(term->pty, u8, len); - if (ret) - return ret; - break; - case KMSCON_VTE_DROP: - default: - break; - } - - return 0; + return add_display(term, disp); } diff --git a/src/terminal.h b/src/terminal.h index 40c4cad..9841a56 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -1,7 +1,7 @@ /* * kmscon - Terminal * - * Copyright (c) 2011 David Herrmann + * Copyright (c) 2011-2012 David Herrmann * Copyright (c) 2011 University of Tuebingen * * Permission is hereby granted, free of charge, to any person obtaining @@ -38,31 +38,36 @@ #include "eloop.h" #include "font.h" #include "gl.h" +#include "input.h" #include "unicode.h" #include "uterm.h" struct kmscon_terminal; -typedef void (*kmscon_terminal_closed_cb) (struct kmscon_terminal *term, - void *data); +enum kmscon_terminal_etype { + KMSCON_TERMINAL_HUP, /* child closed */ + KMSCON_TERMINAL_NO_DISPLAY, /* no more display connected */ +}; + +typedef void (*kmscon_terminal_event_cb) + (struct kmscon_terminal *term, + enum kmscon_terminal_etype type, + void *data); int kmscon_terminal_new(struct kmscon_terminal **out, struct ev_eloop *loop, + struct kmscon_symbol_table *st, struct kmscon_font_factory *ff, struct uterm_video *video, - struct kmscon_symbol_table *st); + struct kmscon_input *input); void kmscon_terminal_ref(struct kmscon_terminal *term); void kmscon_terminal_unref(struct kmscon_terminal *term); int kmscon_terminal_open(struct kmscon_terminal *term, - kmscon_terminal_closed_cb closed_cb, void *data); + kmscon_terminal_event_cb event_cb, void *data); void kmscon_terminal_close(struct kmscon_terminal *term); -int kmscon_terminal_add_output(struct kmscon_terminal *term, +int kmscon_terminal_add_display(struct kmscon_terminal *term, struct uterm_display *disp); -void kmscon_terminal_rm_all_outputs(struct kmscon_terminal *term); - -int kmscon_terminal_input(struct kmscon_terminal *term, - const struct kmscon_input_event *ev); #endif /* KMSCON_TERMINAL_H */ diff --git a/src/ui.c b/src/ui.c index a26e2e8..e77293c 100644 --- a/src/ui.c +++ b/src/ui.c @@ -57,19 +57,18 @@ static void video_event(struct uterm_video *video, void *data) { struct kmscon_ui *ui = data; - struct uterm_display *iter; int ret; - kmscon_terminal_rm_all_outputs(ui->term); - iter = uterm_video_get_displays(ui->video); - for ( ; iter; iter = uterm_display_next(iter)) { - if (uterm_display_get_state(iter) == UTERM_DISPLAY_INACTIVE) { - ret = uterm_display_activate(iter, NULL); + if (ev->action == UTERM_NEW) { + if (uterm_display_get_state(ev->display) == UTERM_DISPLAY_INACTIVE) { + ret = uterm_display_activate(ev->display, NULL); if (ret) - continue; + return; + ret = uterm_display_set_dpms(ev->display, UTERM_DPMS_ON); + if (ret) + return; } - - kmscon_terminal_add_output(ui->term, iter); + kmscon_terminal_add_display(ui->term, ev->display); } } @@ -77,14 +76,6 @@ static void input_event(struct kmscon_input *input, struct kmscon_input_event *ev, void *data) { - struct kmscon_ui *ui = data; - int ret; - - ret = kmscon_terminal_input(ui->term, ev); - if (ret) { - kmscon_terminal_close(ui->term); - ev_eloop_exit(ui->eloop); - } } int kmscon_ui_new(struct kmscon_ui **out, @@ -114,7 +105,8 @@ int kmscon_ui_new(struct kmscon_ui **out, if (ret) goto err_st; - ret = kmscon_terminal_new(&ui->term, eloop, ui->ff, ui->video, ui->st); + ret = kmscon_terminal_new(&ui->term, eloop, ui->st, ui->ff, ui->video, + ui->input); if (ret) goto err_ff;