Changes in uspace/app/terminal/terminal.c [e273e9e:211fd68] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/terminal/terminal.c
re273e9e r211fd68 40 40 #include <errno.h> 41 41 #include <fbfont/font-8x16.h> 42 #include <io/chargrid.h> 42 43 #include <fibril.h> 43 44 #include <gfx/bitmap.h> … … 48 49 #include <io/console.h> 49 50 #include <io/pixelmap.h> 50 #include < macros.h>51 #include <task.h> 51 52 #include <stdarg.h> 52 53 #include <stdio.h> 53 54 #include <stdlib.h> 54 #include <str_error.h>55 55 #include <str.h> 56 #include <task.h>57 56 #include <ui/resource.h> 58 57 #include <ui/ui.h> … … 70 69 71 70 #define TERM_CAPS \ 72 (CONSOLE_CAP_CURSORCTL | CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | \ 73 CONSOLE_CAP_RGB) 74 75 #define SCROLLBACK_MAX_LINES 1000 76 #define MIN_WINDOW_COLS 8 77 #define MIN_WINDOW_ROWS 4 71 (CONSOLE_CAP_STYLE | CONSOLE_CAP_INDEXED | CONSOLE_CAP_RGB) 78 72 79 73 static LIST_INITIALIZE(terms); 80 81 #define COLOR_BRIGHT 882 83 static const pixel_t _basic_colors[16] = {84 [COLOR_BLACK] = PIXEL(255, 0, 0, 0),85 [COLOR_RED] = PIXEL(255, 170, 0, 0),86 [COLOR_GREEN] = PIXEL(255, 0, 170, 0),87 [COLOR_YELLOW] = PIXEL(255, 170, 85, 0),88 [COLOR_BLUE] = PIXEL(255, 0, 0, 170),89 [COLOR_MAGENTA] = PIXEL(255, 170, 0, 170),90 [COLOR_CYAN] = PIXEL(255, 0, 170, 170),91 [COLOR_WHITE] = PIXEL(255, 170, 170, 170),92 93 [COLOR_BLACK | COLOR_BRIGHT] = PIXEL(255, 85, 85, 85),94 [COLOR_RED | COLOR_BRIGHT] = PIXEL(255, 255, 85, 85),95 [COLOR_GREEN | COLOR_BRIGHT] = PIXEL(255, 85, 255, 85),96 [COLOR_YELLOW | COLOR_BRIGHT] = PIXEL(255, 255, 255, 85),97 [COLOR_BLUE | COLOR_BRIGHT] = PIXEL(255, 85, 85, 255),98 [COLOR_MAGENTA | COLOR_BRIGHT] = PIXEL(255, 255, 85, 255),99 [COLOR_CYAN | COLOR_BRIGHT] = PIXEL(255, 85, 255, 255),100 [COLOR_WHITE | COLOR_BRIGHT] = PIXEL(255, 255, 255, 255),101 };102 74 103 75 static errno_t term_open(con_srvs_t *, con_srv_t *); … … 147 119 static void terminal_close_event(ui_window_t *, void *); 148 120 static void terminal_focus_event(ui_window_t *, void *, unsigned); 149 static void terminal_resize_event(ui_window_t *, void *);150 121 static void terminal_kbd_event(ui_window_t *, void *, kbd_event_t *); 151 122 static void terminal_pos_event(ui_window_t *, void *, pos_event_t *); 152 123 static void terminal_unfocus_event(ui_window_t *, void *, unsigned); 153 static void terminal_maximize_event(ui_window_t *, void *);154 static void terminal_unmaximize_event(ui_window_t *, void *);155 124 156 125 static ui_window_cb_t terminal_window_cb = { 157 126 .close = terminal_close_event, 158 127 .focus = terminal_focus_event, 159 .resize = terminal_resize_event,160 128 .kbd = terminal_kbd_event, 161 129 .pos = terminal_pos_event, 162 .unfocus = terminal_unfocus_event, 163 .maximize = terminal_maximize_event, 164 .unmaximize = terminal_unmaximize_event, 130 .unfocus = terminal_unfocus_event 165 131 }; 166 132 … … 178 144 } 179 145 180 static pixel_t termui_color_to_pixel(termui_color_t c) 181 { 182 uint8_t r, g, b; 183 termui_color_to_rgb(c, &r, &g, &b); 184 return PIXEL(255, r, g, b); 185 } 186 187 static termui_color_t termui_color_from_pixel(pixel_t pixel) 188 { 189 return termui_color_from_rgb(RED(pixel), GREEN(pixel), BLUE(pixel)); 190 } 191 192 static termui_cell_t charfield_to_termui_cell(terminal_t *term, const charfield_t *cf) 193 { 194 termui_cell_t cell = { }; 195 196 cell.glyph_idx = fb_font_glyph(cf->ch, NULL); 197 198 switch (cf->attrs.type) { 146 static pixel_t color_table[16] = { 147 [COLOR_BLACK] = PIXEL(255, 0, 0, 0), 148 [COLOR_BLUE] = PIXEL(255, 0, 0, 170), 149 [COLOR_GREEN] = PIXEL(255, 0, 170, 0), 150 [COLOR_CYAN] = PIXEL(255, 0, 170, 170), 151 [COLOR_RED] = PIXEL(255, 170, 0, 0), 152 [COLOR_MAGENTA] = PIXEL(255, 170, 0, 170), 153 [COLOR_YELLOW] = PIXEL(255, 170, 85, 0), 154 [COLOR_WHITE] = PIXEL(255, 170, 170, 170), 155 156 [COLOR_BLACK + 8] = PIXEL(255, 85, 85, 85), 157 [COLOR_BLUE + 8] = PIXEL(255, 85, 85, 255), 158 [COLOR_GREEN + 8] = PIXEL(255, 85, 255, 85), 159 [COLOR_CYAN + 8] = PIXEL(255, 85, 255, 255), 160 [COLOR_RED + 8] = PIXEL(255, 255, 85, 85), 161 [COLOR_MAGENTA + 8] = PIXEL(255, 255, 85, 255), 162 [COLOR_YELLOW + 8] = PIXEL(255, 255, 255, 85), 163 [COLOR_WHITE + 8] = PIXEL(255, 255, 255, 255), 164 }; 165 166 static inline void attrs_rgb(char_attrs_t attrs, pixel_t *bgcolor, pixel_t *fgcolor) 167 { 168 switch (attrs.type) { 199 169 case CHAR_ATTR_STYLE: 200 switch ( cf->attrs.val.style) {170 switch (attrs.val.style) { 201 171 case STYLE_NORMAL: 202 cell.bgcolor = term->default_bgcolor;203 cell.fgcolor = term->default_fgcolor;172 *bgcolor = color_table[COLOR_WHITE + 8]; 173 *fgcolor = color_table[COLOR_BLACK]; 204 174 break; 205 175 case STYLE_EMPHASIS: 206 cell.bgcolor = term->emphasis_bgcolor;207 cell.fgcolor = term->emphasis_fgcolor;176 *bgcolor = color_table[COLOR_WHITE + 8]; 177 *fgcolor = color_table[COLOR_RED + 8]; 208 178 break; 209 179 case STYLE_INVERTED: 210 cell.bgcolor = term->default_bgcolor; 211 cell.fgcolor = term->default_fgcolor; 212 cell.inverted = 1; 180 *bgcolor = color_table[COLOR_BLACK]; 181 *fgcolor = color_table[COLOR_WHITE + 8]; 213 182 break; 214 183 case STYLE_SELECTED: 215 cell.bgcolor = term->selection_bgcolor;216 cell.fgcolor = term->selection_fgcolor;184 *bgcolor = color_table[COLOR_RED + 8]; 185 *fgcolor = color_table[COLOR_WHITE + 8]; 217 186 break; 218 187 } 219 188 break; 220 221 189 case CHAR_ATTR_INDEX: 222 char_attr_index_t index = cf->attrs.val.index; 223 224 int bright = (index.attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0; 225 pixel_t bgcolor = _basic_colors[index.bgcolor]; 226 pixel_t fgcolor = _basic_colors[index.fgcolor | bright]; 227 cell.bgcolor = termui_color_from_pixel(bgcolor); 228 cell.fgcolor = termui_color_from_pixel(fgcolor); 229 230 if (index.attr & CATTR_BLINK) 231 cell.blink = 1; 232 190 *bgcolor = color_table[(attrs.val.index.bgcolor & 7)]; 191 *fgcolor = color_table[(attrs.val.index.fgcolor & 7) | 192 ((attrs.val.index.attr & CATTR_BRIGHT) ? 8 : 0)]; 233 193 break; 234 235 194 case CHAR_ATTR_RGB: 236 cell.bgcolor = termui_color_from_pixel(cf->attrs.val.rgb.bgcolor);237 cell.fgcolor = termui_color_from_pixel(cf->attrs.val.rgb.fgcolor);195 *bgcolor = 0xff000000 | attrs.val.rgb.bgcolor; 196 *fgcolor = 0xff000000 | attrs.val.rgb.fgcolor; 238 197 break; 239 198 } 240 241 return cell;242 199 } 243 200 … … 257 214 } 258 215 259 static void term_draw_cell(terminal_t *term, pixelmap_t *pixelmap, int col, int row, const termui_cell_t *cell) 260 { 261 termui_color_t bg = cell->bgcolor; 262 if (bg == TERMUI_COLOR_DEFAULT) 263 bg = term->default_bgcolor; 264 265 termui_color_t fg = cell->fgcolor; 266 if (fg == TERMUI_COLOR_DEFAULT) 267 fg = term->default_fgcolor; 268 269 pixel_t bgcolor = termui_color_to_pixel(bg); 270 pixel_t fgcolor = termui_color_to_pixel(fg); 271 272 int bx = col * FONT_WIDTH; 273 int by = row * FONT_SCANLINES; 274 275 // TODO: support bold/italic/underline/strike/blink styling 276 277 if (cell->inverted ^ cell->cursor) { 278 pixel_t tmp = bgcolor; 279 bgcolor = fgcolor; 280 fgcolor = tmp; 281 } 282 283 uint32_t glyph = cell->glyph_idx; 284 assert(glyph < FONT_GLYPHS); 285 286 if (glyph == 0) 287 glyph = fb_font_glyph(U' ', NULL); 216 static void term_update_char(terminal_t *term, pixelmap_t *pixelmap, 217 sysarg_t sx, sysarg_t sy, sysarg_t col, sysarg_t row) 218 { 219 charfield_t *field = 220 chargrid_charfield_at(term->backbuf, col, row); 221 222 bool inverted = chargrid_cursor_at(term->backbuf, col, row); 223 224 sysarg_t bx = sx + (col * FONT_WIDTH); 225 sysarg_t by = sy + (row * FONT_SCANLINES); 226 227 pixel_t bgcolor = 0; 228 pixel_t fgcolor = 0; 229 230 if (inverted) 231 attrs_rgb(field->attrs, &fgcolor, &bgcolor); 232 else 233 attrs_rgb(field->attrs, &bgcolor, &fgcolor); 234 235 // FIXME: Glyph type should be actually uint32_t 236 // for full UTF-32 coverage. 237 238 uint16_t glyph = fb_font_glyph(field->ch, NULL); 288 239 289 240 for (unsigned int y = 0; y < FONT_SCANLINES; y++) { … … 297 248 } 298 249 } 299 300 250 term_update_region(term, bx, by, FONT_WIDTH, FONT_SCANLINES); 301 251 } 302 252 303 static void term_render(terminal_t *term) 304 { 305 (void) gfx_bitmap_render(term->bmp, &term->update, &term->off); 306 307 term->update.p0.x = 0; 308 term->update.p0.y = 0; 309 term->update.p1.x = 0; 310 term->update.p1.y = 0; 311 } 312 313 static void termui_refresh_cb(void *userdata) 314 { 315 terminal_t *term = userdata; 316 317 termui_force_viewport_update(term->termui, 0, termui_get_rows(term->termui)); 318 } 319 320 static void termui_scroll_cb(void *userdata, int delta) 321 { 322 (void) delta; 323 324 // Until we have support for hardware accelerated scrolling, just redraw everything. 325 termui_refresh_cb(userdata); 326 } 327 328 static pixelmap_t term_get_pixelmap(terminal_t *term) 329 { 330 pixelmap_t pixelmap = { }; 253 static bool term_update_scroll(terminal_t *term, pixelmap_t *pixelmap, 254 sysarg_t sx, sysarg_t sy) 255 { 256 sysarg_t top_row = chargrid_get_top_row(term->frontbuf); 257 258 if (term->top_row == top_row) { 259 return false; 260 } 261 262 term->top_row = top_row; 263 264 for (sysarg_t row = 0; row < term->rows; row++) { 265 for (sysarg_t col = 0; col < term->cols; col++) { 266 charfield_t *front_field = 267 chargrid_charfield_at(term->frontbuf, col, row); 268 charfield_t *back_field = 269 chargrid_charfield_at(term->backbuf, col, row); 270 bool update = false; 271 272 if (front_field->ch != back_field->ch) { 273 back_field->ch = front_field->ch; 274 update = true; 275 } 276 277 if (!attrs_same(front_field->attrs, back_field->attrs)) { 278 back_field->attrs = front_field->attrs; 279 update = true; 280 } 281 282 front_field->flags &= ~CHAR_FLAG_DIRTY; 283 284 if (update) { 285 term_update_char(term, pixelmap, sx, sy, col, row); 286 } 287 } 288 } 289 290 return true; 291 } 292 293 static bool term_update_cursor(terminal_t *term, pixelmap_t *pixelmap, 294 sysarg_t sx, sysarg_t sy) 295 { 296 bool update = false; 297 298 sysarg_t front_col; 299 sysarg_t front_row; 300 chargrid_get_cursor(term->frontbuf, &front_col, &front_row); 301 302 sysarg_t back_col; 303 sysarg_t back_row; 304 chargrid_get_cursor(term->backbuf, &back_col, &back_row); 305 306 bool front_visibility = 307 chargrid_get_cursor_visibility(term->frontbuf) && 308 term->is_focused; 309 bool back_visibility = 310 chargrid_get_cursor_visibility(term->backbuf); 311 312 if (front_visibility != back_visibility) { 313 chargrid_set_cursor_visibility(term->backbuf, 314 front_visibility); 315 term_update_char(term, pixelmap, sx, sy, back_col, back_row); 316 update = true; 317 } 318 319 if ((front_col != back_col) || (front_row != back_row)) { 320 chargrid_set_cursor(term->backbuf, front_col, front_row); 321 term_update_char(term, pixelmap, sx, sy, back_col, back_row); 322 term_update_char(term, pixelmap, sx, sy, front_col, front_row); 323 update = true; 324 } 325 326 return update; 327 } 328 329 static void term_update(terminal_t *term) 330 { 331 pixelmap_t pixelmap; 331 332 gfx_bitmap_alloc_t alloc; 332 333 errno_t rc = gfx_bitmap_get_alloc(term->bmp, &alloc); 334 if (rc != EOK) 335 return pixelmap; 336 333 gfx_coord2_t pos; 334 errno_t rc; 335 336 rc = gfx_bitmap_get_alloc(term->bmp, &alloc); 337 if (rc != EOK) { 338 return; 339 } 340 341 fibril_mutex_lock(&term->mtx); 337 342 pixelmap.width = term->w; 338 343 pixelmap.height = term->h; 339 344 pixelmap.data = alloc.pixels; 340 return pixelmap; 341 } 342 343 static void term_clear_bitmap(terminal_t *term, pixel_t color) 344 { 345 pixelmap_t pixelmap = term_get_pixelmap(term); 346 if (pixelmap.data == NULL) 345 346 bool update = false; 347 sysarg_t sx = 0; 348 sysarg_t sy = 0; 349 350 if (term_update_scroll(term, &pixelmap, sx, sy)) { 351 update = true; 352 } else { 353 for (sysarg_t y = 0; y < term->rows; y++) { 354 for (sysarg_t x = 0; x < term->cols; x++) { 355 charfield_t *front_field = 356 chargrid_charfield_at(term->frontbuf, x, y); 357 charfield_t *back_field = 358 chargrid_charfield_at(term->backbuf, x, y); 359 bool cupdate = false; 360 361 if ((front_field->flags & CHAR_FLAG_DIRTY) == 362 CHAR_FLAG_DIRTY) { 363 if (front_field->ch != back_field->ch) { 364 back_field->ch = front_field->ch; 365 cupdate = true; 366 } 367 368 if (!attrs_same(front_field->attrs, 369 back_field->attrs)) { 370 back_field->attrs = front_field->attrs; 371 cupdate = true; 372 } 373 374 front_field->flags &= ~CHAR_FLAG_DIRTY; 375 } 376 377 if (cupdate) { 378 term_update_char(term, &pixelmap, sx, sy, x, y); 379 update = true; 380 } 381 } 382 } 383 } 384 385 if (term_update_cursor(term, &pixelmap, sx, sy)) 386 update = true; 387 388 if (update) { 389 pos.x = 4; 390 pos.y = 26; 391 (void) gfx_bitmap_render(term->bmp, &term->update, &pos); 392 393 term->update.p0.x = 0; 394 term->update.p0.y = 0; 395 term->update.p1.x = 0; 396 term->update.p1.y = 0; 397 } 398 399 fibril_mutex_unlock(&term->mtx); 400 } 401 402 static void term_repaint(terminal_t *term) 403 { 404 pixelmap_t pixelmap; 405 gfx_bitmap_alloc_t alloc; 406 errno_t rc; 407 408 rc = gfx_bitmap_get_alloc(term->bmp, &alloc); 409 if (rc != EOK) { 410 printf("Error getting bitmap allocation info.\n"); 347 411 return; 348 349 sysarg_t pixels = pixelmap.height * pixelmap.width; 350 for (sysarg_t i = 0; i < pixels; i++) 351 pixelmap.data[i] = color; 352 353 term_update_region(term, 0, 0, pixelmap.width, pixelmap.height); 354 } 355 356 static void termui_update_cb(void *userdata, int col, int row, const termui_cell_t *cell, int len) 357 { 358 terminal_t *term = userdata; 359 360 pixelmap_t pixelmap = term_get_pixelmap(term); 361 if (pixelmap.data == NULL) 362 return; 363 364 for (int i = 0; i < len; i++) 365 term_draw_cell(term, &pixelmap, col + i, row, &cell[i]); 412 } 413 414 fibril_mutex_lock(&term->mtx); 415 416 pixelmap.width = term->w; 417 pixelmap.height = term->h; 418 pixelmap.data = alloc.pixels; 419 420 sysarg_t sx = 0; 421 sysarg_t sy = 0; 422 423 if (!term_update_scroll(term, &pixelmap, sx, sy)) { 424 for (sysarg_t y = 0; y < term->rows; y++) { 425 for (sysarg_t x = 0; x < term->cols; x++) { 426 charfield_t *front_field = 427 chargrid_charfield_at(term->frontbuf, x, y); 428 charfield_t *back_field = 429 chargrid_charfield_at(term->backbuf, x, y); 430 431 back_field->ch = front_field->ch; 432 back_field->attrs = front_field->attrs; 433 front_field->flags &= ~CHAR_FLAG_DIRTY; 434 435 term_update_char(term, &pixelmap, sx, sy, x, y); 436 } 437 } 438 } 439 440 term_update_cursor(term, &pixelmap, sx, sy); 441 442 fibril_mutex_unlock(&term->mtx); 366 443 } 367 444 … … 403 480 if (pos < size) { 404 481 link_t *link = prodcons_consume(&term->input_pc); 405 terminal_event_t *qevent = list_get_instance(link, 406 terminal_event_t, link); 407 cons_event_t *event = &qevent->ev; 482 cons_event_t *event = list_get_instance(link, cons_event_t, link); 408 483 409 484 /* Accept key presses of printable chars only. */ … … 419 494 } 420 495 421 free( qevent);496 free(event); 422 497 } 423 498 } … … 429 504 static void term_write_char(terminal_t *term, wchar_t ch) 430 505 { 506 sysarg_t updated = 0; 507 508 fibril_mutex_lock(&term->mtx); 509 431 510 switch (ch) { 432 case L'\n':433 termui_put_crlf(term->termui);511 case '\n': 512 updated = chargrid_newline(term->frontbuf); 434 513 break; 435 case L'\r': 436 termui_put_cr(term->termui); 514 case '\r': 437 515 break; 438 case L'\t':439 termui_put_tab(term->termui);516 case '\t': 517 updated = chargrid_tabstop(term->frontbuf, 8); 440 518 break; 441 case L'\b':442 termui_put_backspace(term->termui);519 case '\b': 520 updated = chargrid_backspace(term->frontbuf); 443 521 break; 444 522 default: 445 // TODO: For some languages, we might need support for combining 446 // characters. Currently, we assume every unicode code point is 447 // an individual printed character, which is not always the case. 448 termui_put_glyph(term->termui, fb_font_glyph(ch, NULL), 1); 449 break; 450 } 523 updated = chargrid_putuchar(term->frontbuf, ch, true); 524 } 525 526 fibril_mutex_unlock(&term->mtx); 527 528 if (updated > 1) 529 term_update(term); 451 530 } 452 531 … … 454 533 { 455 534 terminal_t *term = srv_to_terminal(srv); 456 457 fibril_mutex_lock(&term->mtx);458 535 459 536 size_t off = 0; … … 461 538 term_write_char(term, str_decode(data, &off, size)); 462 539 463 fibril_mutex_unlock(&term->mtx);464 465 term_render(term);466 540 gfx_update(term->gc); 467 541 *nwritten = size; 468 469 542 return EOK; 470 543 } … … 474 547 terminal_t *term = srv_to_terminal(srv); 475 548 476 term_ render(term);549 term_update(term); 477 550 gfx_update(term->gc); 478 551 } … … 483 556 484 557 fibril_mutex_lock(&term->mtx); 485 termui_clear_screen(term->termui);486 fibril_mutex_unlock(&term->mtx); 487 488 term_ render(term);558 chargrid_clear(term->frontbuf); 559 fibril_mutex_unlock(&term->mtx); 560 561 term_update(term); 489 562 gfx_update(term->gc); 490 563 } … … 495 568 496 569 fibril_mutex_lock(&term->mtx); 497 termui_set_pos(term->termui, col, row);498 fibril_mutex_unlock(&term->mtx); 499 500 term_ render(term);570 chargrid_set_cursor(term->frontbuf, col, row); 571 fibril_mutex_unlock(&term->mtx); 572 573 term_update(term); 501 574 gfx_update(term->gc); 502 575 } … … 507 580 508 581 fibril_mutex_lock(&term->mtx); 509 int irow, icol; 510 termui_get_pos(term->termui, &icol, &irow); 511 fibril_mutex_unlock(&term->mtx); 512 513 *col = icol; 514 *row = irow; 582 chargrid_get_cursor(term->frontbuf, col, row); 583 fibril_mutex_unlock(&term->mtx); 515 584 516 585 return EOK; … … 522 591 523 592 fibril_mutex_lock(&term->mtx); 524 *cols = term ui_get_cols(term->termui);525 *rows = term ui_get_rows(term->termui);593 *cols = term->cols; 594 *rows = term->rows; 526 595 fibril_mutex_unlock(&term->mtx); 527 596 … … 541 610 terminal_t *term = srv_to_terminal(srv); 542 611 543 termui_cell_t cellstyle = { }; 544 545 switch (style) { 546 case STYLE_NORMAL: 547 cellstyle.bgcolor = term->default_bgcolor; 548 cellstyle.fgcolor = term->default_fgcolor; 549 break; 550 case STYLE_EMPHASIS: 551 cellstyle.bgcolor = term->emphasis_bgcolor; 552 cellstyle.fgcolor = term->emphasis_fgcolor; 553 break; 554 case STYLE_INVERTED: 555 cellstyle.bgcolor = term->default_bgcolor; 556 cellstyle.fgcolor = term->default_fgcolor; 557 cellstyle.inverted = 1; 558 break; 559 case STYLE_SELECTED: 560 cellstyle.bgcolor = term->selection_bgcolor; 561 cellstyle.fgcolor = term->selection_fgcolor; 562 break; 563 } 564 565 fibril_mutex_lock(&term->mtx); 566 termui_set_style(term->termui, cellstyle); 612 fibril_mutex_lock(&term->mtx); 613 chargrid_set_style(term->frontbuf, style); 567 614 fibril_mutex_unlock(&term->mtx); 568 615 } … … 573 620 terminal_t *term = srv_to_terminal(srv); 574 621 575 int bright = (attr & CATTR_BRIGHT) ? COLOR_BRIGHT : 0; 576 577 termui_cell_t cellstyle = { }; 578 cellstyle.bgcolor = termui_color_from_pixel(_basic_colors[bgcolor]); 579 cellstyle.fgcolor = termui_color_from_pixel(_basic_colors[fgcolor | bright]); 580 581 if (attr & CATTR_BLINK) 582 cellstyle.blink = 1; 583 584 fibril_mutex_lock(&term->mtx); 585 termui_set_style(term->termui, cellstyle); 622 fibril_mutex_lock(&term->mtx); 623 chargrid_set_color(term->frontbuf, bgcolor, fgcolor, attr); 586 624 fibril_mutex_unlock(&term->mtx); 587 625 } … … 591 629 { 592 630 terminal_t *term = srv_to_terminal(srv); 593 termui_cell_t cellstyle = { 594 .bgcolor = termui_color_from_pixel(bgcolor), 595 .fgcolor = termui_color_from_pixel(fgcolor), 596 }; 597 598 fibril_mutex_lock(&term->mtx); 599 termui_set_style(term->termui, cellstyle); 631 632 fibril_mutex_lock(&term->mtx); 633 chargrid_set_rgb_color(term->frontbuf, bgcolor, fgcolor); 600 634 fibril_mutex_unlock(&term->mtx); 601 635 } … … 606 640 607 641 fibril_mutex_lock(&term->mtx); 608 termui_set_cursor_visibility(term->termui, visible);609 fibril_mutex_unlock(&term->mtx); 610 611 term_ render(term);642 chargrid_set_cursor_visibility(term->frontbuf, visible); 643 fibril_mutex_unlock(&term->mtx); 644 645 term_update(term); 612 646 gfx_update(term->gc); 613 647 } … … 628 662 fibril_mutex_unlock(&term->mtx); 629 663 630 term_ render(term);664 term_update(term); 631 665 gfx_update(term->gc); 632 666 return EOK; … … 637 671 terminal_t *term = srv_to_terminal(srv); 638 672 link_t *link = prodcons_consume(&term->input_pc); 639 terminal_event_t *ev = list_get_instance(link, terminal_event_t, link);640 641 *event = ev->ev;673 cons_event_t *ev = list_get_instance(link, cons_event_t, link); 674 675 *event = *ev; 642 676 free(ev); 643 677 return EOK; … … 676 710 term->urows = rows; 677 711 term->ubuf = buf; 678 679 /* Scroll back to active screen. */680 termui_history_scroll(term->termui, INT_MAX);681 682 712 fibril_mutex_unlock(&term->mtx); 683 713 … … 700 730 term->ubuf = NULL; 701 731 702 termui_wipe_screen(term->termui, 0);703 704 fibril_mutex_unlock(&term->mtx);705 706 /* Update terminal */707 term_render(term);708 gfx_update(term->gc);709 710 732 if (buf != NULL) 711 733 as_area_destroy(buf); 734 735 fibril_mutex_unlock(&term->mtx); 712 736 } 713 737 … … 724 748 { 725 749 terminal_t *term = srv_to_terminal(srv); 750 charfield_t *ch; 751 sysarg_t col, row; 726 752 727 753 fibril_mutex_lock(&term->mtx); … … 733 759 734 760 /* Make sure we have meaningful coordinates, within bounds */ 735 c1 = min(c1, term->ucols); 736 c1 = min(c1, (sysarg_t) termui_get_cols(term->termui));737 r1 = min(r1, term->urows);738 r1 = min(r1, (sysarg_t) termui_get_rows(term->termui));739 740 if (c0 >= c1 || r0 >= r1) {761 762 if (c1 > term->ucols) 763 c1 = term->ucols; 764 if (c1 > term->cols) 765 c1 = term->cols; 766 if (c0 >= c1) { 741 767 fibril_mutex_unlock(&term->mtx); 742 768 return; 743 769 } 770 if (r1 > term->urows) 771 r1 = term->urows; 772 if (r1 > term->rows) 773 r1 = term->rows; 774 if (r0 >= r1) { 775 fibril_mutex_unlock(&term->mtx); 776 return; 777 } 744 778 745 779 /* Update front buffer from user buffer */ 746 780 747 for (sysarg_t row = r0; row < r1; row++) { 748 termui_cell_t *cells = termui_get_active_row(term->termui, row); 749 750 for (sysarg_t col = c0; col < c1; col++) { 751 cells[col] = charfield_to_termui_cell(term, &term->ubuf[row * term->ucols + col]); 781 for (row = r0; row < r1; row++) { 782 for (col = c0; col < c1; col++) { 783 ch = chargrid_charfield_at(term->frontbuf, col, row); 784 *ch = term->ubuf[row * term->ucols + col]; 752 785 } 753 754 termui_update_cb(term, c0, row, &cells[c0], c1 - c0);755 786 } 756 787 … … 758 789 759 790 /* Update terminal */ 760 term_ render(term);791 term_update(term); 761 792 gfx_update(term->gc); 762 793 } 763 794 764 static errno_t terminal_window_resize(terminal_t *term) 765 { 795 static void deinit_terminal(terminal_t *term) 796 { 797 list_remove(&term->link); 798 799 if (term->frontbuf) 800 chargrid_destroy(term->frontbuf); 801 802 if (term->backbuf) 803 chargrid_destroy(term->backbuf); 804 } 805 806 void terminal_destroy(terminal_t *term) 807 { 808 deinit_terminal(term); 809 free(term); 810 } 811 812 static void terminal_queue_cons_event(terminal_t *term, cons_event_t *ev) 813 { 814 /* Got key press/release event */ 815 cons_event_t *event = 816 (cons_event_t *) malloc(sizeof(cons_event_t)); 817 if (event == NULL) 818 return; 819 820 *event = *ev; 821 link_initialize(&event->link); 822 823 prodcons_produce(&term->input_pc, &event->link); 824 } 825 826 /** Handle window close event. */ 827 static void terminal_close_event(ui_window_t *window, void *arg) 828 { 829 terminal_t *term = (terminal_t *) arg; 830 831 ui_quit(term->ui); 832 } 833 834 /** Handle window focus event. */ 835 static void terminal_focus_event(ui_window_t *window, void *arg, 836 unsigned nfocus) 837 { 838 terminal_t *term = (terminal_t *) arg; 839 840 (void)nfocus; 841 term->is_focused = true; 842 term_update(term); 843 gfx_update(term->gc); 844 } 845 846 /** Handle window keyboard event */ 847 static void terminal_kbd_event(ui_window_t *window, void *arg, 848 kbd_event_t *kbd_event) 849 { 850 terminal_t *term = (terminal_t *) arg; 851 cons_event_t event; 852 853 event.type = CEV_KEY; 854 event.ev.key = *kbd_event; 855 856 terminal_queue_cons_event(term, &event); 857 } 858 859 /** Handle window position event */ 860 static void terminal_pos_event(ui_window_t *window, void *arg, pos_event_t *event) 861 { 862 cons_event_t cevent; 863 terminal_t *term = (terminal_t *) arg; 864 865 sysarg_t sx = -term->off.x; 866 sysarg_t sy = -term->off.y; 867 868 if (event->type == POS_PRESS || event->type == POS_RELEASE || 869 event->type == POS_DCLICK) { 870 cevent.type = CEV_POS; 871 cevent.ev.pos.type = event->type; 872 cevent.ev.pos.pos_id = event->pos_id; 873 cevent.ev.pos.btn_num = event->btn_num; 874 875 cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH; 876 cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES; 877 terminal_queue_cons_event(term, &cevent); 878 } 879 } 880 881 /** Handle window unfocus event. */ 882 static void terminal_unfocus_event(ui_window_t *window, void *arg, 883 unsigned nfocus) 884 { 885 terminal_t *term = (terminal_t *) arg; 886 887 if (nfocus == 0) { 888 term->is_focused = false; 889 term_update(term); 890 gfx_update(term->gc); 891 } 892 } 893 894 static void term_connection(ipc_call_t *icall, void *arg) 895 { 896 terminal_t *term = NULL; 897 898 list_foreach(terms, link, terminal_t, cur) { 899 if (cur->dsid == (service_id_t) ipc_get_arg2(icall)) { 900 term = cur; 901 break; 902 } 903 } 904 905 if (term == NULL) { 906 async_answer_0(icall, ENOENT); 907 return; 908 } 909 910 if (!atomic_flag_test_and_set(&term->refcnt)) 911 chargrid_set_cursor_visibility(term->frontbuf, true); 912 913 con_conn(icall, &term->srvs); 914 } 915 916 errno_t terminal_create(const char *display_spec, sysarg_t width, 917 sysarg_t height, terminal_flags_t flags, const char *command, 918 terminal_t **rterm) 919 { 920 terminal_t *term; 921 gfx_bitmap_params_t params; 922 ui_wnd_params_t wparams; 766 923 gfx_rect_t rect; 767 ui_window_get_app_rect(term->window, &rect); 768 769 int width = rect.p1.x - rect.p0.x; 770 int height = rect.p1.y - rect.p0.y; 771 772 if (!term->gc) 773 term->gc = ui_window_get_gc(term->window); 774 else 775 assert(term->gc == ui_window_get_gc(term->window)); 776 777 if (!term->ui_res) 778 term->ui_res = ui_window_get_res(term->window); 779 else 780 assert(term->ui_res == ui_window_get_res(term->window)); 781 782 gfx_bitmap_t *new_bmp; 783 gfx_bitmap_params_t params; 924 gfx_coord2_t off; 925 gfx_rect_t wrect; 926 errno_t rc; 927 928 term = calloc(1, sizeof(terminal_t)); 929 if (term == NULL) { 930 printf("Out of memory.\n"); 931 return ENOMEM; 932 } 933 934 link_initialize(&term->link); 935 fibril_mutex_initialize(&term->mtx); 936 atomic_flag_clear(&term->refcnt); 937 938 prodcons_initialize(&term->input_pc); 939 term->char_remains_len = 0; 940 941 term->w = width; 942 term->h = height; 943 944 term->cols = width / FONT_WIDTH; 945 term->rows = height / FONT_SCANLINES; 946 947 term->frontbuf = NULL; 948 term->backbuf = NULL; 949 950 term->frontbuf = chargrid_create(term->cols, term->rows, 951 CHARGRID_FLAG_NONE); 952 if (!term->frontbuf) { 953 printf("Error creating front buffer.\n"); 954 rc = ENOMEM; 955 goto error; 956 } 957 958 term->backbuf = chargrid_create(term->cols, term->rows, 959 CHARGRID_FLAG_NONE); 960 if (!term->backbuf) { 961 printf("Error creating back buffer.\n"); 962 rc = ENOMEM; 963 goto error; 964 } 965 966 rect.p0.x = 0; 967 rect.p0.y = 0; 968 rect.p1.x = width; 969 rect.p1.y = height; 970 971 ui_wnd_params_init(&wparams); 972 wparams.caption = "Terminal"; 973 if ((flags & tf_topleft) != 0) 974 wparams.placement = ui_wnd_place_top_left; 975 976 rc = ui_create(display_spec, &term->ui); 977 if (rc != EOK) { 978 printf("Error creating UI on %s.\n", display_spec); 979 goto error; 980 } 981 982 /* 983 * Compute window rectangle such that application area corresponds 984 * to rect 985 */ 986 ui_wdecor_rect_from_app(term->ui, wparams.style, &rect, &wrect); 987 off = wrect.p0; 988 gfx_rect_rtranslate(&off, &wrect, &wparams.rect); 989 990 term->off = off; 991 992 rc = ui_window_create(term->ui, &wparams, &term->window); 993 if (rc != EOK) { 994 printf("Error creating window.\n"); 995 goto error; 996 } 997 998 term->gc = ui_window_get_gc(term->window); 999 term->ui_res = ui_window_get_res(term->window); 1000 1001 ui_window_set_cb(term->window, &terminal_window_cb, (void *) term); 1002 784 1003 gfx_bitmap_params_init(¶ms); 785 1004 params.rect.p0.x = 0; … … 788 1007 params.rect.p1.y = height; 789 1008 790 errno_t rc = gfx_bitmap_create(term->gc, ¶ms, NULL, &new_bmp);1009 rc = gfx_bitmap_create(term->gc, ¶ms, NULL, &term->bmp); 791 1010 if (rc != EOK) { 792 fprintf(stderr, "Error allocating new screen bitmap: %s\n", str_error(rc)); 793 return rc; 794 } 795 796 if (term->bmp) { 797 rc = gfx_bitmap_destroy(term->bmp); 798 if (rc != EOK) 799 fprintf(stderr, "Error deallocating old screen bitmap: %s\n", str_error(rc)); 800 } 801 802 term->bmp = new_bmp; 803 term->w = width; 804 term->h = height; 805 806 term_clear_bitmap(term, termui_color_to_pixel(term->default_bgcolor)); 807 808 return EOK; 809 } 810 811 void terminal_destroy(terminal_t *term) 812 { 813 list_remove(&term->link); 814 815 termui_destroy(term->termui); 816 817 if (term->ubuf) 818 as_area_destroy(term->ubuf); 819 820 ui_destroy(term->ui); 821 free(term); 822 } 823 824 static void terminal_queue_cons_event(terminal_t *term, cons_event_t *ev) 825 { 826 /* Got key press/release event */ 827 terminal_event_t *event = 828 (terminal_event_t *) malloc(sizeof(terminal_event_t)); 829 if (event == NULL) 830 return; 831 832 event->ev = *ev; 833 link_initialize(&event->link); 834 835 prodcons_produce(&term->input_pc, &event->link); 836 } 837 838 /** Handle window close event. */ 839 static void terminal_close_event(ui_window_t *window, void *arg) 840 { 841 terminal_t *term = (terminal_t *) arg; 842 843 ui_quit(term->ui); 844 } 845 846 /** Handle window focus event. */ 847 static void terminal_focus_event(ui_window_t *window, void *arg, 848 unsigned nfocus) 849 { 850 terminal_t *term = (terminal_t *) arg; 851 852 (void)nfocus; 853 term->is_focused = true; 854 term_render(term); 855 gfx_update(term->gc); 856 } 857 858 static void terminal_resize_handler(ui_window_t *window, void *arg) 859 { 860 terminal_t *term = (terminal_t *) arg; 861 862 fibril_mutex_lock(&term->mtx); 863 864 errno_t rc = terminal_window_resize(term); 865 if (rc == EOK) { 866 (void) termui_resize(term->termui, term->w / FONT_WIDTH, term->h / FONT_SCANLINES, SCROLLBACK_MAX_LINES); 867 termui_refresh_cb(term); 868 term_render(term); 869 gfx_update(term->gc); 870 871 cons_event_t event = { .type = CEV_RESIZE }; 872 terminal_queue_cons_event(term, &event); 873 } 874 875 fibril_mutex_unlock(&term->mtx); 876 } 877 878 static void terminal_resize_event(ui_window_t *window, void *arg) 879 { 880 ui_window_def_resize(window); 881 terminal_resize_handler(window, arg); 882 } 883 884 static void terminal_maximize_event(ui_window_t *window, void *arg) 885 { 886 ui_window_def_maximize(window); 887 terminal_resize_handler(window, arg); 888 } 889 890 static void terminal_unmaximize_event(ui_window_t *window, void *arg) 891 { 892 ui_window_def_unmaximize(window); 893 terminal_resize_handler(window, arg); 894 } 895 896 /** Handle window keyboard event */ 897 static void terminal_kbd_event(ui_window_t *window, void *arg, 898 kbd_event_t *kbd_event) 899 { 900 terminal_t *term = (terminal_t *) arg; 901 cons_event_t event; 902 903 event.type = CEV_KEY; 904 event.ev.key = *kbd_event; 905 906 const int PAGE_ROWS = (termui_get_rows(term->termui) * 2) / 3; 907 908 fibril_mutex_lock(&term->mtx); 909 910 if (!term->ubuf && kbd_event->type == KEY_PRESS && 911 (kbd_event->key == KC_PAGE_UP || kbd_event->key == KC_PAGE_DOWN)) { 912 913 termui_history_scroll(term->termui, 914 (kbd_event->key == KC_PAGE_UP) ? -PAGE_ROWS : PAGE_ROWS); 915 916 term_render(term); 917 gfx_update(term->gc); 918 } else { 919 terminal_queue_cons_event(term, &event); 920 } 921 922 fibril_mutex_unlock(&term->mtx); 923 } 924 925 /** Handle window position event */ 926 static void terminal_pos_event(ui_window_t *window, void *arg, pos_event_t *event) 927 { 928 cons_event_t cevent; 929 terminal_t *term = (terminal_t *) arg; 930 931 switch (event->type) { 932 case POS_UPDATE: 933 return; 934 935 case POS_PRESS: 936 case POS_RELEASE: 937 case POS_DCLICK: 938 } 939 940 /* Ignore mouse events when we're in scrollback mode. */ 941 if (termui_scrollback_is_active(term->termui)) 942 return; 943 944 sysarg_t sx = term->off.x; 945 sysarg_t sy = term->off.y; 946 947 if (event->hpos < sx || event->vpos < sy) 948 return; 949 950 cevent.type = CEV_POS; 951 cevent.ev.pos.type = event->type; 952 cevent.ev.pos.pos_id = event->pos_id; 953 cevent.ev.pos.btn_num = event->btn_num; 954 955 cevent.ev.pos.hpos = (event->hpos - sx) / FONT_WIDTH; 956 cevent.ev.pos.vpos = (event->vpos - sy) / FONT_SCANLINES; 957 958 /* Filter out events outside the terminal area. */ 959 int cols = termui_get_cols(term->termui); 960 int rows = termui_get_rows(term->termui); 961 962 if (cevent.ev.pos.hpos < (sysarg_t) cols && cevent.ev.pos.vpos < (sysarg_t) rows) 963 terminal_queue_cons_event(term, &cevent); 964 } 965 966 /** Handle window unfocus event. */ 967 static void terminal_unfocus_event(ui_window_t *window, void *arg, 968 unsigned nfocus) 969 { 970 terminal_t *term = (terminal_t *) arg; 971 972 if (nfocus == 0) { 973 term->is_focused = false; 974 term_render(term); 975 gfx_update(term->gc); 976 } 977 } 978 979 static void term_connection(ipc_call_t *icall, void *arg) 980 { 981 terminal_t *term = NULL; 982 983 list_foreach(terms, link, terminal_t, cur) { 984 if (cur->dsid == (service_id_t) ipc_get_arg2(icall)) { 985 term = cur; 986 break; 987 } 988 } 989 990 if (term == NULL) { 991 async_answer_0(icall, ENOENT); 992 return; 993 } 994 995 if (!atomic_flag_test_and_set(&term->refcnt)) 996 termui_set_cursor_visibility(term->termui, true); 997 998 con_conn(icall, &term->srvs); 999 } 1000 1001 static errno_t term_init_window(terminal_t *term, const char *display_spec, 1002 gfx_coord_t width, gfx_coord_t height, 1003 gfx_coord_t min_width, gfx_coord_t min_height, 1004 terminal_flags_t flags) 1005 { 1006 gfx_rect_t min_rect = { { 0, 0 }, { min_width, min_height } }; 1007 gfx_rect_t wmin_rect; 1008 gfx_rect_t wrect; 1009 1010 errno_t rc = ui_create(display_spec, &term->ui); 1011 if (rc != EOK) { 1012 printf("Error creating UI on %s.\n", display_spec); 1013 return rc; 1014 } 1015 1016 ui_wnd_params_t wparams; 1017 ui_wnd_params_init(&wparams); 1018 wparams.caption = "Terminal"; 1019 wparams.style |= ui_wds_maximize_btn | ui_wds_resizable; 1020 1021 if ((flags & tf_topleft) != 0) 1022 wparams.placement = ui_wnd_place_top_left; 1023 1024 if (ui_is_fullscreen(term->ui)) { 1025 wparams.placement = ui_wnd_place_full_screen; 1026 wparams.style &= ~ui_wds_decorated; 1027 } 1028 1029 /* Compute wrect such that application area corresponds to rect. */ 1030 ui_wdecor_rect_from_app(term->ui, wparams.style, &min_rect, &wrect); 1031 gfx_rect_rtranslate(&wrect.p0, &wrect, &wmin_rect); 1032 wparams.min_size = wmin_rect.p1; 1033 1034 gfx_rect_t rect = { { 0, 0 }, { width, height } }; 1035 ui_wdecor_rect_from_app(term->ui, wparams.style, &rect, &rect); 1036 term->off.x = -rect.p0.x; 1037 term->off.y = -rect.p0.y; 1038 printf("off=%d,%d\n", term->off.x, term->off.y); 1039 gfx_rect_translate(&term->off, &rect, &wparams.rect); 1040 printf("wparams.rect=%d,%d,%d,%d\n", 1041 wparams.rect.p0.x, 1042 wparams.rect.p1.x, 1043 wparams.rect.p0.y, 1044 wparams.rect.p1.y); 1045 1046 rc = ui_window_create(term->ui, &wparams, &term->window); 1047 if (rc != EOK) 1048 return rc; 1049 1050 ui_window_set_cb(term->window, &terminal_window_cb, (void *) term); 1051 return terminal_window_resize(term); 1052 } 1053 1054 errno_t terminal_create(const char *display_spec, sysarg_t width, 1055 sysarg_t height, terminal_flags_t flags, const char *command, 1056 terminal_t **rterm) 1057 { 1058 errno_t rc; 1059 1060 terminal_t *term = calloc(1, sizeof(terminal_t)); 1061 if (term == NULL) { 1062 printf("Out of memory.\n"); 1063 return ENOMEM; 1064 } 1065 1066 link_initialize(&term->link); 1067 fibril_mutex_initialize(&term->mtx); 1068 atomic_flag_clear(&term->refcnt); 1069 1070 prodcons_initialize(&term->input_pc); 1071 term->char_remains_len = 0; 1072 1073 term->default_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]); 1074 term->default_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_BLACK]); 1075 1076 term->emphasis_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]); 1077 term->emphasis_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]); 1078 1079 term->selection_bgcolor = termui_color_from_pixel(_basic_colors[COLOR_RED | COLOR_BRIGHT]); 1080 term->selection_fgcolor = termui_color_from_pixel(_basic_colors[COLOR_WHITE | COLOR_BRIGHT]); 1081 1082 rc = term_init_window(term, display_spec, width, height, 1083 MIN_WINDOW_COLS * FONT_WIDTH, MIN_WINDOW_ROWS * FONT_SCANLINES, flags); 1084 if (rc != EOK) { 1085 printf("Error creating window (%s).\n", str_error(rc)); 1011 printf("Error allocating screen bitmap.\n"); 1086 1012 goto error; 1087 1013 } 1088 1014 1089 term->termui = termui_create(term->w / FONT_WIDTH, 1090 term->h / FONT_SCANLINES, SCROLLBACK_MAX_LINES); 1091 if (!term->termui) { 1092 printf("Error creating terminal UI.\n"); 1093 rc = ENOMEM; 1094 goto error; 1095 } 1096 1097 termui_set_refresh_cb(term->termui, termui_refresh_cb, term); 1098 termui_set_scroll_cb(term->termui, termui_scroll_cb, term); 1099 termui_set_update_cb(term->termui, termui_update_cb, term); 1015 chargrid_clear(term->frontbuf); 1016 chargrid_clear(term->backbuf); 1017 term->top_row = 0; 1100 1018 1101 1019 async_set_fallback_port_handler(term_connection, NULL); … … 1135 1053 term->is_focused = true; 1136 1054 1137 termui_refresh_cb(term); 1055 term->update.p0.x = 0; 1056 term->update.p0.y = 0; 1057 term->update.p1.x = 0; 1058 term->update.p1.y = 0; 1059 1060 term_repaint(term); 1138 1061 1139 1062 *rterm = term; … … 1148 1071 if (term->ui != NULL) 1149 1072 ui_destroy(term->ui); 1150 if (term->termui != NULL) 1151 termui_destroy(term->termui); 1073 if (term->frontbuf != NULL) 1074 chargrid_destroy(term->frontbuf); 1075 if (term->backbuf != NULL) 1076 chargrid_destroy(term->backbuf); 1152 1077 free(term); 1153 1078 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.