diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/xterm/MANIFEST | 4 | ||||
-rw-r--r-- | app/xterm/button.c | 14 | ||||
-rw-r--r-- | app/xterm/charproc.c | 94 | ||||
-rw-r--r-- | app/xterm/graphics.c | 975 | ||||
-rw-r--r-- | app/xterm/graphics.h | 24 | ||||
-rw-r--r-- | app/xterm/graphics_regis.c | 959 | ||||
-rw-r--r-- | app/xterm/graphics_sixel.c | 9 | ||||
-rw-r--r-- | app/xterm/linedata.c | 27 | ||||
-rw-r--r-- | app/xterm/misc.c | 13 | ||||
-rw-r--r-- | app/xterm/package/debian/changelog | 6 | ||||
-rw-r--r-- | app/xterm/package/debian/postinst | 25 | ||||
-rw-r--r-- | app/xterm/package/debian/prerm | 12 | ||||
-rw-r--r-- | app/xterm/package/freebsd/Makefile | 2 | ||||
-rw-r--r-- | app/xterm/package/xterm.spec | 4 | ||||
-rw-r--r-- | app/xterm/ptyx.h | 29 | ||||
-rw-r--r-- | app/xterm/screen.c | 27 | ||||
-rw-r--r-- | app/xterm/trace.c | 8 | ||||
-rw-r--r-- | app/xterm/trace.h | 6 | ||||
-rw-r--r-- | app/xterm/util.c | 33 | ||||
-rw-r--r-- | app/xterm/version.h | 6 | ||||
-rw-r--r-- | app/xterm/vttests/resize.pl | 8 | ||||
-rw-r--r-- | app/xterm/xterm.h | 18 | ||||
-rw-r--r-- | app/xterm/xterm.log.html | 100 | ||||
-rw-r--r-- | app/xterm/xterm.man | 65 |
24 files changed, 1675 insertions, 793 deletions
diff --git a/app/xterm/MANIFEST b/app/xterm/MANIFEST index e9068a65f..b15fa8283 100644 --- a/app/xterm/MANIFEST +++ b/app/xterm/MANIFEST @@ -1,4 +1,4 @@ -MANIFEST for xterm-312, version xterm-312 +MANIFEST for xterm-313, version xterm-313 -------------------------------------------------------------------------------- MANIFEST this file 256colres.h resource-definitions for 256-color mode @@ -150,6 +150,8 @@ package/debian/color.sed build-script package/debian/compat build-script package/debian/control build-script package/debian/copyright build-script +package/debian/postinst post-install script for update-alternatives +package/debian/prerm pre-remove script for update-alternatives package/debian/rules build-script package/debian/source subdirectory package/debian/source/format build-script diff --git a/app/xterm/button.c b/app/xterm/button.c index 8dd739097..30412c74d 100644 --- a/app/xterm/button.c +++ b/app/xterm/button.c @@ -1,4 +1,4 @@ -/* $XTermId: button.c,v 1.482 2014/09/26 23:58:14 tom Exp $ */ +/* $XTermId: button.c,v 1.484 2014/11/13 01:00:26 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -2841,10 +2841,10 @@ PointToCELL(TScreen *screen, * Find the last column at which text was drawn on the given row. */ static int -LastTextCol(TScreen *screen, LineData *ld, int row) +LastTextCol(TScreen *screen, CLineData *ld, int row) { int i = -1; - IAttr *ch; + const IAttr *ch; if (ld != 0) { if (okScrnRow(screen, row)) { @@ -3170,7 +3170,7 @@ static void columnToCell(TScreen *screen, int row, int col, CELL *cell) { while (row < screen->max_row) { - LineData *ld = GET_LINEDATA(screen, row); + CLineData *ld = GET_LINEDATA(screen, row); int last = LastTextCol(screen, ld, row); /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ @@ -3200,7 +3200,7 @@ columnToCell(TScreen *screen, int row, int col, CELL *cell) static int cellToColumn(TScreen *screen, CELL *cell) { - LineData *ld = 0; + CLineData *ld = 0; int col = cell->col; int row = firstRowOfLine(screen, cell->row, False); while (row < cell->row) { @@ -4206,8 +4206,8 @@ Length(TScreen *screen, int scol, int ecol) { - LineData *ld = GET_LINEDATA(screen, row); - int lastcol = LastTextCol(screen, ld, row); + CLineData *ld = GET_LINEDATA(screen, row); + const int lastcol = LastTextCol(screen, ld, row); if (ecol > lastcol) ecol = lastcol; diff --git a/app/xterm/charproc.c b/app/xterm/charproc.c index 67d07e65a..185264200 100644 --- a/app/xterm/charproc.c +++ b/app/xterm/charproc.c @@ -1,4 +1,4 @@ -/* $XTermId: charproc.c,v 1.1370 2014/09/15 23:39:44 tom Exp $ */ +/* $XTermId: charproc.c,v 1.1379 2014/11/28 22:27:20 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -674,6 +674,11 @@ static XtResource xterm_resources[] = Ires(XtNprintAttributes, XtCPrintAttributes, SPS.print_attributes, 1), #endif +#if OPT_REGIS_GRAPHICS + Sres(XtNregisScreenSize, XtCRegisScreenSize, screen.regis_screensize, + "800x1000"), +#endif + #if OPT_SHIFT_FONTS Bres(XtNshiftFonts, XtCShiftFonts, misc.shift_fonts, True), #endif @@ -906,7 +911,7 @@ CheckBogusForeground(TScreen *screen, const char *tag) for (pass = 0; pass < 2; ++pass) { row = screen->cur_row; for (; isClear && (row <= screen->max_row); ++row) { - LineData *ld = getLineData(screen, row)->; + CLineData *ld = getLineData(screen, row); if (ld != 0) { IAttr *attribs = ld->attribs; @@ -4791,7 +4796,7 @@ PreeditPosition(XtermWidget xw) { TInput *input = lookupTInput(xw, (Widget) xw); TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; XPoint spot; XVaNestedList list; @@ -4958,7 +4963,7 @@ dotext(XtermWidget xw, for (offset = 0; offset < len; offset += (Cardinal) this_col) { #if OPT_DEC_CHRSET - LineData *ld = getLineData(screen, screen->cur_row); + CLineData *ld = getLineData(screen, screen->cur_row); #endif last_col = LineMaxCol(screen, ld); @@ -4994,7 +4999,7 @@ dotext(XtermWidget xw, #if OPT_WIDE_CHARS unsigned -visual_width(IChar *str, Cardinal len) +visual_width(const IChar *str, Cardinal len) { /* returns the visual width of a string (doublewide characters count as 2, normalwide characters count as 1) */ @@ -5024,12 +5029,12 @@ HandleStructNotify(Widget w GCC_UNUSED, switch (event->type) { case MapNotify: - TRACE(("HandleStructNotify(MapNotify)\n")); + TRACE(("HandleStructNotify(MapNotify) %#lx\n", event->xmap.window)); resetZIconBeep(xw); mapstate = !IsUnmapped; break; case UnmapNotify: - TRACE(("HandleStructNotify(UnmapNotify)\n")); + TRACE(("HandleStructNotify(UnmapNotify) %#lx\n", event->xunmap.window)); mapstate = IsUnmapped; break; case ConfigureNotify: @@ -5040,7 +5045,8 @@ HandleStructNotify(Widget w GCC_UNUSED, height = event->xconfigure.height; width = event->xconfigure.width; #endif - TRACE(("HandleStructNotify(ConfigureNotify) %d,%d %dx%d\n", + TRACE(("HandleStructNotify(ConfigureNotify) %#lx %d,%d %dx%d\n", + event->xconfigure.window, event->xconfigure.y, event->xconfigure.x, event->xconfigure.height, event->xconfigure.width)); @@ -5090,11 +5096,12 @@ HandleStructNotify(Widget w GCC_UNUSED, } break; case ReparentNotify: - TRACE(("HandleStructNotify(ReparentNotify)\n")); + TRACE(("HandleStructNotify(ReparentNotify) %#lx\n", event->xreparent.window)); break; default: - TRACE(("HandleStructNotify(event %s)\n", - visibleEventType(event->type))); + TRACE(("HandleStructNotify(event %s) %#lx\n", + visibleEventType(event->type), + event->xany.window)); break; } } @@ -6767,7 +6774,6 @@ ToAlternate(XtermWidget xw, Bool clearFirst) (unsigned) MaxCols(screen), &screen->editBuf_data[1]); SwitchBufs(xw, 1, clearFirst); - screen->whichBuf = 1; #if OPT_SAVE_LINES screen->visbuf = screen->editBuf_index[screen->whichBuf]; #endif @@ -6784,7 +6790,6 @@ FromAlternate(XtermWidget xw) TRACE(("FromAlternate\n")); if (screen->scroll_amt) FlushScroll(xw); - screen->whichBuf = 0; SwitchBufs(xw, 0, False); #if OPT_SAVE_LINES screen->visbuf = screen->editBuf_index[screen->whichBuf]; @@ -6799,6 +6804,7 @@ SwitchBufs(XtermWidget xw, int toBuf, Bool clearFirst) TScreen *screen = TScreenOf(xw); int rows, top; + screen->whichBuf = toBuf; if (screen->cursor_state) HideCursor(); @@ -8322,6 +8328,58 @@ VTInitialize(Widget wrequest, BtoS(TScreenOf(wnew)->privatecolorregisters))); #endif +#if OPT_REGIS_GRAPHICS + init_Sres(screen.regis_screensize); + TScreenOf(wnew)->regis_max_high = 800; + TScreenOf(wnew)->regis_max_wide = 1000; + if (!x_strcasecmp(TScreenOf(wnew)->regis_screensize, "auto")) { + TRACE(("setting ReGIS screensize based on terminal_id %d\n", + TScreenOf(wnew)->terminal_id)); + switch (TScreenOf(wnew)->terminal_id) { + case 125: + TScreenOf(wnew)->regis_max_high = 768; + TScreenOf(wnew)->regis_max_wide = 460; + break; + case 240: + TScreenOf(wnew)->regis_max_high = 800; + TScreenOf(wnew)->regis_max_wide = 460; + break; + case 241: + TScreenOf(wnew)->regis_max_high = 800; + TScreenOf(wnew)->regis_max_wide = 460; + break; + case 330: + TScreenOf(wnew)->regis_max_high = 800; + TScreenOf(wnew)->regis_max_wide = 480; + break; + case 340: + TScreenOf(wnew)->regis_max_high = 800; + TScreenOf(wnew)->regis_max_wide = 480; + break; + case 382: + TScreenOf(wnew)->regis_max_high = 960; + TScreenOf(wnew)->regis_max_wide = 750; + break; + } + } else { + int max_high; + int max_wide; + char ignore; + + if (sscanf(TScreenOf(wnew)->regis_screensize, + "%dx%d%c", + &max_high, + &max_wide, + &ignore) == 2) { + TScreenOf(wnew)->regis_max_high = (Dimension) max_high; + TScreenOf(wnew)->regis_max_wide = (Dimension) max_wide; + } + } + TRACE(("maximum ReGIS screensize %dx%d\n", + (int) TScreenOf(wnew)->regis_max_high, + (int) TScreenOf(wnew)->regis_max_wide)); +#endif + #if OPT_SIXEL_GRAPHICS init_Bres(screen.sixel_scrolls_right); TRACE(("initialized SIXEL_SCROLLS_RIGHT to resource default: %s\n", @@ -9676,7 +9734,7 @@ ShowCursor(void) int my_col = 0; #endif int cursor_col; - LineData *ld = 0; + CLineData *ld = 0; if (screen->cursor_state == BLINKED_OFF) return; @@ -10040,7 +10098,7 @@ HideCursor(void) int my_col = 0; #endif int cursor_col; - LineData *ld = 0; + CLineData *ld = 0; #if OPT_WIDE_ATTRS unsigned attr_flags; int which_font = fNorm; @@ -10180,7 +10238,7 @@ HideCursor(void) #endif resetXtermGC(xw, flags, in_selection); - refresh_displayed_graphics(screen, + refresh_displayed_graphics(xw, screen->cursorp.col, screen->cursorp.row, 1, 1); @@ -10219,7 +10277,7 @@ StopBlinking(TScreen *screen) #if OPT_BLINK_TEXT Bool -LineHasBlinking(TScreen *screen, LineData *ld) +LineHasBlinking(TScreen *screen, CLineData *ld) { int col; Bool result = False; @@ -10332,7 +10390,7 @@ RestartBlinking(TScreen *screen GCC_UNUSED) int row; for (row = screen->max_row; row >= 0; row--) { - LineData *ld = getLineData(screen, ROW2INX(screen, row)); + CLineData *ld = getLineData(screen, ROW2INX(screen, row)); if (ld != 0 && LineTstBlinked(ld)) { if (LineHasBlinking(screen, ld)) { diff --git a/app/xterm/graphics.c b/app/xterm/graphics.c index e880d76e3..434b4b02d 100644 --- a/app/xterm/graphics.c +++ b/app/xterm/graphics.c @@ -1,4 +1,4 @@ -/* $XTermId: graphics.c,v 1.47 2014/07/13 01:19:45 Ross.Combs Exp $ */ +/* $XTermId: graphics.c,v 1.58 2014/11/28 21:00:04 tom Exp $ */ /* * Copyright 2013,2014 by Ross Combs @@ -48,10 +48,11 @@ #undef DEBUG_PIXEL #undef DEBUG_REFRESH -/* TODO: +/* + * graphics TODO list + * * ReGIS: * - find a suitable default alphabet zero font instead of scaling Xft fonts - * - load command extension to load by font name (via Xft) * - input and output cursors * - mouse input * - custom coordinate systems @@ -62,6 +63,7 @@ * - command display mode * - scaling/re-rasterization to fit screen * - macros + * - improved fills for narrow angles (track actual lines not just pixels) * * sixel: * - fix problem where new_row < 0 during sixel parsing (see FIXME) @@ -79,25 +81,21 @@ * - research other 41xx and 42xx extensions * * common graphics features: - * - speed up drawing by using an XImage and/or better GC and color handling * - handle light/dark screen modes (CSI?5[hl]) * - update text fg/bg color which overlaps images - * - erase graphic when erasing screen - * - handle graphic updates in scroll regions + * - handle graphic updates in scroll regions (verify effect on graphics) * - handle rectangular area copies (verify they work with graphics) - * - maintain ordered list/array of graphics instead of qsort() - * - erase text under graphic if bg not transparent to avoid flickering (or not: bad if the font changes or window resizes) - * - erase graphics under graphic if same origin and bg not transparent to avoid flickering - * - erase scrolled portions of all graphics on alt buffer - * - delete graphic if scrolled past end of scrollback - * - delete graphic if all pixels are transparent/erased - * - auto-convert color graphics in VT330 mode + * - invalidate graphics under graphic if same origin, at least as big, and bg not transparent + * - invalidate graphic if completely scrolled past end of scrollback + * - invalidate graphic if all pixels are transparent/erased + * - invalidate graphic if completely scrolled out of alt buffer * - posturize requested colors to match hardware palettes (e.g. only four possible shades on VT240) * - color register report/restore * - ability to select/copy graphics for pasting in other programs - * - ability to show non-scrolled sixel graphics in a separate window + * - ability to show non-scroll-mode sixel graphics in a separate window * - ability to show ReGIS graphics in a separate window * - ability to show Tektronix graphics in VT100 window + * - truncate graphics at bottom edge of window? * * new escape sequences: * - way to query text font size without "window ops" (or make "window ops" permissions more fine grained) @@ -107,21 +105,17 @@ * - non-integer text scaling * - free distortionless text rotation * - font characteristics: bold/underline/italic - * - font selection by name - * - user fonts in larger sizes than 8x10 * - remove/increase arbitrary limits (pattern size, pages, alphabets, stack size, font names, etc.) * - comment command * - shade/fill with borders * - sprites (copy portion of page into/out of buffer with scaling and rotation) * - ellipses * - 2D patterns - * - option to set actual size (not just coordinates) + * - option to set actual graphic size (not just coordinate range) * - gradients (for lines and fills) * - line width (RLogin has this and it is mentioned in docs for the DEC ReGIS to Postscript converter) - * - F option for screen command (mentioned in docs for the DEC ReGIS to Postscript converter) * - transparency * - background color as stackable write control - * - RGB triplets * - true color (virtual color registers created upon lookup) * - anti-aliasing */ @@ -133,7 +127,16 @@ * 10 x 13 6 x 13 26 lines + keyboard indicator line * 10 x 10 6 x 10 42 lines + keyboard indicator line * 10 x 8 6 x 8 53 lines + keyboard indicator line -*/ + */ + +typedef struct allocated_color_register { + struct allocated_color_register *next; + Pixel pix; + short r, g, b; +} AllocatedColorRegister; + +#define LOOKUP_WIDTH 16 +static AllocatedColorRegister *allocated_colors[LOOKUP_WIDTH][LOOKUP_WIDTH][LOOKUP_WIDTH]; #define FOR_EACH_SLOT(ii) for (ii = 0U; ii < MAX_GRAPHICS; ii++) @@ -161,11 +164,12 @@ freeGraphic(Graphic *obj) } static Graphic * -allocGraphic(void) +allocGraphic(const TScreen *screen) { Graphic *result = TypeCalloc(Graphic); if (result) { - if (!(result->pixels = TypeCallocN(RegisterNum, MAX_PIXELS))) { + size_t max_pixels = (size_t) (screen->regis_max_wide * screen->regis_max_high); + if (!(result->pixels = TypeCallocN(RegisterNum, max_pixels))) { result = freeGraphic(result); } else if (!(result->private_color_registers = allocRegisters())) { result = freeGraphic(result); @@ -186,13 +190,13 @@ getActiveSlot(unsigned n) } static Graphic * -getInactiveSlot(unsigned n) +getInactiveSlot(const TScreen *screen, unsigned n) { if (n < MAX_GRAPHICS && (!displayed_graphics[n] || !displayed_graphics[n]->valid)) { if (!displayed_graphics[n]) { - displayed_graphics[n] = allocGraphic(); + displayed_graphics[n] = allocGraphic(screen); } return displayed_graphics[n]; } @@ -226,6 +230,11 @@ read_pixel(Graphic *graphic, int x, int y) return graphic->pixels[y * graphic->max_width + x]; } +#define _draw_pixel(G, X, Y, C) \ + do { \ + (G)->pixels[(Y) * (G)->max_width + (X)] = (RegisterNum) (C); \ + } while (0) + void draw_solid_pixel(Graphic *graphic, int x, int y, unsigned color) { @@ -246,11 +255,9 @@ draw_solid_pixel(Graphic *graphic, int x, int y, unsigned color) #endif if (x >= 0 && x < graphic->actual_width && y >= 0 && y < graphic->actual_height) { - graphic->pixels[y * graphic->max_width + x] = (RegisterNum) color; + _draw_pixel(graphic, x, y, color); if (color < MAX_COLOR_REGISTERS) graphic->color_registers_used[color] = 1; - } else { - TRACE(("pixel %d,%d out of bounds\n", x, y)); } } @@ -269,9 +276,24 @@ draw_solid_rectangle(Graphic *graphic, int x1, int y1, int x2, int y2, unsigned EXCHANGE(y1, y2, tmp); } + if (x2 < 0 || x1 >= graphic->actual_width || + y2 < 0 || y1 >= graphic->actual_height) + return; + + if (x1 < 0) + x1 = 0; + if (x2 >= graphic->actual_width) + x2 = graphic->actual_width - 1; + if (y1 < 0) + y1 = 0; + if (y2 >= graphic->actual_height) + y2 = graphic->actual_height - 1; + + if (color < MAX_COLOR_REGISTERS) + graphic->color_registers_used[color] = 1; for (y = y1; y <= y2; y++) - for (x = x1; x < x2; x++) - draw_solid_pixel(graphic, x, y, color); + for (x = x1; x <= x2; x++) + _draw_pixel(graphic, x, y, color); } void @@ -404,7 +426,6 @@ set_color_register(ColorRegister *color_registers, reg->r = (short) r; reg->g = (short) g; reg->b = (short) b; - reg->allocated = 0; } /* Graphics which don't use private colors will act as if they are using a @@ -466,7 +487,7 @@ find_color_register(ColorRegister const *color_registers, int r, int g, int b) /* I have no idea what algorithm DEC used for this. * The documentation warns that it is unpredictable, especially with values * far away from any allocated color so it is probably a very simple - * hueristic rather than something fancy like finding the minimum distance + * heuristic rather than something fancy like finding the minimum distance * in a linear perceptive color space. */ closest_index = MAX_COLOR_REGISTERS; @@ -594,11 +615,11 @@ init_color_registers(ColorRegister *color_registers, int terminal_id) unsigned i; for (i = 0U; i < MAX_COLOR_REGISTERS; i++) { - printf("initial value for register %03u: %d,%d,%d\n", + TRACE(("initial value for register %03u: %d,%d,%d\n", i, color_registers[i].r, color_registers[i].g, - color_registers[i].b); + color_registers[i].b)); } } #endif @@ -652,7 +673,8 @@ get_color_register_count(TScreen const *screen) } static void -init_graphic(Graphic *graphic, +init_graphic(const TScreen *screen, + Graphic *graphic, unsigned type, int terminal_id, int charrow, @@ -660,12 +682,13 @@ init_graphic(Graphic *graphic, unsigned num_color_registers, int private_colors) { + size_t max_pixels = (size_t) (screen->regis_max_wide * screen->regis_max_high); unsigned i; TRACE(("initializing graphic object\n")); graphic->dirty = 1; - for (i = 0U; i < MAX_PIXELS; i++) + for (i = 0U; i < max_pixels; i++) graphic->pixels[i] = COLOR_HOLE; memset(graphic->color_registers_used, 0, sizeof(graphic->color_registers_used)); @@ -688,8 +711,8 @@ init_graphic(Graphic *graphic, * VT382 960x750 sixel only * dxterm ?x? ?x? variable? */ - graphic->max_width = BUFFER_WIDTH; - graphic->max_height = BUFFER_HEIGHT; + graphic->max_width = screen->regis_max_wide; + graphic->max_height = screen->regis_max_high; graphic->actual_width = 0; graphic->actual_height = 0; @@ -726,7 +749,7 @@ get_new_graphic(XtermWidget xw, int charrow, int charcol, unsigned type) unsigned ii; FOR_EACH_SLOT(ii) { - if ((graphic = getInactiveSlot(ii))) { + if ((graphic = getInactiveSlot(screen, ii))) { TRACE(("using fresh graphic index=%u id=%u\n", ii, next_graphic_id)); break; } @@ -755,7 +778,8 @@ get_new_graphic(XtermWidget xw, int charrow, int charcol, unsigned type) graphic->xw = xw; graphic->bufferid = bufferid; graphic->id = next_graphic_id++; - init_graphic(graphic, + init_graphic(screen, + graphic, type, terminal_id, charrow, @@ -800,179 +824,243 @@ get_new_or_matching_graphic(XtermWidget xw, return graphic; } -#define ScaleForXColor(s) (unsigned short) ((long)(s) * 65535 / 100) - -static Pixel -color_register_to_xpixel(ColorRegister *reg, XtermWidget xw) +static int +lookup_allocated_color(const ColorRegister *reg, Pixel *pix) { - if (!reg->allocated) { - XColor def; - - def.red = ScaleForXColor(reg->r); - def.green = ScaleForXColor(reg->g); - def.blue = ScaleForXColor(reg->b); - def.flags = DoRed | DoGreen | DoBlue; - if (!allocateBestRGB(xw, &def)) { - TRACE(("unable to allocate xcolor for color register\n")); - return 0UL; + unsigned const rr = ((unsigned) reg->r * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + unsigned const gg = ((unsigned) reg->g * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + unsigned const bb = ((unsigned) reg->b * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + const AllocatedColorRegister *search; + + for (search = allocated_colors[rr][gg][bb]; search; search = search->next) { + if (search->r == reg->r && + search->g == reg->g && + search->b == reg->b) { + *pix = search->pix; + return 1; } - reg->pix = def.pixel; - reg->allocated = 1; } + *pix = 0UL; + return 0; +} + +#define ScaleForXColor(s) (unsigned short) ((long)(s) * 65535 / CHANNEL_MAX) + +static int +save_allocated_color(const ColorRegister *reg, XtermWidget xw, Pixel *pix) +{ + unsigned const rr = ((unsigned) reg->r * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + unsigned const gg = ((unsigned) reg->g * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + unsigned const bb = ((unsigned) reg->b * (LOOKUP_WIDTH - 1)) / CHANNEL_MAX; + XColor xcolor; + AllocatedColorRegister *new_color; + + xcolor.pixel = 0UL; + xcolor.red = ScaleForXColor(reg->r); + xcolor.green = ScaleForXColor(reg->g); + xcolor.blue = ScaleForXColor(reg->b); + xcolor.flags = DoRed | DoGreen | DoBlue; + if (!allocateBestRGB(xw, &xcolor)) { + TRACE(("unable to allocate xcolor\n")); + *pix = 0UL; + return 0; + } + + *pix = xcolor.pixel; + + if (!(new_color = malloc(sizeof(*new_color)))) { + TRACE(("unable to save pixel %lu\n", (unsigned long) *pix)); + return 0; + } + new_color->r = reg->r; + new_color->g = reg->g; + new_color->b = reg->b; + new_color->pix = *pix; + new_color->next = allocated_colors[rr][gg][bb]; + + allocated_colors[rr][gg][bb] = new_color; + + return 1; +} + +static Pixel +color_register_to_xpixel(const ColorRegister *reg, XtermWidget xw) +{ + Pixel pix; + + if (!lookup_allocated_color(reg, &pix)) + save_allocated_color(reg, xw, &pix); + /* FIXME: with so many possible colors we need to determine * when to free them to be nice to PseudoColor displays */ - return reg->pix; + return pix; } static void refresh_graphic(TScreen const *screen, Graphic const *graphic, - int xbase, - int ybase, - int x, - int y, - int w, - int h) + ColorRegister *buffer, + int refresh_x, + int refresh_y, + int refresh_w, + int refresh_h, + int draw_x, + int draw_y, + int draw_w, + int draw_h) { - Display *display = screen->display; - Window vwindow = WhichVWin(screen)->window; - GC graphics_gc; + int const pw = graphic->pixw; + int const ph = graphic->pixh; + int const graph_x = graphic->charcol * FontWidth(screen); + int const graph_y = graphic->charrow * FontHeight(screen); + int const graph_w = graphic->actual_width; + int const graph_h = graphic->actual_height; int r, c; - int pw, ph; - int rbase, cbase; - RegisterNum color; - RegisterNum old_fg; - XGCValues xgcv; - XtGCMask mask; - int holes, total; + int fillx, filly; + int holes, total, out_of_range; + RegisterNum regnum; - TRACE(("refreshing graphic from %d,%d %dx%d (valid=%d, size=%dx%d, scale=%dx%d max=%dx%d) at base=%d,%d\n", - x, y, w, h, + TRACE(("refreshing graphic %u from %d,%d %dx%d (valid=%d, size=%dx%d, scale=%dx%d max=%dx%d)\n", + graphic->id, + graph_x, graph_y, draw_w, draw_h, graphic->valid, graphic->actual_width, graphic->actual_height, - graphic->pixw, - graphic->pixh, + pw, ph, graphic->max_width, - graphic->max_height, - xbase, ybase)); - - memset(&xgcv, 0, sizeof(xgcv)); - xgcv.foreground = 0UL; - xgcv.graphics_exposures = False; - mask = GCForeground | GCGraphicsExposures; - graphics_gc = XCreateGC(display, vwindow, mask, &xgcv); - - pw = graphic->pixw; - ph = graphic->pixh; + graphic->max_height)); - TRACE(("refreshed graphic covers 0,0 to %d,%d\n", - (graphic->actual_width - 1) * pw + pw - 1, - (graphic->actual_height - 1) * ph + ph - 1)); - TRACE(("refreshed area covers %d,%d to %d,%d\n", - x, y, - x + w - 1, - y + h - 1)); + TRACE(("refresh pixmap starts at %d,%d\n", refresh_x, refresh_y)); - old_fg = COLOR_HOLE; holes = total = 0; - rbase = 0; - for (r = 0; r < graphic->actual_height; r++) { - int rtest = rbase; + out_of_range = 0; + for (r = 0; r < graph_h; r++) { + int pmy = graph_y + r * ph; - rbase += ph; - if (rtest + ph - 1 < y) - continue; - if (rtest > y + h - 1) + if (pmy + ph - 1 < draw_y) continue; + if (pmy > draw_y + draw_h - 1) + break; - cbase = 0; - for (c = 0; c < graphic->actual_width; c++) { - int ctest = cbase; + for (c = 0; c < graph_w; c++) { + int pmx = graph_x + c * pw; - cbase += pw; - if (ctest + pw - 1 < x) - continue; - if (ctest > x + w - 1) + if (pmx + pw - 1 < draw_x) continue; + if (pmx > draw_x + draw_w - 1) + break; total++; - color = graphic->pixels[r * graphic->max_width + c]; - if (color == COLOR_HOLE) { + regnum = graphic->pixels[r * graphic->max_width + c]; + if (regnum == COLOR_HOLE) { holes++; continue; } - if (color != old_fg) { - xgcv.foreground = - color_register_to_xpixel(&graphic->color_registers[color], - graphic->xw); - XChangeGC(display, graphics_gc, mask, &xgcv); - old_fg = color; + for (fillx = 0; fillx < pw; fillx++) { + for (filly = 0; filly < ph; filly++) { + if (pmx < draw_x || pmx > draw_x + draw_w - 1 || + pmy < draw_y || pmy > draw_y + draw_h - 1) { + out_of_range++; + continue; + } + + /* this shouldn't happen, but it doesn't hurt to check */ + if (pmx < refresh_x || pmx > refresh_x + refresh_w - 1 || + pmy < refresh_y || pmy > refresh_y + refresh_h - 1) { + TRACE(("OUT OF RANGE: %d,%d (%d,%d)\n", pmx, pmy, r, c)); + out_of_range++; + continue; + } + + buffer[(pmy - refresh_y) * refresh_w + + (pmx - refresh_x)] = + graphic->color_registers[regnum]; + } } - - XFillRectangle(display, vwindow, graphics_gc, - xbase + ctest, - ybase + rtest, - (unsigned) pw, - (unsigned) ph); } } + TRACE(("done refreshing graphic: %d of %d refreshed pixels were holes; %d were out of pixmap range\n", + holes, total, out_of_range)); +} + #ifdef DEBUG_REFRESH - { - XColor def; - - def.red = (short) (1.0 * 65535.0); - def.green = (short) (0.1 * 65535.0); - def.blue = (short) (1.0 * 65535.0); - def.flags = DoRed | DoGreen | DoBlue; - if (allocateBestRGB(graphic->xw, &def)) { - xgcv.foreground = def.pixel; - XChangeGC(display, graphics_gc, mask, &xgcv); - } - XFillRectangle(display, vwindow, graphics_gc, - xbase + 0, - ybase + 0, - (unsigned) pw, (unsigned) ph); - XFillRectangle(display, vwindow, graphics_gc, - xbase + (graphic->actual_width - 1) * pw, - ybase + (graphic->actual_height - 1) * ph, - (unsigned) pw, (unsigned) ph); - - def.red = (unsigned short) ((1.0 - 0.1 * (rand() / (double) - RAND_MAX) * 65535.0)); - def.green = (unsigned short) ((0.7 + 0.2 * (rand() / (double) - RAND_MAX)) * 65535.0); - def.blue = (unsigned short) ((0.1 + 0.1 * (rand() / (double) - RAND_MAX)) * 65535.0); - def.flags = DoRed | DoGreen | DoBlue; - if (allocateBestRGB(graphic->xw, &def)) { - xgcv.foreground = def.pixel; - XChangeGC(display, graphics_gc, mask, &xgcv); - } - XDrawLine(display, vwindow, graphics_gc, - xbase + x + 0, ybase + y + 0, - xbase + x + w - 1, ybase + y + 0); - XDrawLine(display, vwindow, graphics_gc, - xbase + x + w - 1, ybase + y + 0, - xbase + x + 0, ybase + y + h - 1); - XDrawLine(display, vwindow, graphics_gc, - xbase + x + 0, ybase + y + h - 1, - xbase + x + w - 1, ybase + y + h - 1); - XDrawLine(display, vwindow, graphics_gc, - xbase + x + w - 1, ybase + y + h - 1, - xbase + x + 0, ybase + y + 0); + +#define BASEX(X) ( (draw_x - base_x) + (X) ) +#define BASEY(Y) ( (draw_y - base_y) + (Y) ) + +static void +outline_refresh(TScreen const *screen, + Graphic const *graphic, + Pixmap output_pm, + GC graphics_gc, + int base_x, + int base_y, + int draw_x, + int draw_y, + int draw_w, + int draw_h) +{ + Display *const display = screen->display; + int const pw = graphic->pixw; + int const ph = graphic->pixh; + XGCValues xgcv; + XColor def; + + def.red = (unsigned short) ((1.0 - 0.1 * (rand() / (double) + RAND_MAX) * 65535.0)); + def.green = (unsigned short) ((0.7 + 0.2 * (rand() / (double) + RAND_MAX)) * 65535.0); + def.blue = (unsigned short) ((0.1 + 0.1 * (rand() / (double) + RAND_MAX)) * 65535.0); + def.flags = DoRed | DoGreen | DoBlue; + if (allocateBestRGB(graphic->xw, &def)) { + xgcv.foreground = def.pixel; + XChangeGC(display, graphics_gc, GCForeground, &xgcv); } -#endif - XFlush(display); - TRACE(("done refreshing graphic: %d of %d refreshed pixels were holes\n", - holes, total)); - XFreeGC(display, graphics_gc); + XDrawLine(display, output_pm, graphics_gc, + BASEX(0), BASEY(0), + BASEX(draw_w - 1), BASEY(0)); + XDrawLine(display, output_pm, graphics_gc, + BASEX(0), BASEY(draw_h - 1), + BASEX(draw_w - 1), BASEY(draw_h - 1)); + + XDrawLine(display, output_pm, graphics_gc, + BASEX(0), BASEY(0), + BASEX(0), BASEY(draw_h - 1)); + XDrawLine(display, output_pm, graphics_gc, + BASEX(draw_w - 1), BASEY(0), + BASEX(draw_w - 1), BASEY(draw_h - 1)); + + XDrawLine(display, output_pm, graphics_gc, + BASEX(draw_w - 1), BASEY(0), + BASEX(0), BASEY(draw_h - 1)); + XDrawLine(display, output_pm, graphics_gc, + BASEX(draw_w - 1), BASEY(draw_h - 1), + BASEX(0), BASEY(0)); + + def.red = (short) (0.7 * 65535.0); + def.green = (short) (0.1 * 65535.0); + def.blue = (short) (1.0 * 65535.0); + def.flags = DoRed | DoGreen | DoBlue; + if (allocateBestRGB(graphic->xw, &def)) { + xgcv.foreground = def.pixel; + XChangeGC(display, graphics_gc, GCForeground, &xgcv); + } + XFillRectangle(display, output_pm, graphics_gc, + BASEX(0), + BASEY(0), + (unsigned) pw, (unsigned) ph); + XFillRectangle(display, output_pm, graphics_gc, + BASEX(draw_w - 1 - pw), + BASEY(draw_h - 1 - ph), + (unsigned) pw, (unsigned) ph); } +#endif /* * Primary color hues: @@ -983,27 +1071,25 @@ refresh_graphic(TScreen const *screen, void hls2rgb(int h, int l, int s, short *r, short *g, short *b) { - double hs = (h + 240) % 360; - double hv = hs / 360.0; - double lv = l / 100.0; - double sv = s / 100.0; + const int hs = ((h + 240) / 60) % 6; + const double lv = l / 100.0; + const double sv = s / 100.0; double c, x, m, c2; double r1, g1, b1; - int hpi; if (s == 0) { *r = *g = *b = (short) l; return; } - if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) + c2 = (2.0 * lv) - 1.0; + if (c2 < 0.0) c2 = -c2; c = (1.0 - c2) * sv; - hpi = (int) (hv * 6.0); - x = (hpi & 1) ? c : 0.0; + x = (hs & 1) ? c : 0.0; m = lv - 0.5 * c; - switch (hpi) { + switch (hs) { case 0: r1 = c; g1 = x; @@ -1123,8 +1209,8 @@ dump_graphic(Graphic const *graphic) } /* Erase the portion of any displayed graphic overlapping with a rectangle - * of the given size and location in pixels. - * This is used to allow text to "erase" graphics underneath it. + * of the given size and location in pixels relative to the start of the + * graphic. This is used to allow text to "erase" graphics underneath it. */ static void erase_graphic(Graphic *graphic, int x, int y, int w, int h) @@ -1164,134 +1250,432 @@ compare_graphic_ids(const void *left, const void *right) if (!l->valid || !r->valid) return 0; + + if (l->bufferid < r->bufferid) + return -1; + else if (l->bufferid > r->bufferid) + return 1; + if (l->id < r->id) return -1; else return 1; } -void -refresh_displayed_graphics(TScreen const *screen, - int leftcol, - int toprow, - int ncols, - int nrows) +static void +clip_area(int *orig_x, int *orig_y, int *orig_w, int *orig_h, + int clip_x, int clip_y, int clip_w, int clip_h) { + if (*orig_x < clip_x) { + const int diff = clip_x - *orig_x; + *orig_x += diff; + *orig_w -= diff; + } + if (*orig_w > 0 && *orig_x + *orig_w > clip_x + clip_w) { + *orig_w -= (*orig_x + *orig_w) - (clip_x + clip_w); + } + + if (*orig_y < clip_y) { + const int diff = clip_y - *orig_y; + *orig_y += diff; + *orig_h -= diff; + } + if (*orig_h > 0 && *orig_y + *orig_h > clip_y + clip_h) { + *orig_h -= (*orig_y + *orig_h) - (clip_y + clip_h); + } +} + +/* the coordinates are relative to the screen */ +static void +refresh_graphics(XtermWidget xw, + int leftcol, + int toprow, + int ncols, + int nrows, + int skip_clean) +{ + TScreen *const screen = TScreenOf(xw); + Display *const display = screen->display; + Window const drawable = VDrawable(screen); + int const scroll_y = screen->topline * FontHeight(screen); + int const refresh_x = leftcol * FontWidth(screen); + int const refresh_y = toprow * FontHeight(screen) + scroll_y; + int const refresh_w = ncols * FontWidth(screen); + int const refresh_h = nrows * FontHeight(screen); + int draw_x_min, draw_x_max; + int draw_y_min, draw_y_max; Graphic *ordered_graphics[MAX_GRAPHICS]; - Graphic *graphic; - unsigned ii; - unsigned jj = 0; - int x, y, w, h; - int xbase, ybase; + unsigned ii, jj; + unsigned active_count; + unsigned holes, non_holes; + int xx, yy; + ColorRegister *buffer; + active_count = 0; FOR_EACH_SLOT(ii) { - if ((graphic = getActiveSlot(ii))) { - ordered_graphics[jj++] = graphic; + Graphic *graphic; + if (!(graphic = getActiveSlot(ii))) + continue; + TRACE(("refreshing graphic %d on buffer %d, current buffer %d\n", + graphic->id, graphic->bufferid, screen->whichBuf)); + if (screen->whichBuf == 0) { + if (graphic->bufferid != 0) { + TRACE(("skipping graphic %d from alt buffer (%d) when drawing screen=%d\n", + graphic->id, graphic->bufferid, screen->whichBuf)); + continue; + } + } else { + if (graphic->bufferid == 0 && graphic->charrow >= 0) { + TRACE(("skipping graphic %d from normal buffer (%d) when drawing screen=%d because it is not in scrollback area\n", + graphic->id, graphic->bufferid, screen->whichBuf)); + continue; + } + if (graphic->bufferid == 1 && + graphic->charrow + (graphic->actual_height + + FontHeight(screen) - 1) / + FontHeight(screen) < 0) { + TRACE(("skipping graphic %d from alt buffer (%d) when drawing screen=%d because it is completely in scrollback area\n", + graphic->id, graphic->bufferid, screen->whichBuf)); + continue; + } } + ordered_graphics[active_count++] = graphic; } - if (jj > 1) { + + if (active_count == 0) + return; + if (active_count > 1) { qsort(ordered_graphics, - (size_t) jj, + (size_t) active_count, sizeof(ordered_graphics[0]), compare_graphic_ids); } - for (ii = 0; ii < jj; ++ii) { - graphic = ordered_graphics[ii]; - if (graphic->bufferid != screen->whichBuf) - continue; + if (skip_clean) { + unsigned skip_count; - x = (leftcol - graphic->charcol) * FontWidth(screen); - y = (toprow - graphic->charrow) * FontHeight(screen); - w = ncols * FontWidth(screen); - h = nrows * FontHeight(screen); - - xbase = (OriginX(screen) - + graphic->charcol * FontWidth(screen)); - ybase = (OriginY(screen) - + (graphic->charrow - screen->topline) * FontHeight(screen)); - - if (xbase + x + w + OriginX(screen) > FullWidth(screen)) - w = FullWidth(screen) - (xbase + x + OriginX(screen)); - if (ybase + y + h + OriginY(screen) > FullHeight(screen)) - h = FullHeight(screen) - (ybase + y + OriginY(screen)); - else if (ybase + y < OriginY(screen)) { - int diff = OriginY(screen) - (ybase + y); - y += diff; - h -= diff; + for (jj = 0; jj < active_count; ++jj) { + if (ordered_graphics[jj]->dirty) + break; } + skip_count = jj; + if (skip_count == active_count) + return; - TRACE(("graphics refresh: screen->topline=%d leftcol=%d toprow=%d nrows=%d ncols=%d x=%d y=%d w=%d h=%d xbase=%d ybase=%d\n", - screen->topline, - leftcol, toprow, - nrows, ncols, - x, y, w, h, - xbase, ybase)); - refresh_graphic(screen, graphic, xbase, ybase, x, y, w, h); + active_count -= skip_count; + for (jj = 0; jj < active_count; ++jj) { + ordered_graphics[jj] = ordered_graphics[jj + skip_count]; + } } -} -void -refresh_modified_displayed_graphics(TScreen const *screen) -{ - Graphic *graphic; - unsigned ii; - int leftcol, toprow; - int nrows, ncols; - int x, y, w, h; - int xbase, ybase; + if (!(buffer = malloc(sizeof(*buffer) * + (unsigned) refresh_w * (unsigned) refresh_h))) { + TRACE(("unable to allocate %dx%d buffer for graphics refresh\n", + refresh_w, refresh_h)); + return; + } + for (yy = 0; yy < refresh_h; yy++) { + for (xx = 0; xx < refresh_w; xx++) { + buffer[yy * refresh_w + xx].r = -1; + buffer[yy * refresh_w + xx].g = -1; + buffer[yy * refresh_w + xx].b = -1; + } + } - FOR_EACH_SLOT(ii) { - if (!(graphic = getActiveSlot(ii))) - continue; - if (graphic->bufferid != screen->whichBuf) - continue; - if (!graphic->dirty) - continue; + TRACE(("refresh: screen->topline=%d leftcol=%d toprow=%d nrows=%d ncols=%d (%d,%d %dx%d)\n", + screen->topline, + leftcol, toprow, + nrows, ncols, + refresh_x, refresh_y, + refresh_w, refresh_h)); + + { + int const altarea_x = 0; + int const altarea_y = 0; + int const altarea_w = Width(screen) * FontWidth(screen); + int const altarea_h = Height(screen) * FontHeight(screen); + + int const scrollarea_x = 0; + int const scrollarea_y = scroll_y; + int const scrollarea_w = Width(screen) * FontWidth(screen); + int const scrollarea_h = -scroll_y; + + int const mainarea_x = 0; + int const mainarea_y = scroll_y; + int const mainarea_w = Width(screen) * FontWidth(screen); + int const mainarea_h = -scroll_y + Height(screen) * FontHeight(screen); + + draw_x_min = refresh_x + refresh_w; + draw_x_max = refresh_x - 1; + draw_y_min = refresh_y + refresh_h; + draw_y_max = refresh_y - 1; + for (jj = 0; jj < active_count; ++jj) { + Graphic *graphic = ordered_graphics[jj]; + int draw_x = graphic->charcol * FontWidth(screen); + int draw_y = graphic->charrow * FontHeight(screen); + int draw_w = graphic->actual_width; + int draw_h = graphic->actual_height; + + if (screen->whichBuf != 0) { + if (graphic->bufferid != 0) { + /* clip to alt buffer */ + clip_area(&draw_x, &draw_y, &draw_w, &draw_h, + altarea_x, altarea_y, altarea_w, altarea_h); + } else if (graphic->bufferid == 0) { + /* clip to scrollback area */ + clip_area(&draw_x, &draw_y, &draw_w, &draw_h, + scrollarea_x, scrollarea_y, + scrollarea_w, scrollarea_h); + } + } else { + /* clip to scrollback + normal area */ + clip_area(&draw_x, &draw_y, &draw_w, &draw_h, + mainarea_x, mainarea_y, + mainarea_w, mainarea_h); + } - leftcol = graphic->charcol; - toprow = graphic->charrow; - nrows = (((graphic->actual_height * graphic->pixh) - + FontHeight(screen) - 1) - / FontHeight(screen)); - ncols = (((graphic->actual_width * graphic->pixw) - + FontWidth(screen) - 1) - / FontWidth(screen)); - - x = (leftcol - graphic->charcol) * FontWidth(screen); - y = (toprow - graphic->charrow) * FontHeight(screen); - w = ncols * FontWidth(screen); - h = nrows * FontHeight(screen); - - xbase = (OriginX(screen) - + graphic->charcol * FontWidth(screen)); - ybase = (OriginY(screen) - + (graphic->charrow - screen->topline) * FontHeight(screen)); - - if (xbase + x + w + OriginX(screen) > FullWidth(screen)) - w = FullWidth(screen) - (xbase + x + OriginX(screen)); - if (ybase + y + h + OriginY(screen) > FullHeight(screen)) - h = FullHeight(screen) - (ybase + y + OriginY(screen)); - else if (ybase + y < OriginY(screen)) { - int diff = OriginY(screen) - (ybase + y); - y += diff; - h -= diff; + clip_area(&draw_x, &draw_y, &draw_w, &draw_h, + refresh_x, refresh_y, refresh_w, refresh_h); + + TRACE(("refresh: graph=%u\n", jj)); + TRACE((" refresh_x=%d refresh_y=%d refresh_w=%d refresh_h=%d\n", + refresh_x, refresh_y, refresh_w, refresh_h)); + TRACE((" draw_x=%d draw_y=%d draw_w=%d draw_h=%d\n", + draw_x, draw_y, draw_w, draw_h)); + + if (draw_w > 0 && draw_h > 0) { + refresh_graphic(screen, graphic, buffer, + refresh_x, refresh_y, + refresh_w, refresh_h, + draw_x, draw_y, + draw_w, draw_h); + if (draw_x < draw_x_min) + draw_x_min = draw_x; + if (draw_x + draw_w - 1 > draw_x_max) + draw_x_max = draw_x + draw_w - 1; + if (draw_y < draw_y_min) + draw_y_min = draw_y; + if (draw_y + draw_h - 1 > draw_y_max) + draw_y_max = draw_y + draw_h - 1; + } + graphic->dirty = 0; } + } - TRACE(("full graphics refresh: screen->topline=%d leftcol=%d toprow=%d nrows=%d ncols=%d x=%d y=%d w=%d h=%d xbase=%d ybase=%d\n", - screen->topline, - leftcol, toprow, - nrows, ncols, - x, y, w, h, - xbase, ybase)); - refresh_graphic(screen, graphic, xbase, ybase, x, y, w, h); - graphic->dirty = 0; + if (draw_x_max < refresh_x || + draw_x_min > refresh_x + refresh_w - 1 || + draw_y_max < refresh_y || + draw_y_min > refresh_y + refresh_h - 1) { + free(buffer); + return; + } + + holes = 0U; + non_holes = 0U; + for (yy = draw_y_min - refresh_y; yy <= draw_y_max - refresh_y; yy++) { + for (xx = draw_x_min - refresh_x; xx <= draw_x_max - refresh_x; xx++) { + const ColorRegister color = buffer[yy * refresh_w + xx]; + if (color.r < 0 || color.g < 0 || color.b < 0) { + holes++; + } else { + non_holes++; + } + } + } + + if (non_holes < 1U) { + TRACE(("refresh: visible graphics areas are erased; nothing to do\n")); + free(buffer); + return; } + + /* + * If we have any holes we can't just copy an image rectangle, and masking + * with bitmaps is very expensive. This fallback is surprisingly faster + * than the XPutImage version in some cases, but I don't know why. + * (This is even though there's no X11 primitive for drawing a horizontal + * line of height one and no attempt is made to handle multiple lines at + * once.) + */ + if (holes > 0U) { + GC graphics_gc; + XGCValues xgcv; + ColorRegister last_color; + ColorRegister gc_color; + int run; + + memset(&xgcv, 0, sizeof(xgcv)); + xgcv.graphics_exposures = False; + graphics_gc = XCreateGC(display, drawable, GCGraphicsExposures, &xgcv); + if (graphics_gc == None) { + TRACE(("unable to allocate GC for graphics refresh\n")); + free(buffer); + return; + } + + last_color.r = -1; + last_color.g = -1; + last_color.b = -1; + gc_color.r = -1; + gc_color.g = -1; + gc_color.b = -1; + run = 0; + for (yy = draw_y_min - refresh_y; yy <= draw_y_max - refresh_y; yy++) { + for (xx = draw_x_min - refresh_x; xx <= draw_x_max - refresh_x; + xx++) { + const ColorRegister color = buffer[yy * refresh_w + xx]; + + if (color.r < 0 || color.g < 0 || color.b < 0) { + last_color = color; + if (run > 0) { + XDrawLine(display, drawable, graphics_gc, + OriginX(screen) + refresh_x + xx - run, + (OriginY(screen) - scroll_y) + refresh_y + yy, + OriginX(screen) + refresh_x + xx - 1, + (OriginY(screen) - scroll_y) + refresh_y + yy); + run = 0; + } + continue; + } + + if (color.r != last_color.r || + color.g != last_color.g || + color.b != last_color.b) { + last_color = color; + if (run > 0) { + XDrawLine(display, drawable, graphics_gc, + OriginX(screen) + refresh_x + xx - run, + (OriginY(screen) - scroll_y) + refresh_y + yy, + OriginX(screen) + refresh_x + xx - 1, + (OriginY(screen) - scroll_y) + refresh_y + yy); + run = 0; + } + + if (color.r != gc_color.r || + color.g != gc_color.g || + color.b != gc_color.b) { + xgcv.foreground = + color_register_to_xpixel(&color, xw); + XChangeGC(display, graphics_gc, GCForeground, &xgcv); + gc_color = color; + } + } + run++; + } + if (run > 0) { + last_color.r = -1; + last_color.g = -1; + last_color.b = -1; + XDrawLine(display, drawable, graphics_gc, + OriginX(screen) + refresh_x + xx - run, + (OriginY(screen) - scroll_y) + refresh_y + yy, + OriginX(screen) + refresh_x + xx - 1, + (OriginY(screen) - scroll_y) + refresh_y + yy); + run = 0; + } + } + + XFreeGC(display, graphics_gc); + } else { + XGCValues xgcv; + GC graphics_gc; + ColorRegister old_color; + Pixel fg; + XImage *image; + char *imgdata; + unsigned image_w, image_h; + + memset(&xgcv, 0, sizeof(xgcv)); + xgcv.graphics_exposures = False; + graphics_gc = XCreateGC(display, drawable, GCGraphicsExposures, &xgcv); + if (graphics_gc == None) { + TRACE(("unable to allocate GC for graphics refresh\n")); + free(buffer); + return; + } + + /* FIXME: is it worth reusing the GC/Image/imagedata across calls? */ + /* FIXME: is it worth using shared memory when available? */ + image_w = (unsigned) draw_x_max + 1U - (unsigned) draw_x_min; + image_h = (unsigned) draw_y_max + 1U - (unsigned) draw_y_min; + image = XCreateImage(display, xw->visInfo->visual, + (unsigned) xw->visInfo->depth, + ZPixmap, 0, NULL, + image_w, image_h, + sizeof(int) * 8U, 0); + if (!image) { + TRACE(("unable to allocate XImage for graphics refresh\n")); + XFreeGC(display, graphics_gc); + free(buffer); + return; + } + imgdata = malloc(image_h * (unsigned) image->bytes_per_line); + if (!imgdata) { + TRACE(("unable to allocate XImage for graphics refresh\n")); + XDestroyImage(image); + XFreeGC(display, graphics_gc); + free(buffer); + return; + } + image->data = imgdata; + + fg = 0U; + old_color.r = -1; + old_color.g = -1; + old_color.b = -1; + for (yy = draw_y_min - refresh_y; yy <= draw_y_max - refresh_y; yy++) { + for (xx = draw_x_min - refresh_x; xx <= draw_x_max - refresh_x; + xx++) { + const ColorRegister color = buffer[yy * refresh_w + xx]; + + if (color.r != old_color.r || + color.g != old_color.g || + color.b != old_color.b) { + fg = color_register_to_xpixel(&color, xw); + old_color = color; + } + + XPutPixel(image, xx + refresh_x - draw_x_min, + yy + refresh_y - draw_y_min, fg); + } + } + + XPutImage(display, drawable, graphics_gc, image, + 0, 0, + OriginX(screen) + draw_x_min, + (OriginY(screen) - scroll_y) + draw_y_min, + image_w, image_h); + free(imgdata); + image->data = NULL; + XDestroyImage(image); + XFreeGC(display, graphics_gc); + } + + free(buffer); + XFlush(display); +} + +void +refresh_displayed_graphics(XtermWidget xw, + int leftcol, + int toprow, + int ncols, + int nrows) +{ + refresh_graphics(xw, leftcol, toprow, ncols, nrows, 0); } void -scroll_displayed_graphics(int rows) +refresh_modified_displayed_graphics(XtermWidget xw) { + TScreen const *screen = TScreenOf(xw); + refresh_graphics(xw, 0, 0, MaxCols(screen), MaxRows(screen), 1); +} + +void +scroll_displayed_graphics(XtermWidget xw, int rows) +{ + TScreen const *screen = TScreenOf(xw); Graphic *graphic; unsigned ii; @@ -1301,6 +1685,8 @@ scroll_displayed_graphics(int rows) FOR_EACH_SLOT(ii) { if (!(graphic = getActiveSlot(ii))) continue; + if (graphic->bufferid != screen->whichBuf) + continue; graphic->charrow -= rows; } @@ -1313,18 +1699,29 @@ pixelarea_clear_displayed_graphics(TScreen const *screen, int w, int h) { - Graphic *graphic; unsigned ii; - int x, y; FOR_EACH_SLOT(ii) { + Graphic *graphic; + /* FIXME: are these coordinates (scrolled) screen-relative? */ + int const scroll_y = (screen->whichBuf == 0 + ? screen->topline * FontHeight(screen) + : 0); + int graph_x; + int graph_y; + int x, y; + if (!(graphic = getActiveSlot(ii))) continue; + if (graphic->bufferid != screen->whichBuf) + continue; - x = winx - graphic->charcol * FontWidth(screen); - y = winy - graphic->charrow * FontHeight(screen); + graph_x = graphic->charcol * FontWidth(screen); + graph_y = graphic->charrow * FontHeight(screen); + x = winx - graph_x; + y = (winy - scroll_y) - graph_y; - TRACE(("pixelarea graphics erase: screen->topline=%d winx=%d winy=%d w=%d h=%d x=%d y=%d\n", + TRACE(("pixelarea clear graphics: screen->topline=%d winx=%d winy=%d w=%d h=%d x=%d y=%d\n", screen->topline, winx, winy, w, h, @@ -1340,12 +1737,10 @@ chararea_clear_displayed_graphics(TScreen const *screen, int ncols, int nrows) { - int x, y, w, h; - - x = leftcol * FontWidth(screen); - y = toprow * FontHeight(screen); - w = ncols * FontWidth(screen); - h = nrows * FontHeight(screen); + int const x = leftcol * FontWidth(screen); + int const y = toprow * FontHeight(screen); + int const w = ncols * FontWidth(screen); + int const h = nrows * FontHeight(screen); TRACE(("chararea clear graphics: screen->topline=%d leftcol=%d toprow=%d nrows=%d ncols=%d x=%d y=%d w=%d h=%d\n", screen->topline, diff --git a/app/xterm/graphics.h b/app/xterm/graphics.h index 65390bf5a..f1edaca3e 100644 --- a/app/xterm/graphics.h +++ b/app/xterm/graphics.h @@ -1,4 +1,4 @@ -/* $XTermId: graphics.h,v 1.17 2014/07/13 00:56:45 Ross.Combs Exp $ */ +/* $XTermId: graphics.h,v 1.20 2014/11/28 19:48:36 tom Exp $ */ /* * Copyright 2013,2014 by Ross Combs @@ -39,23 +39,19 @@ #if OPT_GRAPHICS +#define CHANNEL_MAX 100 + typedef struct { - Pixel pix; short r, g, b; - short allocated; } ColorRegister; typedef unsigned short RegisterNum; -#define MAX_COLOR_REGISTERS 256U +#define MAX_COLOR_REGISTERS 1024U #define COLOR_HOLE ((RegisterNum)MAX_COLOR_REGISTERS) #define MAX_GRAPHICS 16U -#define BUFFER_WIDTH 1000 -#define BUFFER_HEIGHT 800 -#define MAX_PIXELS (BUFFER_HEIGHT * BUFFER_WIDTH) - typedef struct { RegisterNum *pixels; ColorRegister *private_color_registers; @@ -93,10 +89,10 @@ extern void update_color_register(Graphic *graphic, unsigned color, int r, int g extern RegisterNum find_color_register(ColorRegister const *color_registers, int r, int g, int b); extern void chararea_clear_displayed_graphics(TScreen const *screen, int leftcol, int toprow, int ncols, int nrows); extern void pixelarea_clear_displayed_graphics(TScreen const *screen, int winx, int winy, int w, int h); -extern void refresh_displayed_graphics(TScreen const *screen, int leftcol, int toprow, int ncols, int nrows); -extern void refresh_modified_displayed_graphics(TScreen const *screen); +extern void refresh_displayed_graphics(XtermWidget xw, int leftcol, int toprow, int ncols, int nrows); +extern void refresh_modified_displayed_graphics(XtermWidget xw); extern void reset_displayed_graphics(TScreen const *screen); -extern void scroll_displayed_graphics(int rows); +extern void scroll_displayed_graphics(XtermWidget xw, int rows); #ifdef NO_LEAKS extern void noleaks_graphics(void); @@ -118,10 +114,10 @@ extern void noleaks_graphics(void); #define find_color_register(color_registers, r, g, b) /* nothing */ #define chararea_clear_displayed_graphics(screen, leftcol, toprow, ncols, nrows) /* nothing */ #define pixelarea_clear_displayed_graphics(screen, winx, winy, w, h) /* nothing */ -#define refresh_displayed_graphics(screen, leftcol, toprow, ncols, nrows) /* nothing */ -#define refresh_modified_displayed_graphics(screen) /* nothing */ +#define refresh_displayed_graphics(xw, leftcol, toprow, ncols, nrows) /* nothing */ +#define refresh_modified_displayed_graphics(xw) /* nothing */ #define reset_displayed_graphics(screen) /* nothing */ -#define scroll_displayed_graphics(rows) /* nothing */ +#define scroll_displayed_graphics(xw, rows) /* nothing */ #endif diff --git a/app/xterm/graphics_regis.c b/app/xterm/graphics_regis.c index 7b02cd14c..ffceb2434 100644 --- a/app/xterm/graphics_regis.c +++ b/app/xterm/graphics_regis.c @@ -1,4 +1,4 @@ -/* $XTermId: graphics_regis.c,v 1.44 2014/09/17 08:35:49 tom Exp $ */ +/* $XTermId: graphics_regis.c,v 1.52 2014/11/28 20:37:24 tom Exp $ */ /* * Copyright 2014 by Ross Combs @@ -37,6 +37,10 @@ #include <math.h> #include <stdlib.h> +#if OPT_DOUBLE_BUFFER +#include <X11/extensions/Xdbe.h> +#endif + #include <data.h> #include <VTparse.h> #include <ptyx.h> @@ -91,8 +95,11 @@ #undef DEBUG_LOAD /* controls for extensions over VT3x0 limitations */ +#define ENABLE_RGB_COLORSPECS #define ENABLE_FREE_ROTATION -#define ENABLE_USER_FONT_SIZE_EXTENSION +#define ENABLE_UPLOAD_ALPHABET_FROM_FONT +#define ENABLE_UPLOAD_ALPHABET_ZERO +#define ENABLE_USER_FONT_SIZE #define ENABLE_VARIABLE_ITALICS #define MIN_ITERATIONS_BEFORE_REFRESH 20U @@ -114,10 +121,11 @@ typedef struct RegisWriteControls { char shading_character; int shading_reference; unsigned shading_reference_dim; + unsigned line_width; } RegisWriteControls; typedef struct RegisTextControls { - unsigned alphabet; + unsigned alphabet_num; unsigned character_set_l; /* default: "(B" (ASCII) */ unsigned character_set_r; /* default: "-@" (Latin-1) */ unsigned character_display_w; @@ -133,15 +141,19 @@ typedef struct RegisTextControls { #define MAX_REGIS_ALPHABETS 8U #define REGIS_ALPHABET_NAME_LEN 11U +#define REGIS_FONTNAME_LEN 256U /* enough for a 16x24 font (about 100KB) */ #define MAX_REGIS_ALPHABET_BYTES (256U * 16U * 24U) #define MAX_GLYPH_PIXELS 8192U #define MAX_GLYPHS 256U +#define INVALID_ALPHABET_NUM ~0U typedef struct RegisAlphabet { unsigned alphabet_num; unsigned pixw, pixh; char name[REGIS_ALPHABET_NAME_LEN]; + char fontname[REGIS_FONTNAME_LEN]; + int use_font; int loaded[MAX_GLYPHS]; unsigned char *bytes; } RegisAlphabet; @@ -225,6 +237,8 @@ typedef struct RegisGraphicsContext { #define WRITE_SHADING_REF_Y 0U #define WRITE_SHADING_REF_X 1U +/* keypress event example: http://iraf.net/forum/viewtopic.php?showtopic=61692 */ + #define ROT_LEFT_N(V, N) ( (((V) << ((N) & 3U )) & 255U) | \ ((V) >> (8U - ((N) & 3U))) ) #define ROT_LEFT(V) ( (((V) << 1U) & 255U) | ((V) >> 7U) ) @@ -255,7 +269,7 @@ isqrt(double d) static void draw_regis_pixel(RegisGraphicsContext *context, int x, int y, - unsigned int value) + unsigned value) { unsigned color = 0; @@ -533,11 +547,11 @@ draw_filled_polygon(RegisGraphicsContext *context) */ if (context->temporary_write_controls.shading_character != '\0') { shade_char_to_pixel(context, pixels, w, h, - WRITE_SHADING_REF_X, old_x, - old_x, old_y); + WRITE_SHADING_REF_X, + old_x, old_x, old_y); } else { - shade_pattern_to_pixel(context, WRITE_SHADING_REF_X, old_x, - old_x, old_y); + shade_pattern_to_pixel(context, WRITE_SHADING_REF_X, + old_x, old_x, old_y); } } inside = 1; @@ -545,11 +559,11 @@ draw_filled_polygon(RegisGraphicsContext *context) if (inside) { if (context->temporary_write_controls.shading_character != '\0') { shade_char_to_pixel(context, pixels, w, h, - WRITE_SHADING_REF_X, old_x, - new_x, new_y); + WRITE_SHADING_REF_X, + old_x, new_x, new_y); } else { - shade_pattern_to_pixel(context, WRITE_SHADING_REF_X, old_x, - new_x, new_y); + shade_pattern_to_pixel(context, WRITE_SHADING_REF_X, + old_x, new_x, new_y); } } if (new_x > old_x + 1) { @@ -1315,7 +1329,7 @@ find_free_alphabet_index(RegisGraphicsContext *context, unsigned alphabet, { unsigned ii, jj; - /* exact match first */ + /* try an exact match */ for (ii = 0U; ii < MAX_REGIS_ALPHABETS; ii++) { if (context->alphabets[ii].alphabet_num == alphabet && context->alphabets[ii].pixw == pixw && @@ -1324,23 +1338,24 @@ find_free_alphabet_index(RegisGraphicsContext *context, unsigned alphabet, } } - /* empty slot next */ + /* otherwise use any empty slot */ for (ii = 0U; ii < MAX_REGIS_ALPHABETS; ii++) { - if (context->alphabets[ii].alphabet_num == 0U && - context->alphabets[ii].pixw == 0U && - context->alphabets[ii].pixh == 0U) { - context->alphabets[0U].alphabet_num = alphabet; - context->alphabets[0U].pixw = pixw; - context->alphabets[0U].pixh = pixh; + if (context->alphabets[ii].alphabet_num == INVALID_ALPHABET_NUM) { + context->alphabets[ii].alphabet_num = alphabet; + context->alphabets[ii].pixw = pixw; + context->alphabets[ii].pixh = pixh; return ii; } } - /* recycle different font size next */ + /* otherwise recycle a slot with a different font size */ for (ii = 0U; ii < MAX_REGIS_ALPHABETS; ii++) { if (context->alphabets[ii].alphabet_num == alphabet) { context->alphabets[ii].pixw = pixw; context->alphabets[ii].pixh = pixh; + context->alphabets[ii].name[0] = '\0'; + context->alphabets[ii].fontname[0] = '\0'; + context->alphabets[ii].use_font = 0; if (context->alphabets[ii].bytes != NULL) { free(context->alphabets[ii].bytes); context->alphabets[ii].bytes = NULL; @@ -1352,11 +1367,13 @@ find_free_alphabet_index(RegisGraphicsContext *context, unsigned alphabet, } } - /* else recycle this arbitrary slot */ + /* finally just recycle this arbitrary slot */ context->alphabets[0U].alphabet_num = alphabet; context->alphabets[0U].pixw = pixw; context->alphabets[0U].pixh = pixh; context->alphabets[0U].name[0] = '\0'; + context->alphabets[0U].fontname[0] = '\0'; + context->alphabets[0U].use_font = 0; if (context->alphabets[0U].bytes != NULL) { free(context->alphabets[0U].bytes); context->alphabets[0U].bytes = NULL; @@ -1364,6 +1381,7 @@ find_free_alphabet_index(RegisGraphicsContext *context, unsigned alphabet, for (jj = 0U; jj < MAX_GLYPHS; jj++) { context->alphabets[0U].loaded[jj] = 0; } + return 0U; } @@ -1389,7 +1407,7 @@ dump_bitmap_pixels(unsigned char const *pixels, unsigned w, unsigned h) #if OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) static int -copy_bitmap_from_xft_font(Display *display, XftFont *font, char ch, +copy_bitmap_from_xft_font(Display *display, XftFont *font, FcChar32 ch, unsigned char *pixels, unsigned w, unsigned h, unsigned xmin, unsigned ymin) { @@ -1398,7 +1416,6 @@ copy_bitmap_from_xft_font(Display *display, XftFont *font, char ch, * - the bitmap for the last M characters and target dimensions * - resuse the pixmap object where possible */ - const FcChar32 ch32 = (FcChar32) ch; /* FIXME: convert correctly */ XftColor bg, fg; Pixmap bitmap; XftDraw *draw; @@ -1437,7 +1454,7 @@ copy_bitmap_from_xft_font(Display *display, XftFont *font, char ch, XftDrawRect(draw, &bg, 0, 0, bmw, bmh); XftDrawString32(draw, &fg, font, 0, font->ascent - (int) ymin, - &ch32, 1); + &ch, 1); image = XGetImage(display, bitmap, (int) xmin, 0, w, h, 1, XYPixmap); if (!image) { @@ -1503,6 +1520,7 @@ get_xft_glyph_dimensions(Display *display, XftFont *font, unsigned *w, return; } + /* FIXME: ch is in UCS32 -- try to support non-ASCII characters */ char_count = 0U; real_minx = workw - 1U; real_maxx = 0U; @@ -1514,7 +1532,7 @@ get_xft_glyph_dimensions(Display *display, XftFont *font, unsigned *w, if (!FcCharSetHasChar(font->charset, ch)) continue; - copy_bitmap_from_xft_font(display, font, (char) ch, pixels, + copy_bitmap_from_xft_font(display, font, ch, pixels, workw, workh, 0U, 0U); pixel_count = 0U; @@ -1593,8 +1611,8 @@ get_xft_glyph_dimensions(Display *display, XftFont *font, unsigned *w, * maxw and maxh without overstepping either dimension. */ static XftFont * -find_best_xft_font_size(Display *display, Screen * screen, unsigned maxw, - unsigned maxh, unsigned max_pixels, +find_best_xft_font_size(Display *display, Screen * screen, char const *fontname, + unsigned maxw, unsigned maxh, unsigned max_pixels, unsigned *w, unsigned *h, unsigned *xmin, unsigned *ymin) { @@ -1638,7 +1656,7 @@ find_best_xft_font_size(Display *display, Screen * screen, unsigned maxw, * doesn't appear to matter). * * In those two cases it literally drops pixels, sometimes whole - * columns, making the glyphs unreadable and ugly even readable. + * columns, making the glyphs unreadable and ugly even when readable. */ /* * FIXME: @@ -1655,9 +1673,9 @@ find_best_xft_font_size(Display *display, Screen * screen, unsigned maxw, font = NULL; /* FIXME: make this name configurable. In practice it may not be - * useful -- there are few fonts which meet the other requirements. + * useful -- there are few fonts which meet all the requirements. */ - if ((pat = XftNameParse(""))) { + if ((pat = XftNameParse(fontname))) { XftPatternBuild(pat, /* arbitrary value */ XFT_SIZE, XftTypeDouble, 12.0, @@ -1791,7 +1809,8 @@ find_best_xft_font_size(Display *display, Screen * screen, unsigned maxw, #endif static int -get_xft_bitmap_of_character(RegisGraphicsContext const *context, char ch, +get_xft_bitmap_of_character(RegisGraphicsContext const *context, + char const *fontname, char ch, unsigned maxw, unsigned maxh, unsigned char *pixels, unsigned max_pixels, unsigned *w, unsigned *h) { @@ -1809,13 +1828,13 @@ get_xft_bitmap_of_character(RegisGraphicsContext const *context, char ch, XftFont *font; unsigned xmin = 0U, ymin = 0U; - if (!(font = find_best_xft_font_size(display, screen, maxw, maxh, + if (!(font = find_best_xft_font_size(display, screen, fontname, maxw, maxh, max_pixels, w, h, &xmin, &ymin))) { TRACE(("Unable to find suitable Xft font\n")); return 0; } - if (!copy_bitmap_from_xft_font(display, font, ch, pixels, *w, *h, + if (!copy_bitmap_from_xft_font(display, font, CharOf(ch), pixels, *w, *h, xmin, ymin)) { TRACE(("Unable to create bitmap for '%c'\n", ch)); XftFontClose(display, font); @@ -1838,32 +1857,28 @@ get_xft_bitmap_of_character(RegisGraphicsContext const *context, char ch, #endif } -#define GLYPH_WIDTH_BYTES(PIXW) ( ((PIXW) + 7U) >> 3U ) - -static int -get_user_bitmap_of_character(RegisGraphicsContext const *context, - char ch, unsigned maxw, unsigned maxh, - unsigned char *pixels, unsigned max_pixels, - unsigned *w, unsigned *h) +static unsigned +find_best_alphabet_index(RegisGraphicsContext const *context, + unsigned minw, unsigned minh, + unsigned maxw, unsigned maxh, + unsigned max_pixels) { unsigned ii; unsigned bestmatch; unsigned bestw, besth; - const unsigned char *glyph; - unsigned xx, yy; - unsigned byte, bit; assert(context); - assert(pixels); - assert(w); - assert(h); + assert(maxw); + assert(maxh); bestmatch = MAX_REGIS_ALPHABETS; bestw = 0U; besth = 0U; for (ii = 0U; ii < MAX_REGIS_ALPHABETS; ii++) { if (context->alphabets[ii].alphabet_num == - context->current_text_controls->alphabet && + context->current_text_controls->alphabet_num && + context->alphabets[ii].pixw >= minw && + context->alphabets[ii].pixh >= minh && context->alphabets[ii].pixw <= maxw && context->alphabets[ii].pixh <= maxh && context->alphabets[ii].pixw > bestw && @@ -1875,29 +1890,48 @@ get_user_bitmap_of_character(RegisGraphicsContext const *context, besth = context->alphabets[ii].pixh; } } - if (bestmatch >= MAX_REGIS_ALPHABETS) { - TRACE(("user bitmap not found (no alphabet or resolution mismatch)\n")); - return 0; - } - if (!context->alphabets[bestmatch].loaded[(unsigned) ch]) { - TRACE(("user bitmap not found (alphabet %u found at index %u but glyph for '%c' not loaded)\n", - context->current_text_controls->alphabet, bestmatch, ch)); + TRACE(("found alphabet %u at index %u size %ux%u font=%s\n", + context->current_text_controls->alphabet_num, bestmatch, + bestw, besth, + context->alphabets[bestmatch].use_font ? + context->alphabets[bestmatch].fontname : "(none)")); + return bestmatch; +} + +#define GLYPH_WIDTH_BYTES(PIXW) ( ((PIXW) + 7U) >> 3U ) + +static int +get_user_bitmap_of_character(RegisGraphicsContext const *context, + char ch, + unsigned alphabet_index, + unsigned char *pixels) +{ + const unsigned char *glyph; + unsigned w, h; + unsigned xx, yy; + unsigned byte, bit; + + assert(context); + assert(pixels); + + if (!context->alphabets[alphabet_index].loaded[(unsigned) ch]) { + TRACE(("in alphabet %u with alphabet index %u user glyph for '%c' not loaded\n", + context->current_text_controls->alphabet_num, alphabet_index, + ch)); return 0; } - glyph = &context->alphabets[bestmatch] - .bytes[(unsigned) ch * - GLYPH_WIDTH_BYTES(context->alphabets[bestmatch].pixw) * - context->alphabets[bestmatch].pixh]; - - *w = bestw; - *h = besth; - for (yy = 0U; yy < besth; yy++) { - for (xx = 0U; xx < bestw; xx++) { - byte = yy * GLYPH_WIDTH_BYTES(bestw) + (xx >> 3U); + + w = context->alphabets[alphabet_index].pixw; + h = context->alphabets[alphabet_index].pixh; + glyph = &context->alphabets[alphabet_index] + .bytes[(unsigned) ch * GLYPH_WIDTH_BYTES(w) * h]; + + for (yy = 0U; yy < h; yy++) { + for (xx = 0U; xx < w; xx++) { + byte = yy * GLYPH_WIDTH_BYTES(w) + (xx >> 3U); bit = xx & 7U; - pixels[yy * bestw + xx] = - ((unsigned) glyph[byte] >> (7U - bit)) & 1U; + pixels[yy * w + xx] = ((unsigned) glyph[byte] >> (7U - bit)) & 1U; } } @@ -1943,46 +1977,69 @@ get_bitmap_of_character(RegisGraphicsContext const *context, char ch, unsigned maxw, unsigned maxh, unsigned char *pixels, unsigned *w, unsigned *h, unsigned max_pixels) { - if (context->current_text_controls->alphabet == 0U) { - if (get_xft_bitmap_of_character(context, ch, maxw, maxh, pixels, - max_pixels, w, h)) { - if (*w <= maxw && *h <= maxh && *w * *h <= max_pixels) { + char const *fontname; + unsigned bestmatch; + + *w = 0U; + *h = 0U; + + bestmatch = find_best_alphabet_index(context, 1U, 1U, maxw, maxh, + max_pixels); + if (bestmatch < MAX_REGIS_ALPHABETS && + get_user_bitmap_of_character(context, ch, bestmatch, pixels)) { + *w = context->alphabets[bestmatch].pixw; + *h = context->alphabets[bestmatch].pixh; + return; + } + + fontname = NULL; + if (bestmatch < MAX_REGIS_ALPHABETS) { + RegisAlphabet const *alpha = &context->alphabets[bestmatch]; + if (alpha && alpha->use_font) + fontname = alpha->fontname; + } + if (!fontname && context->current_text_controls->alphabet_num == 0) { + fontname = ""; + } + + if (fontname && get_xft_bitmap_of_character(context, fontname, ch, + maxw, maxh, pixels, + max_pixels, w, h)) { + if (*w > maxw) { + TRACE(("BUG: Xft glyph is too wide: %ux%u but max is %ux%u\n", + *w, *h, maxw, maxh)); + } else if (*h > maxh) { + TRACE(("BUG: Xft glyph is too tall: %ux%u but max is %ux%u\n", + *w, *h, maxw, maxh)); + } else if (*w * *h > max_pixels) { + TRACE(("BUG: Xft glyph has too many pixels: %u but max is %u\n", + *w * *h, max_pixels)); + } else { #ifdef DEBUG_SPECIFIC_CHAR_METRICS - if (IS_DEBUG_CHAR(ch)) { - printf("got %ux%u Xft bitmap for '%c' target size %ux%u:\n", - *w, *h, - ch, maxw, maxh); - dump_bitmap_pixels(pixels, *w, *h); - printf("\n"); - } -#endif - return; + if (IS_DEBUG_CHAR(ch)) { + printf("got %ux%u Xft bitmap for '%c' target size %ux%u:\n", + *w, *h, + ch, maxw, maxh); + dump_bitmap_pixels(pixels, *w, *h); + printf("\n"); } - TRACE(("giving up on Xft glyph; results are too large\n")); - } - } else { - if (get_user_bitmap_of_character(context, ch, maxw, maxh, pixels, - max_pixels, w, h)) +#endif return; - TRACE(("unable to load user bitmap for character '%c' in alphabet %u at %ux%u\n", - ch, context->current_text_controls->alphabet, maxw, maxh)); + } } - /* fallback -- FIXME: for now fill with junk */ + TRACE(("unable to load any bitmap for character '%c' in alphabet number %u at %ux%u\n", + ch, context->current_text_controls->alphabet_num, maxw, maxh)); + + /* FIXME: this should probably produce an "unknown character" symbol */ { unsigned xx, yy; *w = 8U; *h = 10U; - for (yy = 0U; yy < 10U; yy++) { - for (xx = 0U; xx < 8U; xx++) { - pixels[yy * *w + xx] = (char) ((((((unsigned) ch * 10U) / - (yy + - 1U)) * (xx * (unsigned) - ch)) + - xx) & 1U); - } - } + for (yy = 0U; yy < 10U; yy++) + for (xx = 0U; xx < 8U; xx++) + pixels[yy * *w + xx] = '\0'; } } @@ -2867,114 +2924,290 @@ regis_num_to_int(RegisDataFragment const *input, int *out) return 1; } +#define MIN2(X, Y) ( (X) < (Y) ? (X) : (Y) ) +#define MIN3(X, Y, Z) ( MIN2(MIN2((X), (Y)), MIN2((Y), (Z))) ) +#define MAX2(X, Y) ( (X) > (Y) ? (X) : (Y) ) +#define MAX3(X, Y, Z) ( MAX2(MAX2((X), (Y)), MAX2((Y), (Z))) ) + static int -load_regis_colorspec(Graphic const *graphic, RegisDataFragment const *input, - RegisterNum *out) +load_regis_colorspec(RegisGraphicsContext const *context, + RegisDataFragment const *input, + short *r_out, short *g_out, short *b_out) { - int val; RegisDataFragment colorspec; - RegisDataFragment coloroption; + short r = -1, g = -1, b = -1; + short h = -1, l = -1, s = -1; copy_fragment(&colorspec, input); - TRACE(("looking at colorspec pattern: \"%s\"\n", - fragment_to_tempstr(&colorspec))); + TRACE(("colorspec option: \"%s\"\n", fragment_to_tempstr(&colorspec))); - if (regis_num_to_int(&colorspec, &val)) { - if (val < 0 || val >= (int) graphic->valid_registers) { - /* FIXME: error, truncate, wrap, ...? */ - TRACE(("DATA_ERROR: colorspec value %d is not a valid register\n", - val)); - if (val < 0) { - return 0; - } - val %= (int) graphic->valid_registers; + skip_regis_whitespace(&colorspec); + if (fragment_len(&colorspec) == 1) { + char ch = pop_fragment(&colorspec); + + TRACE(("got ReGIS RGB colorspec pattern '%c' with arguments: \"%s\"\n", + ch, fragment_to_tempstr(&colorspec))); + switch (ch) { + case 'D': + case 'd': + r = 0; + g = 0; + b = 0; + l = 0; + break; + case 'R': + case 'r': + r = 100; + g = 0; + b = 0; + l = 46; + break; + case 'G': + case 'g': + r = 0; + g = 100; + b = 0; + l = 50; + break; + case 'B': + case 'b': + r = 0; + g = 0; + b = 100; + l = 50; + break; + case 'C': + case 'c': + r = 0; + g = 100; + b = 100; + l = 50; + break; + case 'Y': + case 'y': + r = 100; + g = 100; + b = 0; + l = 50; + break; + case 'M': + case 'm': + r = 100; + g = 0; + b = 100; + l = 50; + break; + case 'W': + case 'w': + r = 100; + g = 100; + b = 100; + l = 100; + break; + default: + TRACE(("unknown RGB color name: \"%c\"\n", ch)); + return 0; } - TRACE(("colorspec contains index for register %u\n", val)); - *out = (RegisterNum) val; - return 1; - } + } else { + RegisDataFragment num; + int max, val; + char comp; - if (extract_regis_parenthesized_data(&colorspec, &coloroption)) { - short r, g, b; - TRACE(("option: \"%s\"\n", fragment_to_tempstr(&coloroption))); - - if (fragment_len(&coloroption) == 1) { - char ch = pop_fragment(&coloroption); - - TRACE(("got regis RGB colorspec pattern '%c' with arguments: \"%s\"\n", - ch, fragment_to_tempstr(&coloroption))); - switch (ch) { - case 'D': - case 'd': - r = 0; - g = 0; - b = 0; + while (colorspec.pos < colorspec.len) { + if (skip_regis_whitespace(&colorspec)) + continue; + + comp = pop_fragment(&colorspec); + switch (comp) { + case ',': + /* not sure if this is valid, but it is easy to handle */ + continue; + case 'H': + case 'h': + max = 360; + comp = 'H'; break; - case 'R': + case 'L': + case 'l': + max = 100; + comp = 'L'; + break; + case 'S': + case 's': + max = 100; + comp = 'S'; + break; +#ifdef ENABLE_RGB_COLORSPECS + case 'R': /* RLogin extension */ case 'r': - r = 100; - g = 0; - b = 0; + max = 100; + comp = 'R'; break; - case 'G': + case 'G': /* RLogin extension */ case 'g': - r = 0; - g = 100; - b = 0; + max = 100; + comp = 'G'; break; - case 'B': + case 'B': /* RLogin extension */ case 'b': - r = 0; - g = 0; - b = 100; - break; - case 'C': - case 'c': - r = 0; - g = 100; - b = 100; - break; - case 'Y': - case 'y': - r = 100; - g = 100; - b = 0; - break; - case 'M': - case 'm': - r = 100; - g = 0; - b = 100; - break; - case 'W': - case 'w': - r = 100; - g = 100; - b = 100; + max = 100; + comp = 'B'; break; +#endif default: - TRACE(("unknown RGB color name: \"%c\"\n", ch)); + TRACE(("unrecognized character in colorspec: \"%c\"\n", comp)); return 0; } - } else { - short h, l, s; - if (sscanf(fragment_to_tempstr(&coloroption), - "%*1[Hh]%6hd%*1[Ll]%6hd%*1[Ss]%6hd", - &h, &l, &s) != 3) { - TRACE(("unrecognized colorspec format: \"%s\"\n", - fragment_to_tempstr(&coloroption))); + skip_regis_whitespace(&colorspec); + if (!extract_regis_num(&colorspec, &num)) { + TRACE(("unrecognized character in colorspec: \"%c\"\n", comp)); + return 0; + } + if (!regis_num_to_int(&num, &val)) { + TRACE(("DATA_ERROR: component value %s is not a number\n", + fragment_to_tempstr(&num))); return 0; } + /* FIXME: error, truncate, wrap, ...? */ + if (val < 0 || val > max) { + TRACE(("DATA_ERROR: component value %d out of range\n", val)); + return 0; + } + + switch (comp) { + case 'H': + h = (short) val; + break; + case 'L': + l = (short) val; + break; + case 'S': + s = (short) val; + break; + case 'R': + r = (short) val; + break; + case 'G': + g = (short) val; + break; + case 'B': + b = (short) val; + break; + } + } + + if (h >= 0 && l >= 0 && s >= 0 && r < 0 && g < 0 && b < 0) { + TRACE(("found HLS colorspec to be converted: %hd,%hd,%hd\n", + h, l, s)); hls2rgb(h, l, s, &r, &g, &b); + TRACE(("converted to RGB: %hd,%hd,%hd\n", r, g, b)); + } else if (h < 0 && l < 0 && s < 0 && r >= 0 && g >= 0 && b >= 0) { + TRACE(("found RGB colorspec: %hd,%hd,%hd\n", r, g, b)); + l = (short) ((MIN3(r, g, b) + MAX3(r, g, b)) / 2); + TRACE(("calculated L: %d\n", l)); + } else if (h < 0 && l >= 0 && s < 0 && r < 0 && g < 0 && b < 0) { + TRACE(("found L colorspec to be converted: %hd,%hd,%hd\n", + h, l, s)); + hls2rgb(0, l, 0, &r, &g, &b); + TRACE(("converted to RGB: %hd,%hd,%hd\n", r, g, b)); + } else { + TRACE(("unrecognized colorspec format\n")); + return 0; + } + } + + /* + * The VT240 and VT330 models convert to the closest grayscale value. + */ + if (context->terminal_id == 240 || context->terminal_id == 330) { + hls2rgb(0, l, 0, &r, &g, &b); + TRACE(("converted to grayscale: %hd,%hd,%hd\n", r, g, b)); + } + + *r_out = r; + *g_out = g; + *b_out = b; + + if (colorspec.pos < colorspec.len) { + char skip; + + skip_regis_whitespace(&colorspec); + skip = pop_fragment(&colorspec); + (void) skip; /* variable needed only if tracing */ + TRACE(("DATA_ERROR: ignoring unexpected character in ReGIS colorspec \"%c\"\n", + skip)); + } + + return 1; +} + +static int +load_regis_regnum_or_colorspec(RegisGraphicsContext const *context, + RegisDataFragment const *input, + RegisterNum *out) +{ + int val; + RegisDataFragment colorspec; + RegisDataFragment num; + RegisDataFragment coloroption; + + copy_fragment(&colorspec, input); + TRACE(("looking at colorspec pattern: \"%s\"\n", + fragment_to_tempstr(&colorspec))); + + skip_regis_whitespace(&colorspec); + + if (extract_regis_num(&colorspec, &num)) { + if (!regis_num_to_int(&num, &val)) { + TRACE(("DATA_ERROR: colorspec value %s is not a valid register\n", + fragment_to_tempstr(&num))); + return 0; } - /* FIXME: check for trailing junk? */ - *out = find_color_register(graphic->color_registers, r, g, b); + if (val < 0) { + /* FIXME: error, truncate, wrap, ...? */ + TRACE(("DATA_ERROR: ignoring negative colorspec value: %d\n", val)); + return 0; + } + if (val >= (int) context->graphic->valid_registers) { + /* FIXME: error, truncate, wrap, ...? */ + TRACE(("DATA_ERROR: colorspec value %d is too big; wrapping\n", + val)); + val %= (int) context->graphic->valid_registers; + } + + TRACE(("colorspec contains index for register %u\n", val)); + *out = (RegisterNum) val; + + if (colorspec.pos < colorspec.len) { + char skip; + + skip_regis_whitespace(&colorspec); + skip = pop_fragment(&colorspec); + (void) skip; /* variable needed only if tracing */ + TRACE(("DATA_ERROR: unexpected character after register \"%c\"\n", + skip)); + return 0; + } + + return 1; + } + + if (extract_regis_parenthesized_data(&colorspec, &coloroption)) { + short r, g, b; + + if (!load_regis_colorspec(context, &coloroption, &r, &g, &b)) { + TRACE(("unable to parse colorspec\n")); + return 0; + } + + *out = find_color_register(context->graphic->color_registers, r, g, b); TRACE(("colorspec maps to closest register %u\n", *out)); + return 1; } - TRACE(("unrecognized colorspec format: \"%s\"\n", + TRACE(("expected register number or colorspec, but found: \"%s\"\n", fragment_to_tempstr(&colorspec))); return 0; } @@ -3083,7 +3316,7 @@ load_regis_pixelvector(char const *pixelvector, static int load_regis_write_control(RegisParseState *state, - Graphic const *graphic, + RegisGraphicsContext const *context, int cur_x, int cur_y, int option, RegisDataFragment *arg, @@ -3092,6 +3325,12 @@ load_regis_write_control(RegisParseState *state, TRACE(("checking write control option \"%c\" with arg \"%s\"\n", option, fragment_to_tempstr(arg))); switch (option) { + case 'C': + case 'c': + TRACE(("write control compliment writing mode \"%s\"\n", + fragment_to_tempstr(arg))); + out->write_style = WRITE_STYLE_COMPLEMENT; + break; case 'E': case 'e': TRACE(("write control erase writing mode \"%s\"\n", @@ -3105,7 +3344,7 @@ load_regis_write_control(RegisParseState *state, { int val; if (!regis_num_to_int(arg, &val) || - val < 0 || val >= (int) graphic->valid_registers) { + val < 0 || val >= (int) context->graphic->valid_registers) { TRACE(("interpreting out of range value as 0 FIXME\n")); out->plane_mask = 0U; } else { @@ -3117,12 +3356,27 @@ load_regis_write_control(RegisParseState *state, case 'i': TRACE(("write control foreground color \"%s\"\n", fragment_to_tempstr(arg))); - if (!load_regis_colorspec(graphic, arg, &out->foreground)) { + if (!load_regis_regnum_or_colorspec(context, arg, &out->foreground)) { TRACE(("DATA_ERROR: write control foreground color specifier not recognized: \"%s\"\n", fragment_to_tempstr(arg))); return 0; } break; + case 'L': + case 'l': + TRACE(("write control line width \"%s\" (FIXME: currently ignored)\n", + fragment_to_tempstr(arg))); + { + int val; + if (!regis_num_to_int(arg, &val) || + val < 0 || val >= (int) 9) { + TRACE(("interpreting out of range value as 1 FIXME\n")); + out->line_width = 1U; + } else { + out->line_width = (unsigned) val; + } + } + break; case 'M': case 'm': TRACE(("write control found pixel multiplication factor \"%s\"\n", @@ -3194,7 +3448,8 @@ load_regis_write_control(RegisParseState *state, RegisDataFragment num; int val; - if (extract_regis_num(&suboptionarg, &num)) { + if (extract_regis_num(&suboptionarg, + &num)) { if (!regis_num_to_int(&num, &val) || val < 1) { TRACE(("interpreting out of range pattern multiplier \"%s\" as 2 FIXME\n", @@ -3336,12 +3591,6 @@ load_regis_write_control(RegisParseState *state, } } break; - case 'C': - case 'c': - TRACE(("write control compliment writing mode \"%s\"\n", - fragment_to_tempstr(arg))); - out->write_style = WRITE_STYLE_COMPLEMENT; - break; case 'R': case 'r': TRACE(("write control switch to replacement writing mode \"%s\"\n", @@ -3491,7 +3740,7 @@ load_regis_write_control(RegisParseState *state, static int load_regis_write_control_set(RegisParseState *state, - Graphic const *graphic, + RegisGraphicsContext const *context, int cur_x, int cur_y, RegisDataFragment *controls, RegisWriteControls *out) @@ -3512,7 +3761,7 @@ load_regis_write_control_set(RegisParseState *state, skip_regis_whitespace(&arg); TRACE(("got write control option and value: \"%c\" \"%s\"\n", option, fragment_to_tempstr(&arg))); - if (!load_regis_write_control(state, graphic, + if (!load_regis_write_control(state, context, cur_x, cur_y, option, &arg, out)) { return 0; @@ -3561,6 +3810,7 @@ init_regis_write_controls(int terminal_id, unsigned all_planes, controls->shading_character = '\0'; controls->shading_reference = 0; /* no meaning if shading is disabled */ controls->shading_reference_dim = WRITE_SHADING_REF_Y; + controls->line_width = 1U; /* FIXME: add the rest */ } @@ -3579,12 +3829,13 @@ copy_regis_write_controls(RegisWriteControls const *src, dst->shading_character = src->shading_character; dst->shading_reference = src->shading_reference; dst->shading_reference_dim = src->shading_reference_dim; + dst->line_width = src->line_width; } static void -init_regis_text_controls(RegisTextControls * controls) +init_regis_text_controls(RegisTextControls *controls) { - controls->alphabet = 0U; /* built-in */ + controls->alphabet_num = 0U; /* built-in */ controls->character_set_l = 0U; /* ASCII */ controls->character_set_r = 0U; /* Latin-1 */ get_standard_character_size(1, &controls->character_display_w, @@ -3599,9 +3850,9 @@ init_regis_text_controls(RegisTextControls * controls) } static void -copy_regis_text_controls(RegisTextControls const *src, RegisTextControls * dst) +copy_regis_text_controls(RegisTextControls const *src, RegisTextControls *dst) { - dst->alphabet = src->alphabet; + dst->alphabet_num = src->alphabet_num; dst->character_set_l = src->character_set_l; dst->character_set_r = src->character_set_r; dst->character_display_w = src->character_display_w; @@ -3622,10 +3873,12 @@ init_regis_alphabets(RegisGraphicsContext *context) for (alphabet_index = 0U; alphabet_index < MAX_REGIS_ALPHABETS; alphabet_index++) { - context->alphabets[alphabet_index].alphabet_num = 0U; + context->alphabets[alphabet_index].alphabet_num = INVALID_ALPHABET_NUM; context->alphabets[alphabet_index].pixw = 0U; context->alphabets[alphabet_index].pixh = 0U; context->alphabets[alphabet_index].name[0] = '\0'; + context->alphabets[alphabet_index].fontname[0] = '\0'; + context->alphabets[alphabet_index].use_font = 0; context->alphabets[alphabet_index].bytes = NULL; } } @@ -3719,8 +3972,9 @@ parse_regis_command(RegisParseState *state) /* Load * L - * (S)[w,h] # set glyph size (xterm extension) * (A) # set character set number or name + * (F)"fontname" # load from font (xterm extension) + * (S)[w,h] # set glyph size (xterm extension) * "ascii"xx,xx,xx,xx,xx,xx,xx,xx # pixel values */ TRACE(("found ReGIS command \"%c\" (load charset)\n", ch)); @@ -3728,7 +3982,8 @@ parse_regis_command(RegisParseState *state) state->load_index = MAX_REGIS_ALPHABETS; state->load_w = 8U; state->load_h = 10U; - state->load_alphabet = 1U; + state->load_alphabet = 1U; /* FIXME: is this the correct default */ + state->load_name[0] = '\0'; state->load_glyph = (unsigned) (unsigned char) '\0'; state->load_row = 0U; break; @@ -3774,16 +4029,21 @@ parse_regis_command(RegisParseState *state) * S * (A[<upper left>][<lower right>]) * (C<setting> # 0 (cursor output off), 1 (cursor output on) - * (E # erase to background color, resets shades, curves, and stacks + * (E) # erase to background color, resets shades, curves, and stacks + * (F) # print the graphic and erase the screen (DECprint extension) * (H(P<printer offset>)[<print area cornet>][<print area corner>) * (I<color register>) # set the background to a specific register - * (I(<rgb>)) # set the background to the register closest to an RGB value - * (I(<hls>)) # set the background to the register closest to an HLS color - * (M<color index to set>(L<mono level>)...) # level is 0 ... 100 (sets grayscale registers only) - * (M<color index to set>(<RGB code>)...) # codes are D (black), R (red), G (green), B (blue), C (cyan), Y (yellow), M (magenta), W (white) (sets color and grayscale registers) - * (M<color index to set>(A<RGB code>)...) # codes are D (black), R (red), G (green), B (blue), C (cyan), Y (yellow), M (magenta), W (white) (sets color registers only) + * (I(<rgbcode>)) # set the background to the register closest to an "RGB" color + * (I(R<r>G<g>B<b>)) # set the background to the register closest to an RGB triplet (RLogin extension) + * (I(H<h>L<l>S<s>)) # set the background to the register closest to an HLS triplet + * (I(L<l>)) # set the background to the register closest to a grayscale value + * (M<color index to set>(<rgbcode>)...) # codes are D (black), R (red), G (green), B (blue), C (cyan), Y (yellow), M (magenta), W (white) (sets color and grayscale registers) + * (M<color index to set>(A<rgbcode>)...) # codes are D (black), R (red), G (green), B (blue), C (cyan), Y (yellow), M (magenta), W (white) (sets color registers only) + * (M<color index to set>(R<red>G<green>B<blue>)...) # 0..100, 0..100, 0..100 (sets color and grayscale registers) (RLogin extension) + * (M<color index to set>(AR<red>G<green>B<blue>)...) # 0..100, 0..100, 0..100 (sets color registers only) (RLogin extension) * (M<color index to set>(H<hue>L<lightness>S<saturation>)...) # 0..360, 0..100, 0..100 (sets color and grayscale registers) * (M<color index to set>(AH<hue>L<lightness>S<saturation>)...) # 0..360, 0..100, 0..100 (sets color registers only) + * (M<color index to set>(L<mono level>)...) # level is 0 ... 100 (sets grayscale registers only) * (P<graphics page number>) # 0 (default) or 1 * (T(<time delay ticks>) # 60 ticks per second, up to 32767 ticks * (W(M<factor>) # PV multiplier @@ -3846,8 +4106,11 @@ parse_regis_command(RegisParseState *state) * (E) # erase writing mode * (F<plane>) # set the foreground intensity to a specific register * (I<color register>) # set the foreground to a specific register - * (I(<rgb>)) # set the foreground to the register closest to an RGB value - * (I(<hls>)) # set the foreground to the register closest to an HLS color + * (I(<rgbcode>)) # set the foreground to the register closest to an "RGB" color + * (I(R<r>G<g>B<b>)) # set the foreground to the register closest to an RGB triplet (RLogin extension) + * (I(H<h>L<l>S<s>)) # set the foreground to the register closest to an HLS triplet + * (I(L<l>)) # set the foreground to the register closest to a grayscale value + * (L<width>) # set the line width (RLogin extension) * (M<pixel vector multiplier>) # set the multiplication factor * (N<setting>) # 0 == negative patterns disabled, 1 == negative patterns enabled * (P<pattern number>) # 0..9: 0 == none, 1 == solid, 2 == 50% dash, 3 == dash-dot @@ -4108,7 +4371,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) case 'w': TRACE(("found temporary write options \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control_set(state, context->graphic, + if (!load_regis_write_control_set(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, &optionarg, @@ -4154,7 +4417,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) alphabet)); break; } -#ifdef ENABLE_USER_FONT_SIZE_EXTENSION +#ifndef ENABLE_UPLOAD_ALPHABET_ZERO if (alphabet == 0) { TRACE(("DATA_ERROR: alphabet 0 can not be modified\n")); break; @@ -4170,8 +4433,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) if (strlen(state->temp) == 0U || strlen(state->temp) >= REGIS_ALPHABET_NAME_LEN) { TRACE(("DATA_ERROR: alphabet names must be between 1 and %u characters long: \"%s\" FIXME\n", - REGIS_ALPHABET_NAME_LEN - 1U, - fragment_to_tempstr(&optionarg))); + REGIS_ALPHABET_NAME_LEN - 1U, state->temp)); break; } @@ -4189,14 +4451,80 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) } } break; -#ifdef ENABLE_USER_FONT_SIZE_EXTENSION +#ifdef ENABLE_UPLOAD_ALPHABET_FROM_FONT + case 'F': + case 'f': + TRACE(("found font option \"%s\"\n", + fragment_to_tempstr(&optionarg))); + + if (state->load_index == MAX_REGIS_ALPHABETS) { + state->load_index = find_free_alphabet_index(context, + state->load_alphabet, + state->load_w, + state->load_h); + TRACE(("current alphabet is %u and size is %ux%u; assigning alphabet index %u\n", + state->load_alphabet, state->load_w, state->load_h, state->load_index)); + } + + for (;;) { + RegisDataFragment fontarg; + + if (skip_regis_whitespace(&optionarg)) + continue; + if (extract_regis_num(&optionarg, &fontarg)) { + int enabled; + + TRACE(("fontname enabled: %s\n", fragment_to_tempstr(&fontarg))); + if (!regis_num_to_int(&fontarg, &enabled)) { + TRACE(("DATA_ERROR: unable to parse int in load fontname option: \"%s\"\n", + fragment_to_tempstr(&fontarg))); + break; + } + if (enabled != 0U && enabled != 1U) { + TRACE(("DATA_ERROR: invalid fontname enable state: \"%d\"\n", enabled)); + break; + } + + TRACE(("fontname enabled: %d\n", enabled)); + context->alphabets[state->load_index].use_font = enabled; + continue; + } + if (extract_regis_string(&optionarg, state->temp, + state->templen)) { + if (strlen(state->temp) == 0U || + strlen(state->temp) >= REGIS_FONTNAME_LEN) { + TRACE(("DATA_ERROR: font names must be between 1 and %u characters long: \"%s\"\n", + REGIS_FONTNAME_LEN - 1U, state->temp)); + break; + } + + strcpy(context->alphabets[state->load_index].fontname, + state->temp); + context->alphabets[state->load_index].use_font = 1; + TRACE(("using backing font: %s\n", + context->alphabets[state->load_index].fontname)); + } + + if (!fragment_len(&optionarg)) { + break; + } else { + TRACE(("DATA_ERROR: unexpected text in load fontname option: \"%s\"\n", + fragment_to_tempstr(&optionarg))); + break; + } + } + break; +#endif +#ifdef ENABLE_USER_FONT_SIZE case 'S': case 's': TRACE(("found glyph size option \"%s\"\n", fragment_to_tempstr(&optionarg))); - for (;;) { + while (fragment_len(&optionarg) > 0) { RegisDataFragment sizearg; + if (skip_regis_whitespace(&optionarg)) + continue; if (extract_regis_extent(&optionarg, &sizearg)) { int w, h; unsigned size; @@ -4205,7 +4533,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) fragment_to_tempstr(&sizearg))); if (!load_regis_extent(fragment_to_tempstr(&sizearg), 0, 0, &w, &h)) { - TRACE(("DATA_ERROR: unable to parse extenet in glyph size option: \"%s\"\n", + TRACE(("DATA_ERROR: unable to parse extent in glyph size option: \"%s\"\n", fragment_to_tempstr(&sizearg))); break; } @@ -4226,18 +4554,15 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) break; } - TRACE(("using size: %dx%d\n", w, h)); + TRACE(("using glyph size: %dx%d\n", w, h)); state->load_w = (unsigned) w; state->load_h = (unsigned) h; - } else if (skip_regis_whitespace(&sizearg)) { - ; - } else if (!fragment_len(&sizearg)) { - break; - } else { - TRACE(("DATA_ERROR: expected extent in glyph size option: \"%s\"\n", - fragment_to_tempstr(&sizearg))); - break; + continue; } + + TRACE(("DATA_ERROR: expected extent in glyph size option: \"%s\"\n", + fragment_to_tempstr(&sizearg))); + break; } break; #endif @@ -4324,7 +4649,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) case 'w': TRACE(("found temporary write options \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control_set(state, context->graphic, + if (!load_regis_write_control_set(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, &optionarg, @@ -4586,7 +4911,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) TRACE(("found erase request \"%s\"\n", fragment_to_tempstr(&optionarg))); if (fragment_len(&optionarg)) { - TRACE(("DATA_ERROR: ignoring unexpected argument to ReGIS screen erase option \"%s\"\n", + TRACE(("DATA_ERROR: ignoring unexpected argument to ReGIS erase request \"%s\"\n", fragment_to_tempstr(&optionarg))); return 1; } @@ -4595,6 +4920,21 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) context->graphic->actual_height, context->background); break; + case 'F': + case 'f': + TRACE(("found page eject request \"%s\"\n", + fragment_to_tempstr(&optionarg))); + if (fragment_len(&optionarg)) { + TRACE(("DATA_ERROR: ignoring unexpected argument to ReGIS page eject request \"%s\"\n", + fragment_to_tempstr(&optionarg))); + return 1; + } + /* We aren't going to print anything so no need to deduplicate. */ + draw_solid_rectangle(context->graphic, 0, 0, + context->graphic->actual_width, + context->graphic->actual_height, + context->background); + break; case 'H': case 'h': TRACE(("found hardcopy control \"%s\" FIXME\n", @@ -4610,8 +4950,8 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) case 'i': TRACE(("found screen background color index \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_colorspec(context->graphic, &optionarg, - &context->background)) { + if (!load_regis_regnum_or_colorspec(context, &optionarg, + &context->background)) { TRACE(("DATA_ERROR: screen background color specifier not recognized: \"%s\"\n", fragment_to_tempstr(&optionarg))); return 1; @@ -4624,7 +4964,6 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) { RegisDataFragment regnum; RegisDataFragment colorspec; - char ch; while (fragment_len(&optionarg)) { if (skip_regis_whitespace(&optionarg)) @@ -4653,6 +4992,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) return 1; } + skip_regis_whitespace(&colorspec); switch (peek_fragment(&colorspec)) { case 'A': case 'a': @@ -4666,126 +5006,36 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) TRACE(("mapping register %d to color spec: \"%s\"\n", register_num, fragment_to_tempstr(&colorspec))); - if (fragment_len(&colorspec) == 1) { - short l; - ch = pop_fragment(&colorspec); - - TRACE(("got regis RGB colorspec pattern: \"%s\"\n", - fragment_to_tempstr(&colorspec))); - switch (ch) { - case 'D': - case 'd': - r = 0; - g = 0; - b = 0; - l = 0; - break; - case 'R': - case 'r': - r = 100; - g = 0; - b = 0; - l = 46; - break; - case 'G': - case 'g': - r = 0; - g = 100; - b = 0; - l = 50; - break; - case 'B': - case 'b': - r = 0; - g = 0; - b = 100; - l = 50; - break; - case 'C': - case 'c': - r = 0; - g = 100; - b = 100; - l = 50; - break; - case 'Y': - case 'y': - r = 100; - g = 100; - b = 0; - l = 50; - break; - case 'M': - case 'm': - r = 100; - g = 0; - b = 100; - l = 50; - break; - case 'W': - case 'w': - r = 100; - g = 100; - b = 100; - l = 100; - break; - default: - TRACE(("screen color register mapping with unknown RGB color name: \"%c\"\n", - ch)); - return 1; - } - if (context->terminal_id == 240 || - context->terminal_id == 330) { - /* - * The VT240 and VT330 models force saturation - * to zero. - */ - hls2rgb(0, l, 0, &r, &g, &b); - } - } else { - short h, l, s; - - if (sscanf(fragment_to_tempstr(&colorspec), - "%*1[Hh]%6hd%*1[Ll]%6hd%*1[Ss]%6hd", - &h, &l, &s) != 3) { - h = 0; - s = 0; - if (sscanf(fragment_to_tempstr(&colorspec), - "%*1[Ll]%6hd", &l) != 1) { - TRACE(("unrecognized colorspec: \"%s\"\n", - fragment_to_tempstr(&colorspec))); - return 1; - } - } - if (context->terminal_id == 240 || - context->terminal_id == 330) { - /* - * The VT240 and VT330 models force saturation - * to zero. - */ - h = 0; - s = 0; - } - hls2rgb(h, l, s, &r, &g, &b); + if (!load_regis_colorspec(context, &colorspec, + &r, &g, &b)) { + TRACE(("DATA_ERROR: unable to use colorspec for mapping of register %d\n", + register_num)); + return 1; } if (color_only && (context->terminal_id == 240 || - context->terminal_id == 330)) - continue; - update_color_register(context->graphic, - (RegisterNum) register_num, - r, g, b); + context->terminal_id == 330)) { + TRACE(("NOT setting color register %d to %hd,%hd,%hd\n", + register_num, r, g, b)); + } else { + TRACE(("setting color register %d to %hd,%hd,%hd\n", + register_num, r, g, b)); + update_color_register(context->graphic, + (RegisterNum) register_num, + r, g, b); + } continue; } { char skip; + skip_regis_whitespace(&optionarg); skip = pop_fragment(&optionarg); (void) skip; /* variable needed only if tracing */ - TRACE(("DATA_ERROR: ignoring unexpected character in ReGIS screen color register mapping value \"%c\"\n", + TRACE(("DATA_ERROR: ignoring mapping request with unexpected character \"%c\"\n", skip)); + return 1; } - return 1; } } break; @@ -4861,8 +5111,8 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) break; } - TRACE(("using alphabet: %d\n", alphabet)); - context->current_text_controls->alphabet = (unsigned) alphabet; + TRACE(("using alphabet number: %d\n", alphabet)); + context->current_text_controls->alphabet_num = (unsigned) alphabet; if (fragment_len(&optionarg)) { TRACE(("DATA_ERROR: ignoring trailing junk in text alphabet option \"%s\"\n", @@ -5238,7 +5488,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) case 'w': TRACE(("found temporary write options \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control_set(state, context->graphic, + if (!load_regis_write_control_set(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, &optionarg, @@ -5337,7 +5587,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) case 'w': TRACE(("found temporary write options \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control_set(state, context->graphic, + if (!load_regis_write_control_set(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, &optionarg, @@ -5356,7 +5606,7 @@ parse_regis_option(RegisParseState *state, RegisGraphicsContext *context) skip_regis_whitespace(&optionarg); TRACE(("inspecting permanent write option \"%c\" with value \"%s\"\n", state->option, fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control(state, context->graphic, + if (!load_regis_write_control(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, state->option, &optionarg, @@ -5771,6 +6021,8 @@ parse_regis_items(RegisParseState *state, RegisGraphicsContext *context) state->load_alphabet, state->load_w, state->load_h); + TRACE(("current alphabet is %u and size is %ux%u; assigning alphabet index %u\n", + state->load_alphabet, state->load_w, state->load_h, state->load_index)); } glyph_size = GLYPH_WIDTH_BYTES( @@ -5785,7 +6037,7 @@ parse_regis_items(RegisParseState *state, RegisGraphicsContext *context) } } { unsigned char *glyph; - unsigned int bytew; + unsigned bytew; unsigned byte; unsigned unused_bits; @@ -5928,7 +6180,7 @@ parse_regis_toplevel(RegisParseState *state, RegisGraphicsContext *context) TRACE(("found temporary write options \"%s\"\n", fragment_to_tempstr(&optionarg))); - if (!load_regis_write_control_set(state, context->graphic, + if (!load_regis_write_control_set(state, context, context->graphics_output_cursor_x, context->graphics_output_cursor_y, &optionarg, @@ -5989,9 +6241,16 @@ parse_regis(XtermWidget xw, ANSI *params, char const *string) memset(&context, 0, sizeof(context)); + /* Update the screen scrolling and do a refresh. + * The refresh may not cover the whole graphic. + */ + if (screen->scroll_amt) + FlushScroll(xw); + context.graphic = get_new_or_matching_graphic(xw, charrow, charcol, - 800, 480, + screen->regis_max_wide, + screen->regis_max_high, type); /* * FIXME: Don't initialize parameters for continued command mode, @@ -6003,7 +6262,7 @@ parse_regis(XtermWidget xw, ANSI *params, char const *string) X_GETTIMEOFDAY(&prev_tv); iterations = 0U; - refresh_modified_displayed_graphics(screen); + refresh_modified_displayed_graphics(xw); for (;;) { if (skip_regis_whitespace(&state.input)) @@ -6027,7 +6286,17 @@ parse_regis(XtermWidget xw, ANSI *params, char const *string) /* FIXME: pre-ANSI compilers need memcpy() */ prev_tv = curr_tv; iterations = 0U; - refresh_modified_displayed_graphics(screen); + refresh_modified_displayed_graphics(xw); +#if OPT_DOUBLE_BUFFER + { + XdbeSwapInfo swap; + + swap.swap_window = VWindow(screen); + swap.swap_action = XdbeCopied; + XdbeSwapBuffers(XtDisplay(term), &swap, 1); + XFlush(XtDisplay(xw)); + } +#endif } } continue; @@ -6039,6 +6308,6 @@ parse_regis(XtermWidget xw, ANSI *params, char const *string) free(state.temp); - refresh_modified_displayed_graphics(screen); + refresh_modified_displayed_graphics(xw); TRACE(("DONE! Successfully parsed ReGIS data.\n")); } diff --git a/app/xterm/graphics_sixel.c b/app/xterm/graphics_sixel.c index 2f81cf37f..81c9f30e7 100644 --- a/app/xterm/graphics_sixel.c +++ b/app/xterm/graphics_sixel.c @@ -1,4 +1,4 @@ -/* $XTermId: graphics_sixel.c,v 1.9 2014/07/15 21:07:44 tom Exp $ */ +/* $XTermId: graphics_sixel.c,v 1.10 2014/10/06 09:28:00 Ross.Combs Exp $ */ /* * Copyright 2014 by Ross Combs @@ -571,7 +571,9 @@ parse_sixel(XtermWidget xw, ANSI *params, char const *string) string++; } - /* update the screen */ + /* Update the screen scrolling and do a refresh. + * The refresh may not cover the whole graphic. + */ if (screen->scroll_amt) FlushScroll(xw); @@ -632,7 +634,8 @@ parse_sixel(XtermWidget xw, ANSI *params, char const *string) } finis: - refresh_modified_displayed_graphics(screen); + graphic->dirty = 1; + refresh_modified_displayed_graphics(xw); TRACE(("DONE successfully parsed sixel data\n")); dump_graphic(graphic); diff --git a/app/xterm/linedata.c b/app/xterm/linedata.c index 31a726a42..0ad26e7ea 100644 --- a/app/xterm/linedata.c +++ b/app/xterm/linedata.c @@ -1,7 +1,7 @@ -/* $XTermId: linedata.c,v 1.82 2013/02/08 00:11:16 tom Exp $ */ +/* $XTermId: linedata.c,v 1.85 2014/11/13 01:17:59 tom Exp $ */ /* - * Copyright 2009-2012,2013 by Thomas E. Dickey + * Copyright 2009-2013,2014 by Thomas E. Dickey * * All Rights Reserved * @@ -41,7 +41,7 @@ * If the data comes from the scrollback, defer that to getScrollback(). */ LineData * -getLineData(TScreen * screen, int row) +getLineData(TScreen *screen, int row) { LineData *result = 0; ScrnBuf buffer; @@ -85,7 +85,7 @@ getLineData(TScreen * screen, int row) * TODO: optionally prune unused combining character data from the result. */ void -copyLineData(LineData * dst, LineData * src) +copyLineData(LineData *dst, CLineData *src) { dst->bufHead = src->bufHead; @@ -186,7 +186,10 @@ initLineData(XtermWidget xw) #define CellDataSize(screen) (SizeOfCellData + screen->lineExtra) #define CellDataAddr(screen, data, cell) \ - (CellData *)(void *) ((char *)data + (cell * CellDataSize(screen))) + ( (CellData *)(void *) ((char *)data + (cell * CellDataSize(screen))) ) +#define ConstCellDataAddr(screen, data, cell) \ + ( (const CellData *)(const void *) ( \ + (const char *)data + (cell * CellDataSize(screen))) ) CellData * newCellData(XtermWidget xw, Cardinal count) @@ -200,10 +203,10 @@ newCellData(XtermWidget xw, Cardinal count) } void -saveCellData(TScreen * screen, - CellData * data, +saveCellData(TScreen *screen, + CellData *data, Cardinal cell, - LineData * ld, + CLineData *ld, int column) { CellData *item = CellDataAddr(screen, data, cell); @@ -225,13 +228,13 @@ saveCellData(TScreen * screen, } void -restoreCellData(TScreen * screen, - CellData * data, +restoreCellData(TScreen *screen, + const CellData *data, Cardinal cell, - LineData * ld, + LineData *ld, int column) { - CellData *item = CellDataAddr(screen, data, cell); + const CellData *item = ConstCellDataAddr(screen, data, cell); if (column < MaxCols(screen)) { ld->attribs[column] = item->attribs; diff --git a/app/xterm/misc.c b/app/xterm/misc.c index e16851393..38705c14b 100644 --- a/app/xterm/misc.c +++ b/app/xterm/misc.c @@ -1,4 +1,4 @@ -/* $XTermId: misc.c,v 1.714 2014/09/03 23:59:25 tom Exp $ */ +/* $XTermId: misc.c,v 1.715 2014/10/29 00:54:25 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -1018,15 +1018,10 @@ HandleFocusChange(Widget w GCC_UNUSED, if (screen->quiet_grab && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { /* EMPTY */ ; - } else if ((event->type == FocusIn || event->type == FocusOut) - && event->detail == NotifyPointer) { - /* - * NotifyPointer is sent to the window where the pointer is, and is - * in addition to events sent to the old/new focus-windows. - */ - /* EMPTY */ ; } else if (event->type == FocusIn) { - setXUrgency(xw, False); + if (event->detail != NotifyPointer) { + setXUrgency(xw, False); + } /* * NotifyNonlinear only happens (on FocusIn) if the pointer was not in diff --git a/app/xterm/package/debian/changelog b/app/xterm/package/debian/changelog index 2a486f815..e4e5ea0f1 100644 --- a/app/xterm/package/debian/changelog +++ b/app/xterm/package/debian/changelog @@ -1,3 +1,9 @@ +xterm-dev (313) unstable; urgency=low + + * maintenance updates + + -- Thomas E. Dickey <dickey@invisible-island.net> Mon, 06 Oct 2014 05:26:37 -0400 + xterm-dev (312) unstable; urgency=low * maintenance updates diff --git a/app/xterm/package/debian/postinst b/app/xterm/package/debian/postinst new file mode 100644 index 000000000..d2efe3c79 --- /dev/null +++ b/app/xterm/package/debian/postinst @@ -0,0 +1,25 @@ +#! /bin/sh +echo "** postinst script for xterm: $*" + +set -e + +PRI=60 +ALT=x-terminal-emulator +PKG=xterm-dev + +BINDIR=/usr/bin +MANDIR=/usr/share/man/man1 + +if [ $1 != "upgrade" ] +then + update-alternatives \ + --install \ + $BINDIR/$ALT $ALT \ + $BINDIR/$PKG $PRI \ + --slave $MANDIR/$ALT.1.gz $ALT.1.gz \ + $MANDIR/$PKG.1.gz +fi + +#DEBHELPER# + +exit 0 diff --git a/app/xterm/package/debian/prerm b/app/xterm/package/debian/prerm new file mode 100644 index 000000000..1231a0325 --- /dev/null +++ b/app/xterm/package/debian/prerm @@ -0,0 +1,12 @@ +#! /bin/sh +echo "** prerm script for xterm: $*" + +set -e + +if [ "x$1" != "xupgrade" ]; then + update-alternatives --remove x-terminal-emulator /usr/bin/xterm-dev +fi + +#DEBHELPER# + +exit 0 diff --git a/app/xterm/package/freebsd/Makefile b/app/xterm/package/freebsd/Makefile index 9c22d212c..68404de1c 100644 --- a/app/xterm/package/freebsd/Makefile +++ b/app/xterm/package/freebsd/Makefile @@ -5,7 +5,7 @@ # and "make makesum". PORTNAME= xterm -PORTVERSION= 312 +PORTVERSION= 313 CATEGORIES= x11 MASTER_SITES= ftp://invisible-island.net/xterm/ \ CRITICAL diff --git a/app/xterm/package/xterm.spec b/app/xterm/package/xterm.spec index a9100d06b..beb0c7017 100644 --- a/app/xterm/package/xterm.spec +++ b/app/xterm/package/xterm.spec @@ -1,11 +1,11 @@ -# $XTermId: xterm.spec,v 1.77 2014/09/26 22:42:15 tom Exp $ +# $XTermId: xterm.spec,v 1.78 2014/10/06 09:26:38 tom Exp $ Summary: X terminal emulator (development version) %global my_middle xterm %global my_suffix -dev %global fullname %{my_middle}%{my_suffix} %global my_class XTermDev Name: %{fullname} -Version: 312 +Version: 313 Release: 1 License: X11 Group: User Interface/X diff --git a/app/xterm/ptyx.h b/app/xterm/ptyx.h index d3804556a..002c74c2a 100644 --- a/app/xterm/ptyx.h +++ b/app/xterm/ptyx.h @@ -1,4 +1,4 @@ -/* $XTermId: ptyx.h,v 1.813 2014/09/17 08:24:34 tom Exp $ */ +/* $XTermId: ptyx.h,v 1.816 2014/11/28 19:31:59 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -1472,16 +1472,16 @@ typedef unsigned char IChar; /* for 8-bit characters */ #define BUF_SIZE resource.maxBufSize typedef struct { - Char * next; - Char * last; - int update; /* HandleInterpret */ + Char *next; + Char *last; + int update; /* HandleInterpret */ #if OPT_WIDE_CHARS - IChar utf_data; /* resulting character */ - int utf_size; /* ...number of bytes decoded */ - Char *write_buf; + IChar utf_data; /* resulting character */ + int utf_size; /* ...number of bytes decoded */ + Char *write_buf; unsigned write_len; #endif - Char buffer[1]; + Char buffer[1]; } PtyData; /***====================================================================***/ @@ -1537,6 +1537,8 @@ typedef struct { CharData *combData[1]; /* first enum past fixed-offsets */ } LineData; +typedef const LineData CLineData; + /* * We use CellData in a few places, when copying a cell's data to a temporary * variable. @@ -1568,8 +1570,11 @@ typedef struct { #define ROW2INX(screen, row) ((row) + (screen)->topline) #define INX2ROW(screen, inx) ((inx) - (screen)->topline) +/* these are unused but could be useful for debugging */ +#if 0 #define ROW2ABS(screen, row) ((row) + (screen)->savedlines) #define INX2ABS(screen, inx) ROW2ABS(screen, INX2ROW(screen, inx)) +#endif #define okScrnRow(screen, row) \ ((row) <= ((screen)->max_row - (screen)->topline) \ @@ -2122,7 +2127,7 @@ typedef struct { * the saved lines, taking scrolling into account. */ int topline; /* line number of top, <= 0 */ - long saved_fifo; /* number of lines that've been saved */ + long saved_fifo; /* number of lines that've ever been saved */ int savedlines; /* number of lines that've been saved */ int savelines; /* number of lines off top to save */ int scroll_amt; /* amount to scroll */ @@ -2223,6 +2228,12 @@ typedef struct { unsigned restore_height; #endif +#if OPT_SIXEL_GRAPHICS + String regis_screensize; /* ReGIS given screensize */ + Dimension regis_max_high; /* ...corresponding height */ + Dimension regis_max_wide; /* ...and width */ +#endif + #if OPT_SCROLL_LOCK Boolean allowScrollLock;/* ScrollLock mode */ Boolean allowScrollLock0;/* initial ScrollLock mode */ diff --git a/app/xterm/screen.c b/app/xterm/screen.c index fe0643460..aa7bdbacd 100644 --- a/app/xterm/screen.c +++ b/app/xterm/screen.c @@ -1,4 +1,4 @@ -/* $XTermId: screen.c,v 1.501 2014/07/30 08:06:23 tom Exp $ */ +/* $XTermId: screen.c,v 1.505 2014/11/13 01:04:40 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -402,7 +402,7 @@ unsaveEditBufLines(TScreen *screen, ScrnBuf sb, unsigned n) int extra = (int) (n - j); LineData *dst = (LineData *) scrnHeadAddr(screen, sb, j); #if OPT_FIFO_LINES - LineData *src; + CLineData *src; if (extra > screen->saved_fifo || extra > screen->savelines) { TRACE(("...FIXME: must clear text!\n")); @@ -411,8 +411,8 @@ unsaveEditBufLines(TScreen *screen, ScrnBuf sb, unsigned n) src = getScrollback(screen, -extra); #else unsigned k = (screen->savelines - extra); - LineData *src = (LineData *) scrnHeadAddr(screen, - screen->saveBuf_index, k); + CLineData *src = CLineData *scrnHeadAddr(screen, + screen->saveBuf_index, k); #endif copyLineData(dst, src); } @@ -1027,6 +1027,7 @@ ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size) screen->savelines, n, screen->max_col)); + /* FIXME: this looks wrong -- rcombs */ chararea_clear_displayed_graphics(screen, where + screen->savelines, 0, @@ -1362,7 +1363,7 @@ ScrnDeleteChar(XtermWidget xw, unsigned n) * its line-wrapping state. */ void -ShowWrapMarks(XtermWidget xw, int row, LineData *ld) +ShowWrapMarks(XtermWidget xw, int row, CLineData *ld) { TScreen *screen = TScreenOf(xw); Boolean set = (Boolean) LineTstWrapped(ld); @@ -1399,7 +1400,7 @@ refreshFontGCs(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) /* * Repaints the area enclosed by the parameters. * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are - * coordinates of characters in screen; + * coordinates of characters in screen; * nrows and ncols positive. * all dimensions are based on single-characters. */ @@ -1412,7 +1413,7 @@ ScrnRefresh(XtermWidget xw, Bool force) /* ... leading/trailing spaces */ { TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; int y = toprow * FontHeight(screen) + screen->border; int row; int maxrow = toprow + nrows - 1; @@ -1449,7 +1450,7 @@ ScrnRefresh(XtermWidget xw, #endif #define BLANK_CEL(cell) (chars[cell] == ' ') IChar *chars; - IAttr *attrs; + const IAttr *attrs; int col = leftcol; int maxcol = leftcol + ncols - 1; int hi_col = maxcol; @@ -1755,11 +1756,7 @@ ScrnRefresh(XtermWidget xw, resetXtermGC(xw, flags, hilite); } - refresh_displayed_graphics(screen, - leftcol, - toprow + screen->topline, - ncols, - nrows); + refresh_displayed_graphics(xw, leftcol, toprow, ncols, nrows); /* * If we're in color mode, reset the various GC's to the current @@ -1870,7 +1867,7 @@ ScreenResize(XtermWidget xw, { TScreen *screen = TScreenOf(xw); int code, rows, cols; - int border = 2 * screen->border; + const int border = 2 * screen->border; int move_down_by = 0; #ifdef TTYSIZE_STRUCT TTYSIZE_STRUCT ts; @@ -2207,7 +2204,7 @@ ScreenResize(XtermWidget xw, screen->fullVwin.height = height - border; screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width; - scroll_displayed_graphics(-move_down_by); + scroll_displayed_graphics(xw, -move_down_by); } else if (FullHeight(screen) == height && FullWidth(screen) == width) return (0); /* nothing has changed at all */ diff --git a/app/xterm/trace.c b/app/xterm/trace.c index 590d98832..4fedd38d9 100644 --- a/app/xterm/trace.c +++ b/app/xterm/trace.c @@ -1,4 +1,4 @@ -/* $XTermId: trace.c,v 1.155 2014/04/25 21:30:23 Ross.Combs Exp $ */ +/* $XTermId: trace.c,v 1.156 2014/11/13 01:03:02 tom Exp $ */ /* * Copyright 1997-2013,2014 by Thomas E. Dickey @@ -310,7 +310,7 @@ visibleChars(const Char *buf, unsigned len) } char * -visibleIChars(IChar *buf, unsigned len) +visibleIChars(const IChar *buf, unsigned len) { static char *result; static unsigned used; @@ -627,7 +627,7 @@ TraceScreen(XtermWidget xw, int whichBuf) } void -TraceFocus(Widget w, XEvent * ev) +TraceFocus(Widget w, XEvent *ev) { TRACE(("trace_focus event type %d:%s\n", ev->type, visibleEventType(ev->type))); @@ -783,7 +783,7 @@ TraceWMSizeHints(XtermWidget xw) */ /* ARGSUSED */ static int -no_error(Display *dpy GCC_UNUSED, XErrorEvent * event GCC_UNUSED) +no_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) { return 1; } diff --git a/app/xterm/trace.h b/app/xterm/trace.h index 785b29191..7b7853ba7 100644 --- a/app/xterm/trace.h +++ b/app/xterm/trace.h @@ -1,7 +1,7 @@ -/* $XTermId: trace.h,v 1.72 2013/09/11 21:25:23 tom Exp $ */ +/* $XTermId: trace.h,v 1.73 2014/11/13 01:02:46 tom Exp $ */ /* - * Copyright 1997-2012,2013 by Thomas E. Dickey + * Copyright 1997-2013,2014 by Thomas E. Dickey * * All Rights Reserved * @@ -56,7 +56,7 @@ extern void TraceClose (void); #endif extern char * visibleChars (const Char * /* buf */, unsigned /* len */); -extern char * visibleIChars (IChar * /* buf */, unsigned /* len */); +extern char * visibleIChars (const IChar * /* buf */, unsigned /* len */); extern char * visibleUChar (unsigned); extern const char * visibleDblChrset(unsigned /* chrset */); extern const char * visibleEventType (int); diff --git a/app/xterm/util.c b/app/xterm/util.c index dabeb05cf..f678e498f 100644 --- a/app/xterm/util.c +++ b/app/xterm/util.c @@ -1,4 +1,4 @@ -/* $XTermId: util.c,v 1.660 2014/06/19 22:15:20 tom Exp $ */ +/* $XTermId: util.c,v 1.665 2014/11/13 00:54:35 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -687,7 +687,7 @@ xtermScroll(XtermWidget xw, int amount) } } - scroll_displayed_graphics(amount); + scroll_displayed_graphics(xw, amount); if (refreshheight > 0) { ScrnRefresh(xw, @@ -1019,7 +1019,7 @@ void WriteText(XtermWidget xw, IChar *str, Cardinal len) { TScreen *screen = TScreenOf(xw); - LineData *ld = 0; + CLineData *ld = 0; int fg; unsigned test; unsigned attr_flags = xw->flags; @@ -1321,7 +1321,7 @@ void InsertChar(XtermWidget xw, unsigned n) { TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; unsigned limit; int row = INX2ROW(screen, screen->cur_row); int left = ScrnLeftMargin(xw); @@ -1404,7 +1404,7 @@ void DeleteChar(XtermWidget xw, unsigned n) { TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; unsigned limit; int row = INX2ROW(screen, screen->cur_row); int left = ScrnLeftMargin(xw); @@ -1561,7 +1561,7 @@ static int ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len) { TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; int rc = 1; TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n", @@ -1889,7 +1889,7 @@ screen_has_data(XtermWidget xw) { TScreen *screen = TScreenOf(xw); Boolean result = False; - LineData *ld; + CLineData *ld; int row, col; for (row = 0; row < screen->max_row; ++row) { @@ -1950,8 +1950,7 @@ CopyWait(XtermWidget xw) XEvent *rep = &reply; for (;;) { - XWindowEvent(screen->display, VWindow(screen), - ExposureMask, &reply); + XWindowEvent(screen->display, VWindow(screen), ExposureMask, &reply); switch (reply.type) { case Expose: HandleExposure(xw, &reply); @@ -2028,7 +2027,7 @@ horizontal_copy_area(XtermWidget xw, int amount) /* number of characters to move right */ { TScreen *screen = TScreenOf(xw); - LineData *ld; + CLineData *ld; if ((ld = getLineData(screen, screen->cur_row)) != 0) { int src_x = LineCursorX(screen, ld, firstchar); @@ -2068,7 +2067,7 @@ vertical_copy_area(XtermWidget xw, copy_area(xw, src_x, src_y, w, h, dst_x, dst_y); if (screen->show_wrap_marks) { - LineData *ld; + CLineData *ld; int row; for (row = firstline; row < firstline + nlines; ++row) { if ((ld = getLineData(screen, row)) != 0) { @@ -2803,7 +2802,7 @@ getNormXftFont(XtermWidget xw, * fontconfig/Xft combination prior to 2.2 has a problem with * CJK truetype 'double-width' (bi-width/monospace) fonts leading * to the 's p a c e d o u t' rendering. Consequently, we can't - * rely on XftDrawString8/16 when one of those fonts is used. + * rely on XftDrawString8/16 when one of those fonts is used. * Instead, we need to roll out our own using XftDrawCharSpec. * A patch in the same spirit (but in a rather different form) * was applied to gnome vte and gtk2 port of vim. @@ -2816,7 +2815,7 @@ xtermXftDrawString(XtermWidget xw, XftFont *font, int x, int y, - IChar *text, + const IChar *text, Cardinal len, Bool really) { @@ -3176,7 +3175,7 @@ drawClippedXftString(XtermWidget xw, XftColor *fg_color, int x, int y, - IChar *text, + const IChar *text, Cardinal len) { int ncells = xtermXftWidth(xw, attr_flags, @@ -3311,7 +3310,7 @@ drawXtermText(XtermWidget xw, int start_x, int start_y, int chrset, - IChar *text, + const IChar *text, Cardinal len, int on_wide) { @@ -4481,7 +4480,7 @@ getXtermForeground(XtermWidget xw, unsigned attr_flags, int color) unsigned getXtermCell(TScreen *screen, int row, int col) { - LineData *ld = getLineData(screen, row); + CLineData *ld = getLineData(screen, row); return ((ld && (col < (int) ld->lineSize)) ? ld->charData[col] @@ -4533,7 +4532,7 @@ addXtermCombining(TScreen *screen, int row, int col, unsigned ch) unsigned getXtermCombining(TScreen *screen, int row, int col, int off) { - LineData *ld = getLineData(screen, row); + CLineData *ld = getLineData(screen, row); return ld->combData[off][col]; } #endif diff --git a/app/xterm/version.h b/app/xterm/version.h index cda239e1a..c80679f58 100644 --- a/app/xterm/version.h +++ b/app/xterm/version.h @@ -1,4 +1,4 @@ -/* $XTermId: version.h,v 1.399 2014/09/29 00:37:50 tom Exp $ */ +/* $XTermId: version.h,v 1.401 2014/11/29 02:25:05 tom Exp $ */ /* * Copyright 1998-2013,2014 by Thomas E. Dickey @@ -38,8 +38,8 @@ * version of X to which this version of xterm has been built. The resulting * number in parentheses is my patch number (Thomas E. Dickey). */ -#define XTERM_PATCH 312 -#define XTERM_DATE 2014-09-28 +#define XTERM_PATCH 313 +#define XTERM_DATE 2014-11-28 #ifndef __vendorversion__ #define __vendorversion__ "XTerm/OpenBSD" diff --git a/app/xterm/vttests/resize.pl b/app/xterm/vttests/resize.pl index 07c2ab546..ba28aaaac 100644 --- a/app/xterm/vttests/resize.pl +++ b/app/xterm/vttests/resize.pl @@ -75,26 +75,26 @@ our $original=get_reply("\x1b[18t"); our $high; our $wide; -if ( $original =~ /\x1b\[8;\d+;\d+t/ ) { +if ( defined($original) and ( $original =~ /\x1b\[8;\d+;\d+t/ ) ) { $high=csi_field($original,2); $wide=csi_field($original,3); printf "parsed terminal size $high,$wide\n"; } else { - die "Cannot get terminal size via escape sequence\n"; + die "Cannot get current terminal size via escape sequence\n"; } # our $maximize=get_reply("\x1b[19t"); our $maxhigh; our $maxwide; -if ( $maximize =~ /\x1b\[9;\d+;\d+t/ ) { +if ( defined($maximize) and ( $maximize =~ /^\x1b\[9;\d+;\d+t/ ) ) { $maxhigh=csi_field($maximize,2); $maxwide=csi_field($maximize,3); $maxhigh != 0 or $maxhigh = $high * 2; $maxwide != 0 or $maxwide = $wide * 2; printf "parsed terminal maxsize $maxhigh,$maxwide\n"; } else { - die "Cannot get terminal size via escape sequence\n"; + die "Cannot get maximum terminal size via escape sequence\n"; } our $zapped; diff --git a/app/xterm/xterm.h b/app/xterm/xterm.h index f68cce0af..952da4c5c 100644 --- a/app/xterm/xterm.h +++ b/app/xterm/xterm.h @@ -1,4 +1,4 @@ -/* $XTermId: xterm.h,v 1.746 2014/09/03 23:58:49 tom Exp $ */ +/* $XTermId: xterm.h,v 1.749 2014/11/28 19:30:12 tom Exp $ */ /* * Copyright 1999-2013,2014 by Thomas E. Dickey @@ -517,6 +517,7 @@ extern char **environ; #define XtNprinterNewLine "printerNewLine" #define XtNprivateColorRegisters "privateColorRegisters" #define XtNquietGrab "quietGrab" +#define XtNregisScreenSize "regisScreenSize" #define XtNrenderFont "renderFont" #define XtNresizeGravity "resizeGravity" #define XtNretryInputMethod "retryInputMethod" @@ -694,6 +695,7 @@ extern char **environ; #define XtCPrinterNewLine "PrinterNewLine" #define XtCPrivateColorRegisters "PrivateColorRegisters" #define XtCQuietGrab "QuietGrab" +#define XtCRegisScreenSize "RegisScreenSize" #define XtCRenderFont "RenderFont" #define XtCResizeGravity "ResizeGravity" #define XtCRetryInputMethod "RetryInputMethod" @@ -908,7 +910,7 @@ extern void ToggleCursorBlink(TScreen * /* screen */); #endif #if OPT_BLINK_TEXT -extern Bool LineHasBlinking(TScreen * /* screen */, LineData * /* ld */); +extern Bool LineHasBlinking(TScreen * /* screen */, CLineData * /* ld */); #endif #if OPT_INPUT_METHOD @@ -976,12 +978,12 @@ extern void VTInitModifiers(XtermWidget /* xw */); /* linedata.c */ extern LineData *getLineData(TScreen * /* screen */, int /* row */); -extern void copyLineData(LineData * /* dst */, LineData * /* src */); +extern void copyLineData(LineData * /* dst */, CLineData * /* src */); extern void initLineData(XtermWidget /* xw */); extern CellData *newCellData(XtermWidget /* xw */, Cardinal /* count */); -extern void saveCellData(TScreen * /* screen */, CellData * /* data */, Cardinal /* cell */, LineData * /* ld */, int /* column */); -extern void restoreCellData(TScreen * /* screen */, CellData * /* data */, Cardinal /* cell */, LineData * /* ld */, int /* column */); +extern void saveCellData(TScreen * /* screen */, CellData * /* data */, Cardinal /* cell */, CLineData * /* ld */, int /* column */); +extern void restoreCellData(TScreen * /* screen */, const CellData * /* data */, Cardinal /* cell */, LineData * /* ld */, int /* column */); /* main.c */ #define ENVP_ARG /**/ @@ -1236,7 +1238,7 @@ extern void ScrnInsertLine (XtermWidget /* xw */, ScrnBuf /* sb */, int /* last extern void ScrnRefresh (XtermWidget /* xw */, int /* toprow */, int /* leftcol */, int /* nrows */, int /* ncols */, Bool /* force */); extern void ScrnUpdate (XtermWidget /* xw */, int /* toprow */, int /* leftcol */, int /* nrows */, int /* ncols */, Bool /* force */); extern void ScrnWriteText (XtermWidget /* xw */, IChar * /* str */, unsigned /* flags */, unsigned /* cur_fg_bg */, unsigned /* length */); -extern void ShowWrapMarks (XtermWidget /* xw */, int /* row */, LineData * /* ld */); +extern void ShowWrapMarks (XtermWidget /* xw */, int /* row */, CLineData * /* ld */); extern void setupLineData (TScreen * /* screen */, ScrnBuf /* base */, Char * /* data */, unsigned /* nrow */, unsigned /* ncol */); extern void xtermParseRect (XtermWidget /* xw */, int, int *, XTermRect *); @@ -1345,7 +1347,7 @@ extern Pixel getXtermForeground(XtermWidget /* xw */, unsigned /* flags */, int extern int ClearInLine (XtermWidget /* xw */, int /* row */, int /* col */, unsigned /* len */); extern int HandleExposure (XtermWidget /* xw */, XEvent * /* event */); extern int dimRound (double /* value */); -extern int drawXtermText (XtermWidget /* xw */, unsigned /* attr_flags */, unsigned /* draw_flags */, GC /* gc */, int /* x */, int /* y */, int /* chrset */, IChar * /* text */, Cardinal /* len */, int /* on_wide */); +extern int drawXtermText (XtermWidget /* xw */, unsigned /* attr_flags */, unsigned /* draw_flags */, GC /* gc */, int /* x */, int /* y */, int /* chrset */, const IChar * /* text */, Cardinal /* len */, int /* on_wide */); extern int extendedBoolean(const char * /* value */, const FlagList * /* table */, Cardinal /* limit */); extern void ChangeColors (XtermWidget /* xw */, ScrnColors * /* pNew */); extern void ClearRight (XtermWidget /* xw */, int /* n */); @@ -1499,7 +1501,7 @@ extern void Resolve_XMC (XtermWidget /* xw */); #endif #if OPT_WIDE_CHARS -unsigned visual_width(IChar * /* str */, Cardinal /* len */); +unsigned visual_width(const IChar * /* str */, Cardinal /* len */); #else #define visual_width(a, b) (b) #endif diff --git a/app/xterm/xterm.log.html b/app/xterm/xterm.log.html index 6b8368282..ffdbba782 100644 --- a/app/xterm/xterm.log.html +++ b/app/xterm/xterm.log.html @@ -30,7 +30,7 @@ * sale, use or other dealings in this Software without prior written * * authorization. * ***************************************************************************** - $XTermId: xterm.log.html,v 1.1526 2014/09/29 00:39:23 tom Exp $ + $XTermId: xterm.log.html,v 1.1538 2014/11/29 02:25:58 tom Exp $ --> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> @@ -72,6 +72,8 @@ CHANGELOG</a>).</p> <ul> + <li><a href="#xterm_313">Patch #313 - 2014/11/28</a></li> + <li><a href="#xterm_312">Patch #312 - 2014/09/28</a></li> <li><a href="#xterm_311">Patch #311 - 2014/09/18</a></li> @@ -909,6 +911,100 @@ <li><a href="#xterm_01">Patch #1 - 1996/1/6</a></li> </ul> + <h1><a name="xterm_313" id="xterm_313">Patch #313 - + 2014/11/28</a></h1> + + <ul> + <li>add <code>regisScreenSize</code> resource setting to allow + custom screensizes for ReGIS graphics (prompted by discussion + with Scott Froebe).</li> + + <li>fix some minor issues in manpage (Jens Schweikhardt).</li> + + <li>improve ReGIS font-handling (Ross Combs): + + <ul> + <li>remove "random junk" generation for unknown + characters</li> + + <li>add xterm extension to load user glyphs for alphabet + 0</li> + + <li>add xterm extension to specify loading an alphabet from + a font by name</li> + + <li>fix bug with use of empty alphabet slots which caused + slot 0 to be clobbered</li> + + <li>update/clarify ReGIS-related comments</li> + + <li>add DECprint extension for printing/clearing the screen + (only clearing is performed)</li> + </ul> + </li> + + <li>improve ReGIS colorspec conversion (Ross Combs): + + <ul> + <li>avoid some floating point math for colorspace + conversion</li> + + <li>move two copies of colorspec parsing to a single + function</li> + + <li>change colorspec parsing to handle components being out + of order or with spaces and commas between them</li> + + <li>add support for an extension where RGB components can + be given instead of HLS</li> + </ul> + </li> + + <li>improve use of const, e.g., for the <code>LineData</code> + pointers (patch by Ross Combs).</li> + + <li>clip of graphics that overlap the scrollback buffer and alt + screen (patch by Ross Combs).</li> + + <li>amend change to focus-change events in <a href= + "xterm_287">patch #287</a> to limit it to suppressing the reset + of the urgency-hint, because some useful <code>FocusOut</code> + events were lost (report by Joe Peterson).</li> + + <li>modify dpkg build-script to configure xterm-dev as an + <code>x-terminal-emulator</code> alternative.</li> + + <li>extend the <code>--with-xterm-symlink</code> feature to + make symbolic links for the other programs and scripts.</li> + + <li>minor fix to <code>vttests/resize.pl</code> to avoid + undefined variable when receiving broken/missing response, + e.g., from mrxvt.</li> + + <li>change the way that ReGIS graphics are refreshed (patch by + Ross Combs): + + <ul> + <li>it pre-composes any overlapping graphics to avoid + unnecessary and flickering draws</li> + + <li>it adds a three-dimensional lookup table for RGB -> + pixel values and uses this across all graphics</li> + + <li>it draws in line segments when there is a run of the + same color</li> + + <li>in cases where there are no transparent parts, it uses + an XImage to draw</li> + + <li>it hooks into the double-buffering support if it is + enabled (though this doesn't seem to get rid of all + flicker).</li> + </ul>This has the effect of reducing flicker and speeding up + redraws. + </li> + </ul> + <h1><a name="xterm_312" id="xterm_312">Patch #312 - 2014/09/28</a></h1> @@ -987,7 +1083,7 @@ <li>modify test-package scripts to enable ReGIS graphics.</li> <li>improvements/additions to ReGIS graphics, e.g., drawing - text (Ross Comb).</li> + text (Ross Combs).</li> <li>add <code>--with-Xaw3dxft</code>, to link with Xaw 3d xft library (Stephen P Wall).</li> diff --git a/app/xterm/xterm.man b/app/xterm/xterm.man index 4230ae13e..52dda7fb4 100644 --- a/app/xterm/xterm.man +++ b/app/xterm/xterm.man @@ -1,5 +1,5 @@ '\" t -.\" $XTermId: xterm.man,v 1.582 2014/09/18 08:35:37 tom Exp $ +.\" $XTermId: xterm.man,v 1.586 2014/11/28 22:33:56 tom Exp $ .\" .\" Copyright 1996-2013,2014 by Thomas E. Dickey .\" @@ -97,7 +97,7 @@ It also provides Tektronix 4014 emulation for programs that cannot use the window system directly. If the underlying operating system supports terminal resizing capabilities (for example, the SIGWINCH signal in systems -derived from 4.3bsd), \fI\*n\fP will use the facilities to notify programs +derived from 4.3BSD), \fI\*n\fP will use the facilities to notify programs running in the window whenever it is resized. . .PP @@ -1269,7 +1269,7 @@ with \fI\*n\fP: .B \-bd \fIcolor\fP This option specifies the color to use for the border of the window. The corresponding resource name is \fIborderColor\fP. -\fI\*n\fP uses the X Toolkit default, which is \*(``XtDefaultForeground\*(''. +\fI\*N\fP uses the X Toolkit default, which is \*(``XtDefaultForeground\*(''. .TP 8 .B \-bg \fIcolor\fP This option specifies the color to use for the background of the window. @@ -1398,8 +1398,8 @@ Specifies the preferred size and position of the application when iconified. It is not necessarily obeyed by all window managers. .TP 8 .B "iconHint (\fPclass\fB IconHint)" -Specifies a icon which will be added to the window manager hints. -\fI\*n\fP provides no default value. +Specifies an icon which will be added to the window manager hints. +\fI\*N\fP provides no default value. .IP Set this resource to \*(``none\*('' to omit the hint entirely, using whatever the window manager may decide. @@ -1450,7 +1450,7 @@ The more capable desktop systems allow changing the icon on a per-user basis. .TP 8 .B "iconName (\fPclass\fB IconName)" Specifies a label for \fI\*n\fP when iconified. -\fI\*n\fP provides no default value; +\fI\*N\fP provides no default value; some window managers may assume the application name, e.g., \*(``\*n\*(''. .IP Setting the \fBiconName\fP resource sets the icon label @@ -1622,9 +1622,8 @@ Specifies whether or not Sun/PC keyboard layout should be assumed rather than DEC VT220. This causes the keypad \*(``+' to be mapped to \*(``,'. and -CTRL F1-F12 to F11-F20, depending on the setting of the \fBctrlFKeys\fP -resource. -so \fI\*n\fP emulates a DEC VT220 more accurately. +CTRL F1-F10 to F11-F20, depending on the setting of the \fBctrlFKeys\fP +resource, so \fI\*n\fP emulates a DEC VT220 more accurately. Otherwise (the default, with \fBsunKeyboard\fP set to \*(``false\*(''), \fI\*n\fP uses PC-style bindings for the function keys and keypad. .IP @@ -1726,7 +1725,8 @@ This is part of the logic. When \fI\*n\fP is directed to wait in this fashion, it passes the terminal size from the display end of the pseudo-terminal -to the terminal I/O connection, e.g., according to the window manager. +to the terminal I/O connection, e.g., +using the size according to the window manager. Otherwise, it uses the size as given in resource values or command-line option \fB\-geom\fP. The default is \*(``false\*(''. @@ -1785,7 +1785,7 @@ The active icon is shown. If you are using \fItwm\fP, use this setting to enable active-icons. .TP default (2) -\fI\*n\fP checks at startup, and shows an active icon only for window +\fI\*N\fP checks at startup, and shows an active icon only for window managers which it can identify and which are known to support the feature. These are \fIfvwm\fP (full support), and \fIwindow maker\fP (limited). A few other windows managers (such as \fItwm\fP and \fIctwm\fP) @@ -1865,12 +1865,12 @@ description of the terminal's capabilities, independent of the termcap/terminfo setting: .RS .bP -\fI\*n\fP can tell the querying program how many colors it supports. +\fI\*N\fP can tell the querying program how many colors it supports. This is a constant, depending on how it is compiled, typically 16. It does not change if you alter resource settings, e.g., the \fBboldColors\fP resource. .bP -\fI\*n\fP can tell the querying program what strings are sent by modified +\fI\*N\fP can tell the querying program what strings are sent by modified (shift-, control-, alt-) function- and keypad-keys. Reporting control- and alt-modifiers is a feature that relies on the \fIncurses\fP extended naming. @@ -2019,7 +2019,7 @@ The default is \*(``true\*(''. .TP 8 .B "awaitInput (\fPclass\fB AwaitInput)" -Specifies whether or not the \fI\*n\fR uses a 50 millisecond timeout to +Specifies whether or not \fI\*n\fR uses a 50 millisecond timeout to await input (i.e., to support the Xaw3d arrow scrollbar). The default is \*(``false\*(''. .TP 8 @@ -2096,7 +2096,8 @@ Since X11R6, bitmap fonts have been scaled. The font server claims to provide the bold font that \fI\*n\fP requests, but the result is not always readable. XFree86 introduced a feature which can be used to suppress the scaling. -In the X server's configuration file (e.g., \*(``/etc/X11/XFree86\*(''), you +In the X server's configuration file (e.g., \*(``/etc/X11/XFree86\*('' +or \*(``/etc/X11/xorg.conf\*(''), you can add \*(``:unscaled\*('' to the end of the directory specification for the \*(``misc\*('' fonts, which comprise the fixed-pitch fonts that are used by \fI\*n\fP. @@ -2481,7 +2482,7 @@ SetColor,GetColor,GetAnsiColor .RE .IP The names are listed below. -\fI\*n\fP ignores capitalization, but +\fI\*N\fP ignores capitalization, but they are shown in mixed-case for clarity. .RS .TP 5 @@ -2505,7 +2506,7 @@ SetFont,GetFont .RE .IP The names are listed below. -\fI\*n\fP ignores capitalization, but +\fI\*N\fP ignores capitalization, but they are shown in mixed-case for clarity. .RS .TP 5 @@ -2525,7 +2526,7 @@ SetTcap,GetTcap .RE .IP The names are listed below. -\fI\*n\fP ignores capitalization, but +\fI\*N\fP ignores capitalization, but they are shown in mixed-case for clarity. .RS .TP 5 @@ -2546,7 +2547,7 @@ The default value is .RE .IP The names are listed below. -\fI\*n\fP ignores capitalization, but +\fI\*N\fP ignores capitalization, but they are shown in mixed-case for clarity. Where a number can be used as an alternative, it is given in parentheses after the name. @@ -2651,11 +2652,11 @@ For more background on this, see the \fBmeta\fP function in curses. .IP Note that the \fIAlt\fP key is not necessarily the same as the \fIMeta\fP modifier. -\fIxmodmap\fP lists your key modifiers. +The \fIxmodmap\fP utility lists your key modifiers. X defines modifiers for shift, (caps) lock and control, as well as 5 additional modifiers which are generally used to configure key modifiers. -\fI\*n\fP inspects the same information to find the modifier associated +\fI\*N\fP inspects the same information to find the modifier associated with either \fIMeta\fP key (left or right), and uses that key as the \fIMeta\fP modifier. It also looks for the NumLock key, @@ -3142,7 +3143,7 @@ The resource value (ignoring case) may be: .RS .TP 4 .I true -\fI\*n\fR will use the +\fI\*N\fR will use the encoding specified by the users' LC_CTYPE locale (i.e., LC_ALL, LC_CTYPE, or LANG variables) as far as possible. This is realized @@ -3150,7 +3151,7 @@ by always enabling UTF-8 mode and invoking \fIluit\fR in non-UTF-8 locales. .TP .I medium -\fI\*n\fR will follow users' +\fI\*N\fR will follow users' LC_CTYPE locale only for UTF-8, east Asian, and Thai locales, where the encodings were not supported by conventional 8bit mode with changing fonts. @@ -3165,7 +3166,7 @@ mapping to support those with the Unicode font. For other encodings, \fI\*n\fR assumes that UTF-8 encoding is required. .TP .I false -\fI\*n\fR will use conventional 8bit mode +\fI\*N\fR will use conventional 8bit mode or UTF-8 mode according to \fButf8\fR resource or \fB\-u8\fP option. .RE .IP @@ -3454,7 +3455,7 @@ follows in the resource value. .TP none No selection action is associated with this resource. -\fI\*n\fP interprets it as the end of the list. +\fI\*N\fP interprets it as the end of the list. For example, you may use it to disable triple (and higher) clicking by setting \fBon3Clicks\fP to \*(``none\*(''. .RE @@ -3670,6 +3671,18 @@ when \fINotifyGrab\fP and \fINotifyUngrab\fP event types are received during change of focus. The default is \*(``false\*(''. .TP 8 +.B "regisScreenSize (\fPclass\fB RegisScreenSize)" +If \fI\*n\fR is configured to support ReGIS graphics, +this resource tells \fI\*n\fR the maximum size (in pixels) for graphics. +.IP +\fI\*N\fR accepts a special resource value \*(``auto\*('', +which tells \fI\*n\fR to use the \fBdecTerminalID\fP resource to +set the maximum size based on the hardware terminal's limits. +Otherwise, \fI\*n\fR expects the size to be given as \fIheight\fPx\fIwidth\fP, +e.g., \*(``800x1000\*(''. +.IP +The default resource value is \*(``800x1000\*(''. +.TP 8 .B "renderFont (\fPclass\fB RenderFont)" If \fI\*n\fR is built with the Xft library, this controls whether the \fBfaceName\fR resource is used. @@ -6772,7 +6785,7 @@ Large pastes do not work on some systems. This is not a bug in \fI\*n\fP; it is a bug in the pseudo terminal driver of those systems. -\fI\*n\fP feeds large pastes to the pty only as fast as the pty +\fI\*N\fP feeds large pastes to the pty only as fast as the pty will accept data, but some pty drivers do not return enough information to know if the write has succeeded. . |