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 109*2512a026SMarc-André Lureau QEMUCursor *cursor_ref(QEMUCursor *c) 11028ecbaeeSPaolo Bonzini { 11128ecbaeeSPaolo Bonzini c->refcount++; 112*2512a026SMarc-André Lureau return c; 11328ecbaeeSPaolo Bonzini } 11428ecbaeeSPaolo Bonzini 115f4579e28SMarc-André Lureau void cursor_unref(QEMUCursor *c) 11628ecbaeeSPaolo Bonzini { 11728ecbaeeSPaolo Bonzini if (c == NULL) 11828ecbaeeSPaolo Bonzini return; 11928ecbaeeSPaolo Bonzini c->refcount--; 12028ecbaeeSPaolo Bonzini if (c->refcount) 12128ecbaeeSPaolo Bonzini return; 12228ecbaeeSPaolo Bonzini g_free(c); 12328ecbaeeSPaolo Bonzini } 12428ecbaeeSPaolo Bonzini 12528ecbaeeSPaolo Bonzini int cursor_get_mono_bpl(QEMUCursor *c) 12628ecbaeeSPaolo Bonzini { 127935b3332SMarc-André Lureau return DIV_ROUND_UP(c->width, 8); 12828ecbaeeSPaolo Bonzini } 12928ecbaeeSPaolo Bonzini 13028ecbaeeSPaolo Bonzini void cursor_set_mono(QEMUCursor *c, 13128ecbaeeSPaolo Bonzini uint32_t foreground, uint32_t background, uint8_t *image, 13228ecbaeeSPaolo Bonzini int transparent, uint8_t *mask) 13328ecbaeeSPaolo Bonzini { 13428ecbaeeSPaolo Bonzini uint32_t *data = c->data; 13528ecbaeeSPaolo Bonzini uint8_t bit; 13628ecbaeeSPaolo Bonzini int x,y,bpl; 13736ffc122SPeter Wu bool expand_bitmap_only = image == mask; 13836ffc122SPeter Wu bool has_inverted_colors = false; 13936ffc122SPeter Wu const uint32_t inverted = 0x80000000; 14028ecbaeeSPaolo Bonzini 14136ffc122SPeter Wu /* 14236ffc122SPeter Wu * Converts a monochrome bitmap with XOR mask 'image' and AND mask 'mask': 14336ffc122SPeter Wu * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/drawing-monochrome-pointers 14436ffc122SPeter Wu */ 14528ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 14628ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 14728ecbaeeSPaolo Bonzini bit = 0x80; 14828ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 14928ecbaeeSPaolo Bonzini if (transparent && mask[x/8] & bit) { 15036ffc122SPeter Wu if (!expand_bitmap_only && image[x / 8] & bit) { 15136ffc122SPeter Wu *data = inverted; 15236ffc122SPeter Wu has_inverted_colors = true; 15336ffc122SPeter Wu } else { 15428ecbaeeSPaolo Bonzini *data = 0x00000000; 15536ffc122SPeter Wu } 15628ecbaeeSPaolo Bonzini } else if (!transparent && !(mask[x/8] & bit)) { 15728ecbaeeSPaolo Bonzini *data = 0x00000000; 15828ecbaeeSPaolo Bonzini } else if (image[x/8] & bit) { 15928ecbaeeSPaolo Bonzini *data = 0xff000000 | foreground; 16028ecbaeeSPaolo Bonzini } else { 16128ecbaeeSPaolo Bonzini *data = 0xff000000 | background; 16228ecbaeeSPaolo Bonzini } 16328ecbaeeSPaolo Bonzini bit >>= 1; 16428ecbaeeSPaolo Bonzini if (bit == 0) { 16528ecbaeeSPaolo Bonzini bit = 0x80; 16628ecbaeeSPaolo Bonzini } 16728ecbaeeSPaolo Bonzini } 16828ecbaeeSPaolo Bonzini mask += bpl; 16928ecbaeeSPaolo Bonzini image += bpl; 17028ecbaeeSPaolo Bonzini } 17136ffc122SPeter Wu 17236ffc122SPeter Wu /* 17336ffc122SPeter Wu * If there are any pixels with inverted colors, create an outline (fill 17436ffc122SPeter Wu * transparent neighbors with the background color) and use the foreground 17536ffc122SPeter Wu * color as "inverted" color. 17636ffc122SPeter Wu */ 17736ffc122SPeter Wu if (has_inverted_colors) { 17836ffc122SPeter Wu data = c->data; 17936ffc122SPeter Wu for (y = 0; y < c->height; y++) { 18036ffc122SPeter Wu for (x = 0; x < c->width; x++, data++) { 18136ffc122SPeter Wu if (*data == 0 /* transparent */ && 18236ffc122SPeter Wu ((x > 0 && data[-1] == inverted) || 18336ffc122SPeter Wu (x + 1 < c->width && data[1] == inverted) || 18436ffc122SPeter Wu (y > 0 && data[-c->width] == inverted) || 18536ffc122SPeter Wu (y + 1 < c->height && data[c->width] == inverted))) { 18636ffc122SPeter Wu *data = 0xff000000 | background; 18736ffc122SPeter Wu } 18836ffc122SPeter Wu } 18936ffc122SPeter Wu } 19036ffc122SPeter Wu data = c->data; 19136ffc122SPeter Wu for (x = 0; x < c->width * c->height; x++, data++) { 19236ffc122SPeter Wu if (*data == inverted) { 19336ffc122SPeter Wu *data = 0xff000000 | foreground; 19436ffc122SPeter Wu } 19536ffc122SPeter Wu } 19636ffc122SPeter Wu } 19728ecbaeeSPaolo Bonzini } 19828ecbaeeSPaolo Bonzini 19928ecbaeeSPaolo Bonzini void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image) 20028ecbaeeSPaolo Bonzini { 20128ecbaeeSPaolo Bonzini uint32_t *data = c->data; 20228ecbaeeSPaolo Bonzini uint8_t bit; 20328ecbaeeSPaolo Bonzini int x,y,bpl; 20428ecbaeeSPaolo Bonzini 20528ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 20628ecbaeeSPaolo Bonzini memset(image, 0, bpl * c->height); 20728ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 20828ecbaeeSPaolo Bonzini bit = 0x80; 20928ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 21028ecbaeeSPaolo Bonzini if (((*data & 0xff000000) == 0xff000000) && 21128ecbaeeSPaolo Bonzini ((*data & 0x00ffffff) == foreground)) { 21228ecbaeeSPaolo Bonzini image[x/8] |= bit; 21328ecbaeeSPaolo Bonzini } 21428ecbaeeSPaolo Bonzini bit >>= 1; 21528ecbaeeSPaolo Bonzini if (bit == 0) { 21628ecbaeeSPaolo Bonzini bit = 0x80; 21728ecbaeeSPaolo Bonzini } 21828ecbaeeSPaolo Bonzini } 21928ecbaeeSPaolo Bonzini image += bpl; 22028ecbaeeSPaolo Bonzini } 22128ecbaeeSPaolo Bonzini } 22228ecbaeeSPaolo Bonzini 22328ecbaeeSPaolo Bonzini void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask) 22428ecbaeeSPaolo Bonzini { 22528ecbaeeSPaolo Bonzini uint32_t *data = c->data; 22628ecbaeeSPaolo Bonzini uint8_t bit; 22728ecbaeeSPaolo Bonzini int x,y,bpl; 22828ecbaeeSPaolo Bonzini 22928ecbaeeSPaolo Bonzini bpl = cursor_get_mono_bpl(c); 23028ecbaeeSPaolo Bonzini memset(mask, 0, bpl * c->height); 23128ecbaeeSPaolo Bonzini for (y = 0; y < c->height; y++) { 23228ecbaeeSPaolo Bonzini bit = 0x80; 23328ecbaeeSPaolo Bonzini for (x = 0; x < c->width; x++, data++) { 23428ecbaeeSPaolo Bonzini if ((*data & 0xff000000) != 0xff000000) { 23528ecbaeeSPaolo Bonzini if (transparent != 0) { 23628ecbaeeSPaolo Bonzini mask[x/8] |= bit; 23728ecbaeeSPaolo Bonzini } 23828ecbaeeSPaolo Bonzini } else { 23928ecbaeeSPaolo Bonzini if (transparent == 0) { 24028ecbaeeSPaolo Bonzini mask[x/8] |= bit; 24128ecbaeeSPaolo Bonzini } 24228ecbaeeSPaolo Bonzini } 24328ecbaeeSPaolo Bonzini bit >>= 1; 24428ecbaeeSPaolo Bonzini if (bit == 0) { 24528ecbaeeSPaolo Bonzini bit = 0x80; 24628ecbaeeSPaolo Bonzini } 24728ecbaeeSPaolo Bonzini } 24828ecbaeeSPaolo Bonzini mask += bpl; 24928ecbaeeSPaolo Bonzini } 25028ecbaeeSPaolo Bonzini } 251