diff mbox

[1/3] cursor: add cursor functions.

Message ID 1273063904-6028-2-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann May 5, 2010, 12:51 p.m. UTC
Add a new cursor type to console.h and a bunch of functions to
deal with cursors the (new) cursor.c file.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs |    3 +-
 console.h     |   24 ++++++-
 cursor.c      |  208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 232 insertions(+), 3 deletions(-)
 create mode 100644 cursor.c

Comments

Blue Swirl May 6, 2010, 6:12 p.m. UTC | #1
On 5/5/10, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Add a new cursor type to console.h and a bunch of functions to
>  deal with cursors the (new) cursor.c file.
>
>  Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>  ---
>   Makefile.objs |    3 +-
>   console.h     |   24 ++++++-
>   cursor.c      |  208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 232 insertions(+), 3 deletions(-)
>   create mode 100644 cursor.c
>
>  diff --git a/Makefile.objs b/Makefile.objs
>  index ecdd53e..1ee6e9d 100644
>  --- a/Makefile.objs
>  +++ b/Makefile.objs
>  @@ -48,7 +48,8 @@ common-obj-y = $(block-obj-y)
>   common-obj-y += $(net-obj-y)
>   common-obj-y += $(qobject-obj-y)
>   common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
>  -common-obj-y += readline.o console.o async.o qemu-error.o
>  +common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
>  +
>   common-obj-y += tcg-runtime.o host-utils.o
>   common-obj-y += irq.o ioport.o input.o
>   common-obj-$(CONFIG_PTIMER) += ptimer.o
>  diff --git a/console.h b/console.h
>  index 6def115..88861cb 100644
>  --- a/console.h
>  +++ b/console.h
>  @@ -126,6 +126,27 @@ struct DisplaySurface {
>      struct PixelFormat pf;
>   };
>
>  +/* cursor data format is 32bit RGBA */
>  +typedef struct QEMUCursor {
>  +    int                 width, height;
>  +    int                 hot_x, hot_y;
>  +    int                 refcount;
>  +    uint32_t            data[];
>  +} QEMUCursor;
>  +
>  +QEMUCursor *cursor_alloc(int width, int height);
>  +void cursor_get(QEMUCursor *c);
>  +void cursor_put(QEMUCursor *c);
>  +QEMUCursor *cursor_builtin_hidden(void);
>  +QEMUCursor *cursor_builtin_left_ptr(void);
>  +void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
>  +int cursor_get_mono_bpl(QEMUCursor *c);
>  +void cursor_set_mono(QEMUCursor *c,
>  +                     uint32_t foreground, uint32_t background, uint8_t *image,
>  +                     int transparent, uint8_t *mask);
>  +void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
>  +void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
>  +
>   struct DisplayChangeListener {
>      int idle;
>      uint64_t gui_timer_interval;
>  @@ -158,8 +179,7 @@ struct DisplayState {
>      struct DisplayChangeListener* listeners;
>
>      void (*mouse_set)(int x, int y, int on);
>  -    void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
>  -                          uint8_t *image, uint8_t *mask);
>  +    void (*cursor_define)(QEMUCursor *cursor);
>
>      struct DisplayState *next;
>   };
>  diff --git a/cursor.c b/cursor.c
>  new file mode 100644
>  index 0000000..3995a31
>  --- /dev/null
>  +++ b/cursor.c
>  @@ -0,0 +1,208 @@
>  +#include "qemu-common.h"
>  +#include "console.h"
>  +
>  +static const char cursor_hidden_32[32*32];
>  +static const char cursor_left_ptr_32[32*32] = {
>  +    "                                "
>  +    " X                              "
>  +    " XX                             "
>  +    " X.X                            "
>  +    " X..X                           "
>  +    " X...X                          "
>  +    " X....X                         "
>  +    " X.....X                        "
>  +    " X......X                       "
>  +    " X.......X                      "
>  +    " X........X                     "
>  +    " X.....XXXXX                    "
>  +    " X..X..X                        "
>  +    " X.X X..X                       "
>  +    " XX  X..X                       "
>  +    " X    X..X                      "
>  +    "      X..X                      "
>  +    "       X..X                     "
>  +    "       X..X                     "
>  +    "        XX                      "
>  +    "                                "
>  +};

Is this format standard? How about using X bitmap format instead:
$ cat /usr/include/X11/bitmaps/left_ptr
#define left_ptr_width 16
#define left_ptr_height 16
#define left_ptr_x_hot 3
#define left_ptr_y_hot 1
static char left_ptr_bits[] = {
   0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00,
   0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x07, 0xf8, 0x00, 0xd8, 0x00, 0x88, 0x01,
   0x80, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00};

Then there would be no need of parsing.

>  +
>  +/* for creating built-in cursors */
>  +static void cursor_parse_ascii_art(QEMUCursor *c, const char *ptr)
>  +{
>  +    int i, pixels;
>  +
>  +    pixels = c->width * c->height;
>  +    for (i = 0; i < pixels; i++) {
>  +        switch (ptr[i]) {
>  +        case 'X': /* black */
>  +            c->data[i] = 0xff000000;
>  +            break;
>  +        case '.': /* white */
>  +            c->data[i] = 0xffffffff;
>  +            break;
>  +        case ' ': /* transparent */
>  +        default:
>  +            c->data[i] = 0x00000000;
>  +            break;
>  +        }
>  +    }
>  +}
>  +
>  +/* nice for debugging */
>  +void cursor_print_ascii_art(QEMUCursor *c, const char *prefix)
>  +{
>  +    uint32_t *data = c->data;
>  +    int x,y;
>  +
>  +    for (y = 0; y < c->height; y++) {
>  +        fprintf(stderr, "%s: %2d: |", prefix, y);
>  +        for (x = 0; x < c->width; x++, data++) {
>  +            if ((*data & 0xff000000) != 0xff000000) {
>  +                fprintf(stderr, " "); /* transparent */
>  +            } else if ((*data & 0x00ffffff) == 0x00ffffff) {
>  +                fprintf(stderr, "."); /* white */
>  +            } else if ((*data & 0x00ffffff) == 0x00000000) {
>  +                fprintf(stderr, "X"); /* black */
>  +            } else {
>  +                fprintf(stderr, "o"); /* other */
>  +            }
>  +        }
>  +        fprintf(stderr, "|\n");
>  +    }
>  +}
>  +
>  +QEMUCursor *cursor_builtin_hidden(void)
>  +{
>  +    QEMUCursor *c;
>  +
>  +    c = cursor_alloc(32, 32);
>  +    cursor_parse_ascii_art(c, cursor_hidden_32);
>  +    return c;
>  +}
>  +
>  +QEMUCursor *cursor_builtin_left_ptr(void)
>  +{
>  +    QEMUCursor *c;
>  +
>  +    c = cursor_alloc(32, 32);
>  +    cursor_parse_ascii_art(c, cursor_left_ptr_32);
>  +    c->hot_x = 1;
>  +    c->hot_y = 1;
>  +    return c;
>  +}
>  +
>  +QEMUCursor *cursor_alloc(int width, int height)
>  +{
>  +    QEMUCursor *c;
>  +    int datasize = width * height * sizeof(uint32_t);
>  +
>  +    c = qemu_mallocz(sizeof(QEMUCursor) + datasize);
>  +    c->width  = width;
>  +    c->height = height;
>  +    c->refcount = 1;
>  +    return c;
>  +}
>  +
>  +void cursor_get(QEMUCursor *c)
>  +{
>  +    c->refcount++;
>  +}
>  +
>  +void cursor_put(QEMUCursor *c)
>  +{
>  +    if (c == NULL)
>  +        return;
>  +    c->refcount--;
>  +    if (c->refcount)
>  +        return;
>  +    qemu_free(c);
>  +}
>  +
>  +int cursor_get_mono_bpl(QEMUCursor *c)
>  +{
>  +    return (c->width + 7) / 8;
>  +}
>  +
>  +void cursor_set_mono(QEMUCursor *c,
>  +                     uint32_t foreground, uint32_t background, uint8_t *image,
>  +                     int transparent, uint8_t *mask)
>  +{
>  +    uint32_t *data = c->data;
>  +    uint8_t bit;
>  +    int x,y,bpl;
>  +
>  +    bpl = cursor_get_mono_bpl(c);
>  +    for (y = 0; y < c->height; y++) {
>  +        bit = 0x80;
>  +        for (x = 0; x < c->width; x++, data++) {
>  +            if (transparent && mask[x/8] & bit) {
>  +                *data = 0x00000000;
>  +            } else if (!transparent && !(mask[x/8] & bit)) {
>  +                *data = 0x00000000;
>  +            } else if (image[x/8] & bit) {
>  +                *data = 0xff000000 | foreground;
>  +            } else {
>  +                *data = 0xff000000 | background;
>  +            }
>  +            bit >>= 1;
>  +            if (bit == 0) {
>  +                bit = 0x80;
>  +            }
>  +        }
>  +        mask  += bpl;
>  +        image += bpl;
>  +    }
>  +}
>  +
>  +void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
>  +{
>  +    uint32_t *data = c->data;
>  +    uint8_t bit;
>  +    int x,y,bpl;
>  +
>  +    bpl = cursor_get_mono_bpl(c);
>  +    memset(image, 0, bpl * c->height);
>  +    for (y = 0; y < c->height; y++) {
>  +        bit = 0x80;
>  +        for (x = 0; x < c->width; x++, data++) {
>  +            if (((*data & 0xff000000) == 0xff000000) &&
>  +                ((*data & 0x00ffffff) == foreground)) {
>  +                image[x/8] |= bit;
>  +            }
>  +            bit >>= 1;
>  +            if (bit == 0) {
>  +                bit = 0x80;
>  +            }
>  +        }
>  +        image += bpl;
>  +    }
>  +}
>  +
>  +void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
>  +{
>  +    uint32_t *data = c->data;
>  +    uint8_t bit;
>  +    int x,y,bpl;
>  +
>  +    bpl = cursor_get_mono_bpl(c);
>  +    memset(mask, 0, bpl * c->height);
>  +    for (y = 0; y < c->height; y++) {
>  +        bit = 0x80;
>  +        for (x = 0; x < c->width; x++, data++) {
>  +            if ((*data & 0xff000000) != 0xff000000) {
>  +                if (transparent != 0) {
>  +                    mask[x/8] |= bit;
>  +                }
>  +            } else {
>  +                if (transparent == 0) {
>  +                    mask[x/8] |= bit;
>  +                }
>  +            }
>  +            bit >>= 1;
>  +            if (bit == 0) {
>  +                bit = 0x80;
>  +            }
>  +        }
>  +        mask += bpl;
>  +    }
>  +}
>
> --
>  1.6.6.1
>
>
>
>
Gerd Hoffmann May 6, 2010, 7:27 p.m. UTC | #2
>>   +static const char cursor_left_ptr_32[32*32] = {
>>   +    "                                "
>>   +    " X                              "
>>   +    " XX                             "
>>   +    " X.X                            "
>>   +    " X..X                           "
>>   +    " X...X                          "
>>   +    " X....X                         "
>>   +    " X.....X                        "
>>   +    " X......X                       "
>>   +    " X.......X                      "
>>   +    " X........X                     "
>>   +    " X.....XXXXX                    "
>>   +    " X..X..X                        "
>>   +    " X.X X..X                       "
>>   +    " XX  X..X                       "
>>   +    " X    X..X                      "
>>   +    "      X..X                      "
>>   +    "       X..X                     "
>>   +    "       X..X                     "
>>   +    "        XX                      "
>>   +    "                                "
>>   +};
>
> Is this format standard?

Inspiried by xpm but simplified a bit as full xpm support just for a 
built-in fallback cursor would have been overkill.  The nice thing about 
xpm is that you can use any text editor for editing icons.

> How about using X bitmap format instead:
> $ cat /usr/include/X11/bitmaps/left_ptr

> Then there would be no need of parsing.

Well.  You still would have to convert it as qemu internal cursor format 
is defined as 32bit depth, rgb with alpha channel.  So it doesn't buy 
you that much.

cheers,
   Gerd
Blue Swirl May 6, 2010, 7:42 p.m. UTC | #3
On 5/6/10, Gerd Hoffmann <kraxel@redhat.com> wrote:
> >
> > >  +static const char cursor_left_ptr_32[32*32] = {
> > >  +    "                                "
> > >  +    " X                              "
> > >  +    " XX                             "
> > >  +    " X.X                            "
> > >  +    " X..X                           "
> > >  +    " X...X                          "
> > >  +    " X....X                         "
> > >  +    " X.....X                        "
> > >  +    " X......X                       "
> > >  +    " X.......X                      "
> > >  +    " X........X                     "
> > >  +    " X.....XXXXX                    "
> > >  +    " X..X..X                        "
> > >  +    " X.X X..X                       "
> > >  +    " XX  X..X                       "
> > >  +    " X    X..X                      "
> > >  +    "      X..X                      "
> > >  +    "       X..X                     "
> > >  +    "       X..X                     "
> > >  +    "        XX                      "
> > >  +    "                                "
> > >  +};
> > >
> >
> > Is this format standard?
> >
>
>  Inspiried by xpm but simplified a bit as full xpm support just for a
> built-in fallback cursor would have been overkill.  The nice thing about xpm
> is that you can use any text editor for editing icons.

But for X bitmaps, you can use any real drawing program. The same
would also apply to full xpm. But read on.

> > How about using X bitmap format instead:
> > $ cat /usr/include/X11/bitmaps/left_ptr
> >
>
>
> > Then there would be no need of parsing.
> >
>
>  Well.  You still would have to convert it as qemu internal cursor format is
> defined as 32bit depth, rgb with alpha channel.  So it doesn't buy you that
> much.

There's still more wasted memory compared to binary format.

I think the best would be to store only the 32 bit image and perform
any conversions offline. This was the approach with for example
keyboard tables, we don't convert them at startup but the original
tables are retained as comments.
Paolo Bonzini May 7, 2010, 7:05 a.m. UTC | #4
On 05/06/2010 08:12 PM, Blue Swirl wrote:
> On 5/5/10, Gerd Hoffmann<kraxel@redhat.com>  wrote:
>> Add a new cursor type to console.h and a bunch of functions to
>>   deal with cursors the (new) cursor.c file.
>>
>>   Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
>>   ---
>>    Makefile.objs |    3 +-
>>    console.h     |   24 ++++++-
>>    cursor.c      |  208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>    3 files changed, 232 insertions(+), 3 deletions(-)
>>    create mode 100644 cursor.c
>>
>>   diff --git a/Makefile.objs b/Makefile.objs
>>   index ecdd53e..1ee6e9d 100644
>>   --- a/Makefile.objs
>>   +++ b/Makefile.objs
>>   @@ -48,7 +48,8 @@ common-obj-y = $(block-obj-y)
>>    common-obj-y += $(net-obj-y)
>>    common-obj-y += $(qobject-obj-y)
>>    common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
>>   -common-obj-y += readline.o console.o async.o qemu-error.o
>>   +common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
>>   +
>>    common-obj-y += tcg-runtime.o host-utils.o
>>    common-obj-y += irq.o ioport.o input.o
>>    common-obj-$(CONFIG_PTIMER) += ptimer.o
>>   diff --git a/console.h b/console.h
>>   index 6def115..88861cb 100644
>>   --- a/console.h
>>   +++ b/console.h
>>   @@ -126,6 +126,27 @@ struct DisplaySurface {
>>       struct PixelFormat pf;
>>    };
>>
>>   +/* cursor data format is 32bit RGBA */
>>   +typedef struct QEMUCursor {
>>   +    int                 width, height;
>>   +    int                 hot_x, hot_y;
>>   +    int                 refcount;
>>   +    uint32_t            data[];
>>   +} QEMUCursor;
>>   +
>>   +QEMUCursor *cursor_alloc(int width, int height);
>>   +void cursor_get(QEMUCursor *c);
>>   +void cursor_put(QEMUCursor *c);
>>   +QEMUCursor *cursor_builtin_hidden(void);
>>   +QEMUCursor *cursor_builtin_left_ptr(void);
>>   +void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
>>   +int cursor_get_mono_bpl(QEMUCursor *c);
>>   +void cursor_set_mono(QEMUCursor *c,
>>   +                     uint32_t foreground, uint32_t background, uint8_t *image,
>>   +                     int transparent, uint8_t *mask);
>>   +void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
>>   +void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
>>   +
>>    struct DisplayChangeListener {
>>       int idle;
>>       uint64_t gui_timer_interval;
>>   @@ -158,8 +179,7 @@ struct DisplayState {
>>       struct DisplayChangeListener* listeners;
>>
>>       void (*mouse_set)(int x, int y, int on);
>>   -    void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
>>   -                          uint8_t *image, uint8_t *mask);
>>   +    void (*cursor_define)(QEMUCursor *cursor);
>>
>>       struct DisplayState *next;
>>    };
>>   diff --git a/cursor.c b/cursor.c
>>   new file mode 100644
>>   index 0000000..3995a31
>>   --- /dev/null
>>   +++ b/cursor.c
>>   @@ -0,0 +1,208 @@
>>   +#include "qemu-common.h"
>>   +#include "console.h"
>>   +
>>   +static const char cursor_hidden_32[32*32];
>>   +static const char cursor_left_ptr_32[32*32] = {
>>   +    "                                "
>>   +    " X                              "
>>   +    " XX                             "
>>   +    " X.X                            "
>>   +    " X..X                           "
>>   +    " X...X                          "
>>   +    " X....X                         "
>>   +    " X.....X                        "
>>   +    " X......X                       "
>>   +    " X.......X                      "
>>   +    " X........X                     "
>>   +    " X.....XXXXX                    "
>>   +    " X..X..X                        "
>>   +    " X.X X..X                       "
>>   +    " XX  X..X                       "
>>   +    " X    X..X                      "
>>   +    "      X..X                      "
>>   +    "       X..X                     "
>>   +    "       X..X                     "
>>   +    "        XX                      "
>>   +    "                                "
>>   +};
>
> Is this format standard? How about using X bitmap format instead:
> $ cat /usr/include/X11/bitmaps/left_ptr
> #define left_ptr_width 16
> #define left_ptr_height 16
> #define left_ptr_x_hot 3
> #define left_ptr_y_hot 1
> static char left_ptr_bits[] = {
>     0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00,
>     0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x07, 0xf8, 0x00, 0xd8, 0x00, 0x88, 0x01,
>     0x80, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00};
>
> Then there would be no need of parsing.

You would need _two_ bitmaps (e.g. mask and cursor, so that mask=1 gives 
transparent, mask=0 cursor=0 gives black and mask=0 cursor=1 gives white).

Paolo
Blue Swirl May 7, 2010, 3:23 p.m. UTC | #5
On 5/7/10, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 05/06/2010 08:12 PM, Blue Swirl wrote:
>
> > On 5/5/10, Gerd Hoffmann<kraxel@redhat.com>  wrote:
> >
> > > Add a new cursor type to console.h and a bunch of functions to
> > >  deal with cursors the (new) cursor.c file.
> > >
> > >  Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> > >  ---
> > >   Makefile.objs |    3 +-
> > >   console.h     |   24 ++++++-
> > >   cursor.c      |  208
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >   3 files changed, 232 insertions(+), 3 deletions(-)
> > >   create mode 100644 cursor.c
> > >
> > >  diff --git a/Makefile.objs b/Makefile.objs
> > >  index ecdd53e..1ee6e9d 100644
> > >  --- a/Makefile.objs
> > >  +++ b/Makefile.objs
> > >  @@ -48,7 +48,8 @@ common-obj-y = $(block-obj-y)
> > >   common-obj-y += $(net-obj-y)
> > >   common-obj-y += $(qobject-obj-y)
> > >   common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
> > >  -common-obj-y += readline.o console.o async.o qemu-error.o
> > >  +common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
> > >  +
> > >   common-obj-y += tcg-runtime.o host-utils.o
> > >   common-obj-y += irq.o ioport.o input.o
> > >   common-obj-$(CONFIG_PTIMER) += ptimer.o
> > >  diff --git a/console.h b/console.h
> > >  index 6def115..88861cb 100644
> > >  --- a/console.h
> > >  +++ b/console.h
> > >  @@ -126,6 +126,27 @@ struct DisplaySurface {
> > >      struct PixelFormat pf;
> > >   };
> > >
> > >  +/* cursor data format is 32bit RGBA */
> > >  +typedef struct QEMUCursor {
> > >  +    int                 width, height;
> > >  +    int                 hot_x, hot_y;
> > >  +    int                 refcount;
> > >  +    uint32_t            data[];
> > >  +} QEMUCursor;
> > >  +
> > >  +QEMUCursor *cursor_alloc(int width, int height);
> > >  +void cursor_get(QEMUCursor *c);
> > >  +void cursor_put(QEMUCursor *c);
> > >  +QEMUCursor *cursor_builtin_hidden(void);
> > >  +QEMUCursor *cursor_builtin_left_ptr(void);
> > >  +void cursor_print_ascii_art(QEMUCursor *c, const char
> *prefix);
> > >  +int cursor_get_mono_bpl(QEMUCursor *c);
> > >  +void cursor_set_mono(QEMUCursor *c,
> > >  +                     uint32_t foreground, uint32_t background, uint8_t
> *image,
> > >  +                     int transparent, uint8_t *mask);
> > >  +void cursor_get_mono_image(QEMUCursor *c, int
> foreground, uint8_t *mask);
> > >  +void cursor_get_mono_mask(QEMUCursor *c, int
> transparent, uint8_t *mask);
> > >  +
> > >   struct DisplayChangeListener {
> > >      int idle;
> > >      uint64_t gui_timer_interval;
> > >  @@ -158,8 +179,7 @@ struct DisplayState {
> > >      struct DisplayChangeListener* listeners;
> > >
> > >      void (*mouse_set)(int x, int y, int on);
> > >  -    void (*cursor_define)(int width, int height, int bpp, int hot_x,
> int hot_y,
> > >  -                          uint8_t *image, uint8_t *mask);
> > >  +    void (*cursor_define)(QEMUCursor *cursor);
> > >
> > >      struct DisplayState *next;
> > >   };
> > >  diff --git a/cursor.c b/cursor.c
> > >  new file mode 100644
> > >  index 0000000..3995a31
> > >  --- /dev/null
> > >  +++ b/cursor.c
> > >  @@ -0,0 +1,208 @@
> > >  +#include "qemu-common.h"
> > >  +#include "console.h"
> > >  +
> > >  +static const char cursor_hidden_32[32*32];
> > >  +static const char cursor_left_ptr_32[32*32] = {
> > >  +    "                                "
> > >  +    " X                              "
> > >  +    " XX                             "
> > >  +    " X.X                            "
> > >  +    " X..X                           "
> > >  +    " X...X                          "
> > >  +    " X....X                         "
> > >  +    " X.....X                        "
> > >  +    " X......X                       "
> > >  +    " X.......X                      "
> > >  +    " X........X                     "
> > >  +    " X.....XXXXX                    "
> > >  +    " X..X..X                        "
> > >  +    " X.X X..X                       "
> > >  +    " XX  X..X                       "
> > >  +    " X    X..X                      "
> > >  +    "      X..X                      "
> > >  +    "       X..X                     "
> > >  +    "       X..X                     "
> > >  +    "        XX                      "
> > >  +    "                                "
> > >  +};
> > >
> >
> > Is this format standard? How about using X bitmap format instead:
> > $ cat /usr/include/X11/bitmaps/left_ptr
> > #define left_ptr_width 16
> > #define left_ptr_height 16
> > #define left_ptr_x_hot 3
> > #define left_ptr_y_hot 1
> > static char left_ptr_bits[] = {
> >    0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00,
> >    0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x07, 0xf8, 0x00, 0xd8, 0x00, 0x88, 0x01,
> >    0x80, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00};
> >
> > Then there would be no need of parsing.
> >
>
>  You would need _two_ bitmaps (e.g. mask and cursor, so that mask=1 gives
> transparent, mask=0 cursor=0 gives black and mask=0 cursor=1 gives white).

Yes, but it's still packed more efficiently.

There's yet another way:
#define _ 0,
#define X 0xff000000,
#define o 0xffffffff,
{
 _ _ _ X o X _ _ _
}
#undef _
#undef X
#undef o

This would not allow any drawing tool use, but there are no
conversions at startup.
Gerd Hoffmann May 19, 2010, 8:16 a.m. UTC | #6
>>> Then there would be no need of parsing.
>>
>>   You would need _two_ bitmaps (e.g. mask and cursor, so that mask=1 gives
>> transparent, mask=0 cursor=0 gives black and mask=0 cursor=1 gives white).
>
> Yes, but it's still packed more efficiently.

Well.  You can't have both.  We can have a efficiently packed format 
(i.e. two bitmaps).  Or we can do it in a way which doesn't need 
parsing, but that wouldn't be the most compact format ...

> There's yet another way:
> #define _ 0,
> #define X 0xff000000,
> #define o 0xffffffff,
> {
>   _ _ _ X o X _ _ _
> }
> #undef _
> #undef X
> #undef o

Neat idea ;)

cheers,
   Gerd
Blue Swirl May 19, 2010, 6:57 p.m. UTC | #7
On 5/19/10, Gerd Hoffmann <kraxel@redhat.com> wrote:
> >
> > >
> > > > Then there would be no need of parsing.
> > > >
> > >
> > >  You would need _two_ bitmaps (e.g. mask and cursor, so that mask=1
> gives
> > > transparent, mask=0 cursor=0 gives black and mask=0 cursor=1 gives
> white).
> > >
> >
> > Yes, but it's still packed more efficiently.
> >
>
>  Well.  You can't have both.  We can have a efficiently packed format (i.e.
> two bitmaps).  Or we can do it in a way which doesn't need parsing, but that
> wouldn't be the most compact format ...

You're right, so packing or introducing a small conversion function is
not critical. I'd still prefer a standard format if possible.

> > There's yet another way:
> > #define _ 0,
> > #define X 0xff000000,
> > #define o 0xffffffff,
> > {
> >  _ _ _ X o X _ _ _
> > }
> > #undef _
> > #undef X
> > #undef o
> >
>
>  Neat idea ;)
>
>  cheers,
>   Gerd
>
>
Anthony Liguori May 19, 2010, 7:08 p.m. UTC | #8
On 05/19/2010 01:57 PM, Blue Swirl wrote:
> On 5/19/10, Gerd Hoffmann<kraxel@redhat.com>  wrote:
>    
>>>        
>>>>          
>>>>> Then there would be no need of parsing.
>>>>>
>>>>>            
>>>>   You would need _two_ bitmaps (e.g. mask and cursor, so that mask=1
>>>>          
>> gives
>>      
>>>> transparent, mask=0 cursor=0 gives black and mask=0 cursor=1 gives
>>>>          
>> white).
>>      
>>>>          
>>> Yes, but it's still packed more efficiently.
>>>
>>>        
>>   Well.  You can't have both.  We can have a efficiently packed format (i.e.
>> two bitmaps).  Or we can do it in a way which doesn't need parsing, but that
>> wouldn't be the most compact format ...
>>      
> You're right, so packing or introducing a small conversion function is
> not critical. I'd still prefer a standard format if possible.
>    

Personally, I'd rather see Gerd's original format but read from a file 
instead of hard coded in a .c file.  IOW, a 
/usr/share/qemu/default-cursor.qpm that contained the appropriate 
strings.  A couple extra lines that made it an xpm I think would be 
worth it too.

Regards,

Anthony Liguori

>>> There's yet another way:
>>> #define _ 0,
>>> #define X 0xff000000,
>>> #define o 0xffffffff,
>>> {
>>>   _ _ _ X o X _ _ _
>>> }
>>> #undef _
>>> #undef X
>>> #undef o
>>>
>>>        
>>   Neat idea ;)
>>
>>   cheers,
>>    Gerd
>>
>>
>>      
>
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index ecdd53e..1ee6e9d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -48,7 +48,8 @@  common-obj-y = $(block-obj-y)
 common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
-common-obj-y += readline.o console.o async.o qemu-error.o
+common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
+
 common-obj-y += tcg-runtime.o host-utils.o
 common-obj-y += irq.o ioport.o input.o
 common-obj-$(CONFIG_PTIMER) += ptimer.o
diff --git a/console.h b/console.h
index 6def115..88861cb 100644
--- a/console.h
+++ b/console.h
@@ -126,6 +126,27 @@  struct DisplaySurface {
     struct PixelFormat pf;
 };
 
+/* cursor data format is 32bit RGBA */
+typedef struct QEMUCursor {
+    int                 width, height;
+    int                 hot_x, hot_y;
+    int                 refcount;
+    uint32_t            data[];
+} QEMUCursor;
+
+QEMUCursor *cursor_alloc(int width, int height);
+void cursor_get(QEMUCursor *c);
+void cursor_put(QEMUCursor *c);
+QEMUCursor *cursor_builtin_hidden(void);
+QEMUCursor *cursor_builtin_left_ptr(void);
+void cursor_print_ascii_art(QEMUCursor *c, const char *prefix);
+int cursor_get_mono_bpl(QEMUCursor *c);
+void cursor_set_mono(QEMUCursor *c,
+                     uint32_t foreground, uint32_t background, uint8_t *image,
+                     int transparent, uint8_t *mask);
+void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
+void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
+
 struct DisplayChangeListener {
     int idle;
     uint64_t gui_timer_interval;
@@ -158,8 +179,7 @@  struct DisplayState {
     struct DisplayChangeListener* listeners;
 
     void (*mouse_set)(int x, int y, int on);
-    void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
-                          uint8_t *image, uint8_t *mask);
+    void (*cursor_define)(QEMUCursor *cursor);
 
     struct DisplayState *next;
 };
diff --git a/cursor.c b/cursor.c
new file mode 100644
index 0000000..3995a31
--- /dev/null
+++ b/cursor.c
@@ -0,0 +1,208 @@ 
+#include "qemu-common.h"
+#include "console.h"
+
+static const char cursor_hidden_32[32*32];
+static const char cursor_left_ptr_32[32*32] = {
+    "                                "
+    " X                              "
+    " XX                             "
+    " X.X                            "
+    " X..X                           "
+    " X...X                          "
+    " X....X                         "
+    " X.....X                        "
+    " X......X                       "
+    " X.......X                      "
+    " X........X                     "
+    " X.....XXXXX                    "
+    " X..X..X                        "
+    " X.X X..X                       "
+    " XX  X..X                       "
+    " X    X..X                      "
+    "      X..X                      "
+    "       X..X                     "
+    "       X..X                     "
+    "        XX                      "
+    "                                "
+};
+
+/* for creating built-in cursors */
+static void cursor_parse_ascii_art(QEMUCursor *c, const char *ptr)
+{
+    int i, pixels;
+
+    pixels = c->width * c->height;
+    for (i = 0; i < pixels; i++) {
+        switch (ptr[i]) {
+        case 'X': /* black */
+            c->data[i] = 0xff000000;
+            break;
+        case '.': /* white */
+            c->data[i] = 0xffffffff;
+            break;
+        case ' ': /* transparent */
+        default:
+            c->data[i] = 0x00000000;
+            break;
+        }
+    }
+}
+
+/* nice for debugging */
+void cursor_print_ascii_art(QEMUCursor *c, const char *prefix)
+{
+    uint32_t *data = c->data;
+    int x,y;
+
+    for (y = 0; y < c->height; y++) {
+        fprintf(stderr, "%s: %2d: |", prefix, y);
+        for (x = 0; x < c->width; x++, data++) {
+            if ((*data & 0xff000000) != 0xff000000) {
+                fprintf(stderr, " "); /* transparent */
+            } else if ((*data & 0x00ffffff) == 0x00ffffff) {
+                fprintf(stderr, "."); /* white */
+            } else if ((*data & 0x00ffffff) == 0x00000000) {
+                fprintf(stderr, "X"); /* black */
+            } else {
+                fprintf(stderr, "o"); /* other */
+            }
+        }
+        fprintf(stderr, "|\n");
+    }
+}
+
+QEMUCursor *cursor_builtin_hidden(void)
+{
+    QEMUCursor *c;
+
+    c = cursor_alloc(32, 32);
+    cursor_parse_ascii_art(c, cursor_hidden_32);
+    return c;
+}
+
+QEMUCursor *cursor_builtin_left_ptr(void)
+{
+    QEMUCursor *c;
+
+    c = cursor_alloc(32, 32);
+    cursor_parse_ascii_art(c, cursor_left_ptr_32);
+    c->hot_x = 1;
+    c->hot_y = 1;
+    return c;
+}
+
+QEMUCursor *cursor_alloc(int width, int height)
+{
+    QEMUCursor *c;
+    int datasize = width * height * sizeof(uint32_t);
+
+    c = qemu_mallocz(sizeof(QEMUCursor) + datasize);
+    c->width  = width;
+    c->height = height;
+    c->refcount = 1;
+    return c;
+}
+
+void cursor_get(QEMUCursor *c)
+{
+    c->refcount++;
+}
+
+void cursor_put(QEMUCursor *c)
+{
+    if (c == NULL)
+        return;
+    c->refcount--;
+    if (c->refcount)
+        return;
+    qemu_free(c);
+}
+
+int cursor_get_mono_bpl(QEMUCursor *c)
+{
+    return (c->width + 7) / 8;
+}
+
+void cursor_set_mono(QEMUCursor *c,
+                     uint32_t foreground, uint32_t background, uint8_t *image,
+                     int transparent, uint8_t *mask)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if (transparent && mask[x/8] & bit) {
+                *data = 0x00000000;
+            } else if (!transparent && !(mask[x/8] & bit)) {
+                *data = 0x00000000;
+            } else if (image[x/8] & bit) {
+                *data = 0xff000000 | foreground;
+            } else {
+                *data = 0xff000000 | background;
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        mask  += bpl;
+        image += bpl;
+    }
+}
+
+void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    memset(image, 0, bpl * c->height);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if (((*data & 0xff000000) == 0xff000000) &&
+                ((*data & 0x00ffffff) == foreground)) {
+                image[x/8] |= bit;
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        image += bpl;
+    }
+}
+
+void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
+{
+    uint32_t *data = c->data;
+    uint8_t bit;
+    int x,y,bpl;
+
+    bpl = cursor_get_mono_bpl(c);
+    memset(mask, 0, bpl * c->height);
+    for (y = 0; y < c->height; y++) {
+        bit = 0x80;
+        for (x = 0; x < c->width; x++, data++) {
+            if ((*data & 0xff000000) != 0xff000000) {
+                if (transparent != 0) {
+                    mask[x/8] |= bit;
+                }
+            } else {
+                if (transparent == 0) {
+                    mask[x/8] |= bit;
+                }
+            }
+            bit >>= 1;
+            if (bit == 0) {
+                bit = 0x80;
+            }
+        }
+        mask += bpl;
+    }
+}