diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-05-29 13:15:10 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-05-29 13:15:10 -0700 |
commit | 57b93c0f8ea3901661990de74aef15b44aea5556 (patch) | |
tree | 69d1d8680e1cd6af9d0263d316128f6485312063 | |
parent | ac84b57b4d74606f7f83667a0606deef32b2049d (diff) | |
parent | 5a4cb61ae1ab0068ab53535ed0ccaf41a5e97d2f (diff) | |
download | qemu-57b93c0f8ea3901661990de74aef15b44aea5556.zip qemu-57b93c0f8ea3901661990de74aef15b44aea5556.tar.gz qemu-57b93c0f8ea3901661990de74aef15b44aea5556.tar.bz2 |
Merge tag 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging
UI queue
- virtio: add virtio-multitouch device
- sdl: various keyboard grab fixes
- gtk: enable multi-touch events
- misc fixes
# -----BEGIN PGP SIGNATURE-----
#
# iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmRzVQAcHG1hcmNhbmRy
# ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5a34D/9+1I9XnecCQk4rZhHI
# Fb1fUei4eLNOdxTZUK2zpOkArWf59VNsEa1LFqIiM+0IlWU3gQmrCLRFOuJrDxiA
# ugq9H23QLs3Z7HEab6/aq+VwUy+o1AXowLZBTrEGmw9SZQnrKeu4/prW0f5wbsTf
# u5ALDkJWo733vkbAplsfWPcOLzp3CoTvA89iw/I9eNVYsm6+vBJ+0cRBr0GCPmiJ
# 2xprhGkie491clNlbR3HmOX/RGFmcj/ClPraLXepaQq1gNCqurIrU7V3J/JcY5W0
# YemXDEgpZ8iVt1OOKGKzTftGZzuhRpxAYvSPwjAp1XeEXB7eJEmjUWoFpyVt1tQZ
# 4y6pQGYdM2XW0sbAkt3w2TIgj/odv7L3IHG3UcsBRefl6Pm43G1FuGWjbulQ1ch0
# YyFAr1xNPkWMYSW1MTb4vuTYFO9OEY08W4n+M6O187RUFiuf+W00OZUDqpp6zjqT
# LKjMktilpUOya1LvWU3D5et9LEXFgSrZj9rQlFsuMe3g24ZNPLypQh/jzSFs9ZsW
# At1nIGGrrZDr8YMFnANBudJbJc0Q1+ce5TB6090XSpNn/YXvu2H+n/ceA4/mA6sy
# MlQBrDmifb9iY6+62MbW8wJtiIy8Zi7A632pw8gbqB0ilkg4DNSBR5O42n1Fmhqp
# gLfxN48NN9Bx6H+zPJbwz2aDQQ==
# =3bPI
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 28 May 2023 06:20:00 AM PDT
# gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg: issuer "marcandre.lureau@redhat.com"
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
* tag 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu:
ui/gtk: enable backend to send multi-touch events
ui: add helpers for virtio-multitouch events
virtio-input-pci: add virtio-multitouch-pci
virtio-input: add a virtio-mulitouch device
ui: add the infrastructure to support MT events
virtio-input: generalize virtio_input_key_config()
ui/cursor: make width/height unsigned 16-bit integer
ui/sdl2: disable SDL_HINT_GRAB_KEYBOARD on Windows
ui/sdl2: Grab Alt+F4 also under Windows
ui/sdl2: Grab Alt+Tab also in fullscreen mode
ui/dbus: add a FIXME about texture/dmabuf scanout handling
gtk: add gl-area support on win32
virtio-gpu: add a FIXME for virtio_gpu_load()
win32: wrap socket close() with an exception handler
ui/dbus: fix compilation when GBM && !OPENGL
ui/sdl2: fix surface_gl_update_texture: Assertion 'gls' failed
ui/gtk-egl: fix scaling for cursor position in scanout mode
ui/gtk: use widget size for cursor motion event
ui/gtk: fix passing y0_top parameter to scanout
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r-- | hw/display/virtio-gpu.c | 1 | ||||
-rw-r--r-- | hw/input/virtio-input-hid.c | 156 | ||||
-rw-r--r-- | hw/virtio/virtio-input-pci.c | 25 | ||||
-rw-r--r-- | include/hw/virtio/virtio-input.h | 9 | ||||
-rw-r--r-- | include/sysemu/os-win32.h | 4 | ||||
-rw-r--r-- | include/ui/console.h | 4 | ||||
-rw-r--r-- | include/ui/input.h | 8 | ||||
-rw-r--r-- | qapi/ui.json | 68 | ||||
-rw-r--r-- | replay/replay-input.c | 18 | ||||
-rw-r--r-- | ui/cursor.c | 3 | ||||
-rw-r--r-- | ui/dbus-listener.c | 15 | ||||
-rw-r--r-- | ui/gtk-egl.c | 6 | ||||
-rw-r--r-- | ui/gtk-gl-area.c | 2 | ||||
-rw-r--r-- | ui/gtk.c | 106 | ||||
-rw-r--r-- | ui/input.c | 42 | ||||
-rw-r--r-- | ui/sdl2-gl.c | 4 | ||||
-rw-r--r-- | ui/sdl2.c | 7 | ||||
-rw-r--r-- | ui/trace-events | 1 | ||||
-rw-r--r-- | util/oslib-win32.c | 23 |
19 files changed, 442 insertions, 60 deletions
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 66ac9b6..66cddd9 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1289,6 +1289,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, /* load & apply scanout state */ vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { + /* FIXME: should take scanout.r.{x,y} into account */ scanout = &g->parent_obj.scanout[i]; if (!scanout->resource_id) { continue; diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index a7a244a..7053ad7 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -16,9 +16,10 @@ #include "standard-headers/linux/input.h" -#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard" -#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse" -#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet" +#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard" +#define VIRTIO_ID_NAME_MOUSE "QEMU Virtio Mouse" +#define VIRTIO_ID_NAME_TABLET "QEMU Virtio Tablet" +#define VIRTIO_ID_NAME_MULTITOUCH "QEMU Virtio MultiTouch" /* ----------------------------------------------------------------- */ @@ -30,6 +31,7 @@ static const unsigned short keymap_button[INPUT_BUTTON__MAX] = { [INPUT_BUTTON_WHEEL_DOWN] = BTN_GEAR_DOWN, [INPUT_BUTTON_SIDE] = BTN_SIDE, [INPUT_BUTTON_EXTRA] = BTN_EXTRA, + [INPUT_BUTTON_TOUCH] = BTN_TOUCH, }; static const unsigned short axismap_rel[INPUT_AXIS__MAX] = { @@ -42,32 +44,38 @@ static const unsigned short axismap_abs[INPUT_AXIS__MAX] = { [INPUT_AXIS_Y] = ABS_Y, }; +static const unsigned short axismap_tch[INPUT_AXIS__MAX] = { + [INPUT_AXIS_X] = ABS_MT_POSITION_X, + [INPUT_AXIS_Y] = ABS_MT_POSITION_Y, +}; + /* ----------------------------------------------------------------- */ -static void virtio_input_key_config(VirtIOInput *vinput, - const unsigned short *keymap, - size_t mapsize) +static void virtio_input_extend_config(VirtIOInput *vinput, + const unsigned short *map, + size_t mapsize, + uint8_t select, uint8_t subsel) { - virtio_input_config keys; + virtio_input_config ext; int i, bit, byte, bmax = 0; - memset(&keys, 0, sizeof(keys)); + memset(&ext, 0, sizeof(ext)); for (i = 0; i < mapsize; i++) { - bit = keymap[i]; + bit = map[i]; if (!bit) { continue; } byte = bit / 8; bit = bit % 8; - keys.u.bitmap[byte] |= (1 << bit); + ext.u.bitmap[byte] |= (1 << bit); if (bmax < byte+1) { bmax = byte+1; } } - keys.select = VIRTIO_INPUT_CFG_EV_BITS; - keys.subsel = EV_KEY; - keys.size = bmax; - virtio_input_add_config(vinput, &keys); + ext.select = select; + ext.subsel = subsel; + ext.size = bmax; + virtio_input_add_config(vinput, &ext); } static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, @@ -80,6 +88,7 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, InputKeyEvent *key; InputMoveEvent *move; InputBtnEvent *btn; + InputMultiTouchEvent *mtt; switch (evt->type) { case INPUT_EVENT_KIND_KEY: @@ -136,6 +145,24 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src, event.value = cpu_to_le32(move->value); virtio_input_send(vinput, &event); break; + case INPUT_EVENT_KIND_MTT: + mtt = evt->u.mtt.data; + if (mtt->type == INPUT_MULTI_TOUCH_TYPE_DATA) { + event.type = cpu_to_le16(EV_ABS); + event.code = cpu_to_le16(axismap_tch[mtt->axis]); + event.value = cpu_to_le32(mtt->value); + virtio_input_send(vinput, &event); + } else { + event.type = cpu_to_le16(EV_ABS); + event.code = cpu_to_le16(ABS_MT_SLOT); + event.value = cpu_to_le32(mtt->slot); + virtio_input_send(vinput, &event); + event.type = cpu_to_le16(EV_ABS); + event.code = cpu_to_le16(ABS_MT_TRACKING_ID); + event.value = cpu_to_le32(mtt->tracking_id); + virtio_input_send(vinput, &event); + } + break; default: /* keep gcc happy */ break; @@ -281,8 +308,9 @@ static void virtio_keyboard_init(Object *obj) vhid->handler = &virtio_keyboard_handler; virtio_input_init_config(vinput, virtio_keyboard_config); - virtio_input_key_config(vinput, qemu_input_map_qcode_to_linux, - qemu_input_map_qcode_to_linux_len); + virtio_input_extend_config(vinput, qemu_input_map_qcode_to_linux, + qemu_input_map_qcode_to_linux_len, + VIRTIO_INPUT_CFG_EV_BITS, EV_KEY); } static const TypeInfo virtio_keyboard_info = { @@ -373,8 +401,9 @@ static void virtio_mouse_init(Object *obj) virtio_input_init_config(vinput, vhid->wheel_axis ? virtio_mouse_config_v2 : virtio_mouse_config_v1); - virtio_input_key_config(vinput, keymap_button, - ARRAY_SIZE(keymap_button)); + virtio_input_extend_config(vinput, keymap_button, + ARRAY_SIZE(keymap_button), + VIRTIO_INPUT_CFG_EV_BITS, EV_KEY); } static const TypeInfo virtio_mouse_info = { @@ -497,8 +526,9 @@ static void virtio_tablet_init(Object *obj) virtio_input_init_config(vinput, vhid->wheel_axis ? virtio_tablet_config_v2 : virtio_tablet_config_v1); - virtio_input_key_config(vinput, keymap_button, - ARRAY_SIZE(keymap_button)); + virtio_input_extend_config(vinput, keymap_button, + ARRAY_SIZE(keymap_button), + VIRTIO_INPUT_CFG_EV_BITS, EV_KEY); } static const TypeInfo virtio_tablet_info = { @@ -511,12 +541,98 @@ static const TypeInfo virtio_tablet_info = { /* ----------------------------------------------------------------- */ +static QemuInputHandler virtio_multitouch_handler = { + .name = VIRTIO_ID_NAME_MULTITOUCH, + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_MTT, + .event = virtio_input_handle_event, + .sync = virtio_input_handle_sync, +}; + +static struct virtio_input_config virtio_multitouch_config[] = { + { + .select = VIRTIO_INPUT_CFG_ID_NAME, + .size = sizeof(VIRTIO_ID_NAME_MULTITOUCH), + .u.string = VIRTIO_ID_NAME_MULTITOUCH, + },{ + .select = VIRTIO_INPUT_CFG_ID_DEVIDS, + .size = sizeof(struct virtio_input_devids), + .u.ids = { + .bustype = const_le16(BUS_VIRTUAL), + .vendor = const_le16(0x0627), /* same we use for usb hid devices */ + .product = const_le16(0x0003), + .version = const_le16(0x0001), + }, + },{ + .select = VIRTIO_INPUT_CFG_ABS_INFO, + .subsel = ABS_MT_SLOT, + .size = sizeof(virtio_input_absinfo), + .u.abs.min = const_le32(INPUT_EVENT_SLOTS_MIN), + .u.abs.max = const_le32(INPUT_EVENT_SLOTS_MAX), + },{ + .select = VIRTIO_INPUT_CFG_ABS_INFO, + .subsel = ABS_MT_TRACKING_ID, + .size = sizeof(virtio_input_absinfo), + .u.abs.min = const_le32(INPUT_EVENT_SLOTS_MIN), + .u.abs.max = const_le32(INPUT_EVENT_SLOTS_MAX), + },{ + .select = VIRTIO_INPUT_CFG_ABS_INFO, + .subsel = ABS_MT_POSITION_X, + .size = sizeof(virtio_input_absinfo), + .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), + .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), + },{ + .select = VIRTIO_INPUT_CFG_ABS_INFO, + .subsel = ABS_MT_POSITION_Y, + .size = sizeof(virtio_input_absinfo), + .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN), + .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX), + }, + { /* end of list */ }, +}; + +static void virtio_multitouch_init(Object *obj) +{ + VirtIOInputHID *vhid = VIRTIO_INPUT_HID(obj); + VirtIOInput *vinput = VIRTIO_INPUT(obj); + unsigned short abs_props[] = { + INPUT_PROP_DIRECT, + }; + unsigned short abs_bits[] = { + ABS_MT_SLOT, + ABS_MT_TRACKING_ID, + ABS_MT_POSITION_X, + ABS_MT_POSITION_Y, + }; + + vhid->handler = &virtio_multitouch_handler; + virtio_input_init_config(vinput, virtio_multitouch_config); + virtio_input_extend_config(vinput, keymap_button, + ARRAY_SIZE(keymap_button), + VIRTIO_INPUT_CFG_EV_BITS, EV_KEY); + virtio_input_extend_config(vinput, abs_props, + ARRAY_SIZE(abs_props), + VIRTIO_INPUT_CFG_PROP_BITS, 0); + virtio_input_extend_config(vinput, abs_bits, + ARRAY_SIZE(abs_bits), + VIRTIO_INPUT_CFG_EV_BITS, EV_ABS); +} + +static const TypeInfo virtio_multitouch_info = { + .name = TYPE_VIRTIO_MULTITOUCH, + .parent = TYPE_VIRTIO_INPUT_HID, + .instance_size = sizeof(VirtIOInputHID), + .instance_init = virtio_multitouch_init, +}; + +/* ----------------------------------------------------------------- */ + static void virtio_register_types(void) { type_register_static(&virtio_input_hid_info); type_register_static(&virtio_keyboard_info); type_register_static(&virtio_mouse_info); type_register_static(&virtio_tablet_info); + type_register_static(&virtio_multitouch_info); } type_init(virtio_register_types) diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c index a9d0992..a53edf4 100644 --- a/hw/virtio/virtio-input-pci.c +++ b/hw/virtio/virtio-input-pci.c @@ -25,10 +25,11 @@ struct VirtIOInputPCI { VirtIOInput vdev; }; -#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" -#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" -#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" -#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" +#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" +#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" +#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" +#define TYPE_VIRTIO_MULTITOUCH_PCI "virtio-multitouch-pci" OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHIDPCI, VIRTIO_INPUT_HID_PCI) struct VirtIOInputHIDPCI { @@ -102,6 +103,14 @@ static void virtio_tablet_initfn(Object *obj) TYPE_VIRTIO_TABLET); } +static void virtio_multitouch_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_MULTITOUCH); +} + static const TypeInfo virtio_input_pci_info = { .name = TYPE_VIRTIO_INPUT_PCI, .parent = TYPE_VIRTIO_PCI, @@ -140,6 +149,13 @@ static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = { .instance_init = virtio_tablet_initfn, }; +static const VirtioPCIDeviceTypeInfo virtio_multitouch_pci_info = { + .generic_name = TYPE_VIRTIO_MULTITOUCH_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_multitouch_initfn, +}; + static void virtio_pci_input_register(void) { /* Base types: */ @@ -150,6 +166,7 @@ static void virtio_pci_input_register(void) virtio_pci_types_register(&virtio_keyboard_pci_info); virtio_pci_types_register(&virtio_mouse_pci_info); virtio_pci_types_register(&virtio_tablet_pci_info); + virtio_pci_types_register(&virtio_multitouch_pci_info); } type_init(virtio_pci_input_register) diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index f2da63d..08f1591 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -24,10 +24,11 @@ OBJECT_DECLARE_TYPE(VirtIOInput, VirtIOInputClass, #define VIRTIO_INPUT_GET_PARENT_CLASS(obj) \ OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT) -#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid-device" -#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device" -#define TYPE_VIRTIO_MOUSE "virtio-mouse-device" -#define TYPE_VIRTIO_TABLET "virtio-tablet-device" +#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid-device" +#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device" +#define TYPE_VIRTIO_MOUSE "virtio-mouse-device" +#define TYPE_VIRTIO_TABLET "virtio-tablet-device" +#define TYPE_VIRTIO_MULTITOUCH "virtio-multitouch-device" OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHID, VIRTIO_INPUT_HID) #define VIRTIO_INPUT_HID_GET_PARENT_CLASS(obj) \ diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 15c296e..65f6c9e 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -259,6 +259,10 @@ ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags); ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen); +EXCEPTION_DISPOSITION +win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*, + struct _CONTEXT*, void*); + #ifdef __cplusplus } #endif diff --git a/include/ui/console.h b/include/ui/console.h index 2a8fab0..ae5ec46 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -144,13 +144,13 @@ typedef struct QemuUIInfo { /* cursor data format is 32bit RGBA */ typedef struct QEMUCursor { - int width, height; + uint16_t width, height; int hot_x, hot_y; int refcount; uint32_t data[]; } QEMUCursor; -QEMUCursor *cursor_alloc(int width, int height); +QEMUCursor *cursor_alloc(uint16_t width, uint16_t height); QEMUCursor *cursor_ref(QEMUCursor *c); void cursor_unref(QEMUCursor *c); QEMUCursor *cursor_builtin_hidden(void); diff --git a/include/ui/input.h b/include/ui/input.h index c86219a..c29a730 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -8,9 +8,12 @@ #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_MASK_MTT (1<<INPUT_EVENT_KIND_MTT) #define INPUT_EVENT_ABS_MIN 0x0000 #define INPUT_EVENT_ABS_MAX 0x7FFF +#define INPUT_EVENT_SLOTS_MIN 0x0 +#define INPUT_EVENT_SLOTS_MAX 0xa typedef struct QemuInputHandler QemuInputHandler; typedef struct QemuInputHandlerState QemuInputHandlerState; @@ -61,6 +64,11 @@ int qemu_input_scale_axis(int value, 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_queue_mtt(QemuConsole *src, InputMultiTouchType type, int slot, + int tracking_id); +void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value, + int min_in, int max_in, + int slot, int tracking_id); void qemu_input_check_mode_change(void); void qemu_add_mouse_mode_change_notifier(Notifier *notify); diff --git a/qapi/ui.json b/qapi/ui.json index d51e340..2755395 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1055,11 +1055,13 @@ # # @extra: rear side button of a 5-button mouse (since 2.9) # +# @touch: screen contact on a multi-touch device (since 8.1) +# # Since: 2.0 ## { 'enum' : 'InputButton', 'data' : [ 'left', 'middle', 'right', 'wheel-up', 'wheel-down', 'side', - 'extra', 'wheel-left', 'wheel-right' ] } + 'extra', 'wheel-left', 'wheel-right', 'touch' ] } ## # @InputAxis: @@ -1072,6 +1074,17 @@ 'data' : [ 'x', 'y' ] } ## +# @InputMultiTouchType: +# +# Type of a multi-touch event. +# +# Since: 8.1 +## +{ 'enum' : 'InputMultiTouchType', + 'data' : [ 'begin', 'update', 'end', 'cancel', 'data' ] } + + +## # @InputKeyEvent: # # Keyboard input event. @@ -1118,12 +1131,45 @@ 'value' : 'int' } } ## +# @InputMultiTouchEvent: +# +# MultiTouch input event. +# +# @slot: Which slot has generated the event. +# +# @tracking-id: ID to correlate this event with previously generated +# events. +# +# @axis: Which axis is referenced by @value. +# +# @value: Contact position. +# +# Since: 8.1 +## +{ 'struct' : 'InputMultiTouchEvent', + 'data' : { 'type' : 'InputMultiTouchType', + 'slot' : 'int', + 'tracking-id': 'int', + 'axis' : 'InputAxis', + 'value' : 'int' } } + +## # @InputEventKind: # +# @key: a keyboard input event +# +# @btn: a pointer button input event +# +# @rel: a relative pointer motion input event +# +# @abs: an absolute pointer motion input event +# +# @mtt: a multi-touch input event +# # Since: 2.0 ## { 'enum': 'InputEventKind', - 'data': [ 'key', 'btn', 'rel', 'abs' ] } + 'data': [ 'key', 'btn', 'rel', 'abs', 'mtt' ] } ## # @InputKeyEventWrapper: @@ -1150,16 +1196,19 @@ 'data': { 'data': 'InputMoveEvent' } } ## +# @InputMultiTouchEventWrapper: +# +# Since: 8.1 +## +{ 'struct': 'InputMultiTouchEventWrapper', + 'data': { 'data': 'InputMultiTouchEvent' } } + +## # @InputEvent: # # Input event union. # -# @type: the input type, one of: -# -# - 'key': Input event of Keyboard -# - 'btn': Input event of pointer buttons -# - 'rel': Input event of relative pointer motion -# - 'abs': Input event of absolute pointer motion +# @type: the type of input event # # Since: 2.0 ## @@ -1169,7 +1218,8 @@ 'data' : { 'key' : 'InputKeyEventWrapper', 'btn' : 'InputBtnEventWrapper', 'rel' : 'InputMoveEventWrapper', - 'abs' : 'InputMoveEventWrapper' } } + 'abs' : 'InputMoveEventWrapper', + 'mtt' : 'InputMultiTouchEventWrapper' } } ## # @input-send-event: diff --git a/replay/replay-input.c b/replay/replay-input.c index 1147e3d..bee3dbe 100644 --- a/replay/replay-input.c +++ b/replay/replay-input.c @@ -22,6 +22,7 @@ void replay_save_input_event(InputEvent *evt) InputKeyEvent *key; InputBtnEvent *btn; InputMoveEvent *move; + InputMultiTouchEvent *mtt; replay_put_dword(evt->type); switch (evt->type) { @@ -58,6 +59,14 @@ void replay_save_input_event(InputEvent *evt) replay_put_dword(move->axis); replay_put_qword(move->value); break; + case INPUT_EVENT_KIND_MTT: + mtt = evt->u.mtt.data; + replay_put_dword(mtt->type); + replay_put_qword(mtt->slot); + replay_put_qword(mtt->tracking_id); + replay_put_dword(mtt->axis); + replay_put_qword(mtt->value); + break; case INPUT_EVENT_KIND__MAX: /* keep gcc happy */ break; @@ -73,6 +82,7 @@ InputEvent *replay_read_input_event(void) InputBtnEvent btn; InputMoveEvent rel; InputMoveEvent abs; + InputMultiTouchEvent mtt; evt.type = replay_get_dword(); switch (evt.type) { @@ -109,6 +119,14 @@ InputEvent *replay_read_input_event(void) evt.u.abs.data->axis = (InputAxis)replay_get_dword(); evt.u.abs.data->value = replay_get_qword(); break; + case INPUT_EVENT_KIND_MTT: + evt.u.mtt.data = &mtt; + evt.u.mtt.data->type = (InputMultiTouchType)replay_get_dword(); + evt.u.mtt.data->slot = replay_get_qword(); + evt.u.mtt.data->tracking_id = replay_get_qword(); + evt.u.mtt.data->axis = (InputAxis)replay_get_dword(); + evt.u.mtt.data->value = replay_get_qword(); + break; case INPUT_EVENT_KIND__MAX: /* keep gcc happy */ break; diff --git a/ui/cursor.c b/ui/cursor.c index 6fe6799..29717b3e 100644 --- a/ui/cursor.c +++ b/ui/cursor.c @@ -90,11 +90,12 @@ QEMUCursor *cursor_builtin_left_ptr(void) return cursor_parse_xpm(cursor_left_ptr_xpm); } -QEMUCursor *cursor_alloc(int width, int height) +QEMUCursor *cursor_alloc(uint16_t width, uint16_t height) { QEMUCursor *c; size_t datasize = width * height * sizeof(uint32_t); + /* Modern physical hardware typically uses 512x512 sprites */ if (width > 512 || height > 512) { return NULL; } diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 911acdc..23034ee 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -50,7 +50,7 @@ struct _DBusDisplayListener { G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT) -#ifdef CONFIG_GBM +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) static void dbus_update_gl_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) @@ -102,6 +102,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, return; } + /* FIXME: add missing x/y/w/h support */ qemu_dbus_display1_listener_call_scanout_dmabuf( ddl->proxy, g_variant_new_handle(0), @@ -129,6 +130,10 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl, .width = backing_width, .height = backing_height, .y0_top = backing_y_0_top, + .x = x, + .y = y, + .scanout_width = w, + .scanout_height = h, }; assert(tex_id); @@ -239,7 +244,7 @@ static void dbus_refresh(DisplayChangeListener *dcl) graphic_hw_update(dcl->con); } -#ifdef CONFIG_GBM +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) static void dbus_gl_gfx_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { @@ -302,7 +307,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl, DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); } -#ifdef CONFIG_GBM +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, struct DisplaySurface *new_surface) { @@ -369,7 +374,7 @@ static void dbus_cursor_define(DisplayChangeListener *dcl, NULL); } -#ifdef CONFIG_GBM +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) const DisplayChangeListenerOps dbus_gl_dcl_ops = { .dpy_name = "dbus-gl", .dpy_gfx_update = dbus_gl_gfx_update, @@ -417,7 +422,7 @@ dbus_display_listener_constructed(GObject *object) DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object); ddl->dcl.ops = &dbus_dcl_ops; -#ifdef CONFIG_GBM +#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM) if (display_opengl) { ddl->dcl.ops = &dbus_gl_dcl_ops; } diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index e844317..1913004 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -88,8 +88,8 @@ void gd_egl_draw(VirtualConsole *vc) #endif gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h); - vc->gfx.scale_x = (double)ww / vc->gfx.w; - vc->gfx.scale_y = (double)wh / vc->gfx.h; + vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds); + vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds); glFlush(); #ifdef CONFIG_GBM @@ -256,7 +256,7 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, } gd_egl_scanout_texture(dcl, dmabuf->texture, - false, dmabuf->width, dmabuf->height, + dmabuf->y0_top, dmabuf->width, dmabuf->height, 0, 0, dmabuf->width, dmabuf->height); if (dmabuf->allow_fences) { diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 7696df1..c384a15 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -298,7 +298,7 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl, } gd_gl_area_scanout_texture(dcl, dmabuf->texture, - false, dmabuf->width, dmabuf->height, + dmabuf->y0_top, dmabuf->width, dmabuf->height, 0, 0, dmabuf->width, dmabuf->height); if (dmabuf->allow_fences) { @@ -130,6 +130,13 @@ typedef struct VCChardev VCChardev; DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV, TYPE_CHARDEV_VC) +struct touch_slot { + int x; + int y; + int tracking_id; +}; +static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX]; + bool gtk_use_gl_area; static void gd_grab_pointer(VirtualConsole *vc, const char *reason); @@ -869,7 +876,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; - GdkWindow *window; int x, y; int mx, my; int fbh, fbw; @@ -882,10 +888,9 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - window = gtk_widget_get_window(vc->gfx.drawing_area); - ww = gdk_window_get_width(window); - wh = gdk_window_get_height(window); - ws = gdk_window_get_scale_factor(window); + ww = gtk_widget_get_allocated_width(widget); + wh = gtk_widget_get_allocated_height(widget); + ws = gtk_widget_get_scale_factor(widget); mx = my = 0; if (ww > fbw) { @@ -1059,6 +1064,82 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll, } +static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch, + void *opaque) +{ + VirtualConsole *vc = opaque; + struct touch_slot *slot; + uint64_t num_slot = GPOINTER_TO_UINT(touch->sequence); + bool needs_sync = false; + int update; + int type = -1; + int i; + + if (num_slot >= INPUT_EVENT_SLOTS_MAX) { + warn_report("gtk: unexpected touch slot number: % " PRId64" >= %d\n", + num_slot, INPUT_EVENT_SLOTS_MAX); + return FALSE; + } + + slot = &touch_slots[num_slot]; + slot->x = touch->x; + slot->y = touch->y; + + switch (touch->type) { + case GDK_TOUCH_BEGIN: + type = INPUT_MULTI_TOUCH_TYPE_BEGIN; + slot->tracking_id = num_slot; + break; + case GDK_TOUCH_UPDATE: + type = INPUT_MULTI_TOUCH_TYPE_UPDATE; + break; + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + type = INPUT_MULTI_TOUCH_TYPE_END; + break; + default: + warn_report("gtk: unexpected touch event type\n"); + } + + for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) { + if (i == num_slot) { + update = type; + } else { + update = INPUT_MULTI_TOUCH_TYPE_UPDATE; + } + + slot = &touch_slots[i]; + + if (slot->tracking_id == -1) { + continue; + } + + if (update == INPUT_MULTI_TOUCH_TYPE_END) { + slot->tracking_id = -1; + qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id); + needs_sync = true; + } else { + qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id); + qemu_input_queue_btn(vc->gfx.dcl.con, INPUT_BUTTON_TOUCH, true); + qemu_input_queue_mtt_abs(vc->gfx.dcl.con, + INPUT_AXIS_X, (int) slot->x, + 0, surface_width(vc->gfx.ds), + i, slot->tracking_id); + qemu_input_queue_mtt_abs(vc->gfx.dcl.con, + INPUT_AXIS_Y, (int) slot->y, + 0, surface_height(vc->gfx.ds), + i, slot->tracking_id); + needs_sync = true; + } + } + + if (needs_sync) { + qemu_input_event_sync(); + } + + return TRUE; +} + static const guint16 *gd_get_keymap(size_t *maplen) { GdkDisplay *dpy = gdk_display_get_default(); @@ -1980,6 +2061,8 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) G_CALLBACK(gd_key_event), vc); g_signal_connect(vc->gfx.drawing_area, "key-release-event", G_CALLBACK(gd_key_event), vc); + g_signal_connect(vc->gfx.drawing_area, "touch-event", + G_CALLBACK(gd_touch_event), vc); g_signal_connect(vc->gfx.drawing_area, "enter-notify-event", G_CALLBACK(gd_enter_event), vc); @@ -2089,6 +2172,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, GSList *group, GtkWidget *view_menu) { bool zoom_to_fit = false; + int i; vc->label = qemu_console_get_label(con); vc->s = s; @@ -2136,6 +2220,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_TOUCH_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK | @@ -2171,6 +2256,11 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, s->free_scale = true; } + for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) { + struct touch_slot *slot = &touch_slots[i]; + slot->tracking_id = -1; + } + return group; } @@ -2446,6 +2536,12 @@ static void early_gtk_display_init(DisplayOptions *opts) gtk_gl_area_init(); } else #endif +#if defined(GDK_WINDOWING_WIN32) + if (GDK_IS_WIN32_DISPLAY(gdk_display_get_default())) { + gtk_use_gl_area = true; + gtk_gl_area_init(); + } else +#endif { #ifdef CONFIG_X11 DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON; @@ -212,6 +212,7 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) InputKeyEvent *key; InputBtnEvent *btn; InputMoveEvent *move; + InputMultiTouchEvent *mtt; if (src) { idx = qemu_console_get_index(src); @@ -250,6 +251,11 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) name = InputAxis_str(move->axis); trace_input_event_abs(idx, name, move->value); break; + case INPUT_EVENT_KIND_MTT: + mtt = evt->u.mtt.data; + name = InputAxis_str(mtt->axis); + trace_input_event_mtt(idx, name, mtt->value); + break; case INPUT_EVENT_KIND__MAX: /* keep gcc happy */ break; @@ -541,6 +547,42 @@ void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, qemu_input_event_send(src, &evt); } +void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type, + int slot, int tracking_id) +{ + InputMultiTouchEvent mtt = { + .type = type, + .slot = slot, + .tracking_id = tracking_id, + }; + InputEvent evt = { + .type = INPUT_EVENT_KIND_MTT, + .u.mtt.data = &mtt, + }; + + qemu_input_event_send(src, &evt); +} + +void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value, + int min_in, int max_in, int slot, int tracking_id) +{ + InputMultiTouchEvent mtt = { + .type = INPUT_MULTI_TOUCH_TYPE_DATA, + .slot = slot, + .tracking_id = tracking_id, + .axis = axis, + .value = qemu_input_scale_axis(value, min_in, max_in, + INPUT_EVENT_ABS_MIN, + INPUT_EVENT_ABS_MAX), + }; + InputEvent evt = { + .type = INPUT_EVENT_KIND_MTT, + .u.mtt.data = &mtt, + }; + + qemu_input_event_send(src, &evt); +} + void qemu_input_check_mode_change(void) { static int current_is_absolute; diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c index 39cab8c..bbfa70e 100644 --- a/ui/sdl2-gl.c +++ b/ui/sdl2-gl.c @@ -67,6 +67,10 @@ void sdl2_gl_update(DisplayChangeListener *dcl, assert(scon->opengl); + if (!scon->real_window) { + return; + } + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h); scon->updates++; @@ -855,7 +855,14 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* only available since SDL 2.0.8 */ SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); #endif +#ifndef CONFIG_WIN32 + /* QEMU uses its own low level keyboard hook procecure on Windows */ SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); +#endif +#ifdef SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED + SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "0"); +#endif + SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1"); memset(&info, 0, sizeof(info)); SDL_VERSION(&info.version); diff --git a/ui/trace-events b/ui/trace-events index 977577f..6747361 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -90,6 +90,7 @@ input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qco input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d" input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d" input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" +input_event_mtt(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" input_event_sync(void) "" input_mouse_mode(int absolute) "absolute %d" diff --git a/util/oslib-win32.c b/util/oslib-win32.c index a986387..fafbab8 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -479,6 +479,13 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, return ret; } +EXCEPTION_DISPOSITION +win32_close_exception_handler(struct _EXCEPTION_RECORD*, + void*, struct _CONTEXT*, void*) +{ + return EXCEPTION_EXECUTE_HANDLER; +} + #undef close int qemu_close_socket_osfhandle(int fd) { @@ -504,12 +511,16 @@ int qemu_close_socket_osfhandle(int fd) return -1; } - /* - * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle, - * but the FD is actually freed - */ - if (close(fd) < 0 && errno != EBADF) { - return -1; + __try1(win32_close_exception_handler) { + /* + * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying + * handle, but the FD is actually freed + */ + if (close(fd) < 0 && errno != EBADF) { + return -1; + } + } + __except1 { } if (!SetHandleInformation((HANDLE)s, flags, flags)) { |