graphics.c revision 894e0ac8
1894e0ac8Smrg/* $XTermId: graphics.c,v 1.43 2014/05/28 22:27:07 tom Exp $ */ 2e0a2b6dfSmrg 3e0a2b6dfSmrg/* 4894e0ac8Smrg * Copyright 2013,2014 by Ross Combs 5e0a2b6dfSmrg * 6e0a2b6dfSmrg * All Rights Reserved 7e0a2b6dfSmrg * 8e0a2b6dfSmrg * Permission is hereby granted, free of charge, to any person obtaining a 9e0a2b6dfSmrg * copy of this software and associated documentation files (the 10e0a2b6dfSmrg * "Software"), to deal in the Software without restriction, including 11e0a2b6dfSmrg * without limitation the rights to use, copy, modify, merge, publish, 12e0a2b6dfSmrg * distribute, sublicense, and/or sell copies of the Software, and to 13e0a2b6dfSmrg * permit persons to whom the Software is furnished to do so, subject to 14e0a2b6dfSmrg * the following conditions: 15e0a2b6dfSmrg * 16e0a2b6dfSmrg * The above copyright notice and this permission notice shall be included 17e0a2b6dfSmrg * in all copies or substantial portions of the Software. 18e0a2b6dfSmrg * 19e0a2b6dfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20e0a2b6dfSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21e0a2b6dfSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22e0a2b6dfSmrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23e0a2b6dfSmrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24e0a2b6dfSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25e0a2b6dfSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26e0a2b6dfSmrg * 27e0a2b6dfSmrg * Except as contained in this notice, the name(s) of the above copyright 28e0a2b6dfSmrg * holders shall not be used in advertising or otherwise to promote the 29e0a2b6dfSmrg * sale, use or other dealings in this Software without prior written 30e0a2b6dfSmrg * authorization. 31e0a2b6dfSmrg */ 32e0a2b6dfSmrg 33e0a2b6dfSmrg#include <xterm.h> 34e0a2b6dfSmrg 35e0a2b6dfSmrg#include <stdio.h> 36e0a2b6dfSmrg#include <ctype.h> 37e0a2b6dfSmrg#include <stdlib.h> 38e0a2b6dfSmrg 39e0a2b6dfSmrg#include <data.h> 40e0a2b6dfSmrg#include <ptyx.h> 41e0a2b6dfSmrg 42e0a2b6dfSmrg#include <assert.h> 43e0a2b6dfSmrg#include <graphics.h> 44e0a2b6dfSmrg 45894e0ac8Smrg#undef DUMP_BITMAP 46894e0ac8Smrg#undef DUMP_COLORS 47894e0ac8Smrg#undef DEBUG_PALETTE 48894e0ac8Smrg#undef DEBUG_PIXEL 49e0a2b6dfSmrg#undef DEBUG_REFRESH 50e0a2b6dfSmrg 51e0a2b6dfSmrg/* TODO: 52e0a2b6dfSmrg * ReGIS: 53894e0ac8Smrg * - shading with text 54894e0ac8Smrg * - polygon filling 55894e0ac8Smrg * - plane write control 56894e0ac8Smrg * - fix interpolated curves to more closely match implementation (identical despite direction and starting point) 57894e0ac8Smrg * - text 58894e0ac8Smrg * - input and output cursors 59894e0ac8Smrg * - mouse input 60894e0ac8Smrg * - stacks 61894e0ac8Smrg * - investigate second graphic page for ReGIS -- does it also apply to text and sixel graphics? are the contents preserved? 62894e0ac8Smrg * - font upload, italics, and other text attributes 63894e0ac8Smrg * - enter/leave during a command 64894e0ac8Smrg * - command display mode 65894e0ac8Smrg * - scrolling 66894e0ac8Smrg * - custom coordinate systems 67894e0ac8Smrg * - scaling/re-rasterization to fit screen 68894e0ac8Smrg * - macros 69e0a2b6dfSmrg * sixel: 70894e0ac8Smrg * - fix problem where new_row < 0 during sixel parsing (see FIXME) 71894e0ac8Smrg * VT55/VT105 waveform graphics 72894e0ac8Smrg * - everything 73894e0ac8Smrg * common: 74894e0ac8Smrg * - handle light/dark screen modes (CSI?5[hl]) 75894e0ac8Smrg * - update text fg/bg color which overlaps images 76e0a2b6dfSmrg * - erase graphic when erasing screen 77894e0ac8Smrg * - handle graphic updates in scroll regions 78894e0ac8Smrg * - handle rectangular area copies (verify they work with graphics) 79e0a2b6dfSmrg * - maintain ordered list/array instead of qsort() 80894e0ac8Smrg * - erase text under graphic if bg not transparent to avoid flickering (or not: bad if the font changes or window resizes) 81894e0ac8Smrg * - erase graphics under graphic if same origin and bg not transparent to avoid flickering 82e0a2b6dfSmrg * - erase scrolled portions of all graphics on alt buffer 83e0a2b6dfSmrg * - delete graphic if scrolled past end of scrollback 84e0a2b6dfSmrg * - delete graphic if all pixels are transparent/erased 85894e0ac8Smrg * - dynamic memory allocation of graphics buffers, add configurable limits 86e0a2b6dfSmrg * - auto convert color graphics in VT330 mode 87894e0ac8Smrg * - posturize requested colors to match hardware palettes (e.g. four possible shades on VT240) 88894e0ac8Smrg * - color register report/restore 89894e0ac8Smrg * escape sequences: 90e0a2b6dfSmrg * - way to query font size without "window ops" (or make "window ops" permissions more fine grained) 91e0a2b6dfSmrg * - way to query and/or set the maximum number of color registers 92894e0ac8Smrg * - way to query and set the number of graphics pages 93894e0ac8Smrg * ReGIS extensions: 94894e0ac8Smrg * - gradients 95894e0ac8Smrg * - line width (RLogin has this and it is mentioned in docs for the DEC ReGIS to Postscript converter) 96894e0ac8Smrg * - F option for screen command (mentioned in docs for the DEC ReGIS to Postscript converter) 97894e0ac8Smrg * - transparency 98894e0ac8Smrg * - background color as stackable write control 99894e0ac8Smrg * - RGB triplets 100894e0ac8Smrg * - true color (virtual color registers created upon lookup) 101894e0ac8Smrg * - anti-aliasing 102e0a2b6dfSmrg */ 103e0a2b6dfSmrg 104e0a2b6dfSmrg/* font sizes: 105e0a2b6dfSmrg * VT510: 106e0a2b6dfSmrg * 80 Columns 132 Columns Maximum Number of Lines 107e0a2b6dfSmrg * 10 x 16 6 x 16 26 lines + keyboard indicator line 108894e0ac8Smrg * 10 x 13 6 x 13 26 lines + keyboard indicator line 109e0a2b6dfSmrg * 10 x 10 6 x 10 42 lines + keyboard indicator line 110e0a2b6dfSmrg * 10 x 8 6 x 8 53 lines + keyboard indicator line 111e0a2b6dfSmrg*/ 112e0a2b6dfSmrg 113894e0ac8Smrg#define FOR_EACH_SLOT(ii) for (ii = 0U; ii < MAX_GRAPHICS; ii++) 114894e0ac8Smrg 115894e0ac8Smrgstatic ColorRegister *shared_color_registers; 116894e0ac8Smrgstatic Graphic *displayed_graphics[MAX_GRAPHICS]; 117894e0ac8Smrgstatic unsigned next_graphic_id = 0U; 118894e0ac8Smrg 119894e0ac8Smrgstatic ColorRegister * 120894e0ac8SmrgallocRegisters(void) 121e0a2b6dfSmrg{ 122894e0ac8Smrg return TypeCallocN(ColorRegister, MAX_COLOR_REGISTERS); 123894e0ac8Smrg} 124894e0ac8Smrg 125894e0ac8Smrgstatic Graphic * 126894e0ac8SmrgfreeGraphic(Graphic *obj) 127894e0ac8Smrg{ 128894e0ac8Smrg if (obj) { 129894e0ac8Smrg if (obj->pixels) 130894e0ac8Smrg free(obj->pixels); 131894e0ac8Smrg if (obj->private_color_registers) 132894e0ac8Smrg free(obj->private_color_registers); 133894e0ac8Smrg free(obj); 134894e0ac8Smrg } 135894e0ac8Smrg return NULL; 136894e0ac8Smrg} 137894e0ac8Smrg 138894e0ac8Smrgstatic Graphic * 139894e0ac8SmrgallocGraphic(void) 140894e0ac8Smrg{ 141894e0ac8Smrg Graphic *result = TypeCalloc(Graphic); 142894e0ac8Smrg if (result) { 143894e0ac8Smrg if (!(result->pixels = TypeCallocN(RegisterNum, MAX_PIXELS))) { 144894e0ac8Smrg result = freeGraphic(result); 145894e0ac8Smrg } else if (!(result->private_color_registers = allocRegisters())) { 146894e0ac8Smrg result = freeGraphic(result); 147e0a2b6dfSmrg } 148e0a2b6dfSmrg } 149894e0ac8Smrg return result; 150894e0ac8Smrg} 151e0a2b6dfSmrg 152894e0ac8Smrgstatic Graphic * 153894e0ac8SmrggetActiveSlot(unsigned n) 154894e0ac8Smrg{ 155894e0ac8Smrg if (n < MAX_GRAPHICS && 156894e0ac8Smrg displayed_graphics[n] && 157894e0ac8Smrg displayed_graphics[n]->valid) { 158894e0ac8Smrg return displayed_graphics[n]; 159894e0ac8Smrg } 160894e0ac8Smrg return NULL; 161e0a2b6dfSmrg} 162e0a2b6dfSmrg 163894e0ac8Smrgstatic Graphic * 164894e0ac8SmrggetInactiveSlot(unsigned n) 165894e0ac8Smrg{ 166894e0ac8Smrg if (n < MAX_GRAPHICS && 167894e0ac8Smrg (!displayed_graphics[n] || 168894e0ac8Smrg !displayed_graphics[n]->valid)) { 169894e0ac8Smrg if (!displayed_graphics[n]) { 170894e0ac8Smrg displayed_graphics[n] = allocGraphic(); 171894e0ac8Smrg } 172894e0ac8Smrg return displayed_graphics[n]; 173894e0ac8Smrg } 174894e0ac8Smrg return NULL; 175894e0ac8Smrg} 176894e0ac8Smrg 177894e0ac8Smrgstatic ColorRegister * 178894e0ac8SmrggetSharedRegisters(void) 179894e0ac8Smrg{ 180894e0ac8Smrg if (!shared_color_registers) 181894e0ac8Smrg shared_color_registers = allocRegisters(); 182894e0ac8Smrg return shared_color_registers; 183894e0ac8Smrg} 184e0a2b6dfSmrg 185e0a2b6dfSmrgstatic void 186894e0ac8SmrgdeactivateSlot(unsigned n) 187e0a2b6dfSmrg{ 188894e0ac8Smrg if (n < MAX_GRAPHICS) { 189894e0ac8Smrg displayed_graphics[n] = freeGraphic(displayed_graphics[n]); 190894e0ac8Smrg } 191894e0ac8Smrg} 192e0a2b6dfSmrg 193894e0ac8Smrgextern RegisterNum 194894e0ac8Smrgread_pixel(Graphic *graphic, int x, int y) 195894e0ac8Smrg{ 196894e0ac8Smrg if (x < 0 && x >= graphic->actual_width && 197894e0ac8Smrg y < 0 && y >= graphic->actual_height) { 198894e0ac8Smrg return COLOR_HOLE; 199e0a2b6dfSmrg } 200894e0ac8Smrg 201894e0ac8Smrg return graphic->pixels[y * graphic->max_width + x]; 202e0a2b6dfSmrg} 203e0a2b6dfSmrg 204894e0ac8Smrgvoid 205894e0ac8Smrgdraw_solid_pixel(Graphic *graphic, int x, int y, unsigned color) 206e0a2b6dfSmrg{ 207894e0ac8Smrg assert(color <= MAX_COLOR_REGISTERS); 208e0a2b6dfSmrg 209894e0ac8Smrg#ifdef DEBUG_PIXEL 210894e0ac8Smrg TRACE(("drawing pixel at %d,%d color=%hu (hole=%hu, [%d,%d,%d])\n", 211894e0ac8Smrg x, 212894e0ac8Smrg y, 213e0a2b6dfSmrg color, 214894e0ac8Smrg COLOR_HOLE, 215e0a2b6dfSmrg ((color != COLOR_HOLE) 216894e0ac8Smrg ? (unsigned) graphic->color_registers[color].r : 0U), 217e0a2b6dfSmrg ((color != COLOR_HOLE) 218894e0ac8Smrg ? (unsigned) graphic->color_registers[color].g : 0U), 219e0a2b6dfSmrg ((color != COLOR_HOLE) 220894e0ac8Smrg ? (unsigned) graphic->color_registers[color].b : 0U))); 221894e0ac8Smrg#endif 222894e0ac8Smrg if (x >= 0 && x < graphic->actual_width && 223894e0ac8Smrg y >= 0 && y < graphic->actual_height) { 224894e0ac8Smrg graphic->pixels[y * graphic->max_width + x] = (RegisterNum) color; 225894e0ac8Smrg if (color < MAX_COLOR_REGISTERS) 226894e0ac8Smrg graphic->color_registers_used[color] = 1; 227894e0ac8Smrg } else { 228894e0ac8Smrg TRACE(("pixel %d,%d out of bounds\n", x, y)); 229894e0ac8Smrg } 230894e0ac8Smrg} 231894e0ac8Smrg 232894e0ac8Smrgvoid 233894e0ac8Smrgdraw_solid_rectangle(Graphic *graphic, int x1, int y1, int x2, int y2, unsigned color) 234894e0ac8Smrg{ 235894e0ac8Smrg int x, y; 236894e0ac8Smrg int tmp; 237894e0ac8Smrg 238894e0ac8Smrg assert(color <= MAX_COLOR_REGISTERS); 239894e0ac8Smrg 240894e0ac8Smrg if (x1 > x2) { 241894e0ac8Smrg EXCHANGE(x1, x2, tmp); 242894e0ac8Smrg } 243894e0ac8Smrg if (y1 > y2) { 244894e0ac8Smrg EXCHANGE(y1, y2, tmp); 245894e0ac8Smrg } 246894e0ac8Smrg 247894e0ac8Smrg for (y = y1; y <= y2; y++) 248894e0ac8Smrg for (x = x1; x < x2; x++) 249894e0ac8Smrg draw_solid_pixel(graphic, x, y, color); 250894e0ac8Smrg} 251894e0ac8Smrg 252894e0ac8Smrgvoid 253894e0ac8Smrgdraw_solid_line(Graphic *graphic, int x1, int y1, int x2, int y2, unsigned color) 254894e0ac8Smrg{ 255894e0ac8Smrg int x, y; 256894e0ac8Smrg int dx, dy; 257894e0ac8Smrg int dir, diff; 258894e0ac8Smrg 259894e0ac8Smrg assert(color <= MAX_COLOR_REGISTERS); 260894e0ac8Smrg 261894e0ac8Smrg dx = abs(x1 - x2); 262894e0ac8Smrg dy = abs(y1 - y2); 263894e0ac8Smrg 264894e0ac8Smrg if (dx > dy) { 265894e0ac8Smrg if (x1 > x2) { 266894e0ac8Smrg int tmp; 267894e0ac8Smrg EXCHANGE(x1, x2, tmp); 268894e0ac8Smrg EXCHANGE(y1, y2, tmp); 269894e0ac8Smrg } 270894e0ac8Smrg if (y1 < y2) 271894e0ac8Smrg dir = 1; 272894e0ac8Smrg else if (y1 > y2) 273894e0ac8Smrg dir = -1; 274894e0ac8Smrg else 275894e0ac8Smrg dir = 0; 276894e0ac8Smrg 277894e0ac8Smrg diff = 0; 278894e0ac8Smrg y = y1; 279894e0ac8Smrg for (x = x1; x <= x2; x++) { 280894e0ac8Smrg if (diff >= dx) { 281894e0ac8Smrg diff -= dx; 282894e0ac8Smrg y += dir; 283e0a2b6dfSmrg } 284894e0ac8Smrg diff += dy; 285894e0ac8Smrg draw_solid_pixel(graphic, x, y, color); 286894e0ac8Smrg } 287894e0ac8Smrg } else { 288894e0ac8Smrg if (y1 > y2) { 289894e0ac8Smrg int tmp; 290894e0ac8Smrg EXCHANGE(x1, x2, tmp); 291894e0ac8Smrg EXCHANGE(y1, y2, tmp); 292894e0ac8Smrg } 293894e0ac8Smrg if (x1 < x2) 294894e0ac8Smrg dir = 1; 295894e0ac8Smrg else if (x1 > x2) 296894e0ac8Smrg dir = -1; 297894e0ac8Smrg else 298894e0ac8Smrg dir = 0; 299894e0ac8Smrg 300894e0ac8Smrg diff = 0; 301894e0ac8Smrg x = x1; 302894e0ac8Smrg for (y = y1; y <= y2; y++) { 303894e0ac8Smrg if (diff >= dy) { 304894e0ac8Smrg diff -= dy; 305894e0ac8Smrg x += dir; 306894e0ac8Smrg } 307894e0ac8Smrg diff += dx; 308894e0ac8Smrg draw_solid_pixel(graphic, x, y, color); 309e0a2b6dfSmrg } 310e0a2b6dfSmrg } 311e0a2b6dfSmrg} 312e0a2b6dfSmrg 313e0a2b6dfSmrgstatic void 314894e0ac8Smrgset_color_register(ColorRegister *color_registers, 315894e0ac8Smrg unsigned color, 316894e0ac8Smrg int r, 317894e0ac8Smrg int g, 318894e0ac8Smrg int b) 319e0a2b6dfSmrg{ 320e0a2b6dfSmrg ColorRegister *reg = &color_registers[color]; 321e0a2b6dfSmrg reg->r = (short) r; 322e0a2b6dfSmrg reg->g = (short) g; 323e0a2b6dfSmrg reg->b = (short) b; 324e0a2b6dfSmrg reg->allocated = 0; 325e0a2b6dfSmrg} 326e0a2b6dfSmrg 327894e0ac8Smrg/* Graphics which don't use private colors will act as if they are using a 328894e0ac8Smrg * device-wide color palette. 329894e0ac8Smrg */ 330894e0ac8Smrgstatic void 331894e0ac8Smrgset_shared_color_register(unsigned color, int r, int g, int b) 332894e0ac8Smrg{ 333894e0ac8Smrg Graphic *graphic; 334894e0ac8Smrg unsigned ii; 335894e0ac8Smrg 336894e0ac8Smrg assert(color < MAX_COLOR_REGISTERS); 337894e0ac8Smrg 338894e0ac8Smrg set_color_register(getSharedRegisters(), color, r, g, b); 339894e0ac8Smrg 340894e0ac8Smrg FOR_EACH_SLOT(ii) { 341894e0ac8Smrg if (!(graphic = getActiveSlot(ii))) 342894e0ac8Smrg continue; 343894e0ac8Smrg if (graphic->private_colors) 344894e0ac8Smrg continue; 345894e0ac8Smrg 346894e0ac8Smrg if (graphic->color_registers_used[ii]) { 347894e0ac8Smrg graphic->dirty = 1; 348894e0ac8Smrg } 349894e0ac8Smrg } 350894e0ac8Smrg} 351894e0ac8Smrg 352894e0ac8Smrgvoid 353894e0ac8Smrgupdate_color_register(Graphic *graphic, 354894e0ac8Smrg unsigned color, 355894e0ac8Smrg int r, 356894e0ac8Smrg int g, 357894e0ac8Smrg int b) 358894e0ac8Smrg{ 359894e0ac8Smrg assert(color < MAX_COLOR_REGISTERS); 360894e0ac8Smrg 361894e0ac8Smrg if (graphic->private_colors) { 362894e0ac8Smrg set_color_register(graphic->private_color_registers, 363894e0ac8Smrg color, r, g, b); 364894e0ac8Smrg if (graphic->color_registers_used[color]) { 365894e0ac8Smrg graphic->dirty = 1; 366894e0ac8Smrg } 367894e0ac8Smrg graphic->color_registers_used[color] = 1; 368894e0ac8Smrg } else { 369894e0ac8Smrg set_shared_color_register(color, r, g, b); 370894e0ac8Smrg } 371894e0ac8Smrg} 372894e0ac8Smrg 373894e0ac8Smrg#define SQUARE(X) ( (X) * (X) ) 374894e0ac8Smrg 375894e0ac8SmrgRegisterNum 376894e0ac8Smrgfind_color_register(ColorRegister const *color_registers, int r, int g, int b) 377894e0ac8Smrg{ 378894e0ac8Smrg unsigned i; 379894e0ac8Smrg unsigned d; 380894e0ac8Smrg unsigned closest_index; 381894e0ac8Smrg unsigned closest_distance; 382894e0ac8Smrg 383894e0ac8Smrg /* I have no idea what algorithm DEC used for this. 384894e0ac8Smrg * The documentation warns that it is unpredictable, especially with values 385894e0ac8Smrg * far away from any allocated color so it is probably a very simple 386894e0ac8Smrg * hueristic rather than something fancy like finding the minimum distance 387894e0ac8Smrg * in a linear perceptive color space. 388894e0ac8Smrg */ 389894e0ac8Smrg closest_index = MAX_COLOR_REGISTERS; 390894e0ac8Smrg closest_distance = 0U; 391894e0ac8Smrg for (i = 0U; i < MAX_COLOR_REGISTERS; i++) { 392894e0ac8Smrg d = (unsigned) (SQUARE(2 * (color_registers[i].r - r)) + 393894e0ac8Smrg SQUARE(3 * (color_registers[i].g - g)) + 394894e0ac8Smrg SQUARE(1 * (color_registers[i].b - b))); 395894e0ac8Smrg if (closest_index == MAX_COLOR_REGISTERS || d < closest_distance) { 396894e0ac8Smrg closest_index = i; 397894e0ac8Smrg closest_distance = d; 398894e0ac8Smrg } 399894e0ac8Smrg } 400894e0ac8Smrg 401894e0ac8Smrg TRACE(("found closest color register to %d,%d,%d: %u (distance %u value %d,%d,%d)\n", 402894e0ac8Smrg r, g, b, 403894e0ac8Smrg closest_index, 404894e0ac8Smrg closest_distance, 405894e0ac8Smrg color_registers[closest_index].r, 406894e0ac8Smrg color_registers[closest_index].g, 407894e0ac8Smrg color_registers[closest_index].b)); 408894e0ac8Smrg return (RegisterNum) closest_index; 409894e0ac8Smrg} 410894e0ac8Smrg 411e0a2b6dfSmrgstatic void 412e0a2b6dfSmrginit_color_registers(ColorRegister *color_registers, int terminal_id) 413e0a2b6dfSmrg{ 414894e0ac8Smrg TRACE(("setting initial colors for terminal %d\n", terminal_id)); 415e0a2b6dfSmrg { 416894e0ac8Smrg unsigned i; 417e0a2b6dfSmrg 418e0a2b6dfSmrg for (i = 0U; i < MAX_COLOR_REGISTERS; i++) { 419894e0ac8Smrg set_color_register(color_registers, (RegisterNum) i, 0, 0, 0); 420e0a2b6dfSmrg } 421e0a2b6dfSmrg } 422e0a2b6dfSmrg 423e0a2b6dfSmrg /* 424e0a2b6dfSmrg * default color registers: 425e0a2b6dfSmrg * (mono) (color) 426e0a2b6dfSmrg * VK100/GIGI (fixed) 427e0a2b6dfSmrg * VT125: 428e0a2b6dfSmrg * 0: 0% 0% 429e0a2b6dfSmrg * 1: 33% blue 430e0a2b6dfSmrg * 2: 66% red 431e0a2b6dfSmrg * 3: 100% green 432e0a2b6dfSmrg * VT240: 433e0a2b6dfSmrg * 0: 0% 0% 434e0a2b6dfSmrg * 1: 33% blue 435e0a2b6dfSmrg * 2: 66% red 436e0a2b6dfSmrg * 3: 100% green 437e0a2b6dfSmrg * VT241: 438e0a2b6dfSmrg * 0: 0% 0% 439e0a2b6dfSmrg * 1: 33% blue 440e0a2b6dfSmrg * 2: 66% red 441e0a2b6dfSmrg * 3: 100% green 442e0a2b6dfSmrg * VT330: 443e0a2b6dfSmrg * 0: 0% 0% (bg for light on dark mode) 444e0a2b6dfSmrg * 1: 33% blue (red?) 445e0a2b6dfSmrg * 2: 66% red (green?) 446e0a2b6dfSmrg * 3: 100% green (yellow?) (fg for light on dark mode) 447e0a2b6dfSmrg * VT340: 448e0a2b6dfSmrg * 0: 0% 0% (bg for light on dark mode) 449e0a2b6dfSmrg * 1: 14% blue 450e0a2b6dfSmrg * 2: 29% red 451e0a2b6dfSmrg * 3: 43% green 452e0a2b6dfSmrg * 4: 57% magenta 453e0a2b6dfSmrg * 5: 71% cyan 454e0a2b6dfSmrg * 6: 86% yellow 455e0a2b6dfSmrg * 7: 100% 50% (fg for light on dark mode) 456e0a2b6dfSmrg * 8: 0% 25% 457e0a2b6dfSmrg * 9: 14% gray-blue 458e0a2b6dfSmrg * 10: 29% gray-red 459e0a2b6dfSmrg * 11: 43% gray-green 460e0a2b6dfSmrg * 12: 57% gray-magenta 461e0a2b6dfSmrg * 13: 71% gray-cyan 462e0a2b6dfSmrg * 14: 86% gray-yellow 463894e0ac8Smrg * 15: 100% 75% ("white") 464894e0ac8Smrg * VT382: 465894e0ac8Smrg * ? (FIXME: B&W only?) 466e0a2b6dfSmrg * dxterm: 467e0a2b6dfSmrg * ? 468e0a2b6dfSmrg */ 469e0a2b6dfSmrg switch (terminal_id) { 470e0a2b6dfSmrg case 125: 471e0a2b6dfSmrg case 241: 472894e0ac8Smrg set_color_register(color_registers, 0, 0, 0, 0); 473894e0ac8Smrg set_color_register(color_registers, 1, 0, 0, 100); 474894e0ac8Smrg set_color_register(color_registers, 2, 0, 100, 0); 475894e0ac8Smrg set_color_register(color_registers, 3, 100, 0, 0); 476e0a2b6dfSmrg break; 477e0a2b6dfSmrg case 240: 478e0a2b6dfSmrg case 330: 479894e0ac8Smrg set_color_register(color_registers, 0, 0, 0, 0); 480894e0ac8Smrg set_color_register(color_registers, 1, 33, 33, 33); 481894e0ac8Smrg set_color_register(color_registers, 2, 66, 66, 66); 482894e0ac8Smrg set_color_register(color_registers, 3, 100, 100, 100); 483e0a2b6dfSmrg break; 484e0a2b6dfSmrg case 340: 485e0a2b6dfSmrg default: 486894e0ac8Smrg set_color_register(color_registers, 0, 0, 0, 0); 487894e0ac8Smrg set_color_register(color_registers, 1, 20, 20, 80); 488894e0ac8Smrg set_color_register(color_registers, 2, 80, 13, 13); 489894e0ac8Smrg set_color_register(color_registers, 3, 20, 80, 20); 490894e0ac8Smrg set_color_register(color_registers, 4, 80, 20, 80); 491894e0ac8Smrg set_color_register(color_registers, 5, 20, 80, 80); 492894e0ac8Smrg set_color_register(color_registers, 6, 80, 80, 20); 493894e0ac8Smrg set_color_register(color_registers, 7, 53, 53, 53); 494894e0ac8Smrg set_color_register(color_registers, 8, 26, 26, 26); 495894e0ac8Smrg set_color_register(color_registers, 9, 33, 33, 60); 496894e0ac8Smrg set_color_register(color_registers, 10, 60, 26, 26); 497894e0ac8Smrg set_color_register(color_registers, 11, 33, 60, 33); 498894e0ac8Smrg set_color_register(color_registers, 12, 60, 33, 60); 499894e0ac8Smrg set_color_register(color_registers, 13, 33, 60, 60); 500894e0ac8Smrg set_color_register(color_registers, 14, 60, 60, 33); 501894e0ac8Smrg set_color_register(color_registers, 15, 80, 80, 80); 502894e0ac8Smrg break; 503894e0ac8Smrg case 382: /* FIXME: verify */ 504894e0ac8Smrg set_color_register(color_registers, 0, 0, 0, 0); 505894e0ac8Smrg set_color_register(color_registers, 1, 100, 100, 100); 506e0a2b6dfSmrg break; 507e0a2b6dfSmrg } 508e0a2b6dfSmrg 509894e0ac8Smrg#ifdef DEBUG_PALETTE 510894e0ac8Smrg { 511894e0ac8Smrg unsigned i; 512e0a2b6dfSmrg 513894e0ac8Smrg for (i = 0U; i < MAX_COLOR_REGISTERS; i++) { 514894e0ac8Smrg printf("initial value for register %03u: %d,%d,%d\n", 515894e0ac8Smrg i, 516894e0ac8Smrg color_registers[i].r, 517894e0ac8Smrg color_registers[i].g, 518894e0ac8Smrg color_registers[i].b); 519894e0ac8Smrg } 520894e0ac8Smrg } 521894e0ac8Smrg#endif 522894e0ac8Smrg} 523e0a2b6dfSmrg 524894e0ac8Smrgunsigned 525894e0ac8Smrgget_color_register_count(TScreen const *screen) 526894e0ac8Smrg{ 527894e0ac8Smrg unsigned num_color_registers; 528e0a2b6dfSmrg 529894e0ac8Smrg if (screen->numcolorregisters >= 0) { 530894e0ac8Smrg num_color_registers = (unsigned) screen->numcolorregisters; 531894e0ac8Smrg } else { 532894e0ac8Smrg num_color_registers = 0U; 533894e0ac8Smrg } 534e0a2b6dfSmrg 535894e0ac8Smrg if (num_color_registers > 1U) { 536894e0ac8Smrg if (num_color_registers > MAX_COLOR_REGISTERS) 537894e0ac8Smrg return MAX_COLOR_REGISTERS; 538894e0ac8Smrg return num_color_registers; 539894e0ac8Smrg } 540e0a2b6dfSmrg 541e0a2b6dfSmrg /* 542e0a2b6dfSmrg * color capabilities: 543e0a2b6dfSmrg * VK100/GIGI 1 plane (12x1 pixel attribute blocks) colorspace is 8 fixed colors (black, white, red, green, blue, cyan, yellow, magenta) 544e0a2b6dfSmrg * VT125 2 planes (4 registers) colorspace is (64?) (color), ? (grayscale) 545894e0ac8Smrg * VT240 2 planes (4 registers) colorspace is 4 shades (grayscale) 546e0a2b6dfSmrg * VT241 2 planes (4 registers) colorspace is ? (color), ? shades (grayscale) 547e0a2b6dfSmrg * VT330 2 planes (4 registers) colorspace is 4 shades (grayscale) 548e0a2b6dfSmrg * VT340 4 planes (16 registers) colorspace is r16g16b16 (color), 16 shades (grayscale) 549894e0ac8Smrg * VT382 1 plane (two fixed colors: black and white) FIXME: verify 550e0a2b6dfSmrg * dxterm ? 551e0a2b6dfSmrg */ 552894e0ac8Smrg switch (screen->terminal_id) { 553e0a2b6dfSmrg case 125: 554894e0ac8Smrg return 4U; 555e0a2b6dfSmrg case 240: 556894e0ac8Smrg return 4U; 557e0a2b6dfSmrg case 241: 558894e0ac8Smrg return 4U; 559e0a2b6dfSmrg case 330: 560894e0ac8Smrg return 4U; 561e0a2b6dfSmrg case 340: 562894e0ac8Smrg return 16U; 563894e0ac8Smrg case 382: 564894e0ac8Smrg return 2U; 565e0a2b6dfSmrg default: 566894e0ac8Smrg /* unknown graphics model -- might as well be generous */ 567894e0ac8Smrg return MAX_COLOR_REGISTERS; 568e0a2b6dfSmrg } 569894e0ac8Smrg} 570894e0ac8Smrg 571894e0ac8Smrgstatic void 572894e0ac8Smrginit_graphic(Graphic *graphic, 573894e0ac8Smrg unsigned type, 574894e0ac8Smrg int terminal_id, 575894e0ac8Smrg int charrow, 576894e0ac8Smrg int charcol, 577894e0ac8Smrg unsigned num_color_registers, 578894e0ac8Smrg int private_colors) 579894e0ac8Smrg{ 580894e0ac8Smrg unsigned i; 581894e0ac8Smrg 582894e0ac8Smrg TRACE(("initializing graphic object\n")); 583894e0ac8Smrg 584894e0ac8Smrg graphic->dirty = 1; 585894e0ac8Smrg for (i = 0U; i < MAX_PIXELS; i++) 586894e0ac8Smrg graphic->pixels[i] = COLOR_HOLE; 587894e0ac8Smrg memset(graphic->color_registers_used, 0, sizeof(graphic->color_registers_used)); 588e0a2b6dfSmrg 589e0a2b6dfSmrg /* 590e0a2b6dfSmrg * text and graphics interactions: 591e0a2b6dfSmrg * VK100/GIGI text writes on top of graphics buffer, color attribute shared with text 592e0a2b6dfSmrg * VT240,VT241,VT330,VT340 text writes on top of graphics buffer 593894e0ac8Smrg * VT382 text writes on top of graphics buffer FIXME: verify 594e0a2b6dfSmrg * VT125 graphics buffer overlaid on top of text in B&W display, text not present in color display 595e0a2b6dfSmrg */ 596e0a2b6dfSmrg 597894e0ac8Smrg /* 598894e0ac8Smrg * dimensions (ReGIS logical, physical): 599894e0ac8Smrg * VK100/GIGI 768x4?? 768x240(status?) 600894e0ac8Smrg * VT125 768x460 768x230(+10status) (1:2 aspect ratio, ReGIS halves vertical addresses through "odd y emulation") 601894e0ac8Smrg * VT240 800x460 800x230(+10status) (1:2 aspect ratio, ReGIS halves vertical addresses through "odd y emulation") 602894e0ac8Smrg * VT241 800x460 800x230(+10status) (1:2 aspect ratio, ReGIS halves vertical addresses through "odd y emulation") 603894e0ac8Smrg * VT330 800x480 800x480(+?status) 604894e0ac8Smrg * VT340 800x480 800x480(+?status) 605894e0ac8Smrg * VT382 960x750 sixel only 606894e0ac8Smrg * dxterm ?x? ?x? variable? 607894e0ac8Smrg */ 608894e0ac8Smrg graphic->max_width = BUFFER_WIDTH; 609894e0ac8Smrg graphic->max_height = BUFFER_HEIGHT; 610e0a2b6dfSmrg 611e0a2b6dfSmrg graphic->actual_width = 0; 612e0a2b6dfSmrg graphic->actual_height = 0; 613e0a2b6dfSmrg 614894e0ac8Smrg graphic->pixw = 1; 615894e0ac8Smrg graphic->pixh = 1; 616894e0ac8Smrg 617894e0ac8Smrg graphic->valid_registers = num_color_registers; 618894e0ac8Smrg TRACE(("%d color registers\n", graphic->valid_registers)); 619894e0ac8Smrg 620e0a2b6dfSmrg graphic->private_colors = private_colors; 621e0a2b6dfSmrg if (graphic->private_colors) { 622894e0ac8Smrg TRACE(("using private color registers\n")); 623e0a2b6dfSmrg init_color_registers(graphic->private_color_registers, terminal_id); 624e0a2b6dfSmrg graphic->color_registers = graphic->private_color_registers; 625e0a2b6dfSmrg } else { 626894e0ac8Smrg TRACE(("using shared color registers\n")); 627894e0ac8Smrg graphic->color_registers = getSharedRegisters(); 628e0a2b6dfSmrg } 629e0a2b6dfSmrg 630894e0ac8Smrg graphic->charrow = charrow; 631894e0ac8Smrg graphic->charcol = charcol; 632894e0ac8Smrg graphic->type = type; 633e0a2b6dfSmrg graphic->valid = 0; 634e0a2b6dfSmrg} 635e0a2b6dfSmrg 636894e0ac8SmrgGraphic * 637894e0ac8Smrgget_new_graphic(XtermWidget xw, int charrow, int charcol, unsigned type) 638e0a2b6dfSmrg{ 639e0a2b6dfSmrg TScreen const *screen = TScreenOf(xw); 640e0a2b6dfSmrg int bufferid = screen->whichBuf; 641e0a2b6dfSmrg int terminal_id = screen->terminal_id; 642894e0ac8Smrg Graphic *graphic; 643894e0ac8Smrg unsigned ii; 644e0a2b6dfSmrg 645894e0ac8Smrg FOR_EACH_SLOT(ii) { 646894e0ac8Smrg if ((graphic = getInactiveSlot(ii))) { 647894e0ac8Smrg TRACE(("using fresh graphic index=%u id=%u\n", ii, next_graphic_id)); 648e0a2b6dfSmrg break; 649894e0ac8Smrg } 650e0a2b6dfSmrg } 651e0a2b6dfSmrg 652894e0ac8Smrg /* if none are free, recycle the graphic scrolled back the farthest */ 653894e0ac8Smrg if (!graphic) { 654e0a2b6dfSmrg int min_charrow = 0; 655894e0ac8Smrg Graphic *min_graphic = NULL; 656e0a2b6dfSmrg 657894e0ac8Smrg FOR_EACH_SLOT(ii) { 658894e0ac8Smrg if (!(graphic = getActiveSlot(ii))) 659894e0ac8Smrg continue; 660e0a2b6dfSmrg if (!min_graphic || graphic->charrow < min_charrow) { 661e0a2b6dfSmrg min_charrow = graphic->charrow; 662e0a2b6dfSmrg min_graphic = graphic; 663e0a2b6dfSmrg } 664e0a2b6dfSmrg } 665894e0ac8Smrg TRACE(("recycling old graphic index=%u id=%u\n", ii, next_graphic_id)); 666e0a2b6dfSmrg graphic = min_graphic; 667e0a2b6dfSmrg } 668e0a2b6dfSmrg 669894e0ac8Smrg if (graphic) { 670894e0ac8Smrg unsigned num_color_registers; 671894e0ac8Smrg num_color_registers = get_color_register_count(screen); 672894e0ac8Smrg graphic->xw = xw; 673894e0ac8Smrg graphic->bufferid = bufferid; 674894e0ac8Smrg graphic->id = next_graphic_id++; 675894e0ac8Smrg init_graphic(graphic, 676894e0ac8Smrg type, 677894e0ac8Smrg terminal_id, 678894e0ac8Smrg charrow, 679894e0ac8Smrg charcol, 680894e0ac8Smrg num_color_registers, 681894e0ac8Smrg screen->privatecolorregisters); 682894e0ac8Smrg } 683e0a2b6dfSmrg return graphic; 684e0a2b6dfSmrg} 685e0a2b6dfSmrg 686894e0ac8SmrgGraphic * 687894e0ac8Smrgget_new_or_matching_graphic(XtermWidget xw, 688894e0ac8Smrg int charrow, 689894e0ac8Smrg int charcol, 690894e0ac8Smrg int actual_width, 691894e0ac8Smrg int actual_height, 692894e0ac8Smrg unsigned type) 693e0a2b6dfSmrg{ 694894e0ac8Smrg TScreen const *screen = TScreenOf(xw); 695894e0ac8Smrg int bufferid = screen->whichBuf; 696894e0ac8Smrg Graphic *graphic; 697894e0ac8Smrg unsigned ii; 698894e0ac8Smrg 699894e0ac8Smrg FOR_EACH_SLOT(ii) { 700894e0ac8Smrg if ((graphic = getActiveSlot(ii)) && 701894e0ac8Smrg graphic->type == type && 702894e0ac8Smrg graphic->bufferid == bufferid && 703894e0ac8Smrg graphic->charrow == charrow && 704894e0ac8Smrg graphic->charcol == charcol && 705894e0ac8Smrg graphic->actual_width == actual_width && 706894e0ac8Smrg graphic->actual_height == actual_height) { 707894e0ac8Smrg TRACE(("found existing graphic index=%u id=%u\n", ii, graphic->id)); 708894e0ac8Smrg return graphic; 709e0a2b6dfSmrg } 710e0a2b6dfSmrg } 711e0a2b6dfSmrg 712894e0ac8Smrg /* if no match get a new graphic */ 713894e0ac8Smrg if ((graphic = get_new_graphic(xw, charrow, charcol, type))) { 714894e0ac8Smrg graphic->actual_width = actual_width; 715894e0ac8Smrg graphic->actual_height = actual_height; 716e0a2b6dfSmrg } 717894e0ac8Smrg return graphic; 718e0a2b6dfSmrg} 719e0a2b6dfSmrg 720e0a2b6dfSmrg#define ScaleForXColor(s) (unsigned short) ((long)(s) * 65535 / 100) 721e0a2b6dfSmrg 722e0a2b6dfSmrgstatic Pixel 723894e0ac8Smrgcolor_register_to_xpixel(ColorRegister *reg, XtermWidget xw) 724e0a2b6dfSmrg{ 725e0a2b6dfSmrg if (!reg->allocated) { 726e0a2b6dfSmrg XColor def; 727e0a2b6dfSmrg 728e0a2b6dfSmrg def.red = ScaleForXColor(reg->r); 729e0a2b6dfSmrg def.green = ScaleForXColor(reg->g); 730e0a2b6dfSmrg def.blue = ScaleForXColor(reg->b); 731e0a2b6dfSmrg def.flags = DoRed | DoGreen | DoBlue; 732e0a2b6dfSmrg if (!allocateBestRGB(xw, &def)) { 733894e0ac8Smrg TRACE(("unable to allocate xcolor for color register\n")); 734e0a2b6dfSmrg return 0UL; 735e0a2b6dfSmrg } 736e0a2b6dfSmrg reg->pix = def.pixel; 737e0a2b6dfSmrg reg->allocated = 1; 738e0a2b6dfSmrg } 739e0a2b6dfSmrg 740e0a2b6dfSmrg /* FIXME: with so many possible colors we need to determine 741e0a2b6dfSmrg * when to free them to be nice to PseudoColor displays 742e0a2b6dfSmrg */ 743e0a2b6dfSmrg return reg->pix; 744e0a2b6dfSmrg} 745e0a2b6dfSmrg 746e0a2b6dfSmrgstatic void 747894e0ac8Smrgrefresh_graphic(TScreen const *screen, 748894e0ac8Smrg Graphic const *graphic, 749894e0ac8Smrg int xbase, 750894e0ac8Smrg int ybase, 751894e0ac8Smrg int x, 752894e0ac8Smrg int y, 753894e0ac8Smrg int w, 754894e0ac8Smrg int h) 755e0a2b6dfSmrg{ 756e0a2b6dfSmrg Display *display = screen->display; 757e0a2b6dfSmrg Window vwindow = WhichVWin(screen)->window; 758e0a2b6dfSmrg GC graphics_gc; 759e0a2b6dfSmrg int r, c; 760e0a2b6dfSmrg int pw, ph; 761894e0ac8Smrg int rbase, cbase; 762e0a2b6dfSmrg RegisterNum color; 763e0a2b6dfSmrg RegisterNum old_fg; 764e0a2b6dfSmrg XGCValues xgcv; 765e0a2b6dfSmrg XtGCMask mask; 766e0a2b6dfSmrg int holes, total; 767e0a2b6dfSmrg 768894e0ac8Smrg TRACE(("refreshing graphic from %d,%d %dx%d (valid=%d, size=%dx%d, scale=%dx%d max=%dx%d) at base=%d,%d\n", 769e0a2b6dfSmrg x, y, w, h, 770e0a2b6dfSmrg graphic->valid, 771e0a2b6dfSmrg graphic->actual_width, 772e0a2b6dfSmrg graphic->actual_height, 773894e0ac8Smrg graphic->pixw, 774894e0ac8Smrg graphic->pixh, 775e0a2b6dfSmrg graphic->max_width, 776e0a2b6dfSmrg graphic->max_height, 777e0a2b6dfSmrg xbase, ybase)); 778e0a2b6dfSmrg 779e0a2b6dfSmrg memset(&xgcv, 0, sizeof(xgcv)); 780e0a2b6dfSmrg xgcv.foreground = 0UL; 781e0a2b6dfSmrg xgcv.graphics_exposures = False; 782e0a2b6dfSmrg mask = GCForeground | GCGraphicsExposures; 783e0a2b6dfSmrg graphics_gc = XCreateGC(display, vwindow, mask, &xgcv); 784e0a2b6dfSmrg 785e0a2b6dfSmrg pw = graphic->pixw; 786e0a2b6dfSmrg ph = graphic->pixh; 787e0a2b6dfSmrg 788e0a2b6dfSmrg TRACE(("refreshed graphic covers 0,0 to %d,%d\n", 789e0a2b6dfSmrg (graphic->actual_width - 1) * pw + pw - 1, 790e0a2b6dfSmrg (graphic->actual_height - 1) * ph + ph - 1)); 791e0a2b6dfSmrg TRACE(("refreshed area covers %d,%d to %d,%d\n", 792e0a2b6dfSmrg x, y, 793e0a2b6dfSmrg x + w - 1, 794e0a2b6dfSmrg y + h - 1)); 795e0a2b6dfSmrg 796e0a2b6dfSmrg old_fg = COLOR_HOLE; 797e0a2b6dfSmrg holes = total = 0; 798894e0ac8Smrg rbase = 0; 799894e0ac8Smrg for (r = 0; r < graphic->actual_height; r++) { 800894e0ac8Smrg int rtest = rbase; 801894e0ac8Smrg 802894e0ac8Smrg rbase += ph; 803894e0ac8Smrg if (rtest + ph - 1 < y) 804894e0ac8Smrg continue; 805894e0ac8Smrg if (rtest > y + h - 1) 806894e0ac8Smrg continue; 807894e0ac8Smrg 808894e0ac8Smrg cbase = 0; 809e0a2b6dfSmrg for (c = 0; c < graphic->actual_width; c++) { 810894e0ac8Smrg int ctest = cbase; 811e0a2b6dfSmrg 812894e0ac8Smrg cbase += pw; 813894e0ac8Smrg if (ctest + pw - 1 < x) 814894e0ac8Smrg continue; 815894e0ac8Smrg if (ctest > x + w - 1) 816894e0ac8Smrg continue; 817e0a2b6dfSmrg 818e0a2b6dfSmrg total++; 819e0a2b6dfSmrg color = graphic->pixels[r * graphic->max_width + c]; 820e0a2b6dfSmrg if (color == COLOR_HOLE) { 821e0a2b6dfSmrg holes++; 822e0a2b6dfSmrg continue; 823e0a2b6dfSmrg } 824e0a2b6dfSmrg 825e0a2b6dfSmrg if (color != old_fg) { 826e0a2b6dfSmrg xgcv.foreground = 827894e0ac8Smrg color_register_to_xpixel(&graphic->color_registers[color], 828e0a2b6dfSmrg graphic->xw); 829e0a2b6dfSmrg XChangeGC(display, graphics_gc, mask, &xgcv); 830e0a2b6dfSmrg old_fg = color; 831e0a2b6dfSmrg } 832e0a2b6dfSmrg 833e0a2b6dfSmrg XFillRectangle(display, vwindow, graphics_gc, 834894e0ac8Smrg xbase + ctest, 835894e0ac8Smrg ybase + rtest, 836894e0ac8Smrg (unsigned) pw, 837894e0ac8Smrg (unsigned) ph); 838e0a2b6dfSmrg } 839894e0ac8Smrg } 840e0a2b6dfSmrg 841e0a2b6dfSmrg#ifdef DEBUG_REFRESH 842e0a2b6dfSmrg { 843e0a2b6dfSmrg XColor def; 844e0a2b6dfSmrg 845e0a2b6dfSmrg def.red = (short) (1.0 * 65535.0); 846e0a2b6dfSmrg def.green = (short) (0.1 * 65535.0); 847e0a2b6dfSmrg def.blue = (short) (1.0 * 65535.0); 848e0a2b6dfSmrg def.flags = DoRed | DoGreen | DoBlue; 849e0a2b6dfSmrg if (allocateBestRGB(graphic->xw, &def)) { 850e0a2b6dfSmrg xgcv.foreground = def.pixel; 851e0a2b6dfSmrg XChangeGC(display, graphics_gc, mask, &xgcv); 852e0a2b6dfSmrg } 853e0a2b6dfSmrg XFillRectangle(display, vwindow, graphics_gc, 854e0a2b6dfSmrg xbase + 0, 855e0a2b6dfSmrg ybase + 0, 856e0a2b6dfSmrg (unsigned) pw, (unsigned) ph); 857e0a2b6dfSmrg XFillRectangle(display, vwindow, graphics_gc, 858e0a2b6dfSmrg xbase + (graphic->actual_width - 1) * pw, 859e0a2b6dfSmrg ybase + (graphic->actual_height - 1) * ph, 860e0a2b6dfSmrg (unsigned) pw, (unsigned) ph); 861e0a2b6dfSmrg 862e0a2b6dfSmrg def.red = (unsigned short) ((1.0 - 0.1 * (rand() / (double) 863e0a2b6dfSmrg RAND_MAX) * 65535.0)); 864e0a2b6dfSmrg def.green = (unsigned short) ((0.7 + 0.2 * (rand() / (double) 865e0a2b6dfSmrg RAND_MAX)) * 65535.0); 866e0a2b6dfSmrg def.blue = (unsigned short) ((0.1 + 0.1 * (rand() / (double) 867e0a2b6dfSmrg RAND_MAX)) * 65535.0); 868e0a2b6dfSmrg def.flags = DoRed | DoGreen | DoBlue; 869e0a2b6dfSmrg if (allocateBestRGB(graphic->xw, &def)) { 870e0a2b6dfSmrg xgcv.foreground = def.pixel; 871e0a2b6dfSmrg XChangeGC(display, graphics_gc, mask, &xgcv); 872e0a2b6dfSmrg } 873e0a2b6dfSmrg XDrawLine(display, vwindow, graphics_gc, 874e0a2b6dfSmrg xbase + x + 0, ybase + y + 0, 875e0a2b6dfSmrg xbase + x + w - 1, ybase + y + 0); 876e0a2b6dfSmrg XDrawLine(display, vwindow, graphics_gc, 877e0a2b6dfSmrg xbase + x + w - 1, ybase + y + 0, 878e0a2b6dfSmrg xbase + x + 0, ybase + y + h - 1); 879e0a2b6dfSmrg XDrawLine(display, vwindow, graphics_gc, 880e0a2b6dfSmrg xbase + x + 0, ybase + y + h - 1, 881e0a2b6dfSmrg xbase + x + w - 1, ybase + y + h - 1); 882e0a2b6dfSmrg XDrawLine(display, vwindow, graphics_gc, 883e0a2b6dfSmrg xbase + x + w - 1, ybase + y + h - 1, 884e0a2b6dfSmrg xbase + x + 0, ybase + y + 0); 885e0a2b6dfSmrg } 886e0a2b6dfSmrg#endif 887e0a2b6dfSmrg XFlush(display); 888894e0ac8Smrg TRACE(("done refreshing graphic: %d of %d refreshed pixels were holes\n", 889e0a2b6dfSmrg holes, total)); 890e0a2b6dfSmrg 891e0a2b6dfSmrg XFreeGC(display, graphics_gc); 892e0a2b6dfSmrg} 893e0a2b6dfSmrg 894e0a2b6dfSmrg/* 895e0a2b6dfSmrg * Primary color hues: 896e0a2b6dfSmrg * blue: 0 degrees 897e0a2b6dfSmrg * red: 120 degrees 898e0a2b6dfSmrg * green: 240 degrees 899e0a2b6dfSmrg */ 900894e0ac8Smrgvoid 901e0a2b6dfSmrghls2rgb(int h, int l, int s, short *r, short *g, short *b) 902e0a2b6dfSmrg{ 903e0a2b6dfSmrg double hs = (h + 240) % 360; 904e0a2b6dfSmrg double hv = hs / 360.0; 905e0a2b6dfSmrg double lv = l / 100.0; 906e0a2b6dfSmrg double sv = s / 100.0; 907894e0ac8Smrg double c, x, m, c2; 908e0a2b6dfSmrg double r1, g1, b1; 909e0a2b6dfSmrg int hpi; 910e0a2b6dfSmrg 911e0a2b6dfSmrg if (s == 0) { 912e0a2b6dfSmrg *r = *g = *b = (short) l; 913e0a2b6dfSmrg return; 914e0a2b6dfSmrg } 915e0a2b6dfSmrg 916894e0ac8Smrg if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) 917894e0ac8Smrg c2 = -c2; 918894e0ac8Smrg c = (1.0 - c2) * sv; 919e0a2b6dfSmrg hpi = (int) (hv * 6.0); 920e0a2b6dfSmrg x = (hpi & 1) ? c : 0.0; 921e0a2b6dfSmrg m = lv - 0.5 * c; 922e0a2b6dfSmrg 923e0a2b6dfSmrg switch (hpi) { 924e0a2b6dfSmrg case 0: 925e0a2b6dfSmrg r1 = c; 926e0a2b6dfSmrg g1 = x; 927e0a2b6dfSmrg b1 = 0.0; 928e0a2b6dfSmrg break; 929e0a2b6dfSmrg case 1: 930e0a2b6dfSmrg r1 = x; 931e0a2b6dfSmrg g1 = c; 932e0a2b6dfSmrg b1 = 0.0; 933e0a2b6dfSmrg break; 934e0a2b6dfSmrg case 2: 935e0a2b6dfSmrg r1 = 0.0; 936e0a2b6dfSmrg g1 = c; 937e0a2b6dfSmrg b1 = x; 938e0a2b6dfSmrg break; 939e0a2b6dfSmrg case 3: 940e0a2b6dfSmrg r1 = 0.0; 941e0a2b6dfSmrg g1 = x; 942e0a2b6dfSmrg b1 = c; 943e0a2b6dfSmrg break; 944e0a2b6dfSmrg case 4: 945e0a2b6dfSmrg r1 = x; 946e0a2b6dfSmrg g1 = 0.0; 947e0a2b6dfSmrg b1 = c; 948e0a2b6dfSmrg break; 949e0a2b6dfSmrg case 5: 950e0a2b6dfSmrg r1 = c; 951e0a2b6dfSmrg g1 = 0.0; 952e0a2b6dfSmrg b1 = x; 953e0a2b6dfSmrg break; 954e0a2b6dfSmrg default: 955894e0ac8Smrg TRACE(("Bad HLS input: [%d,%d,%d], returning white\n", h, l, s)); 956e0a2b6dfSmrg *r = (short) 100; 957e0a2b6dfSmrg *g = (short) 100; 958e0a2b6dfSmrg *b = (short) 100; 959e0a2b6dfSmrg return; 960e0a2b6dfSmrg } 961e0a2b6dfSmrg 962e0a2b6dfSmrg *r = (short) ((r1 + m) * 100.0 + 0.5); 963e0a2b6dfSmrg *g = (short) ((g1 + m) * 100.0 + 0.5); 964e0a2b6dfSmrg *b = (short) ((b1 + m) * 100.0 + 0.5); 965e0a2b6dfSmrg 966e0a2b6dfSmrg if (*r < 0) 967e0a2b6dfSmrg *r = 0; 968e0a2b6dfSmrg else if (*r > 100) 969e0a2b6dfSmrg *r = 100; 970e0a2b6dfSmrg if (*g < 0) 971e0a2b6dfSmrg *g = 0; 972e0a2b6dfSmrg else if (*g > 100) 973e0a2b6dfSmrg *g = 100; 974e0a2b6dfSmrg if (*b < 0) 975e0a2b6dfSmrg *b = 0; 976e0a2b6dfSmrg else if (*b > 100) 977e0a2b6dfSmrg *b = 100; 978e0a2b6dfSmrg} 979e0a2b6dfSmrg 980894e0ac8Smrgvoid 981894e0ac8Smrgdump_graphic(Graphic const *graphic) 982e0a2b6dfSmrg{ 983894e0ac8Smrg#if defined(DUMP_COLORS) || defined(DUMP_BITMAP) 984894e0ac8Smrg RegisterNum color; 985894e0ac8Smrg#endif 986894e0ac8Smrg#ifdef DUMP_BITMAP 987894e0ac8Smrg int r, c; 988894e0ac8Smrg ColorRegister const *reg; 989894e0ac8Smrg#endif 990e0a2b6dfSmrg 991894e0ac8Smrg (void) graphic; 992e0a2b6dfSmrg 993894e0ac8Smrg TRACE(("graphic stats: id=%u charrow=%d charcol=%d actual_width=%d actual_height=%d pixw=%d pixh=%d\n", 994894e0ac8Smrg graphic->id, 995894e0ac8Smrg graphic->charrow, 996894e0ac8Smrg graphic->charcol, 997894e0ac8Smrg graphic->actual_width, 998894e0ac8Smrg graphic->actual_height, 999894e0ac8Smrg graphic->pixw, 1000894e0ac8Smrg graphic->pixh)); 1001e0a2b6dfSmrg 1002894e0ac8Smrg#ifdef DUMP_COLORS 1003894e0ac8Smrg TRACE(("graphic colors:\n")); 1004894e0ac8Smrg for (color = 0; color < graphic->valid_registers; color++) { 1005894e0ac8Smrg TRACE(("%03u: %d,%d,%d\n", 1006894e0ac8Smrg color, 1007894e0ac8Smrg graphic->color_registers[color].r, 1008894e0ac8Smrg graphic->color_registers[color].g, 1009894e0ac8Smrg graphic->color_registers[color].b)); 1010e0a2b6dfSmrg } 1011e0a2b6dfSmrg#endif 1012e0a2b6dfSmrg 1013894e0ac8Smrg#ifdef DUMP_BITMAP 1014894e0ac8Smrg TRACE(("graphic pixels:\n")); 1015894e0ac8Smrg for (r = 0; r < graphic->actual_height; r++) { 1016894e0ac8Smrg for (c = 0; c < graphic->actual_width; c++) { 1017894e0ac8Smrg color = graphic->pixels[r * graphic->max_width + c]; 1018894e0ac8Smrg if (color == COLOR_HOLE) { 1019894e0ac8Smrg TRACE(("?")); 1020e0a2b6dfSmrg } else { 1021894e0ac8Smrg reg = &graphic->color_registers[color]; 1022894e0ac8Smrg if (reg->r + reg->g + reg->b > 200) { 1023894e0ac8Smrg TRACE(("#")); 1024894e0ac8Smrg } else if (reg->r + reg->g + reg->b > 150) { 1025894e0ac8Smrg TRACE(("%%")); 1026894e0ac8Smrg } else if (reg->r + reg->g + reg->b > 100) { 1027894e0ac8Smrg TRACE((":")); 1028894e0ac8Smrg } else if (reg->r + reg->g + reg->b > 80) { 1029894e0ac8Smrg TRACE((".")); 1030894e0ac8Smrg } else { 1031894e0ac8Smrg TRACE((" ")); 1032e0a2b6dfSmrg } 1033e0a2b6dfSmrg } 1034e0a2b6dfSmrg } 1035894e0ac8Smrg TRACE(("\n")); 1036e0a2b6dfSmrg } 1037e0a2b6dfSmrg 1038894e0ac8Smrg TRACE(("\n")); 1039894e0ac8Smrg#endif 1040e0a2b6dfSmrg} 1041e0a2b6dfSmrg 1042e0a2b6dfSmrg/* Erase the portion of any displayed graphic overlapping with a rectangle 1043e0a2b6dfSmrg * of the given size and location in pixels. 1044e0a2b6dfSmrg * This is used to allow text to "erase" graphics underneath it. 1045e0a2b6dfSmrg */ 1046e0a2b6dfSmrgstatic void 1047894e0ac8Smrgerase_graphic(Graphic *graphic, int x, int y, int w, int h) 1048e0a2b6dfSmrg{ 1049e0a2b6dfSmrg RegisterNum hole = COLOR_HOLE; 1050e0a2b6dfSmrg int pw, ph; 1051e0a2b6dfSmrg int r, c; 1052894e0ac8Smrg int rbase, cbase; 1053e0a2b6dfSmrg 1054e0a2b6dfSmrg pw = graphic->pixw; 1055e0a2b6dfSmrg ph = graphic->pixh; 1056e0a2b6dfSmrg 1057894e0ac8Smrg TRACE(("erasing graphic %d,%d %dx%d\n", x, y, w, h)); 1058e0a2b6dfSmrg 1059894e0ac8Smrg rbase = 0; 1060e0a2b6dfSmrg for (r = 0; r < graphic->actual_height; r++) { 1061894e0ac8Smrg if (rbase + ph - 1 >= y 1062894e0ac8Smrg && rbase <= y + h - 1) { 1063894e0ac8Smrg cbase = 0; 1064894e0ac8Smrg for (c = 0; c < graphic->actual_width; c++) { 1065894e0ac8Smrg if (cbase + pw - 1 >= x 1066894e0ac8Smrg && cbase <= x + w - 1) { 1067894e0ac8Smrg graphic->pixels[r * graphic->max_width + c] = hole; 1068894e0ac8Smrg } 1069894e0ac8Smrg cbase += pw; 1070894e0ac8Smrg } 1071e0a2b6dfSmrg } 1072894e0ac8Smrg rbase += ph; 1073e0a2b6dfSmrg } 1074e0a2b6dfSmrg} 1075e0a2b6dfSmrg 1076e0a2b6dfSmrgstatic int 1077894e0ac8Smrgcompare_graphic_ids(const void *left, const void *right) 1078e0a2b6dfSmrg{ 1079894e0ac8Smrg const Graphic *l = *(const Graphic *const *) left; 1080894e0ac8Smrg const Graphic *r = *(const Graphic *const *) right; 1081e0a2b6dfSmrg 1082e0a2b6dfSmrg if (!l->valid || !r->valid) 1083e0a2b6dfSmrg return 0; 1084e0a2b6dfSmrg if (l->id < r->id) 1085e0a2b6dfSmrg return -1; 1086e0a2b6dfSmrg else 1087e0a2b6dfSmrg return 1; 1088e0a2b6dfSmrg} 1089e0a2b6dfSmrg 1090894e0ac8Smrgvoid 1091e0a2b6dfSmrgrefresh_displayed_graphics(TScreen const *screen, 1092e0a2b6dfSmrg int leftcol, 1093e0a2b6dfSmrg int toprow, 1094e0a2b6dfSmrg int ncols, 1095e0a2b6dfSmrg int nrows) 1096e0a2b6dfSmrg{ 1097894e0ac8Smrg Graphic *ordered_graphics[MAX_GRAPHICS]; 1098894e0ac8Smrg Graphic *graphic; 1099894e0ac8Smrg unsigned ii; 1100894e0ac8Smrg unsigned jj = 0; 1101e0a2b6dfSmrg int x, y, w, h; 1102e0a2b6dfSmrg int xbase, ybase; 1103e0a2b6dfSmrg 1104894e0ac8Smrg FOR_EACH_SLOT(ii) { 1105894e0ac8Smrg if ((graphic = getActiveSlot(ii))) { 1106894e0ac8Smrg ordered_graphics[jj++] = graphic; 1107894e0ac8Smrg } 1108894e0ac8Smrg } 1109894e0ac8Smrg if (jj > 1) { 1110894e0ac8Smrg qsort(ordered_graphics, 1111894e0ac8Smrg (size_t) jj, 1112894e0ac8Smrg sizeof(ordered_graphics[0]), 1113894e0ac8Smrg compare_graphic_ids); 1114e0a2b6dfSmrg } 1115e0a2b6dfSmrg 1116894e0ac8Smrg for (ii = 0; ii < jj; ++ii) { 1117e0a2b6dfSmrg graphic = ordered_graphics[ii]; 1118894e0ac8Smrg if (graphic->bufferid != screen->whichBuf) 1119e0a2b6dfSmrg continue; 1120e0a2b6dfSmrg 1121e0a2b6dfSmrg x = (leftcol - graphic->charcol) * FontWidth(screen); 1122e0a2b6dfSmrg y = (toprow - graphic->charrow) * FontHeight(screen); 1123e0a2b6dfSmrg w = ncols * FontWidth(screen); 1124e0a2b6dfSmrg h = nrows * FontHeight(screen); 1125e0a2b6dfSmrg 1126e0a2b6dfSmrg xbase = (OriginX(screen) 1127e0a2b6dfSmrg + graphic->charcol * FontWidth(screen)); 1128e0a2b6dfSmrg ybase = (OriginY(screen) 1129e0a2b6dfSmrg + (graphic->charrow - screen->topline) * FontHeight(screen)); 1130e0a2b6dfSmrg 1131e0a2b6dfSmrg if (xbase + x + w + OriginX(screen) > FullWidth(screen)) 1132e0a2b6dfSmrg w = FullWidth(screen) - (xbase + x + OriginX(screen)); 1133e0a2b6dfSmrg if (ybase + y + h + OriginY(screen) > FullHeight(screen)) 1134e0a2b6dfSmrg h = FullHeight(screen) - (ybase + y + OriginY(screen)); 1135e0a2b6dfSmrg else if (ybase + y < OriginY(screen)) { 1136e0a2b6dfSmrg int diff = OriginY(screen) - (ybase + y); 1137e0a2b6dfSmrg y += diff; 1138e0a2b6dfSmrg h -= diff; 1139e0a2b6dfSmrg } 1140e0a2b6dfSmrg 1141e0a2b6dfSmrg 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", 1142e0a2b6dfSmrg screen->topline, 1143e0a2b6dfSmrg leftcol, toprow, 1144e0a2b6dfSmrg nrows, ncols, 1145e0a2b6dfSmrg x, y, w, h, 1146e0a2b6dfSmrg xbase, ybase)); 1147894e0ac8Smrg refresh_graphic(screen, graphic, xbase, ybase, x, y, w, h); 1148e0a2b6dfSmrg } 1149e0a2b6dfSmrg} 1150e0a2b6dfSmrg 1151894e0ac8Smrgvoid 1152e0a2b6dfSmrgrefresh_modified_displayed_graphics(TScreen const *screen) 1153e0a2b6dfSmrg{ 1154894e0ac8Smrg Graphic *graphic; 1155894e0ac8Smrg unsigned ii; 1156e0a2b6dfSmrg int leftcol, toprow; 1157e0a2b6dfSmrg int nrows, ncols; 1158e0a2b6dfSmrg int x, y, w, h; 1159e0a2b6dfSmrg int xbase, ybase; 1160e0a2b6dfSmrg 1161894e0ac8Smrg FOR_EACH_SLOT(ii) { 1162894e0ac8Smrg if (!(graphic = getActiveSlot(ii))) 1163894e0ac8Smrg continue; 1164894e0ac8Smrg if (graphic->bufferid != screen->whichBuf) 1165894e0ac8Smrg continue; 1166894e0ac8Smrg if (!graphic->dirty) 1167e0a2b6dfSmrg continue; 1168e0a2b6dfSmrg 1169e0a2b6dfSmrg leftcol = graphic->charcol; 1170e0a2b6dfSmrg toprow = graphic->charrow; 1171e0a2b6dfSmrg nrows = (((graphic->actual_height * graphic->pixh) 1172e0a2b6dfSmrg + FontHeight(screen) - 1) 1173e0a2b6dfSmrg / FontHeight(screen)); 1174e0a2b6dfSmrg ncols = (((graphic->actual_width * graphic->pixw) 1175e0a2b6dfSmrg + FontWidth(screen) - 1) 1176e0a2b6dfSmrg / FontWidth(screen)); 1177e0a2b6dfSmrg 1178e0a2b6dfSmrg x = (leftcol - graphic->charcol) * FontWidth(screen); 1179e0a2b6dfSmrg y = (toprow - graphic->charrow) * FontHeight(screen); 1180e0a2b6dfSmrg w = ncols * FontWidth(screen); 1181e0a2b6dfSmrg h = nrows * FontHeight(screen); 1182e0a2b6dfSmrg 1183e0a2b6dfSmrg xbase = (OriginX(screen) 1184e0a2b6dfSmrg + graphic->charcol * FontWidth(screen)); 1185e0a2b6dfSmrg ybase = (OriginY(screen) 1186e0a2b6dfSmrg + (graphic->charrow - screen->topline) * FontHeight(screen)); 1187e0a2b6dfSmrg 1188e0a2b6dfSmrg if (xbase + x + w + OriginX(screen) > FullWidth(screen)) 1189e0a2b6dfSmrg w = FullWidth(screen) - (xbase + x + OriginX(screen)); 1190e0a2b6dfSmrg if (ybase + y + h + OriginY(screen) > FullHeight(screen)) 1191e0a2b6dfSmrg h = FullHeight(screen) - (ybase + y + OriginY(screen)); 1192e0a2b6dfSmrg else if (ybase + y < OriginY(screen)) { 1193e0a2b6dfSmrg int diff = OriginY(screen) - (ybase + y); 1194e0a2b6dfSmrg y += diff; 1195e0a2b6dfSmrg h -= diff; 1196e0a2b6dfSmrg } 1197e0a2b6dfSmrg 1198e0a2b6dfSmrg 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", 1199e0a2b6dfSmrg screen->topline, 1200e0a2b6dfSmrg leftcol, toprow, 1201e0a2b6dfSmrg nrows, ncols, 1202e0a2b6dfSmrg x, y, w, h, 1203e0a2b6dfSmrg xbase, ybase)); 1204894e0ac8Smrg refresh_graphic(screen, graphic, xbase, ybase, x, y, w, h); 1205e0a2b6dfSmrg graphic->dirty = 0; 1206e0a2b6dfSmrg } 1207e0a2b6dfSmrg} 1208e0a2b6dfSmrg 1209894e0ac8Smrgvoid 1210e0a2b6dfSmrgscroll_displayed_graphics(int rows) 1211e0a2b6dfSmrg{ 1212894e0ac8Smrg Graphic *graphic; 1213894e0ac8Smrg unsigned ii; 1214e0a2b6dfSmrg 1215e0a2b6dfSmrg TRACE(("graphics scroll: moving all up %d rows\n", rows)); 1216894e0ac8Smrg /* FIXME: VT125 ReGIS graphics are fixed at the upper left of the display; need to verify */ 1217894e0ac8Smrg 1218894e0ac8Smrg FOR_EACH_SLOT(ii) { 1219894e0ac8Smrg if (!(graphic = getActiveSlot(ii))) 1220e0a2b6dfSmrg continue; 1221e0a2b6dfSmrg 1222e0a2b6dfSmrg graphic->charrow -= rows; 1223e0a2b6dfSmrg } 1224e0a2b6dfSmrg} 1225e0a2b6dfSmrg 1226894e0ac8Smrgvoid 1227e0a2b6dfSmrgpixelarea_clear_displayed_graphics(TScreen const *screen, 1228e0a2b6dfSmrg int winx, 1229e0a2b6dfSmrg int winy, 1230e0a2b6dfSmrg int w, 1231e0a2b6dfSmrg int h) 1232e0a2b6dfSmrg{ 1233894e0ac8Smrg Graphic *graphic; 1234894e0ac8Smrg unsigned ii; 1235e0a2b6dfSmrg int x, y; 1236e0a2b6dfSmrg 1237894e0ac8Smrg FOR_EACH_SLOT(ii) { 1238894e0ac8Smrg if (!(graphic = getActiveSlot(ii))) 1239e0a2b6dfSmrg continue; 1240e0a2b6dfSmrg 1241e0a2b6dfSmrg x = winx - graphic->charcol * FontWidth(screen); 1242e0a2b6dfSmrg y = winy - graphic->charrow * FontHeight(screen); 1243e0a2b6dfSmrg 1244e0a2b6dfSmrg TRACE(("pixelarea graphics erase: screen->topline=%d winx=%d winy=%d w=%d h=%d x=%d y=%d\n", 1245e0a2b6dfSmrg screen->topline, 1246e0a2b6dfSmrg winx, winy, 1247e0a2b6dfSmrg w, h, 1248e0a2b6dfSmrg x, y)); 1249894e0ac8Smrg erase_graphic(graphic, x, y, w, h); 1250e0a2b6dfSmrg } 1251e0a2b6dfSmrg} 1252e0a2b6dfSmrg 1253894e0ac8Smrgvoid 1254e0a2b6dfSmrgchararea_clear_displayed_graphics(TScreen const *screen, 1255e0a2b6dfSmrg int leftcol, 1256e0a2b6dfSmrg int toprow, 1257e0a2b6dfSmrg int ncols, 1258e0a2b6dfSmrg int nrows) 1259e0a2b6dfSmrg{ 1260e0a2b6dfSmrg int x, y, w, h; 1261e0a2b6dfSmrg 1262e0a2b6dfSmrg x = leftcol * FontWidth(screen); 1263e0a2b6dfSmrg y = toprow * FontHeight(screen); 1264e0a2b6dfSmrg w = ncols * FontWidth(screen); 1265e0a2b6dfSmrg h = nrows * FontHeight(screen); 1266e0a2b6dfSmrg 1267e0a2b6dfSmrg TRACE(("chararea clear graphics: screen->topline=%d leftcol=%d toprow=%d nrows=%d ncols=%d x=%d y=%d w=%d h=%d\n", 1268e0a2b6dfSmrg screen->topline, 1269e0a2b6dfSmrg leftcol, toprow, 1270e0a2b6dfSmrg nrows, ncols, 1271e0a2b6dfSmrg x, y, w, h)); 1272e0a2b6dfSmrg pixelarea_clear_displayed_graphics(screen, x, y, w, h); 1273e0a2b6dfSmrg} 1274e0a2b6dfSmrg 1275894e0ac8Smrgvoid 1276e0a2b6dfSmrgreset_displayed_graphics(TScreen const *screen) 1277e0a2b6dfSmrg{ 1278894e0ac8Smrg unsigned ii; 1279894e0ac8Smrg 1280894e0ac8Smrg init_color_registers(getSharedRegisters(), screen->terminal_id); 1281894e0ac8Smrg 1282894e0ac8Smrg TRACE(("resetting all graphics\n")); 1283894e0ac8Smrg FOR_EACH_SLOT(ii) { 1284894e0ac8Smrg deactivateSlot(ii); 1285894e0ac8Smrg } 1286894e0ac8Smrg} 1287894e0ac8Smrg 1288894e0ac8Smrg#ifdef NO_LEAKS 1289894e0ac8Smrgvoid 1290894e0ac8Smrgnoleaks_graphics(void) 1291894e0ac8Smrg{ 1292894e0ac8Smrg unsigned ii; 1293894e0ac8Smrg 1294894e0ac8Smrg FOR_EACH_SLOT(ii) { 1295894e0ac8Smrg deactivateSlot(ii); 1296e0a2b6dfSmrg } 1297e0a2b6dfSmrg} 1298894e0ac8Smrg#endif 1299