1e16f4c87SPeter Maydell #include "qemu/osdep.h" 228ecbaeeSPaolo Bonzini #include "ui/console.h" 328ecbaeeSPaolo Bonzini 428ecbaeeSPaolo Bonzini #include "cursor_hidden.xpm" 528ecbaeeSPaolo Bonzini #include "cursor_left_ptr.xpm" 628ecbaeeSPaolo Bonzini 728ecbaeeSPaolo Bonzini /* for creating built-in cursors */ 828ecbaeeSPaolo Bonzini static QEMUCursor *cursor_parse_xpm(const char *xpm[]) 928ecbaeeSPaolo Bonzini { 1028ecbaeeSPaolo Bonzini QEMUCursor *c; 1128ecbaeeSPaolo Bonzini uint32_t ctab[128]; 1228ecbaeeSPaolo Bonzini unsigned int width, height, colors, chars; 1328ecbaeeSPaolo Bonzini unsigned int line = 0, i, r, g, b, x, y, pixel; 1428ecbaeeSPaolo Bonzini char name[16]; 1528ecbaeeSPaolo Bonzini uint8_t idx; 1628ecbaeeSPaolo Bonzini 1728ecbaeeSPaolo Bonzini /* parse header line: width, height, #colors, #chars */ 1828ecbaeeSPaolo Bonzini if (sscanf(xpm[line], "%u %u %u %u", 1928ecbaeeSPaolo Bonzini &width, &height, &colors, &chars) != 4) { 2028ecbaeeSPaolo Bonzini fprintf(stderr, "%s: header parse error: \"%s\"\n", 21a89f364aSAlistair Francis __func__, xpm[line]); 2228ecbaeeSPaolo Bonzini return NULL; 2328ecbaeeSPaolo Bonzini } 2428ecbaeeSPaolo Bonzini if (chars != 1) { 25a89f364aSAlistair Francis fprintf(stderr, "%s: chars != 1 not supported\n", __func__); 2628ecbaeeSPaolo Bonzini return NULL; 2728ecbaeeSPaolo Bonzini } 2828ecbaeeSPaolo Bonzini line++; 2928ecbaeeSPaolo Bonzini 3028ecbaeeSPaolo Bonzini /* parse color table */ 3128ecbaeeSPaolo Bonzini for (i = 0; i < colors; i++, line++) { 3228ecbaeeSPaolo Bonzini if (sscanf(xpm[line], "%c c %15s", &idx, name) == 2) { 3328ecbaeeSPaolo Bonzini if (sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3) { 3428ecbaeeSPaolo Bonzini ctab[idx] = (0xff << 24) | (b << 16) | (g << 8) | r; 3528ecbaeeSPaolo Bonzini continue; 3628ecbaeeSPaolo Bonzini } 3728ecbaeeSPaolo Bonzini if (strcmp(name, "None") == 0) { 3828ecbaeeSPaolo Bonzini ctab[idx] = 0x00000000; 3928ecbaeeSPaolo Bonzini continue; 4028ecbaeeSPaolo Bonzini } 4128ecbaeeSPaolo Bonzini } 4228ecbaeeSPaolo Bonzini fprintf(stderr, "%s: color parse error: \"%s\"\n", 43a89f364aSAlistair Francis __func__, xpm[line]); 4428ecbaeeSPaolo Bonzini return NULL; 4528ecbaeeSPaolo Bonzini } 4628ecbaeeSPaolo Bonzini 4728ecbaeeSPaolo Bonzini /* parse pixel data */ 4828ecbaeeSPaolo Bonzini c = cursor_alloc(width, height); 49fa892e9aSMauro Matteo Cascella assert(c != NULL); 50fa892e9aSMauro Matteo Cascella 5128ecbaeeSPaolo Bonzini for (pixel = 0, y = 0; y < height; y++, line++) { 5228ecbaeeSPaolo Bonzini for (x = 0; x < height; x++, pixel++) { 5328ecbaeeSPaolo Bonzini idx = xpm[line][x]; 5428ecbaeeSPaolo Bonzini c->data[pixel] = ctab[idx]; 5528ecbaeeSPaolo Bonzini } 5628ecbaeeSPaolo Bonzini } 5728ecbaeeSPaolo Bonzini return c; 5828ecbaeeSPaolo Bonzini } 5928ecbaeeSPaolo Bonzini 6028ecbaeeSPaolo Bonzini /* nice for debugging */ 6128ecbaeeSPaolo Bonzini void cursor_print_ascii_art(QEMUCursor *c, const char *prefix) 6228ecbaeeSPaolo Bonzini { 6328ecbaeeSPaolo Bonzini uint32_t *data = c->data; 6428ecbaeeSPaolo Bonzini int x,y; 6528ecbaeeSPaolo Bonzini 6628ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 6728ecbaeeSPaolo Bonzini fprintf(stderr, "%s: %2d: |", prefix, y); 6828ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 6928ecbaeeSPaolo Bonzini if ((*data & 0xff000000) != 0xff000000) { 7028ecbaeeSPaolo Bonzini fprintf(stderr, " "); /* transparent */ 7128ecbaeeSPaolo Bonzini } else if ((*data & 0x00ffffff) == 0x00ffffff) { 7228ecbaeeSPaolo Bonzini fprintf(stderr, "."); /* white */ 7328ecbaeeSPaolo Bonzini } else if ((*data & 0x00ffffff) == 0x00000000) { 7428ecbaeeSPaolo Bonzini fprintf(stderr, "X"); /* black */ 7528ecbaeeSPaolo Bonzini } else { 7628ecbaeeSPaolo Bonzini fprintf(stderr, "o"); /* other */ 7728ecbaeeSPaolo Bonzini } 7828ecbaeeSPaolo Bonzini } 7928ecbaeeSPaolo Bonzini fprintf(stderr, "|\n"); 8028ecbaeeSPaolo Bonzini } 8128ecbaeeSPaolo Bonzini } 8228ecbaeeSPaolo Bonzini 8328ecbaeeSPaolo Bonzini QEMUCursor *cursor_builtin_hidden(void) 8428ecbaeeSPaolo Bonzini { 859be38598SEduardo Habkost return cursor_parse_xpm(cursor_hidden_xpm); 8628ecbaeeSPaolo Bonzini } 8728ecbaeeSPaolo Bonzini 8828ecbaeeSPaolo Bonzini QEMUCursor *cursor_builtin_left_ptr(void) 8928ecbaeeSPaolo Bonzini { 909be38598SEduardo Habkost return cursor_parse_xpm(cursor_left_ptr_xpm); 9128ecbaeeSPaolo Bonzini } 9228ecbaeeSPaolo Bonzini 9328ecbaeeSPaolo Bonzini QEMUCursor *cursor_alloc(int width, int height) 9428ecbaeeSPaolo Bonzini { 9528ecbaeeSPaolo Bonzini QEMUCursor *c; 96fa892e9aSMauro Matteo Cascella size_t datasize = width * height * sizeof(uint32_t); 97fa892e9aSMauro Matteo Cascella 98fa892e9aSMauro Matteo Cascella if (width > 512 || height > 512) { 99fa892e9aSMauro Matteo Cascella return NULL; 100fa892e9aSMauro Matteo Cascella } 10128ecbaeeSPaolo Bonzini 10228ecbaeeSPaolo Bonzini c = g_malloc0(sizeof(QEMUCursor) + datasize); 10328ecbaeeSPaolo Bonzini c->width = width; 10428ecbaeeSPaolo Bonzini c->height = height; 10528ecbaeeSPaolo Bonzini c->refcount = 1; 10628ecbaeeSPaolo Bonzini return c; 10728ecbaeeSPaolo Bonzini } 10828ecbaeeSPaolo Bonzini 10928ecbaeeSPaolo Bonzini void cursor_get(QEMUCursor *c) 11028ecbaeeSPaolo Bonzini { 11128ecbaeeSPaolo Bonzini c->refcount++; 11228ecbaeeSPaolo Bonzini } 11328ecbaeeSPaolo Bonzini 114*f4579e28SMarc-André Lureau void cursor_unref(QEMUCursor *c) 11528ecbaeeSPaolo Bonzini { 11628ecbaeeSPaolo Bonzini if (c == NULL) 11728ecbaeeSPaolo Bonzini return; 11828ecbaeeSPaolo Bonzini c->refcount--; 11928ecbaeeSPaolo Bonzini if (c->refcount) 12028ecbaeeSPaolo Bonzini return; 12128ecbaeeSPaolo Bonzini g_free(c); 12228ecbaeeSPaolo Bonzini } 12328ecbaeeSPaolo Bonzini 12428ecbaeeSPaolo Bonzini int cursor_get_mono_bpl(QEMUCursor *c) 12528ecbaeeSPaolo Bonzini { 126935b3332SMarc-André Lureau return DIV_ROUND_UP(c->width, 8); 12728ecbaeeSPaolo Bonzini } 12828ecbaeeSPaolo Bonzini 12928ecbaeeSPaolo Bonzini void cursor_set_mono(QEMUCursor *c, 13028ecbaeeSPaolo Bonzini uint32_t foreground, uint32_t background, uint8_t *image, 13128ecbaeeSPaolo Bonzini int transparent, uint8_t *mask) 13228ecbaeeSPaolo Bonzini { 13328ecbaeeSPaolo Bonzini uint32_t *data = c->data; 13428ecbaeeSPaolo Bonzini uint8_t bit; 13528ecbaeeSPaolo Bonzini int x,y,bpl; 13636ffc122SPeter Wu bool expand_bitmap_only = image == mask; 13736ffc122SPeter Wu bool has_inverted_colors = false; 13836ffc122SPeter Wu const uint32_t inverted = 0x80000000; 13928ecbaeeSPaolo Bonzini 14036ffc122SPeter Wu /* 14136ffc122SPeter Wu * Converts a monochrome bitmap with XOR mask 'image' and AND mask 'mask': 14236ffc122SPeter Wu * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/drawing-monochrome-pointers 14336ffc122SPeter Wu */ 14428ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 14528ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 14628ecbaeeSPaolo Bonzini bit = 0x80; 14728ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 14828ecbaeeSPaolo Bonzini if (transparent && mask[x/8] & bit) { 14936ffc122SPeter Wu if (!expand_bitmap_only && image[x / 8] & bit) { 15036ffc122SPeter Wu *data = inverted; 15136ffc122SPeter Wu has_inverted_colors = true; 15236ffc122SPeter Wu } else { 15328ecbaeeSPaolo Bonzini *data = 0x00000000; 15436ffc122SPeter Wu } 15528ecbaeeSPaolo Bonzini } else if (!transparent && !(mask[x/8] & bit)) { 15628ecbaeeSPaolo Bonzini *data = 0x00000000; 15728ecbaeeSPaolo Bonzini } else if (image[x/8] & bit) { 15828ecbaeeSPaolo Bonzini *data = 0xff000000 | foreground; 15928ecbaeeSPaolo Bonzini } else { 16028ecbaeeSPaolo Bonzini *data = 0xff000000 | background; 16128ecbaeeSPaolo Bonzini } 16228ecbaeeSPaolo Bonzini bit >>= 1; 16328ecbaeeSPaolo Bonzini if (bit == 0) { 16428ecbaeeSPaolo Bonzini bit = 0x80; 16528ecbaeeSPaolo Bonzini } 16628ecbaeeSPaolo Bonzini } 16728ecbaeeSPaolo Bonzini mask += bpl; 16828ecbaeeSPaolo Bonzini image += bpl; 16928ecbaeeSPaolo Bonzini } 17036ffc122SPeter Wu 17136ffc122SPeter Wu /* 17236ffc122SPeter Wu * If there are any pixels with inverted colors, create an outline (fill 17336ffc122SPeter Wu * transparent neighbors with the background color) and use the foreground 17436ffc122SPeter Wu * color as "inverted" color. 17536ffc122SPeter Wu */ 17636ffc122SPeter Wu if (has_inverted_colors) { 17736ffc122SPeter Wu data = c->data; 17836ffc122SPeter Wu for (y = 0; y < c->height; y++) { 17936ffc122SPeter Wu for (x = 0; x < c->width; x++, data++) { 18036ffc122SPeter Wu if (*data == 0 /* transparent */ && 18136ffc122SPeter Wu ((x > 0 && data[-1] == inverted) || 18236ffc122SPeter Wu (x + 1 < c->width && data[1] == inverted) || 18336ffc122SPeter Wu (y > 0 && data[-c->width] == inverted) || 18436ffc122SPeter Wu (y + 1 < c->height && data[c->width] == inverted))) { 18536ffc122SPeter Wu *data = 0xff000000 | background; 18636ffc122SPeter Wu } 18736ffc122SPeter Wu } 18836ffc122SPeter Wu } 18936ffc122SPeter Wu data = c->data; 19036ffc122SPeter Wu for (x = 0; x < c->width * c->height; x++, data++) { 19136ffc122SPeter Wu if (*data == inverted) { 19236ffc122SPeter Wu *data = 0xff000000 | foreground; 19336ffc122SPeter Wu } 19436ffc122SPeter Wu } 19536ffc122SPeter Wu } 19628ecbaeeSPaolo Bonzini } 19728ecbaeeSPaolo Bonzini 19828ecbaeeSPaolo Bonzini void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image) 19928ecbaeeSPaolo Bonzini { 20028ecbaeeSPaolo Bonzini uint32_t *data = c->data; 20128ecbaeeSPaolo Bonzini uint8_t bit; 20228ecbaeeSPaolo Bonzini int x,y,bpl; 20328ecbaeeSPaolo Bonzini 20428ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 20528ecbaeeSPaolo Bonzini memset(image, 0, bpl * c->height); 20628ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 20728ecbaeeSPaolo Bonzini bit = 0x80; 20828ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 20928ecbaeeSPaolo Bonzini if (((*data & 0xff000000) == 0xff000000) && 21028ecbaeeSPaolo Bonzini ((*data & 0x00ffffff) == foreground)) { 21128ecbaeeSPaolo Bonzini image[x/8] |= bit; 21228ecbaeeSPaolo Bonzini } 21328ecbaeeSPaolo Bonzini bit >>= 1; 21428ecbaeeSPaolo Bonzini if (bit == 0) { 21528ecbaeeSPaolo Bonzini bit = 0x80; 21628ecbaeeSPaolo Bonzini } 21728ecbaeeSPaolo Bonzini } 21828ecbaeeSPaolo Bonzini image += bpl; 21928ecbaeeSPaolo Bonzini } 22028ecbaeeSPaolo Bonzini } 22128ecbaeeSPaolo Bonzini 22228ecbaeeSPaolo Bonzini void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask) 22328ecbaeeSPaolo Bonzini { 22428ecbaeeSPaolo Bonzini uint32_t *data = c->data; 22528ecbaeeSPaolo Bonzini uint8_t bit; 22628ecbaeeSPaolo Bonzini int x,y,bpl; 22728ecbaeeSPaolo Bonzini 22828ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 22928ecbaeeSPaolo Bonzini memset(mask, 0, bpl * c->height); 23028ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 23128ecbaeeSPaolo Bonzini bit = 0x80; 23228ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 23328ecbaeeSPaolo Bonzini if ((*data & 0xff000000) != 0xff000000) { 23428ecbaeeSPaolo Bonzini if (transparent != 0) { 23528ecbaeeSPaolo Bonzini mask[x/8] |= bit; 23628ecbaeeSPaolo Bonzini } 23728ecbaeeSPaolo Bonzini } else { 23828ecbaeeSPaolo Bonzini if (transparent == 0) { 23928ecbaeeSPaolo Bonzini mask[x/8] |= bit; 24028ecbaeeSPaolo Bonzini } 24128ecbaeeSPaolo Bonzini } 24228ecbaeeSPaolo Bonzini bit >>= 1; 24328ecbaeeSPaolo Bonzini if (bit == 0) { 24428ecbaeeSPaolo Bonzini bit = 0x80; 24528ecbaeeSPaolo Bonzini } 24628ecbaeeSPaolo Bonzini } 24728ecbaeeSPaolo Bonzini mask += bpl; 24828ecbaeeSPaolo Bonzini } 24928ecbaeeSPaolo Bonzini } 250