/* * This function dynamically adds support for wide-characters. */ void ChangeToWide(TScreen * screen) { unsigned new_bufoffset = (OFF_COM2H + 1); int savelines = screen->scrollWidget ? screen->savelines : 0; if (screen->wide_chars) return; TRACE(("ChangeToWide\n")); if (xtermLoadWideFonts(term, True)) { if (savelines < 0) savelines = 0; ReallocateBufOffsets(&screen->allbuf, &screen->sbuf_address, (unsigned) (MaxRows(screen) + savelines), (unsigned) MaxCols(screen), new_bufoffset); if (screen->altbuf) ReallocateBufOffsets(&screen->altbuf, &screen->abuf_address, (unsigned) MaxRows(screen), (unsigned) MaxCols(screen), new_bufoffset); screen->wide_chars = True; term->num_ptrs = new_bufoffset; screen->visbuf = &screen->allbuf[MAX_PTRS * savelines]; update_font_utf8_mode(); SetVTFont(term, screen->menu_font_number, TRUE, NULL); } TRACE(("...ChangeToWide\n")); }
void WindowScroll(XtermWidget xw, int top, Bool always GCC_UNUSED) { TScreen *screen = TScreenOf(xw); #if OPT_SCROLL_LOCK if (screen->allowScrollLock && (screen->scroll_lock && !always)) { if (screen->scroll_dirty) { screen->scroll_dirty = False; ScrnRefresh(xw, 0, 0, MaxRows(screen), MaxCols(screen), False); } } else #endif { int i; if (top < -screen->savedlines) { top = -screen->savedlines; } else if (top > 0) { top = 0; } if ((i = screen->topline - top) != 0) { int lines; int scrolltop, scrollheight, refreshtop; if (screen->cursor_state) HideCursor(); lines = i > 0 ? i : -i; if (lines > MaxRows(screen)) lines = MaxRows(screen); scrollheight = screen->max_row - lines + 1; if (i > 0) refreshtop = scrolltop = 0; else { scrolltop = lines; refreshtop = scrollheight; } scrolling_copy_area(xw, scrolltop, scrollheight, -i); screen->topline = top; ScrollSelection(screen, i, True); xtermClear2(xw, OriginX(screen), OriginY(screen) + refreshtop * FontHeight(screen), (unsigned) Width(screen), (unsigned) (lines * FontHeight(screen))); ScrnRefresh(xw, refreshtop, 0, lines, MaxCols(screen), False); #if OPT_BLINK_CURS || OPT_BLINK_TEXT RestartBlinking(screen); #endif } } ScrollBarDrawThumb(screen->scrollWidget); }
/* * After writing text to the screen, resolve mismatch between the current * location and any attributes that would have been set by preceding locations. */ void Resolve_XMC(XtermWidget xw) { TScreen *screen = TScreenOf(xw); LineData *ld; Bool changed = False; Char start; Char my_attrs = CharOf(screen->xmc_attributes & XMC_FLAGS); int row = screen->cur_row; int col = screen->cur_col; /* Find the preceding cell. */ ld = getLineData(screen, row); if (ld->charData[col] != XMC_GLITCH) { if (col != 0) { col--; } else if (!screen->xmc_inline && row != 0) { ld = getLineData(screen, --row); col = LineMaxCol(screen, ld); } } start = (ld->attribs[col] & my_attrs); /* Now propagate the starting state until we reach a cell which holds * a glitch. */ for (;;) { if (col < LineMaxCol(screen, ld)) { col++; } else if (!screen->xmc_inline && row < screen->max_row) { col = 0; ld = getLineData(screen, ++row); } else break; if (ld->charData[col] == XMC_GLITCH) break; if ((ld->attribs[col] & my_attrs) != start) { ld->attribs[col] = CharOf(start | (ld->attribs[col] & ~my_attrs)); changed = True; } } TRACE(("XMC %s (%s:%d/%d) from %d,%d to %d,%d\n", changed ? "Ripple" : "Nochange", BtoS(xw->flags & my_attrs), my_attrs, start, screen->cur_row, screen->cur_col, row, col)); if (changed) { ScrnUpdate(xw, screen->cur_row, 0, row + 1 - screen->cur_row, MaxCols(screen), True); } }
static void repaint_line(XtermWidget xw, unsigned newChrSet) { TScreen *screen = TScreenOf(xw); LineData *ld; int curcol = screen->cur_col; int currow = screen->cur_row; int width = MaxCols(screen); unsigned len = (unsigned) width; assert(width > 0); /* * Ignore repetition. */ if (!IsLeftRightMode(xw) && (ld = getLineData(screen, currow)) != 0) { unsigned oldChrSet = GetLineDblCS(ld); if (oldChrSet != newChrSet) { TRACE(("repaint_line(%2d,%2d) (%s -> %s)\n", currow, screen->cur_col, visibleDblChrset(oldChrSet), visibleDblChrset(newChrSet))); HideCursor(); /* If switching from single-width, keep the cursor in the visible part * of the line. */ if (CSET_DOUBLE(newChrSet)) { width /= 2; if (curcol > width) curcol = width; } /* * ScrnRefresh won't paint blanks for us if we're switching between a * single-size and double-size font. So we paint our own. */ ClearCurBackground(xw, currow, 0, 1, len, (unsigned) LineFontWidth(screen, ld)); SetLineDblCS(ld, newChrSet); set_cur_col(screen, 0); ScrnUpdate(xw, currow, 0, 1, (int) len, True); set_cur_col(screen, curcol); } } }
/* * Writes str into buf at screen's current row and column. Characters are set * to match flags. */ void ScreenWrite(TScreen * screen, PAIRED_CHARS(Char * str, Char * str2), unsigned flags, unsigned cur_fg_bg, unsigned length) { #if OPT_ISO_COLORS #if OPT_EXT_COLORS Char *fbf = 0; Char *fbb = 0; #else Char *fb = 0; #endif #endif #if OPT_DEC_CHRSET Char *cb = 0; #endif Char *attrs; int avail = MaxCols(screen) - screen->cur_col; Char *chars; int wrappedbit; #if OPT_WIDE_CHARS Char starcol1, starcol2; Char *comb1l = 0, *comb1h = 0, *comb2l = 0, *comb2h = 0; #endif unsigned real_width = visual_width(PAIRED_CHARS(str, str2), length); if (avail <= 0) return; if (length > (unsigned) avail) length = avail; if (length == 0 || real_width == 0) return; chars = SCRN_BUF_CHARS(screen, screen->cur_row) + screen->cur_col; attrs = SCRN_BUF_ATTRS(screen, screen->cur_row) + screen->cur_col; if_OPT_WIDE_CHARS(screen, { comb1l = SCRN_BUF_COM1L(screen, screen->cur_row) + screen->cur_col; comb1h = SCRN_BUF_COM1H(screen, screen->cur_row) + screen->cur_col; comb2l = SCRN_BUF_COM2L(screen, screen->cur_row) + screen->cur_col; comb2h = SCRN_BUF_COM2H(screen, screen->cur_row) + screen->cur_col; });
/* * Allocate a new row in the scrollback FIFO, returning a pointer to it. */ LineData * addScrollback(TScreen * screen) { ScrnBuf where = 0; unsigned which; unsigned ncols = (unsigned) MaxCols(screen); Char *block; if (screen->saveBuf_index != 0) { screen->saved_fifo++; TRACE(("addScrollback %lu\n", screen->saved_fifo)); /* first, see which index we'll use */ which = (unsigned) (screen->saved_fifo % screen->savelines); where = scrnHeadAddr(screen, screen->saveBuf_index, which); /* discard any obsolete index data */ if (screen->saved_fifo > screen->savelines) { LineData *prior = (LineData *) where; /* * setupLineData uses the attribs as the first address used from the * data block. */ if (prior->attribs != 0) { TRACE(("...freeing prior FIFO data in slot %d: %p->%p\n", which, (void *) prior, prior->attribs)); free(prior->attribs); prior->attribs = 0; } } /* allocate the new data */ block = allocScrnData(screen, 1, ncols); /* record the new data in the index */ setupLineData(screen, where, (Char *) block, 1, ncols); TRACE(("...storing new FIFO data in slot %d: %p->%p\n", which, (void *) where, block)); } return (LineData *) where; }
static void dumpSvgScreen(XtermWidget xw, FILE *fp) { TScreen *s = TScreenOf(xw); int row; fprintf(fp, " <rect x='0' y='0' width='%u' height='%u' fill='%s'/>\n", cols * CELLW + 2 * (bw + ib), rows * CELLH + 2 * (bw + ib), PixelToCSSColor(xw, xw->core.border_pixel)); fprintf(fp, " <rect x='%u' y='%u' width='%u' height='%u' fill='%s'/>\n", bw, bw, MaxCols(s) * CELLW + 2 * ib, (unsigned) (rows * CELLH + 2 * ib), PixelToCSSColor(xw, xw->old_background)); for (row = s->top_marg; row <= s->bot_marg; ++row) { fprintf(fp, " <!-- Row %d -->\n", row); dumpSvgLine(xw, row, fp); } }
static void dumpSvgHeader(XtermWidget xw, FILE *fp) { TScreen *s = TScreenOf(xw); rows = s->bot_marg - s->top_marg + 1; cols = MaxCols(s); bw = BorderWidth(xw); ib = s->border; fputs("<?xml version='1.0' encoding='UTF-8'?>\n", fp); fputs("<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'\n", fp); fputs(" 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>\n", fp); fputs("<svg xmlns='http://www.w3.org/2000/svg'\n", fp); fputs(" version='1.1' baseProfile='full'\n", fp); fprintf(fp, " viewBox='0 0 %d %d'>\n", 2 * (bw + ib) + cols * CELLW, 2 * (bw + ib) + rows * CELLH); fprintf(fp, " <desc>%s Screen Dump</desc>\n", xtermVersion()); fprintf(fp, " <g font-size='%.2f' font-family='monospace, monospace'>\n", 0.80 * CELLH); }
void saveCellData(TScreen * screen, CellData * data, Cardinal cell, LineData * ld, int column) { CellData *item = CellDataAddr(screen, data, cell); if (column < MaxCols(screen)) { item->attribs = ld->attribs[column]; #if OPT_ISO_COLORS item->color = ld->color[column]; #endif item->charData = ld->charData[column]; if_OPT_WIDE_CHARS(screen, { size_t off; item->combSize = ld->combSize; for_each_combData(off, ld) { item->combData[off] = ld->combData[off][column]; } }) }
/* * moves the cursor left n, no wrap around */ void CursorBack(TScreen * screen, int n) { int i, j, k, rev; if ((rev = (term->flags & (REVERSEWRAP | WRAPAROUND)) == (REVERSEWRAP | WRAPAROUND)) != 0 && screen->do_wrap) n--; if ((screen->cur_col -= n) < 0) { if (rev) { if ((i = ((j = MaxCols(screen)) * screen->cur_row) + screen->cur_col) < 0) { k = j * MaxRows(screen); i += ((-i) / k + 1) * k; } set_cur_row(screen, i / j); set_cur_col(screen, i % j); } else set_cur_col(screen, 0); } screen->do_wrap = 0; }
/* * Given a row-number, find the corresponding data for the line in the VT100 * widget. Row numbers can be positive or negative. * * If the data comes from the scrollback, defer that to getScrollback(). */ LineData * getLineData(TScreen * screen, int row) { LineData *result = 0; ScrnBuf buffer; int max_row = screen->max_row; if (row >= 0) { buffer = screen->visbuf; } else { #if OPT_FIFO_LINES buffer = 0; result = getScrollback(screen, row); #else buffer = screen->saveBuf_index; row += screen->savelines; max_row += screen->savelines; #endif } if (row >= 0 && row <= max_row) { result = (LineData *) scrnHeadAddr(screen, buffer, (unsigned) row); if (result != 0) { #if 1 /* FIXME - these should be done in setupLineData, etc. */ result->lineSize = (Dimension) MaxCols(screen); #if OPT_WIDE_CHARS if (screen->wide_chars) { result->combSize = (Char) screen->max_combining; } else { result->combSize = 0; } #endif #endif /* FIXME */ } } return result; }
/* Resize the text window for a terminal screen, modifying the * appropriate WM_SIZE_HINTS and taking advantage of bit gravity. */ void DoResizeScreen(XtermWidget xw) { TScreen *screen = TScreenOf(xw); int border = 2 * screen->border; int min_wide = border + screen->fullVwin.sb_info.width; int min_high = border; XtGeometryResult geomreqresult; Dimension reqWidth, reqHeight, repWidth, repHeight; #ifndef NO_ACTIVE_ICON VTwin *saveWin = WhichVWin(screen); /* all units here want to be in the normal font units */ WhichVWin(screen) = &screen->fullVwin; #endif /* NO_ACTIVE_ICON */ /* * I'm going to try to explain, as I understand it, why we * have to do XGetWMNormalHints and XSetWMNormalHints here, * although I can't guarantee that I've got it right. * * In a correctly written toolkit program, the Shell widget * parses the user supplied geometry argument. However, * because of the way xterm does things, the VT100 widget does * the parsing of the geometry option, not the Shell widget. * The result of this is that the Shell widget doesn't set the * correct window manager hints, and doesn't know that the * user has specified a geometry. * * The XtVaSetValues call below tells the Shell widget to * change its hints. However, since it's confused about the * hints to begin with, it doesn't get them all right when it * does the SetValues -- it undoes some of what the VT100 * widget did when it originally set the hints. * * To fix this, we do the following: * * 1. Get the sizehints directly from the window, going around * the (confused) shell widget. * 2. Call XtVaSetValues to let the shell widget know which * hints have changed. Note that this may not even be * necessary, since we're going to right ahead after that * and set the hints ourselves, but it's good to put it * here anyway, so that when we finally do fix the code so * that the Shell does the right thing with hints, we * already have the XtVaSetValues in place. * 3. We set the sizehints directly, this fixing up whatever * damage was done by the Shell widget during the * XtVaSetValues. * * Gross, huh? * * The correct fix is to redo VTRealize, VTInitialize and * VTSetValues so that font processing happens early enough to * give back responsibility for the size hints to the Shell. * * Someday, we hope to have time to do this. Someday, we hope * to have time to completely rewrite xterm. */ TRACE(("DoResizeScreen\n")); #if 1 /* ndef nothack */ /* * NOTE: the hints and the XtVaSetValues() must match. */ TRACE(("%s@%d -- ", __FILE__, __LINE__)); TRACE_WM_HINTS(xw); getXtermSizeHints(xw); xtermSizeHints(xw, ScrollbarWidth(screen)); /* These are obsolete, but old clients may use them */ xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width; xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height; #if OPT_MAXIMIZE /* assure single-increment resize for fullscreen */ if (xw->work.ewmh[0].mode) { xw->hints.width_inc = 1; xw->hints.height_inc = 1; } #endif /* OPT_MAXIMIZE */ #endif XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints); reqWidth = (Dimension) (MaxCols(screen) * FontWidth(screen) + min_wide); reqHeight = (Dimension) (MaxRows(screen) * FontHeight(screen) + min_high); #if OPT_MAXIMIZE /* compensate for fullscreen mode */ if (xw->work.ewmh[0].mode) { Screen *xscreen = DefaultScreenOfDisplay(xw->screen.display); reqWidth = (Dimension) WidthOfScreen(xscreen); reqHeight = (Dimension) HeightOfScreen(xscreen); ScreenResize(xw, reqWidth, reqHeight, &xw->flags); } #endif /* OPT_MAXIMIZE */ TRACE(("...requesting screensize chars %dx%d, pixels %dx%d\n", MaxRows(screen), MaxCols(screen), reqHeight, reqWidth)); geomreqresult = REQ_RESIZE((Widget) xw, reqWidth, reqHeight, &repWidth, &repHeight); if (geomreqresult == XtGeometryAlmost) { TRACE(("...almost, retry screensize %dx%d\n", repHeight, repWidth)); geomreqresult = REQ_RESIZE((Widget) xw, repWidth, repHeight, NULL, NULL); } if (geomreqresult != XtGeometryYes) { /* The resize wasn't successful, so we might need to adjust our idea of how large the screen is. */ TRACE(("...still no (%d) - resize the core-class\n", geomreqresult)); xw->core.widget_class->core_class.resize((Widget) xw); } #if 1 /* ndef nothack */ /* * XtMakeResizeRequest() has the undesirable side-effect of clearing * the window manager's hints, even on a failed request. This would * presumably be fixed if the shell did its own work. */ if (xw->hints.flags && repHeight && repWidth) { xw->hints.height = repHeight; xw->hints.width = repWidth; TRACE_HINTS(&xw->hints); XSetWMNormalHints(screen->display, VShellWindow(xw), &xw->hints); } #endif XSync(screen->display, False); /* synchronize */ if (xtermAppPending()) xevents(); #ifndef NO_ACTIVE_ICON WhichVWin(screen) = saveWin; #endif /* NO_ACTIVE_ICON */ }
static void dumpSvgLine(XtermWidget xw, int row, FILE *fp) { TScreen *s = TScreenOf(xw); int inx = ROW2INX(s, row); LineData *ld = getLineData(s, inx); int col, sal, i; /* sal: same attribute length */ if (ld == 0) return; for (col = 0; col < MaxCols(s); col += sal) { XColor fgcolor, bgcolor; /* Count how many consecutive cells have the same color & attributes. */ for (sal = 1; col + sal < MaxCols(s); ++sal) { #if OPT_ISO_COLORS if (ld->color[col] != ld->color[col + sal]) break; #endif if (ld->attribs[col] != ld->attribs[col + sal]) break; } fgcolor.pixel = xw->old_foreground; bgcolor.pixel = xw->old_background; #if OPT_ISO_COLORS if (ld->attribs[col] & FG_COLOR) { unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]); fgcolor.pixel = s->Acolors[fg].value; } if (ld->attribs[col] & BG_COLOR) { unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]); bgcolor.pixel = s->Acolors[bg].value; } #endif XQueryColor(xw->screen.display, xw->core.colormap, &fgcolor); XQueryColor(xw->screen.display, xw->core.colormap, &bgcolor); if (ld->attribs[col] & BLINK) { /* White on red. */ fgcolor.red = fgcolor.green = fgcolor.blue = 65535u; bgcolor.red = 65535u; bgcolor.green = bgcolor.blue = 0u; } #if OPT_WIDE_ATTRS if (ld->attribs[col] & ATR_FAINT) { fgcolor.red = (unsigned short) ((2 * fgcolor.red) / 3); fgcolor.green = (unsigned short) ((2 * fgcolor.green) / 3); fgcolor.blue = (unsigned short) ((2 * fgcolor.blue) / 3); } #endif if (ld->attribs[col] & INVERSE) { XColor tmp = fgcolor; fgcolor = bgcolor; bgcolor = tmp; } /* Draw the background rectangle. */ fprintf(fp, " <rect x='%d' y='%d' ", bw + ib + col * CELLW, bw + ib + row * CELLH); fprintf(fp, "height='%d' width='%d' ", CELLH, sal * CELLW); fprintf(fp, "fill='rgb(%.2f%%, %.2f%%, %.2f%%)'/>\n", RGBPCT(bgcolor)); /* Now the <text>. */ /* * SVG: Rendering text strings into a given rectangle is a challenge. * Some renderers accept and do the right thing with the 'textLength' * attribute, while others ignore it. The only predictable way to place * (even monospaced) text properly is to do it character by character. */ fprintf(fp, " <g"); if (ld->attribs[col] & BOLD) fprintf(fp, " font-weight='bold'"); #if OPT_WIDE_ATTRS if (ld->attribs[col] & ATR_ITALIC) fprintf(fp, " font-style='italic'"); #endif fprintf(fp, " fill='rgb(%.2f%%, %.2f%%, %.2f%%)'>\n", RGBPCT(fgcolor)); for (i = 0; i < sal; ++i) { IChar chr = ld->charData[col + i]; if (chr == ' ') continue; fprintf(fp, " <text x='%d' y='%d'>", bw + ib + (col + i) * CELLW, bw + ib + row * CELLH + (CELLH * 3) / 4); #if OPT_WIDE_CHARS if (chr > 127) { /* Ignore hidden characters. */ if (chr != HIDDEN_CHAR) { Char temp[10]; *convertToUTF8(temp, chr) = 0; fputs((char *) temp, fp); } } else #endif switch (chr) { case 0: /* This sometimes happens when resizing... ignore. */ break; case '&': fputs("&", fp); break; case '<': fputs("<", fp); break; case '>': fputs(">", fp); break; default: fputc((int) chr, fp); } fprintf(fp, "</text>\n"); } fprintf(fp, " </g>\n"); #define HLINE(x) \ fprintf(fp, " <line x1='%d' y1='%d' " \ "x2='%d' y2='%d' " \ "stroke='rgb(%.2f%%, %.2f%%, %.2f%%)'/>\n", \ bw + ib + col * CELLW, bw + ib + row * CELLH + CELLH - (x), \ bw + ib + (col + sal) * CELLW, bw + ib + row * CELLH + CELLH - (x), \ RGBPCT(fgcolor)) /* Now the line attributes. */ if (ld->attribs[col] & UNDERLINE) { HLINE(4); } #if OPT_WIDE_ATTRS if (ld->attribs[col] & ATR_STRIKEOUT) { HLINE(9); } if (ld->attribs[col] & ATR_DBL_UNDER) { HLINE(3); HLINE(1); } #endif } }