Download ide/native/terminal/terminal_view.cpp from Snapkitty/sovereign-engine-v2: direct link, hf CLI and curl.
- Browser
- Download file 18.5 kB
-
https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/ide/native/terminal/terminal_view.cpp
- Command line
-
hf download hf://Snapkitty/sovereign-engine-v2/ide/native/terminal/terminal_view.cpp
-
curl -L -o terminal_view.cpp https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/ide/native/terminal/terminal_view.cpp
18.5 kB
| /* | |
| * Sovereign IDE β Terminal View | |
| * ANSI/VT100 parser + Direct2D renderer on top of the ConPTY backend. | |
| * | |
| * Cell grid: TERM_COLS Γ TERM_ROWS fixed-size character cells. | |
| * ANSI sequences handled: SGR colours (0-7 fg/bg, bold, reset), | |
| * cursor motion (CUP/CUU/CUD/CUF/CUB/CHA/VPA/ED/EL/CR/LF/BS), | |
| * and the scroll region (DECSTBM). | |
| */ | |
| extern "C" { | |
| } | |
| /* ANSI colour palette (dark theme) */ | |
| static const D2D1_COLOR_F ANSI_COLORS[8] = { | |
| { 0.075f, 0.075f, 0.090f, 1.0f }, /* 0 black β near-black bg */ | |
| { 0.800f, 0.200f, 0.200f, 1.0f }, /* 1 red */ | |
| { 0.180f, 0.700f, 0.290f, 1.0f }, /* 2 green */ | |
| { 0.780f, 0.700f, 0.200f, 1.0f }, /* 3 yellow */ | |
| { 0.290f, 0.510f, 0.900f, 1.0f }, /* 4 blue */ | |
| { 0.700f, 0.290f, 0.800f, 1.0f }, /* 5 magenta */ | |
| { 0.200f, 0.700f, 0.780f, 1.0f }, /* 6 cyan */ | |
| { 0.820f, 0.820f, 0.820f, 1.0f }, /* 7 white / default fg */ | |
| }; | |
| static const D2D1_COLOR_F C_CURSOR = { 0.980f, 0.980f, 0.980f, 0.85f }; | |
| /* Terminal cell */ | |
| struct Cell { | |
| wchar_t ch; | |
| uint8_t fg; /* 0-7 */ | |
| uint8_t bg; /* 0-7 */ | |
| bool bold; | |
| }; | |
| /* ANSI escape parser state */ | |
| enum ParseState { PS_NORMAL, PS_ESC, PS_CSI }; | |
| struct TerminalView { | |
| HWND hwnd; | |
| int pixel_w, pixel_h; | |
| ID2D1Factory *d2d; | |
| ID2D1HwndRenderTarget *rt; | |
| IDWriteFactory *dw; | |
| IDWriteTextFormat *fmt; | |
| IDWriteTextFormat *fmt_bold; | |
| ID2D1SolidColorBrush *brushes[8]; /* ANSI colours */ | |
| ID2D1SolidColorBrush *br_cursor; | |
| float cell_w, cell_h; | |
| Cell grid[TERM_ROWS][TERM_COLS]; | |
| int cur_row, cur_col; | |
| uint8_t cur_fg, cur_bg; | |
| bool cur_bold; | |
| int scroll_top, scroll_bot; /* DECSTBM region, 0-based */ | |
| /* ANSI parser */ | |
| ParseState ps; | |
| char csi_buf[64]; | |
| int csi_len; | |
| Terminal *pty; | |
| char read_buf[4096]; | |
| }; | |
| /* ββ helpers βββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| static void cell_clear(Cell *c, uint8_t bg) { | |
| c->ch = L' '; c->fg = 7; c->bg = bg; c->bold = false; | |
| } | |
| static void grid_clear(TerminalView *tv) { | |
| for (int r = 0; r < TERM_ROWS; r++) | |
| for (int c = 0; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[r][c], 0); | |
| } | |
| static void scroll_up(TerminalView *tv, int top, int bot) { | |
| for (int r = top; r < bot; r++) | |
| memcpy(tv->grid[r], tv->grid[r+1], sizeof(tv->grid[0])); | |
| for (int c = 0; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[bot][c], tv->cur_bg); | |
| } | |
| static void newline(TerminalView *tv) { | |
| tv->cur_col = 0; | |
| if (tv->cur_row < tv->scroll_bot) | |
| tv->cur_row++; | |
| else | |
| scroll_up(tv, tv->scroll_top, tv->scroll_bot); | |
| } | |
| static void put_char(TerminalView *tv, wchar_t ch) { | |
| if (tv->cur_col >= TERM_COLS) { | |
| tv->cur_col = 0; | |
| if (tv->cur_row < tv->scroll_bot) tv->cur_row++; | |
| else scroll_up(tv, tv->scroll_top, tv->scroll_bot); | |
| } | |
| Cell *c = &tv->grid[tv->cur_row][tv->cur_col]; | |
| c->ch = ch; c->fg = tv->cur_fg; c->bg = tv->cur_bg; c->bold = tv->cur_bold; | |
| tv->cur_col++; | |
| } | |
| /* Parse a single CSI param (1-based default d) */ | |
| static int csi_param(const char *buf, int idx, int def) { | |
| /* buf is semicolon-separated params, e.g. "2;31" */ | |
| const char *p = buf; | |
| for (int i = 0; i < idx; i++) { | |
| p = strchr(p, ';'); | |
| if (!p) return def; | |
| p++; | |
| } | |
| if (*p == '\0' || *p == ';') return def; | |
| return atoi(p); | |
| } | |
| static void apply_sgr(TerminalView *tv, const char *params) { | |
| /* Walk semicolon-delimited numbers */ | |
| char tmp[64]; | |
| strncpy_s(tmp, 64, params, 63); | |
| char *tok = tmp; | |
| char *next; | |
| do { | |
| next = strchr(tok, ';'); | |
| if (next) *next = '\0'; | |
| int n = (*tok == '\0') ? 0 : atoi(tok); | |
| if (n == 0) { tv->cur_fg = 7; tv->cur_bg = 0; tv->cur_bold = false; } | |
| else if (n == 1) tv->cur_bold = true; | |
| else if (n == 22) tv->cur_bold = false; | |
| else if (n >= 30 && n <= 37) tv->cur_fg = (uint8_t)(n - 30); | |
| else if (n == 39) tv->cur_fg = 7; | |
| else if (n >= 40 && n <= 47) tv->cur_bg = (uint8_t)(n - 40); | |
| else if (n == 49) tv->cur_bg = 0; | |
| /* bright variants */ | |
| else if (n >= 90 && n <= 97) tv->cur_fg = (uint8_t)(n - 90); | |
| else if (n >= 100 && n <= 107) tv->cur_bg = (uint8_t)(n - 100); | |
| if (next) tok = next + 1; | |
| } while (next); | |
| } | |
| static void dispatch_csi(TerminalView *tv) { | |
| char *buf = tv->csi_buf; | |
| int len = tv->csi_len; | |
| if (len == 0) return; | |
| char final = buf[len - 1]; | |
| buf[len - 1] = '\0'; /* null-terminate params portion */ | |
| const char *params = buf; | |
| int p1 = csi_param(params, 0, 1); | |
| int p2 = csi_param(params, 1, 1); | |
| switch (final) { | |
| case 'A': /* CUU */ tv->cur_row = (tv->cur_row - p1 < 0) ? 0 : tv->cur_row - p1; break; | |
| case 'B': /* CUD */ tv->cur_row = (tv->cur_row + p1 >= TERM_ROWS) ? TERM_ROWS-1 : tv->cur_row + p1; break; | |
| case 'C': /* CUF */ tv->cur_col = (tv->cur_col + p1 >= TERM_COLS) ? TERM_COLS-1 : tv->cur_col + p1; break; | |
| case 'D': /* CUB */ tv->cur_col = (tv->cur_col - p1 < 0) ? 0 : tv->cur_col - p1; break; | |
| case 'H': /* CUP */ case 'f': | |
| tv->cur_row = (p1 < 1 ? 1 : p1) - 1; | |
| tv->cur_col = (p2 < 1 ? 1 : p2) - 1; | |
| if (tv->cur_row >= TERM_ROWS) tv->cur_row = TERM_ROWS - 1; | |
| if (tv->cur_col >= TERM_COLS) tv->cur_col = TERM_COLS - 1; | |
| break; | |
| case 'G': /* CHA */ tv->cur_col = (p1 < 1 ? 1 : p1) - 1; break; | |
| case 'd': /* VPA */ tv->cur_row = (p1 < 1 ? 1 : p1) - 1; break; | |
| case 'J': /* ED */ | |
| if (p1 == 2 || p1 == 3) grid_clear(tv); | |
| else if (p1 == 0) { | |
| for (int c = tv->cur_col; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[tv->cur_row][c], tv->cur_bg); | |
| for (int r = tv->cur_row+1; r < TERM_ROWS; r++) | |
| for (int c = 0; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[r][c], tv->cur_bg); | |
| } | |
| break; | |
| case 'K': /* EL */ | |
| if (p1 == 0) | |
| for (int c = tv->cur_col; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[tv->cur_row][c], tv->cur_bg); | |
| else if (p1 == 1) | |
| for (int c = 0; c <= tv->cur_col; c++) | |
| cell_clear(&tv->grid[tv->cur_row][c], tv->cur_bg); | |
| else | |
| for (int c = 0; c < TERM_COLS; c++) | |
| cell_clear(&tv->grid[tv->cur_row][c], tv->cur_bg); | |
| break; | |
| case 'r': /* DECSTBM */ | |
| tv->scroll_top = (p1 < 1 ? 1 : p1) - 1; | |
| tv->scroll_bot = (p2 < 1 ? TERM_ROWS : p2) - 1; | |
| if (tv->scroll_top >= TERM_ROWS) tv->scroll_top = 0; | |
| if (tv->scroll_bot >= TERM_ROWS) tv->scroll_bot = TERM_ROWS - 1; | |
| break; | |
| case 'm': /* SGR */ | |
| apply_sgr(tv, params); | |
| break; | |
| default: break; | |
| } | |
| } | |
| static void feed_byte(TerminalView *tv, char byte) { | |
| switch (tv->ps) { | |
| case PS_NORMAL: | |
| if (byte == '\x1b') { tv->ps = PS_ESC; return; } | |
| if (byte == '\r') { tv->cur_col = 0; return; } | |
| if (byte == '\n') { newline(tv); return; } | |
| if (byte == '\b') { if (tv->cur_col > 0) tv->cur_col--; return; } | |
| if (byte == '\t') { | |
| tv->cur_col = (tv->cur_col + 8) & ~7; | |
| if (tv->cur_col >= TERM_COLS) tv->cur_col = TERM_COLS - 1; | |
| return; | |
| } | |
| if ((unsigned char)byte >= 0x20) { | |
| /* UTF-8 single-byte only for now; multibyte β replacement char */ | |
| put_char(tv, (wchar_t)(unsigned char)byte); | |
| } | |
| break; | |
| case PS_ESC: | |
| if (byte == '[') { tv->ps = PS_CSI; tv->csi_len = 0; return; } | |
| if (byte == 'c') { grid_clear(tv); tv->cur_row = 0; tv->cur_col = 0; } | |
| tv->ps = PS_NORMAL; | |
| break; | |
| case PS_CSI: | |
| if (tv->csi_len < 63) | |
| tv->csi_buf[tv->csi_len++] = byte; | |
| /* Final byte is in range 0x40β0x7E */ | |
| if (byte >= 0x40 && byte <= 0x7E) { | |
| tv->csi_buf[tv->csi_len] = '\0'; | |
| dispatch_csi(tv); | |
| tv->ps = PS_NORMAL; | |
| tv->csi_len = 0; | |
| } | |
| break; | |
| } | |
| } | |
| static void feed_bytes(TerminalView *tv, const char *data, size_t len) { | |
| for (size_t i = 0; i < len; i++) | |
| feed_byte(tv, data[i]); | |
| } | |
| /* ββ D2D init / destroy ββββββββββββββββββββββββββββββββββββββββ */ | |
| static HRESULT init_d2d(TerminalView *tv) { | |
| HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &tv->d2d); | |
| if (FAILED(hr)) return hr; | |
| hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), | |
| reinterpret_cast<IUnknown **>(&tv->dw)); | |
| if (FAILED(hr)) return hr; | |
| tv->dw->CreateTextFormat(L"Consolas", nullptr, | |
| DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, | |
| DWRITE_FONT_STRETCH_NORMAL, FONT_SIZE, L"en-us", &tv->fmt); | |
| tv->dw->CreateTextFormat(L"Consolas", nullptr, | |
| DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL, | |
| DWRITE_FONT_STRETCH_NORMAL, FONT_SIZE, L"en-us", &tv->fmt_bold); | |
| /* Measure one cell */ | |
| IDWriteTextLayout *tl = nullptr; | |
| tv->dw->CreateTextLayout(L"M", 1, tv->fmt, 1000.0f, 1000.0f, &tl); | |
| if (tl) { | |
| DWRITE_TEXT_METRICS m; tl->GetMetrics(&m); | |
| tv->cell_w = m.width; tv->cell_h = m.height + 2.0f; | |
| tl->Release(); | |
| } else { | |
| tv->cell_w = 8.0f; tv->cell_h = 16.0f; | |
| } | |
| RECT rc; GetClientRect(tv->hwnd, &rc); | |
| tv->d2d->CreateHwndRenderTarget( | |
| D2D1::RenderTargetProperties(), | |
| D2D1::HwndRenderTargetProperties(tv->hwnd, | |
| D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), | |
| &tv->rt); | |
| if (tv->rt) { | |
| for (int i = 0; i < 8; i++) | |
| tv->rt->CreateSolidColorBrush(ANSI_COLORS[i], &tv->brushes[i]); | |
| tv->rt->CreateSolidColorBrush(C_CURSOR, &tv->br_cursor); | |
| } | |
| return S_OK; | |
| } | |
| /* ββ Public API ββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| extern "C" SovResult terminal_view_create(TerminalView **out, HWND hwnd) { | |
| TerminalView *tv = (TerminalView *)calloc(1, sizeof(TerminalView)); | |
| if (!tv) return SOV_ERR_ALLOC; | |
| tv->hwnd = hwnd; | |
| tv->cur_fg = 7; | |
| tv->cur_bg = 0; | |
| tv->scroll_top = 0; | |
| tv->scroll_bot = TERM_ROWS - 1; | |
| grid_clear(tv); | |
| init_d2d(tv); /* best-effort β rt may be null on failure, paint checks */ | |
| /* Compute initial cols/rows from pixel size */ | |
| RECT rc; GetClientRect(hwnd, &rc); | |
| tv->pixel_w = rc.right - rc.left; | |
| tv->pixel_h = rc.bottom - rc.top; | |
| uint16_t cols = (tv->cell_w > 0) ? (uint16_t)(tv->pixel_w / tv->cell_w) : 80; | |
| uint16_t rows = (tv->cell_h > 0) ? (uint16_t)(tv->pixel_h / tv->cell_h) : 24; | |
| if (cols < 10) cols = 80; | |
| if (rows < 4) rows = 24; | |
| /* Best-effort: ConPTY may not be available on older Windows */ | |
| SovResult r = terminal_create(&tv->pty, cols, rows); | |
| if (r != SOV_OK) { | |
| /* Fall back to a "no pty" display β still renders */ | |
| tv->pty = nullptr; | |
| const char *msg = "Terminal unavailable (requires Windows 10 1809+)\r\n"; | |
| feed_bytes(tv, msg, strlen(msg)); | |
| } else { | |
| const char *banner = "\x1b[32mSovereign IDE Terminal\x1b[0m\r\n"; | |
| feed_bytes(tv, banner, strlen(banner)); | |
| } | |
| *out = tv; | |
| return SOV_OK; | |
| } | |
| extern "C" void terminal_view_destroy(TerminalView *tv) { | |
| if (!tv) return; | |
| if (tv->pty) terminal_destroy(tv->pty); | |
| if (tv->br_cursor) tv->br_cursor->Release(); | |
| for (int i = 0; i < 8; i++) if (tv->brushes[i]) tv->brushes[i]->Release(); | |
| if (tv->fmt) tv->fmt->Release(); | |
| if (tv->fmt_bold) tv->fmt_bold->Release(); | |
| if (tv->rt) tv->rt->Release(); | |
| if (tv->d2d) tv->d2d->Release(); | |
| if (tv->dw) tv->dw->Release(); | |
| free(tv); | |
| } | |
| extern "C" void terminal_view_resize(TerminalView *tv, int w, int h) { | |
| tv->pixel_w = w; tv->pixel_h = h; | |
| if (tv->rt) tv->rt->Resize(D2D1::SizeU((UINT32)w, (UINT32)h)); | |
| if (tv->pty && tv->cell_w > 0 && tv->cell_h > 0) { | |
| uint16_t cols = (uint16_t)(w / tv->cell_w); | |
| uint16_t rows = (uint16_t)(h / tv->cell_h); | |
| if (cols < 10) cols = 80; | |
| if (rows < 4) rows = 24; | |
| terminal_resize(tv->pty, cols, rows); | |
| } | |
| } | |
| extern "C" void terminal_view_tick(TerminalView *tv) { | |
| if (!tv->pty) return; | |
| size_t nread = 0; | |
| if (terminal_read(tv->pty, tv->read_buf, sizeof(tv->read_buf), &nread) == SOV_OK && nread > 0) { | |
| feed_bytes(tv, tv->read_buf, nread); | |
| InvalidateRect(tv->hwnd, NULL, FALSE); | |
| } | |
| } | |
| extern "C" void terminal_view_key_down(TerminalView *tv, UINT vk, UINT mods) { | |
| if (!tv->pty) return; | |
| char seq[8] = {0}; | |
| int slen = 0; | |
| bool ctrl = (mods & 2) != 0; | |
| switch (vk) { | |
| case VK_RETURN: seq[0] = '\r'; slen = 1; break; | |
| case VK_BACK: seq[0] = '\x7f'; slen = 1; break; | |
| case VK_TAB: seq[0] = '\t'; slen = 1; break; | |
| case VK_ESCAPE: seq[0] = '\x1b'; slen = 1; break; | |
| case VK_UP: seq[0]='\x1b';seq[1]='[';seq[2]='A'; slen=3; break; | |
| case VK_DOWN: seq[0]='\x1b';seq[1]='[';seq[2]='B'; slen=3; break; | |
| case VK_RIGHT: seq[0]='\x1b';seq[1]='[';seq[2]='C'; slen=3; break; | |
| case VK_LEFT: seq[0]='\x1b';seq[1]='[';seq[2]='D'; slen=3; break; | |
| case VK_HOME: seq[0]='\x1b';seq[1]='[';seq[2]='H'; slen=3; break; | |
| case VK_END: seq[0]='\x1b';seq[1]='[';seq[2]='F'; slen=3; break; | |
| case VK_DELETE: seq[0]='\x1b';seq[1]='[';seq[2]='3';seq[3]='~'; slen=4; break; | |
| default: | |
| if (ctrl && vk >= 'A' && vk <= 'Z') { | |
| seq[0] = (char)(vk - 'A' + 1); slen = 1; | |
| } | |
| break; | |
| } | |
| if (slen > 0) terminal_write(tv->pty, seq, (size_t)slen); | |
| } | |
| extern "C" void terminal_view_char(TerminalView *tv, wchar_t ch) { | |
| if (!tv->pty) return; | |
| if (ch < 0x20 || ch == 0x7F) return; /* handled by key_down */ | |
| /* Convert to UTF-8 */ | |
| char utf8[4]; | |
| int ulen = 0; | |
| if (ch < 0x80) { | |
| utf8[0] = (char)ch; ulen = 1; | |
| } else if (ch < 0x800) { | |
| utf8[0] = (char)(0xC0 | (ch >> 6)); | |
| utf8[1] = (char)(0x80 | (ch & 0x3F)); | |
| ulen = 2; | |
| } else { | |
| utf8[0] = (char)(0xE0 | (ch >> 12)); | |
| utf8[1] = (char)(0x80 | ((ch >> 6) & 0x3F)); | |
| utf8[2] = (char)(0x80 | (ch & 0x3F)); | |
| ulen = 3; | |
| } | |
| terminal_write(tv->pty, utf8, (size_t)ulen); | |
| } | |
| extern "C" void terminal_view_paint(TerminalView *tv) { | |
| if (!tv->rt && tv->d2d) { | |
| RECT rc; GetClientRect(tv->hwnd, &rc); | |
| UINT W = rc.right > rc.left ? (UINT)(rc.right - rc.left) : 1; | |
| UINT H = rc.bottom > rc.top ? (UINT)(rc.bottom - rc.top) : 1; | |
| tv->d2d->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), | |
| D2D1::HwndRenderTargetProperties(tv->hwnd, D2D1::SizeU(W, H)), &tv->rt); | |
| if (tv->rt) { | |
| for (int i = 0; i < 8; i++) | |
| tv->rt->CreateSolidColorBrush(ANSI_COLORS[i], &tv->brushes[i]); | |
| tv->rt->CreateSolidColorBrush(C_CURSOR, &tv->br_cursor); | |
| } | |
| } | |
| if (!tv->rt) return; | |
| tv->rt->BeginDraw(); | |
| tv->rt->Clear(&ANSI_COLORS[0]); | |
| int visible_rows = (tv->cell_h > 0) ? (int)(tv->pixel_h / tv->cell_h) + 1 : TERM_ROWS; | |
| int visible_cols = (tv->cell_w > 0) ? (int)(tv->pixel_w / tv->cell_w) + 1 : TERM_COLS; | |
| if (visible_rows > TERM_ROWS) visible_rows = TERM_ROWS; | |
| if (visible_cols > TERM_COLS) visible_cols = TERM_COLS; | |
| for (int r = 0; r < visible_rows; r++) { | |
| for (int c = 0; c < visible_cols; c++) { | |
| Cell *cell = &tv->grid[r][c]; | |
| float x = c * tv->cell_w; | |
| float y = r * tv->cell_h; | |
| D2D1_RECT_F cr = D2D1::RectF(x, y, x + tv->cell_w, y + tv->cell_h); | |
| /* Background β only draw if non-default */ | |
| if (cell->bg != 0) { | |
| tv->rt->FillRectangle(cr, tv->brushes[cell->bg & 7]); | |
| } | |
| /* Character */ | |
| if (cell->ch != L' ' && cell->ch != L'\0') { | |
| auto *fmt = cell->bold ? tv->fmt_bold : tv->fmt; | |
| tv->rt->DrawText(&cell->ch, 1, fmt, cr, tv->brushes[cell->fg & 7]); | |
| } | |
| } | |
| } | |
| /* Cursor block */ | |
| { | |
| float cx = tv->cur_col * tv->cell_w; | |
| float cy = tv->cur_row * tv->cell_h; | |
| D2D1_RECT_F cur_r = D2D1::RectF(cx, cy, cx + tv->cell_w, cy + tv->cell_h); | |
| tv->rt->FillRectangle(cur_r, tv->br_cursor); | |
| /* Redraw char under cursor inverted */ | |
| Cell *cc = &tv->grid[tv->cur_row][tv->cur_col]; | |
| if (cc->ch != L' ' && cc->ch != L'\0') { | |
| auto *fmt = cc->bold ? tv->fmt_bold : tv->fmt; | |
| tv->rt->DrawText(&cc->ch, 1, fmt, cur_r, tv->brushes[0]); | |
| } | |
| } | |
| HRESULT hr = tv->rt->EndDraw(nullptr, nullptr); | |
| if (hr == (HRESULT)D2DERR_RECREATE_TARGET) { | |
| tv->rt->Release(); tv->rt = nullptr; | |
| RECT rc; GetClientRect(tv->hwnd, &rc); | |
| tv->d2d->CreateHwndRenderTarget( | |
| D2D1::RenderTargetProperties(), | |
| D2D1::HwndRenderTargetProperties(tv->hwnd, | |
| D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), | |
| &tv->rt); | |
| if (tv->rt) { | |
| for (int i = 0; i < 8; i++) | |
| tv->rt->CreateSolidColorBrush(ANSI_COLORS[i], &tv->brushes[i]); | |
| tv->rt->CreateSolidColorBrush(C_CURSOR, &tv->br_cursor); | |
| } | |
| } | |
| } | |