diff options
Diffstat (limited to 'include/ui')
-rw-r--r-- | include/ui/clipboard.h | 226 | ||||
-rw-r--r-- | include/ui/console.h | 487 | ||||
-rw-r--r-- | include/ui/egl-context.h | 13 | ||||
-rw-r--r-- | include/ui/egl-helpers.h | 66 | ||||
-rw-r--r-- | include/ui/gtk.h | 224 | ||||
-rw-r--r-- | include/ui/input.h | 120 | ||||
-rw-r--r-- | include/ui/kbd-state.h | 102 | ||||
-rw-r--r-- | include/ui/pixel_ops.h | 53 | ||||
-rw-r--r-- | include/ui/qemu-pixman.h | 92 | ||||
-rw-r--r-- | include/ui/qemu-spice-module.h | 44 | ||||
-rw-r--r-- | include/ui/qemu-spice.h | 61 | ||||
-rw-r--r-- | include/ui/sdl2.h | 85 | ||||
-rw-r--r-- | include/ui/shader.h | 13 | ||||
-rw-r--r-- | include/ui/spice-display.h | 190 | ||||
-rw-r--r-- | include/ui/win32-kbd-hook.h | 14 |
15 files changed, 1790 insertions, 0 deletions
diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h new file mode 100644 index 000000000..6298986b1 --- /dev/null +++ b/include/ui/clipboard.h @@ -0,0 +1,226 @@ +#ifndef QEMU_CLIPBOARD_H +#define QEMU_CLIPBOARD_H + +#include "qemu/notify.h" + +/** + * DOC: Introduction + * + * The header ``ui/clipboard.h`` declares the qemu clipboard interface. + * + * All qemu elements which want use the clipboard can register as + * clipboard peer. Subsequently they can set the clipboard content + * and get notifications for clipboard updates. + * + * Typical users are user interfaces (gtk), remote access protocols + * (vnc) and devices talking to the guest (vdagent). + * + * Even though the design allows different data types only plain text + * is supported for now. + */ + +typedef enum QemuClipboardType QemuClipboardType; +typedef enum QemuClipboardSelection QemuClipboardSelection; +typedef struct QemuClipboardPeer QemuClipboardPeer; +typedef struct QemuClipboardInfo QemuClipboardInfo; + +/** + * enum QemuClipboardType + * + * @QEMU_CLIPBOARD_TYPE_TEXT: text/plain; charset=utf-8 + * @QEMU_CLIPBOARD_TYPE__COUNT: type count. + */ +enum QemuClipboardType { + QEMU_CLIPBOARD_TYPE_TEXT, + QEMU_CLIPBOARD_TYPE__COUNT, +}; + +/* same as VD_AGENT_CLIPBOARD_SELECTION_* */ +/** + * enum QemuClipboardSelection + * + * @QEMU_CLIPBOARD_SELECTION_CLIPBOARD: clipboard (explitcit cut+paste). + * @QEMU_CLIPBOARD_SELECTION_PRIMARY: primary selection (select + middle mouse button). + * @QEMU_CLIPBOARD_SELECTION_SECONDARY: secondary selection (dunno). + * @QEMU_CLIPBOARD_SELECTION__COUNT: selection count. + */ +enum QemuClipboardSelection { + QEMU_CLIPBOARD_SELECTION_CLIPBOARD, + QEMU_CLIPBOARD_SELECTION_PRIMARY, + QEMU_CLIPBOARD_SELECTION_SECONDARY, + QEMU_CLIPBOARD_SELECTION__COUNT, +}; + +/** + * struct QemuClipboardPeer + * + * @name: peer name. + * @update: notifier for clipboard updates. + * @request: callback for clipboard data requests. + * + * Clipboard peer description. + */ +struct QemuClipboardPeer { + const char *name; + Notifier update; + void (*request)(QemuClipboardInfo *info, + QemuClipboardType type); +}; + +/** + * struct QemuClipboardInfo + * + * @refcount: reference counter. + * @owner: clipboard owner. + * @selection: clipboard selection. + * @types: clipboard data array (one entry per type). + * + * Clipboard content data and metadata. + */ +struct QemuClipboardInfo { + uint32_t refcount; + QemuClipboardPeer *owner; + QemuClipboardSelection selection; + struct { + bool available; + bool requested; + size_t size; + void *data; + } types[QEMU_CLIPBOARD_TYPE__COUNT]; +}; + +/** + * qemu_clipboard_peer_register + * + * @peer: peer information. + * + * Register clipboard peer. Registering is needed for both active + * (set+grab clipboard) and passive (watch clipboard for updates) + * interaction with the qemu clipboard. + */ +void qemu_clipboard_peer_register(QemuClipboardPeer *peer); + +/** + * qemu_clipboard_peer_unregister + * + * @peer: peer information. + * + * Unregister clipboard peer. + */ +void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer); + +/** + * qemu_clipboard_peer_owns + * + * @peer: peer information. + * @selection: clipboard selection. + * + * Return TRUE if the peer owns the clipboard. + */ +bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer, + QemuClipboardSelection selection); + +/** + * qemu_clipboard_peer_release + * + * @peer: peer information. + * @selection: clipboard selection. + * + * If the peer owns the clipboard, release it. + */ +void qemu_clipboard_peer_release(QemuClipboardPeer *peer, + QemuClipboardSelection selection); + +/** + * qemu_clipboard_info + * + * @selection: clipboard selection. + * + * Return the current clipboard data & owner informations. + */ +QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection); + +/** + * qemu_clipboard_info_new + * + * @owner: clipboard owner. + * @selection: clipboard selection. + * + * Allocate a new QemuClipboardInfo and initialize it with the given + * @owner and @selection. + * + * QemuClipboardInfo is a reference-counted struct. The new struct is + * returned with a reference already taken (i.e. reference count is + * one). + */ +QemuClipboardInfo *qemu_clipboard_info_new(QemuClipboardPeer *owner, + QemuClipboardSelection selection); +/** + * qemu_clipboard_info_ref + * + * @info: clipboard info. + * + * Increase @info reference count. + */ +QemuClipboardInfo *qemu_clipboard_info_ref(QemuClipboardInfo *info); + +/** + * qemu_clipboard_info_unref + * + * @info: clipboard info. + * + * Decrease @info reference count. When the count goes down to zero + * free the @info struct itself and all clipboard data. + */ +void qemu_clipboard_info_unref(QemuClipboardInfo *info); + +/** + * qemu_clipboard_update + * + * @info: clipboard info. + * + * Update the qemu clipboard. Notify all registered peers (including + * the clipboard owner) that the qemu clipboard has been updated. + * + * This is used for both new completely clipboard content and for + * clipboard data updates in response to qemu_clipboard_request() + * calls. + */ +void qemu_clipboard_update(QemuClipboardInfo *info); + +/** + * qemu_clipboard_request + * + * @info: clipboard info. + * @type: clipboard data type. + * + * Request clipboard content. Typically the clipboard owner only + * advertises the available data types and provides the actual data + * only on request. + */ +void qemu_clipboard_request(QemuClipboardInfo *info, + QemuClipboardType type); + +/** + * qemu_clipboard_set_data + * + * @peer: clipboard peer. + * @info: clipboard info. + * @type: clipboard data type. + * @size: data size. + * @data: data blob. + * @update: notify peers about the update. + * + * Set clipboard content for the given @type. This function will make + * a copy of the content data and store that. + */ +void qemu_clipboard_set_data(QemuClipboardPeer *peer, + QemuClipboardInfo *info, + QemuClipboardType type, + uint32_t size, + const void *data, + bool update); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuClipboardInfo, qemu_clipboard_info_unref) + +#endif /* QEMU_CLIPBOARD_H */ diff --git a/include/ui/console.h b/include/ui/console.h new file mode 100644 index 000000000..6d678924f --- /dev/null +++ b/include/ui/console.h @@ -0,0 +1,487 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "ui/qemu-pixman.h" +#include "qom/object.h" +#include "qemu/notify.h" +#include "qemu/error-report.h" +#include "qapi/qapi-types-ui.h" + +#ifdef CONFIG_OPENGL +# include <epoxy/gl.h> +# include "ui/shader.h" +#endif + +/* keyboard/mouse support */ + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 +#define MOUSE_EVENT_WHEELUP 0x08 +#define MOUSE_EVENT_WHEELDN 0x10 + +/* identical to the ps/2 keyboard bits */ +#define QEMU_SCROLL_LOCK_LED (1 << 0) +#define QEMU_NUM_LOCK_LED (1 << 1) +#define QEMU_CAPS_LOCK_LED (1 << 2) + +/* in ms */ +#define GUI_REFRESH_INTERVAL_DEFAULT 30 +#define GUI_REFRESH_INTERVAL_IDLE 3000 + +/* Color number is match to standard vga palette */ +enum qemu_color_names { + QEMU_COLOR_BLACK = 0, + QEMU_COLOR_BLUE = 1, + QEMU_COLOR_GREEN = 2, + QEMU_COLOR_CYAN = 3, + QEMU_COLOR_RED = 4, + QEMU_COLOR_MAGENTA = 5, + QEMU_COLOR_YELLOW = 6, + QEMU_COLOR_WHITE = 7 +}; +/* Convert to curses char attributes */ +#define ATTR2CHTYPE(c, fg, bg, bold) \ + ((bold) << 21 | (bg) << 11 | (fg) << 8 | (c)) + +typedef void QEMUPutKBDEvent(void *opaque, int keycode); +typedef void QEMUPutLEDEvent(void *opaque, int ledstate); +typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); + +typedef struct QEMUPutMouseEntry QEMUPutMouseEntry; +typedef struct QEMUPutKbdEntry QEMUPutKbdEntry; +typedef struct QEMUPutLEDEntry QEMUPutLEDEntry; + +QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, + void *opaque); +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name); +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); +void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry); + +QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque); +void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); + +void kbd_put_ledstate(int ledstate); + +void hmp_mouse_set(Monitor *mon, const QDict *qdict); + +/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx + constants) */ +#define QEMU_KEY_ESC1(c) ((c) | 0xe100) +#define QEMU_KEY_BACKSPACE 0x007f +#define QEMU_KEY_UP QEMU_KEY_ESC1('A') +#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') +#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') +#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') +#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) +#define QEMU_KEY_END QEMU_KEY_ESC1(4) +#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) +#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) +#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) + +#define QEMU_KEY_CTRL_UP 0xe400 +#define QEMU_KEY_CTRL_DOWN 0xe401 +#define QEMU_KEY_CTRL_LEFT 0xe402 +#define QEMU_KEY_CTRL_RIGHT 0xe403 +#define QEMU_KEY_CTRL_HOME 0xe404 +#define QEMU_KEY_CTRL_END 0xe405 +#define QEMU_KEY_CTRL_PAGEUP 0xe406 +#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 + +void kbd_put_keysym_console(QemuConsole *s, int keysym); +bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl); +void kbd_put_string_console(QemuConsole *s, const char *str, int len); +void kbd_put_keysym(int keysym); + +/* consoles */ + +#define TYPE_QEMU_CONSOLE "qemu-console" +OBJECT_DECLARE_TYPE(QemuConsole, QemuConsoleClass, QEMU_CONSOLE) + + +struct QemuConsoleClass { + ObjectClass parent_class; +}; + +#define QEMU_ALLOCATED_FLAG 0x01 +#define QEMU_PLACEHOLDER_FLAG 0x02 + +typedef struct DisplaySurface { + pixman_format_code_t format; + pixman_image_t *image; + uint8_t flags; +#ifdef CONFIG_OPENGL + GLenum glformat; + GLenum gltype; + GLuint texture; +#endif +} DisplaySurface; + +typedef struct QemuUIInfo { + /* physical dimension */ + uint16_t width_mm; + uint16_t height_mm; + /* geometry */ + int xoff; + int yoff; + uint32_t width; + uint32_t height; +} QemuUIInfo; + +/* 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); + +typedef void *QEMUGLContext; +typedef struct QEMUGLParams QEMUGLParams; + +struct QEMUGLParams { + int major_ver; + int minor_ver; +}; + +typedef struct QemuDmaBuf { + int fd; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t fourcc; + uint64_t modifier; + uint32_t texture; + uint32_t x; + uint32_t y; + uint32_t scanout_width; + uint32_t scanout_height; + bool y0_top; + void *sync; + int fence_fd; + bool allow_fences; + bool draw_submitted; +} QemuDmaBuf; + +typedef struct DisplayState DisplayState; + +typedef struct DisplayChangeListenerOps { + const char *dpy_name; + + /* optional */ + void (*dpy_refresh)(DisplayChangeListener *dcl); + + /* optional */ + void (*dpy_gfx_update)(DisplayChangeListener *dcl, + int x, int y, int w, int h); + /* optional */ + void (*dpy_gfx_switch)(DisplayChangeListener *dcl, + struct DisplaySurface *new_surface); + /* optional */ + bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl, + pixman_format_code_t format); + + /* optional */ + void (*dpy_text_cursor)(DisplayChangeListener *dcl, + int x, int y); + /* optional */ + void (*dpy_text_resize)(DisplayChangeListener *dcl, + int w, int h); + /* optional */ + void (*dpy_text_update)(DisplayChangeListener *dcl, + int x, int y, int w, int h); + + /* optional */ + void (*dpy_mouse_set)(DisplayChangeListener *dcl, + int x, int y, int on); + /* optional */ + void (*dpy_cursor_define)(DisplayChangeListener *dcl, + QEMUCursor *cursor); + + /* required if GL */ + QEMUGLContext (*dpy_gl_ctx_create)(DisplayChangeListener *dcl, + QEMUGLParams *params); + /* required if GL */ + void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl, + QEMUGLContext ctx); + /* required if GL */ + int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl, + QEMUGLContext ctx); + + /* required if GL */ + void (*dpy_gl_scanout_disable)(DisplayChangeListener *dcl); + /* required if GL */ + void (*dpy_gl_scanout_texture)(DisplayChangeListener *dcl, + uint32_t backing_id, + bool backing_y_0_top, + uint32_t backing_width, + uint32_t backing_height, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h); + /* optional (default to true if has dpy_gl_scanout_dmabuf) */ + bool (*dpy_has_dmabuf)(DisplayChangeListener *dcl); + /* optional */ + void (*dpy_gl_scanout_dmabuf)(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); + /* optional */ + void (*dpy_gl_cursor_dmabuf)(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf, bool have_hot, + uint32_t hot_x, uint32_t hot_y); + /* optional */ + void (*dpy_gl_cursor_position)(DisplayChangeListener *dcl, + uint32_t pos_x, uint32_t pos_y); + /* optional */ + void (*dpy_gl_release_dmabuf)(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); + /* required if GL */ + void (*dpy_gl_update)(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); + +} DisplayChangeListenerOps; + +struct DisplayChangeListener { + uint64_t update_interval; + const DisplayChangeListenerOps *ops; + DisplayState *ds; + QemuConsole *con; + + QLIST_ENTRY(DisplayChangeListener) next; +}; + +DisplayState *init_displaystate(void); +DisplaySurface *qemu_create_displaysurface_from(int width, int height, + pixman_format_code_t format, + int linesize, uint8_t *data); +DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image); +DisplaySurface *qemu_create_placeholder_surface(int w, int h, + const char *msg); +PixelFormat qemu_default_pixelformat(int bpp); + +DisplaySurface *qemu_create_displaysurface(int width, int height); +void qemu_free_displaysurface(DisplaySurface *surface); + +static inline int is_buffer_shared(DisplaySurface *surface) +{ + return !(surface->flags & QEMU_ALLOCATED_FLAG); +} + +static inline int is_placeholder(DisplaySurface *surface) +{ + return surface->flags & QEMU_PLACEHOLDER_FLAG; +} + +void register_displaychangelistener(DisplayChangeListener *dcl); +void update_displaychangelistener(DisplayChangeListener *dcl, + uint64_t interval); +void unregister_displaychangelistener(DisplayChangeListener *dcl); + +bool dpy_ui_info_supported(QemuConsole *con); +const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con); +int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info); + +void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); +void dpy_gfx_update_full(QemuConsole *con); +void dpy_gfx_replace_surface(QemuConsole *con, + DisplaySurface *surface); +void dpy_text_cursor(QemuConsole *con, int x, int y); +void dpy_text_update(QemuConsole *con, int x, int y, int w, int h); +void dpy_text_resize(QemuConsole *con, int w, int h); +void dpy_mouse_set(QemuConsole *con, int x, int y, int on); +void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor); +bool dpy_cursor_define_supported(QemuConsole *con); +bool dpy_gfx_check_format(QemuConsole *con, + pixman_format_code_t format); + +void dpy_gl_scanout_disable(QemuConsole *con); +void dpy_gl_scanout_texture(QemuConsole *con, + uint32_t backing_id, bool backing_y_0_top, + uint32_t backing_width, uint32_t backing_height, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); +void dpy_gl_scanout_dmabuf(QemuConsole *con, + QemuDmaBuf *dmabuf); +void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf, + bool have_hot, uint32_t hot_x, uint32_t hot_y); +void dpy_gl_cursor_position(QemuConsole *con, + uint32_t pos_x, uint32_t pos_y); +void dpy_gl_release_dmabuf(QemuConsole *con, + QemuDmaBuf *dmabuf); +void dpy_gl_update(QemuConsole *con, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); + +QEMUGLContext dpy_gl_ctx_create(QemuConsole *con, + QEMUGLParams *params); +void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx); +int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx); + +bool console_has_gl(QemuConsole *con); + +static inline int surface_stride(DisplaySurface *s) +{ + return pixman_image_get_stride(s->image); +} + +static inline void *surface_data(DisplaySurface *s) +{ + return pixman_image_get_data(s->image); +} + +static inline int surface_width(DisplaySurface *s) +{ + return pixman_image_get_width(s->image); +} + +static inline int surface_height(DisplaySurface *s) +{ + return pixman_image_get_height(s->image); +} + +static inline int surface_bits_per_pixel(DisplaySurface *s) +{ + int bits = PIXMAN_FORMAT_BPP(s->format); + return bits; +} + +static inline int surface_bytes_per_pixel(DisplaySurface *s) +{ + int bits = PIXMAN_FORMAT_BPP(s->format); + return DIV_ROUND_UP(bits, 8); +} + +static inline pixman_format_code_t surface_format(DisplaySurface *s) +{ + return s->format; +} + +typedef uint32_t console_ch_t; + +static inline void console_write_ch(console_ch_t *dest, uint32_t ch) +{ + *dest = ch; +} + +enum { + GRAPHIC_FLAGS_NONE = 0, + /* require a console/display with GL callbacks */ + GRAPHIC_FLAGS_GL = 1 << 0, + /* require a console/display with DMABUF import */ + GRAPHIC_FLAGS_DMABUF = 1 << 1, +}; + +typedef struct GraphicHwOps { + int (*get_flags)(void *opaque); /* optional, default 0 */ + void (*invalidate)(void *opaque); + void (*gfx_update)(void *opaque); + bool gfx_update_async; /* if true, calls graphic_hw_update_done() */ + void (*text_update)(void *opaque, console_ch_t *text); + void (*update_interval)(void *opaque, uint64_t interval); + int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); + void (*gl_block)(void *opaque, bool block); + void (*gl_flushed)(void *opaque); +} GraphicHwOps; + +QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, + const GraphicHwOps *ops, + void *opaque); +void graphic_console_set_hwops(QemuConsole *con, + const GraphicHwOps *hw_ops, + void *opaque); +void graphic_console_close(QemuConsole *con); + +void graphic_hw_update(QemuConsole *con); +void graphic_hw_update_done(QemuConsole *con); +void graphic_hw_invalidate(QemuConsole *con); +void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata); +void graphic_hw_gl_block(QemuConsole *con, bool block); +void graphic_hw_gl_flushed(QemuConsole *con); + +void qemu_console_early_init(void); + +QemuConsole *qemu_console_lookup_by_index(unsigned int index); +QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head); +QemuConsole *qemu_console_lookup_by_device_name(const char *device_id, + uint32_t head, Error **errp); +QemuConsole *qemu_console_lookup_unused(void); +bool qemu_console_is_visible(QemuConsole *con); +bool qemu_console_is_graphic(QemuConsole *con); +bool qemu_console_is_fixedsize(QemuConsole *con); +bool qemu_console_is_gl_blocked(QemuConsole *con); +char *qemu_console_get_label(QemuConsole *con); +int qemu_console_get_index(QemuConsole *con); +uint32_t qemu_console_get_head(QemuConsole *con); +int qemu_console_get_width(QemuConsole *con, int fallback); +int qemu_console_get_height(QemuConsole *con, int fallback); +/* Return the low-level window id for the console */ +int qemu_console_get_window_id(QemuConsole *con); +/* Set the low-level window id for the console */ +void qemu_console_set_window_id(QemuConsole *con, int window_id); + +void console_select(unsigned int index); +void qemu_console_resize(QemuConsole *con, int width, int height); +DisplaySurface *qemu_console_surface(QemuConsole *con); + +/* console-gl.c */ +#ifdef CONFIG_OPENGL +bool console_gl_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format); +void surface_gl_create_texture(QemuGLShader *gls, + DisplaySurface *surface); +void surface_gl_update_texture(QemuGLShader *gls, + DisplaySurface *surface, + int x, int y, int w, int h); +void surface_gl_render_texture(QemuGLShader *gls, + DisplaySurface *surface); +void surface_gl_destroy_texture(QemuGLShader *gls, + DisplaySurface *surface); +void surface_gl_setup_viewport(QemuGLShader *gls, + DisplaySurface *surface, + int ww, int wh); +#endif + +typedef struct QemuDisplay QemuDisplay; + +struct QemuDisplay { + DisplayType type; + void (*early_init)(DisplayOptions *opts); + void (*init)(DisplayState *ds, DisplayOptions *opts); +}; + +void qemu_display_register(QemuDisplay *ui); +bool qemu_display_find_default(DisplayOptions *opts); +void qemu_display_early_init(DisplayOptions *opts); +void qemu_display_init(DisplayState *ds, DisplayOptions *opts); +void qemu_display_help(void); + +/* vnc.c */ +void vnc_display_init(const char *id, Error **errp); +void vnc_display_open(const char *id, Error **errp); +void vnc_display_add_client(const char *id, int csock, bool skipauth); +int vnc_display_password(const char *id, const char *password); +int vnc_display_pw_expire(const char *id, time_t expires); +void vnc_parse(const char *str); +int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp); +bool vnc_display_reload_certs(const char *id, Error **errp); + +/* input.c */ +int index_from_key(const char *key, size_t key_length); + +#ifdef CONFIG_LINUX +/* udmabuf.c */ +int udmabuf_fd(void); +#endif + +#endif diff --git a/include/ui/egl-context.h b/include/ui/egl-context.h new file mode 100644 index 000000000..9374fe41e --- /dev/null +++ b/include/ui/egl-context.h @@ -0,0 +1,13 @@ +#ifndef EGL_CONTEXT_H +#define EGL_CONTEXT_H + +#include "ui/console.h" +#include "ui/egl-helpers.h" + +QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params); +void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx); +int qemu_egl_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx); + +#endif /* EGL_CONTEXT_H */ diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h new file mode 100644 index 000000000..2fb6e0dd6 --- /dev/null +++ b/include/ui/egl-helpers.h @@ -0,0 +1,66 @@ +#ifndef EGL_HELPERS_H +#define EGL_HELPERS_H + +#include <epoxy/gl.h> +#include <epoxy/egl.h> +#ifdef CONFIG_GBM +#include <gbm.h> +#endif +#include "ui/console.h" +#include "ui/shader.h" + +extern EGLDisplay *qemu_egl_display; +extern EGLConfig qemu_egl_config; +extern DisplayGLMode qemu_egl_mode; + +typedef struct egl_fb { + int width; + int height; + GLuint texture; + GLuint framebuffer; + bool delete_texture; + QemuDmaBuf *dmabuf; +} egl_fb; + +void egl_fb_destroy(egl_fb *fb); +void egl_fb_setup_default(egl_fb *fb, int width, int height); +void egl_fb_setup_for_tex(egl_fb *fb, int width, int height, + GLuint texture, bool delete); +void egl_fb_setup_new_tex(egl_fb *fb, int width, int height); +void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip); +void egl_fb_read(DisplaySurface *dst, egl_fb *src); + +void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip); +void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip, + int x, int y, double scale_x, double scale_y); + +#ifdef CONFIG_GBM + +extern int qemu_egl_rn_fd; +extern struct gbm_device *qemu_egl_rn_gbm_dev; +extern EGLContext qemu_egl_rn_ctx; + +int egl_rendernode_init(const char *rendernode, DisplayGLMode mode); +int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc, + EGLuint64KHR *modifier); + +void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf); +void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf); +void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf); +void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf); + +#endif + +EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win); + +#if defined(CONFIG_X11) || defined(CONFIG_GBM) + +int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode); +int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode); + +#endif + +EGLContext qemu_egl_init_ctx(void); +bool qemu_egl_has_dmabuf(void); + +#endif /* EGL_HELPERS_H */ diff --git a/include/ui/gtk.h b/include/ui/gtk.h new file mode 100644 index 000000000..7d22affd3 --- /dev/null +++ b/include/ui/gtk.h @@ -0,0 +1,224 @@ +#ifndef UI_GTK_H +#define UI_GTK_H + +/* Work around an -Wstrict-prototypes warning in GTK headers */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#include <gtk/gtk.h> +#pragma GCC diagnostic pop + +#include <gdk/gdkkeysyms.h> + +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> +#include <X11/XKBlib.h> +#endif + +#ifdef GDK_WINDOWING_WAYLAND +#include <gdk/gdkwayland.h> +#endif + +#include "ui/clipboard.h" +#include "ui/console.h" +#include "ui/kbd-state.h" +#if defined(CONFIG_OPENGL) +#include "ui/egl-helpers.h" +#include "ui/egl-context.h" +#endif +#ifdef CONFIG_VTE +#include "qemu/fifo8.h" +#endif + +#define MAX_VCS 10 + +typedef struct GtkDisplayState GtkDisplayState; + +typedef struct VirtualGfxConsole { + GtkWidget *drawing_area; + DisplayChangeListener dcl; + QKbdState *kbd; + DisplaySurface *ds; + pixman_image_t *convert; + cairo_surface_t *surface; + double scale_x; + double scale_y; +#if defined(CONFIG_OPENGL) + QemuGLShader *gls; + EGLContext ectx; + EGLSurface esurface; + int glupdates; + int x, y, w, h; + egl_fb guest_fb; + egl_fb win_fb; + egl_fb cursor_fb; + int cursor_x; + int cursor_y; + bool y0_top; + bool scanout_mode; + bool has_dmabuf; +#endif +} VirtualGfxConsole; + +#if defined(CONFIG_VTE) +typedef struct VirtualVteConsole { + GtkWidget *box; + GtkWidget *scrollbar; + GtkWidget *terminal; + Chardev *chr; + Fifo8 out_fifo; + bool echo; +} VirtualVteConsole; +#endif + +typedef enum VirtualConsoleType { + GD_VC_GFX, + GD_VC_VTE, +} VirtualConsoleType; + +typedef struct VirtualConsole { + GtkDisplayState *s; + char *label; + GtkWidget *window; + GtkWidget *menu_item; + GtkWidget *tab_item; + GtkWidget *focus; + VirtualConsoleType type; + union { + VirtualGfxConsole gfx; +#if defined(CONFIG_VTE) + VirtualVteConsole vte; +#endif + }; +} VirtualConsole; + +struct GtkDisplayState { + GtkWidget *window; + + GtkWidget *menu_bar; + + GtkAccelGroup *accel_group; + + GtkWidget *machine_menu_item; + GtkWidget *machine_menu; + GtkWidget *pause_item; + GtkWidget *reset_item; + GtkWidget *powerdown_item; + GtkWidget *quit_item; + + GtkWidget *view_menu_item; + GtkWidget *view_menu; + GtkWidget *full_screen_item; + GtkWidget *copy_item; + GtkWidget *zoom_in_item; + GtkWidget *zoom_out_item; + GtkWidget *zoom_fixed_item; + GtkWidget *zoom_fit_item; + GtkWidget *grab_item; + GtkWidget *grab_on_hover_item; + + int nb_vcs; + VirtualConsole vc[MAX_VCS]; + + GtkWidget *show_tabs_item; + GtkWidget *untabify_item; + GtkWidget *show_menubar_item; + + GtkWidget *vbox; + GtkWidget *notebook; + int button_mask; + gboolean last_set; + int last_x; + int last_y; + int grab_x_root; + int grab_y_root; + VirtualConsole *kbd_owner; + VirtualConsole *ptr_owner; + + gboolean full_screen; + + GdkCursor *null_cursor; + Notifier mouse_mode_notifier; + gboolean free_scale; + + bool external_pause_update; + + QemuClipboardPeer cbpeer; + uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT]; + GtkClipboard *gtkcb[QEMU_CLIPBOARD_SELECTION__COUNT]; + bool cbowner[QEMU_CLIPBOARD_SELECTION__COUNT]; + + DisplayOptions *opts; +}; + +extern bool gtk_use_gl_area; + +/* ui/gtk.c */ +void gd_update_windowsize(VirtualConsole *vc); +int gd_monitor_update_interval(GtkWidget *widget); +void gd_hw_gl_flushed(void *vc); + +/* ui/gtk-egl.c */ +void gd_egl_init(VirtualConsole *vc); +void gd_egl_draw(VirtualConsole *vc); +void gd_egl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h); +void gd_egl_refresh(DisplayChangeListener *dcl); +void gd_egl_switch(DisplayChangeListener *dcl, + DisplaySurface *surface); +QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params); +void gd_egl_scanout_disable(DisplayChangeListener *dcl); +void gd_egl_scanout_texture(DisplayChangeListener *dcl, + uint32_t backing_id, + bool backing_y_0_top, + uint32_t backing_width, + uint32_t backing_height, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h); +void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); +void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf, bool have_hot, + uint32_t hot_x, uint32_t hot_y); +void gd_egl_cursor_position(DisplayChangeListener *dcl, + uint32_t pos_x, uint32_t pos_y); +void gd_egl_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); +void gd_egl_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); +void gtk_egl_init(DisplayGLMode mode); +int gd_egl_make_current(DisplayChangeListener *dcl, + QEMUGLContext ctx); + +/* ui/gtk-gl-area.c */ +void gd_gl_area_init(VirtualConsole *vc); +void gd_gl_area_draw(VirtualConsole *vc); +void gd_gl_area_update(DisplayChangeListener *dcl, + int x, int y, int w, int h); +void gd_gl_area_refresh(DisplayChangeListener *dcl); +void gd_gl_area_switch(DisplayChangeListener *dcl, + DisplaySurface *surface); +QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params); +void gd_gl_area_destroy_context(DisplayChangeListener *dcl, + QEMUGLContext ctx); +void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf); +void gd_gl_area_scanout_texture(DisplayChangeListener *dcl, + uint32_t backing_id, + bool backing_y_0_top, + uint32_t backing_width, + uint32_t backing_height, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h); +void gd_gl_area_scanout_disable(DisplayChangeListener *dcl); +void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); +void gtk_gl_area_init(void); +int gd_gl_area_make_current(DisplayChangeListener *dcl, + QEMUGLContext ctx); + +/* gtk-clipboard.c */ +void gd_clipboard_init(GtkDisplayState *gd); + +#endif /* UI_GTK_H */ diff --git a/include/ui/input.h b/include/ui/input.h new file mode 100644 index 000000000..c86219a1c --- /dev/null +++ b/include/ui/input.h @@ -0,0 +1,120 @@ +#ifndef INPUT_H +#define INPUT_H + +#include "qapi/qapi-types-ui.h" +#include "qemu/notify.h" + +#define INPUT_EVENT_MASK_KEY (1<<INPUT_EVENT_KIND_KEY) +#define INPUT_EVENT_MASK_BTN (1<<INPUT_EVENT_KIND_BTN) +#define INPUT_EVENT_MASK_REL (1<<INPUT_EVENT_KIND_REL) +#define INPUT_EVENT_MASK_ABS (1<<INPUT_EVENT_KIND_ABS) + +#define INPUT_EVENT_ABS_MIN 0x0000 +#define INPUT_EVENT_ABS_MAX 0x7FFF + +typedef struct QemuInputHandler QemuInputHandler; +typedef struct QemuInputHandlerState QemuInputHandlerState; + +typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src, + InputEvent *evt); +typedef void (*QemuInputHandlerSync)(DeviceState *dev); + +struct QemuInputHandler { + const char *name; + uint32_t mask; + QemuInputHandlerEvent event; + QemuInputHandlerSync sync; +}; + +QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, + QemuInputHandler *handler); +void qemu_input_handler_activate(QemuInputHandlerState *s); +void qemu_input_handler_deactivate(QemuInputHandlerState *s); +void qemu_input_handler_unregister(QemuInputHandlerState *s); +void qemu_input_handler_bind(QemuInputHandlerState *s, + const char *device_id, int head, + Error **errp); +void qemu_input_event_send(QemuConsole *src, InputEvent *evt); +void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt); +void qemu_input_event_sync(void); +void qemu_input_event_sync_impl(void); + +void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down); +void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down); +void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down); +void qemu_input_event_send_key_delay(uint32_t delay_ms); +int qemu_input_key_number_to_qcode(unsigned int nr); +int qemu_input_key_value_to_number(const KeyValue *value); +int qemu_input_key_value_to_qcode(const KeyValue *value); +int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, + int *codes); +int qemu_input_linux_to_qcode(unsigned int lnx); + +void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down); +void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, + uint32_t button_old, uint32_t button_new); + +bool qemu_input_is_absolute(void); +int qemu_input_scale_axis(int value, + int min_in, int max_in, + int min_out, int max_out); +void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value); +void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, + int min_in, int max_in); + +void qemu_input_check_mode_change(void); +void qemu_add_mouse_mode_change_notifier(Notifier *notify); +void qemu_remove_mouse_mode_change_notifier(Notifier *notify); + +extern const guint qemu_input_map_atset1_to_qcode_len; +extern const guint16 qemu_input_map_atset1_to_qcode[]; + +extern const guint qemu_input_map_linux_to_qcode_len; +extern const guint16 qemu_input_map_linux_to_qcode[]; + +extern const guint qemu_input_map_qcode_to_atset1_len; +extern const guint16 qemu_input_map_qcode_to_atset1[]; + +extern const guint qemu_input_map_qcode_to_atset2_len; +extern const guint16 qemu_input_map_qcode_to_atset2[]; + +extern const guint qemu_input_map_qcode_to_atset3_len; +extern const guint16 qemu_input_map_qcode_to_atset3[]; + +extern const guint qemu_input_map_qcode_to_linux_len; +extern const guint16 qemu_input_map_qcode_to_linux[]; + +extern const guint qemu_input_map_qcode_to_qnum_len; +extern const guint16 qemu_input_map_qcode_to_qnum[]; + +extern const guint qemu_input_map_qcode_to_sun_len; +extern const guint16 qemu_input_map_qcode_to_sun[]; + +extern const guint qemu_input_map_qnum_to_qcode_len; +extern const guint16 qemu_input_map_qnum_to_qcode[]; + +extern const guint qemu_input_map_usb_to_qcode_len; +extern const guint16 qemu_input_map_usb_to_qcode[]; + +extern const guint qemu_input_map_win32_to_qcode_len; +extern const guint16 qemu_input_map_win32_to_qcode[]; + +extern const guint qemu_input_map_x11_to_qcode_len; +extern const guint16 qemu_input_map_x11_to_qcode[]; + +extern const guint qemu_input_map_xorgevdev_to_qcode_len; +extern const guint16 qemu_input_map_xorgevdev_to_qcode[]; + +extern const guint qemu_input_map_xorgkbd_to_qcode_len; +extern const guint16 qemu_input_map_xorgkbd_to_qcode[]; + +extern const guint qemu_input_map_xorgxquartz_to_qcode_len; +extern const guint16 qemu_input_map_xorgxquartz_to_qcode[]; + +extern const guint qemu_input_map_xorgxwin_to_qcode_len; +extern const guint16 qemu_input_map_xorgxwin_to_qcode[]; + +extern const guint qemu_input_map_osx_to_qcode_len; +extern const guint16 qemu_input_map_osx_to_qcode[]; + +#endif /* INPUT_H */ diff --git a/include/ui/kbd-state.h b/include/ui/kbd-state.h new file mode 100644 index 000000000..eb9067dd5 --- /dev/null +++ b/include/ui/kbd-state.h @@ -0,0 +1,102 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef QEMU_UI_KBD_STATE_H +#define QEMU_UI_KBD_STATE_H + +#include "qapi/qapi-types-ui.h" + +typedef enum QKbdModifier QKbdModifier; + +enum QKbdModifier { + QKBD_MOD_NONE = 0, + + QKBD_MOD_SHIFT, + QKBD_MOD_CTRL, + QKBD_MOD_ALT, + QKBD_MOD_ALTGR, + + QKBD_MOD_NUMLOCK, + QKBD_MOD_CAPSLOCK, + + QKBD_MOD__MAX +}; + +typedef struct QKbdState QKbdState; + +/** + * qkbd_state_init: init keyboard state tracker. + * + * Allocates and initializes keyboard state struct. + * + * @con: QemuConsole for this state tracker. Gets passed down to + * qemu_input_*() functions when sending key events to the guest. + */ +QKbdState *qkbd_state_init(QemuConsole *con); + +/** + * qkbd_state_free: free keyboard tracker state. + * + * @kbd: state tracker state. + */ +void qkbd_state_free(QKbdState *kbd); + +/** + * qkbd_state_key_event: process key event. + * + * Update keyboard state, send event to the guest. + * + * This function takes care to not send suspious events (keyup event + * for a key not pressed for example). + * + * @kbd: state tracker state. + * @qcode: the key pressed or released. + * @down: true for key down events, false otherwise. + */ +void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down); + +/** + * qkbd_state_set_delay: set key press delay. + * + * When set the specified delay will be added after each key event, + * using qemu_input_event_send_key_delay(). + * + * @kbd: state tracker state. + * @delay_ms: the delay in miliseconds. + */ +void qkbd_state_set_delay(QKbdState *kbd, int delay_ms); + +/** + * qkbd_state_key_get: get key state. + * + * Returns true when the key is down. + * + * @kbd: state tracker state. + * @qcode: the key to query. + */ +bool qkbd_state_key_get(QKbdState *kbd, QKeyCode qcode); + +/** + * qkbd_state_modifier_get: get modifier state. + * + * Returns true when the modifier is active. + * + * @kbd: state tracker state. + * @mod: the modifier to query. + */ +bool qkbd_state_modifier_get(QKbdState *kbd, QKbdModifier mod); + +/** + * qkbd_state_lift_all_keys: lift all pressed keys. + * + * This sends key up events to the guest for all keys which are in + * down state. + * + * @kbd: state tracker state. + */ +void qkbd_state_lift_all_keys(QKbdState *kbd); + +#endif /* QEMU_UI_KBD_STATE_H */ diff --git a/include/ui/pixel_ops.h b/include/ui/pixel_ops.h new file mode 100644 index 000000000..d390adfd1 --- /dev/null +++ b/include/ui/pixel_ops.h @@ -0,0 +1,53 @@ +static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); +} + +static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); +} + +static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); +} + +static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g, + unsigned int b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return (b << 16) | (g << 8) | r; +} + +static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, + unsigned int b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return (b << 16) | (g << 8) | r; +} diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h new file mode 100644 index 000000000..806ddcd7c --- /dev/null +++ b/include/ui/qemu-pixman.h @@ -0,0 +1,92 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_PIXMAN_H +#define QEMU_PIXMAN_H + +/* pixman-0.16.0 headers have a redundant declaration */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#include <pixman.h> +#pragma GCC diagnostic pop + +/* + * pixman image formats are defined to be native endian, + * that means host byte order on qemu. So we go define + * fixed formats here for cases where it is needed, like + * feeding libjpeg / libpng and writing screenshots. + */ + +#ifdef HOST_WORDS_BIGENDIAN +# define PIXMAN_BE_r8g8b8 PIXMAN_r8g8b8 +# define PIXMAN_BE_x8r8g8b8 PIXMAN_x8r8g8b8 +# define PIXMAN_BE_a8r8g8b8 PIXMAN_a8r8g8b8 +# define PIXMAN_BE_b8g8r8x8 PIXMAN_b8g8r8x8 +# define PIXMAN_BE_b8g8r8a8 PIXMAN_b8g8r8a8 +# define PIXMAN_BE_r8g8b8x8 PIXMAN_r8g8b8x8 +# define PIXMAN_BE_r8g8b8a8 PIXMAN_r8g8b8a8 +# define PIXMAN_BE_x8b8g8r8 PIXMAN_x8b8g8r8 +# define PIXMAN_BE_a8b8g8r8 PIXMAN_a8b8g8r8 +# define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8 +# define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8 +# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8 +#else +# define PIXMAN_BE_r8g8b8 PIXMAN_b8g8r8 +# define PIXMAN_BE_x8r8g8b8 PIXMAN_b8g8r8x8 +# define PIXMAN_BE_a8r8g8b8 PIXMAN_b8g8r8a8 +# define PIXMAN_BE_b8g8r8x8 PIXMAN_x8r8g8b8 +# define PIXMAN_BE_b8g8r8a8 PIXMAN_a8r8g8b8 +# define PIXMAN_BE_r8g8b8x8 PIXMAN_x8b8g8r8 +# define PIXMAN_BE_r8g8b8a8 PIXMAN_a8b8g8r8 +# define PIXMAN_BE_x8b8g8r8 PIXMAN_r8g8b8x8 +# define PIXMAN_BE_a8b8g8r8 PIXMAN_r8g8b8a8 +# define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8 +# define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8 +# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8 +#endif + +/* -------------------------------------------------------------------- */ + +typedef struct PixelFormat { + uint8_t bits_per_pixel; + uint8_t bytes_per_pixel; + uint8_t depth; /* color depth in bits */ + uint32_t rmask, gmask, bmask, amask; + uint8_t rshift, gshift, bshift, ashift; + uint8_t rmax, gmax, bmax, amax; + uint8_t rbits, gbits, bbits, abits; +} PixelFormat; + +PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format); +pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian); +pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format); +uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman); +int qemu_pixman_get_type(int rshift, int gshift, int bshift); +pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf); +bool qemu_pixman_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format); + +pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, + int width); +void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, + int width, int x, int y); +void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y, + pixman_image_t *linebuf); +pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, + pixman_image_t *image); +void qemu_pixman_image_unref(pixman_image_t *image); + +pixman_color_t qemu_pixman_color(PixelFormat *pf, uint32_t color); +pixman_image_t *qemu_pixman_glyph_from_vgafont(int height, const uint8_t *font, + unsigned int ch); +void qemu_pixman_glyph_render(pixman_image_t *glyph, + pixman_image_t *surface, + pixman_color_t *fgcol, + pixman_color_t *bgcol, + int x, int y, int cw, int ch); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref) + +#endif /* QEMU_PIXMAN_H */ diff --git a/include/ui/qemu-spice-module.h b/include/ui/qemu-spice-module.h new file mode 100644 index 000000000..1f22d557e --- /dev/null +++ b/include/ui/qemu-spice-module.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_SPICE_MODULE_H +#define QEMU_SPICE_MODULE_H + +#ifdef CONFIG_SPICE +#include <spice.h> +#endif + +typedef struct SpiceInfo SpiceInfo; + +struct QemuSpiceOps { + void (*init)(void); + void (*display_init)(void); + int (*migrate_info)(const char *h, int p, int t, const char *s); + int (*set_passwd)(const char *passwd, + bool fail_if_connected, bool disconnect_if_connected); + int (*set_pw_expire)(time_t expires); + int (*display_add_client)(int csock, int skipauth, int tls); +#ifdef CONFIG_SPICE + int (*add_interface)(SpiceBaseInstance *sin); + SpiceInfo* (*qmp_query)(Error **errp); +#endif +}; + +extern int using_spice; +extern struct QemuSpiceOps qemu_spice; + +#endif diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h new file mode 100644 index 000000000..71ecd6cfd --- /dev/null +++ b/include/ui/qemu-spice.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_SPICE_H +#define QEMU_SPICE_H + +#include "qapi/error.h" +#include "ui/qemu-spice-module.h" + +#ifdef CONFIG_SPICE + +#include <spice.h> +#include "qemu/config-file.h" + +void qemu_spice_input_init(void); +void qemu_spice_display_init(void); +void qemu_spice_display_init_done(void); +bool qemu_spice_have_display_interface(QemuConsole *con); +int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con); +int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, + const char *subject); + +#if !defined(SPICE_SERVER_VERSION) || (SPICE_SERVER_VERSION < 0xc06) +#define SPICE_NEEDS_SET_MM_TIME 1 +#else +#define SPICE_NEEDS_SET_MM_TIME 0 +#endif + +#else /* CONFIG_SPICE */ + +#include "qemu/error-report.h" + +#define spice_displays 0 + +#endif /* CONFIG_SPICE */ + +static inline bool qemu_using_spice(Error **errp) +{ + if (!using_spice) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE, + "SPICE is not in use"); + return false; + } + return true; +} + +#endif /* QEMU_SPICE_H */ diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h new file mode 100644 index 000000000..f85c117a7 --- /dev/null +++ b/include/ui/sdl2.h @@ -0,0 +1,85 @@ +#ifndef SDL2_H +#define SDL2_H + +/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */ +#undef WIN32_LEAN_AND_MEAN + +#include <SDL.h> +#include <SDL_syswm.h> +#ifdef CONFIG_SDL_IMAGE +# include <SDL_image.h> +#endif + +#include "ui/kbd-state.h" +#ifdef CONFIG_OPENGL +# include "ui/egl-helpers.h" +#endif + +struct sdl2_console { + DisplayChangeListener dcl; + DisplaySurface *surface; + DisplayOptions *opts; + SDL_Texture *texture; + SDL_Window *real_window; + SDL_Renderer *real_renderer; + int idx; + int last_vm_running; /* per console for caption reasons */ + int x, y, w, h; + int hidden; + int opengl; + int updates; + int idle_counter; + int ignore_hotkeys; + SDL_GLContext winctx; + QKbdState *kbd; +#ifdef CONFIG_OPENGL + QemuGLShader *gls; + egl_fb guest_fb; + egl_fb win_fb; + bool y0_top; + bool scanout_mode; +#endif +}; + +void sdl2_window_create(struct sdl2_console *scon); +void sdl2_window_destroy(struct sdl2_console *scon); +void sdl2_window_resize(struct sdl2_console *scon); +void sdl2_poll_events(struct sdl2_console *scon); + +void sdl2_process_key(struct sdl2_console *scon, + SDL_KeyboardEvent *ev); + +void sdl2_2d_update(DisplayChangeListener *dcl, + int x, int y, int w, int h); +void sdl2_2d_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface); +void sdl2_2d_refresh(DisplayChangeListener *dcl); +void sdl2_2d_redraw(struct sdl2_console *scon); +bool sdl2_2d_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format); + +void sdl2_gl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h); +void sdl2_gl_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface); +void sdl2_gl_refresh(DisplayChangeListener *dcl); +void sdl2_gl_redraw(struct sdl2_console *scon); + +QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params); +void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx); +int sdl2_gl_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx); + +void sdl2_gl_scanout_disable(DisplayChangeListener *dcl); +void sdl2_gl_scanout_texture(DisplayChangeListener *dcl, + uint32_t backing_id, + bool backing_y_0_top, + uint32_t backing_width, + uint32_t backing_height, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h); +void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h); + +#endif /* SDL2_H */ diff --git a/include/ui/shader.h b/include/ui/shader.h new file mode 100644 index 000000000..4c5acb2ce --- /dev/null +++ b/include/ui/shader.h @@ -0,0 +1,13 @@ +#ifndef QEMU_SHADER_H +#define QEMU_SHADER_H + +#include <epoxy/gl.h> + +typedef struct QemuGLShader QemuGLShader; + +void qemu_gl_run_texture_blit(QemuGLShader *gls, bool flip); + +QemuGLShader *qemu_gl_init_shader(void); +void qemu_gl_fini_shader(QemuGLShader *gls); + +#endif /* QEMU_SHADER_H */ diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h new file mode 100644 index 000000000..ed298d58f --- /dev/null +++ b/include/ui/spice-display.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UI_SPICE_DISPLAY_H +#define UI_SPICE_DISPLAY_H + +#include <spice.h> +#include <spice/ipc_ring.h> +#include <spice/enums.h> +#include <spice/qxl_dev.h> + +#include "qemu/thread.h" +#include "ui/qemu-pixman.h" +#include "ui/console.h" + +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) +# if SPICE_SERVER_VERSION >= 0x000d01 /* release 0.13.1 */ +# define HAVE_SPICE_GL 1 +# include "ui/egl-helpers.h" +# include "ui/egl-context.h" +# endif +#endif + +#define NUM_MEMSLOTS 8 +#define MEMSLOT_GENERATION_BITS 8 +#define MEMSLOT_SLOT_BITS 8 + +#define MEMSLOT_GROUP_HOST 0 +#define MEMSLOT_GROUP_GUEST 1 +#define NUM_MEMSLOTS_GROUPS 2 + +/* + * Internal enum to differenciate between options for + * io calls that have a sync (old) version and an _async (new) + * version: + * QXL_SYNC: use the old version + * QXL_ASYNC: use the new version and make sure there are no two + * happening at the same time. This is used for guest initiated + * calls + */ +typedef enum qxl_async_io { + QXL_SYNC, + QXL_ASYNC, +} qxl_async_io; + +enum { + QXL_COOKIE_TYPE_IO, + QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, + QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + QXL_COOKIE_TYPE_GL_DRAW_DONE, +}; + +typedef struct QXLCookie { + int type; + uint64_t io; + union { + uint32_t surface_id; + QXLRect area; + struct { + QXLRect area; + int redraw; + } render; + void *data; + } u; +} QXLCookie; + +QXLCookie *qxl_cookie_new(int type, uint64_t io); + +typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; +typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; +typedef struct SimpleSpiceCursor SimpleSpiceCursor; + +struct SimpleSpiceDisplay { + DisplaySurface *ds; + DisplayChangeListener dcl; + void *buf; + int bufsize; + QXLInstance qxl; + uint32_t unique; + pixman_image_t *surface; + pixman_image_t *mirror; + int32_t num_surfaces; + + QXLRect dirty; + int notify; + + /* + * All struct members below this comment can be accessed from + * both spice server and qemu (iothread) context and any access + * to them must be protected by the lock. + */ + QemuMutex lock; + QTAILQ_HEAD(, SimpleSpiceUpdate) updates; + + /* cursor (without qxl): displaychangelistener -> spice server */ + SimpleSpiceCursor *ptr_define; + SimpleSpiceCursor *ptr_move; + int16_t ptr_x, ptr_y; + int16_t hot_x, hot_y; + + /* cursor (with qxl): qxl local renderer -> displaychangelistener */ + QEMUCursor *cursor; + int mouse_x, mouse_y; + QEMUBH *cursor_bh; + +#ifdef HAVE_SPICE_GL + /* opengl rendering */ + QEMUBH *gl_unblock_bh; + QEMUTimer *gl_unblock_timer; + QemuGLShader *gls; + int gl_updates; + bool have_scanout; + bool have_surface; + + QemuDmaBuf *guest_dmabuf; + bool guest_dmabuf_refresh; + bool render_cursor; + + egl_fb guest_fb; + egl_fb blit_fb; + egl_fb cursor_fb; + bool have_hot; +#endif +}; + +struct SimpleSpiceUpdate { + QXLDrawable drawable; + QXLImage image; + QXLCommandExt ext; + uint8_t *bitmap; + QTAILQ_ENTRY(SimpleSpiceUpdate) next; +}; + +struct SimpleSpiceCursor { + QXLCursorCmd cmd; + QXLCommandExt ext; + QXLCursor cursor; +}; + +extern bool spice_opengl; + +int qemu_spice_rect_is_empty(const QXLRect* r); +void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r); + +void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update); +void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); +void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); +void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); +void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd); + +void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h); +void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, + DisplaySurface *surface); +void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); +void qemu_spice_cursor_refresh_bh(void *opaque); + +void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async); +void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, + uint32_t sid); +void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + QXLDevSurfaceCreate *surface, + qxl_async_io async); +void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async); +void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); +void qemu_spice_display_start(void); +void qemu_spice_display_stop(void); +int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); + +bool qemu_spice_fill_device_address(QemuConsole *con, + char *device_address, + size_t size); + +#endif diff --git a/include/ui/win32-kbd-hook.h b/include/ui/win32-kbd-hook.h new file mode 100644 index 000000000..4bd9f00f9 --- /dev/null +++ b/include/ui/win32-kbd-hook.h @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef UI_WIN32_KBD_HOOK_H +#define UI_WIN32_KBD_HOOK_H + +void win32_kbd_set_window(void *hwnd); +void win32_kbd_set_grab(bool grab); + +#endif |