Merge "[Embedded Emulator] UI Styling Update." into emu-master-dev
diff --git a/android-qemu2-glue/qemu-user-event-agent-impl.c b/android-qemu2-glue/qemu-user-event-agent-impl.c
index d253ed8..4b1fffd 100644
--- a/android-qemu2-glue/qemu-user-event-agent-impl.c
+++ b/android-qemu2-glue/qemu-user-event-agent-impl.c
@@ -108,6 +108,15 @@
         kbd_mouse_event(dx, dy, dz, buttonsState);
 }
 
+static void user_event_mouse_wheel(int dx, int dy, int displayId) {
+    if (VERBOSE_CHECK(keys)) {
+        printf(">> MOUSE WHEEL [%d %d]\n", dx, dy);
+    }
+    if (feature_is_enabled(kFeature_VirtioMouse)) {
+        kbd_mouse_wheel_event(dx, dy);
+    }
+}
+
 static void user_event_rotary(int delta) {
     VERBOSE_PRINT(keys, ">> ROTARY [%d]\n", delta);
 
@@ -127,12 +136,12 @@
         .sendKeyCode = user_event_keycode,
         .sendKeyCodes = user_event_keycodes,
         .sendMouseEvent = user_event_mouse,
+        .sendMouseWheelEvent = user_event_mouse_wheel,
         .sendRotaryEvent = user_event_rotary,
         .sendGenericEvent = user_event_generic,
         .sendGenericEvents = user_event_generic_events,
         .onNewUserEvent = on_new_event,
-        .eventsDropped = goldfish_event_drop_count };
-
+        .eventsDropped = goldfish_event_drop_count};
 
 const QAndroidUserEventAgent* const gQAndroidUserEventAgent =
         &sQAndroidUserEventAgent;
diff --git a/android/android-emu/android/emulation/control/AgentLogger.cpp b/android/android-emu/android/emulation/control/AgentLogger.cpp
index 123bd4f..c3e7f64 100644
--- a/android/android-emu/android/emulation/control/AgentLogger.cpp
+++ b/android/android-emu/android/emulation/control/AgentLogger.cpp
@@ -119,6 +119,8 @@
         .sendKeyCode = agent_fwd_with_logging(realUserEventAgent, sendKeyCode),
         .sendKeyCodes = agent_fwd_with_logging_as_array(realUserEventAgent, sendKeyCodes),
         .sendMouseEvent = agent_fwd_with_logging(realUserEventAgent, sendMouseEvent),
+        .sendMouseWheelEvent =
+                agent_fwd_with_logging(realUserEventAgent, sendMouseWheelEvent),
         .sendRotaryEvent = agent_fwd(realUserEventAgent, sendRotaryEvent),
         .sendGenericEvent = agent_fwd_with_logging(realUserEventAgent, sendGenericEvent),
         .sendGenericEvents = agent_fwd_with_logging_as_array(realUserEventAgent, sendGenericEvents),
diff --git a/android/android-emu/android/emulation/control/user_event_agent.h b/android/android-emu/android/emulation/control/user_event_agent.h
index fe13366..fc2cbe5 100644
--- a/android/android-emu/android/emulation/control/user_event_agent.h
+++ b/android/android-emu/android/emulation/control/user_event_agent.h
@@ -36,6 +36,8 @@
                            int dz,
                            int buttonsState,
                            int displayId);
+    // Mouse wheel event.
+    void (*sendMouseWheelEvent)(int dx, int dy, int displayId);
 
     // Rotary encoder events
     // delta is a positive or negative value indicating the change of angle
diff --git a/android/android-emu/android/emulator-window.c b/android/android-emu/android/emulator-window.c
index 39279d4..f862c29 100644
--- a/android/android-emu/android/emulator-window.c
+++ b/android/android-emu/android/emulator-window.c
@@ -111,6 +111,12 @@
     user_event_agent->sendMouseEvent(x, y, 0, state, displayId);
 }
 
+static void emulator_window_window_mouse_wheel_event(int x_delta,
+                                                     int y_delta,
+                                                     int display_id) {
+    user_event_agent->sendMouseWheelEvent(x_delta, y_delta, display_id);
+}
+
 static void emulator_window_window_rotary_input_event(int delta) {
     user_event_agent->sendRotaryEvent(delta);
 }
@@ -212,6 +218,7 @@
     static const SkinWindowFuncs my_window_funcs = {
         .key_event = &emulator_window_window_key_event,
         .mouse_event = &emulator_window_window_mouse_event,
+        .mouse_wheel_event = &emulator_window_window_mouse_wheel_event,
         .rotary_input_event = &emulator_window_window_rotary_input_event,
         .set_device_orientation = &emulator_window_set_device_orientation,
         .opengles_show = &emulator_window_opengles_show_window,
diff --git a/android/android-emu/android/skin/event.h b/android/android-emu/android/skin/event.h
index 1f33cdb..b67a5f5 100644
--- a/android/android-emu/android/skin/event.h
+++ b/android/android-emu/android/skin/event.h
@@ -29,6 +29,7 @@
     kEventMouseButtonDown,
     kEventMouseButtonUp,
     kEventMouseMotion,
+    kEventMouseWheel,
     kEventQuit,
     kEventScrollBarChanged,
     kEventRotaryInput,
@@ -85,6 +86,11 @@
 } SkinEventMouseData;
 
 typedef struct {
+    int x_delta;
+    int y_delta;
+} SkinEventWheelData;
+
+typedef struct {
     SkinRotation rotation;
 } SkinEventLayoutRotateData;
 
@@ -129,6 +135,7 @@
         SkinEventKeyData key;
         SkinEventGenericData generic_event;
         SkinEventMouseData mouse;
+        SkinEventWheelData wheel;
         SkinEventScrollData scroll;
         SkinEventRotaryInputData rotary_input;
         SkinEventTextInputData text;
diff --git a/android/android-emu/android/skin/qt/emulator-qt-window.cpp b/android/android-emu/android/skin/qt/emulator-qt-window.cpp
index f976a43..3a54fdb 100644
--- a/android/android-emu/android/skin/qt/emulator-qt-window.cpp
+++ b/android/android-emu/android/skin/qt/emulator-qt-window.cpp
@@ -2343,6 +2343,20 @@
     queueSkinEvent(skin_event);
 }
 
+void EmulatorQtWindow::handleMouseWheelEvent(int delta,
+                                             Qt::Orientation orientation) {
+    SkinEvent* skin_event = createSkinEvent(kEventMouseWheel);
+    skin_event->u.wheel.x_delta = 0;
+    skin_event->u.wheel.y_delta = 0;
+    if (orientation == Qt::Horizontal) {
+        skin_event->u.wheel.x_delta = delta;
+    } else {
+        skin_event->u.wheel.y_delta = delta;
+    }
+
+    queueSkinEvent(skin_event);
+}
+
 void EmulatorQtWindow::forwardKeyEventToEmulator(SkinEventType type,
                                                  QKeyEvent* event) {
     SkinEvent* skin_event = createSkinEvent(type);
@@ -2775,16 +2789,23 @@
 
 void EmulatorQtWindow::wheelEvent(QWheelEvent* event) {
     if (mIgnoreWheelEvent) {
-      event->ignore();
+        event->ignore();
+    } else if (android::featurecontrol::isEnabled(
+                       android::featurecontrol::VirtioMouse)) {
+        if (mMouseGrabbed) {
+            handleMouseWheelEvent(event->delta() / 8, event->orientation());
+        }
     } else {
-      if (!mWheelScrollTimer.isActive()) {
-        handleMouseEvent(kEventMouseButtonDown, kMouseButtonLeft, event->pos(), QPoint(0,0));
-        mWheelScrollPos = event->pos();
-      }
+        if (!mWheelScrollTimer.isActive()) {
+            handleMouseEvent(kEventMouseButtonDown, kMouseButtonLeft,
+                             event->pos(), QPoint(0, 0));
+            mWheelScrollPos = event->pos();
+        }
 
-      mWheelScrollTimer.start();
-      mWheelScrollPos.setY(mWheelScrollPos.y() + event->delta() / 8);
-      handleMouseEvent(kEventMouseMotion, kMouseButtonLeft, mWheelScrollPos, QPoint(0,0));
+        mWheelScrollTimer.start();
+        mWheelScrollPos.setY(mWheelScrollPos.y() + event->delta() / 8);
+        handleMouseEvent(kEventMouseMotion, kMouseButtonLeft, mWheelScrollPos,
+                         QPoint(0, 0));
     }
 }
 
diff --git a/android/android-emu/android/skin/qt/emulator-qt-window.h b/android/android-emu/android/skin/qt/emulator-qt-window.h
index e6369ce..4b50545 100644
--- a/android/android-emu/android/skin/qt/emulator-qt-window.h
+++ b/android/android-emu/android/skin/qt/emulator-qt-window.h
@@ -229,6 +229,7 @@
                           const QPoint& pos,
                           const QPoint& gPos,
                           bool skipSync = false);
+    void handleMouseWheelEvent(int delta, Qt::Orientation orientation);
     void panHorizontal(bool left);
     void panVertical(bool up);
     SkinEvent* createSkinEvent(SkinEventType type);
diff --git a/android/android-emu/android/skin/ui.c b/android/android-emu/android/skin/ui.c
index 0acec45..e0c2838 100644
--- a/android/android-emu/android/skin/ui.c
+++ b/android/android-emu/android/skin/ui.c
@@ -332,6 +332,12 @@
             skin_window_process_event(ui->window, &ev);
             break;
 
+        case kEventMouseWheel:
+            DE("EVENT: kEventMouseWheel x_delta=%d y_delta=%d\n",
+               ev.u.wheel.x_delta, ev.u.wheel.y_delta);
+            skin_window_process_event(ui->window, &ev);
+            break;
+
         case kEventMouseStartTracking:
             DE("EVENT: kEventMouseStartTracking\n");
             skin_window_process_event(ui->window, &ev);
diff --git a/android/android-emu/android/skin/window.c b/android/android-emu/android/skin/window.c
index cbaccb5..8dee3fc 100644
--- a/android/android-emu/android/skin/window.c
+++ b/android/android-emu/android/skin/window.c
@@ -1092,6 +1092,14 @@
                                    id);
 }
 
+static void add_mouse_wheel_event(SkinWindow* window,
+                                  int32_t x_delta,
+                                  int32_t y_delta) {
+    uint32_t id = 0;
+    // TODO(liyl): handle multi-display and display rotation.
+    window->win_funcs->mouse_wheel_event(x_delta, y_delta, id);
+}
+
 static void
 add_finger_event(SkinWindow* window,
                  FingerState* finger,
@@ -2289,6 +2297,13 @@
         }
         break;
 
+    case kEventMouseWheel:
+        if (feature_is_enabled(kFeature_VirtioMouse) && mouse->tracking) {
+            add_mouse_wheel_event(window, ev->u.wheel.x_delta,
+                                  ev->u.wheel.y_delta);
+        }
+        break;
+
     case kEventMouseStartTracking:
         window->mouse.tracking = 1;
         break;
diff --git a/android/android-emu/android/skin/window.h b/android/android-emu/android/skin/window.h
index c6d36c7..e78daa1b 100644
--- a/android/android-emu/android/skin/window.h
+++ b/android/android-emu/android/skin/window.h
@@ -25,6 +25,7 @@
 typedef struct SkinWindowFuncs {
     void (*key_event)(unsigned keycode, int down);
     void (*mouse_event)(unsigned x, unsigned y, unsigned state, int displayId);
+    void (*mouse_wheel_event)(int x_delta, int y_delta, int displayId);
     void (*rotary_input_event)(int delta);
     void (*set_device_orientation)(SkinRotation rotation);
     int (*opengles_show)(void* winhandle,
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index aa10bbe..13b77a9 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -46,6 +46,8 @@
 static const unsigned short axismap_rel[INPUT_AXIS__MAX] = {
     [INPUT_AXIS_X]                   = REL_X,
     [INPUT_AXIS_Y]                   = REL_Y,
+    [INPUT_AXIS_X_WHEEL]             = REL_HWHEEL,
+    [INPUT_AXIS_Y_WHEEL]             = REL_WHEEL,
 };
 
 static const unsigned short axismap_abs[INPUT_AXIS__MAX] = {
diff --git a/include/ui/console.h b/include/ui/console.h
index 17fc09f..2336e50 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -69,6 +69,8 @@
 
 void kbd_mouse_event(int dx, int dy, int dz, int buttonsState);
 
+void kbd_mouse_wheel_event(int dx, int dy);
+
 struct MouseTransformInfo {
     /* Touchscreen resolution */
     int x;
diff --git a/qemu2-auto-generated/qapi/qapi-types-ui.h b/qemu2-auto-generated/qapi/qapi-types-ui.h
index bb8d242..16594ed 100644
--- a/qemu2-auto-generated/qapi/qapi-types-ui.h
+++ b/qemu2-auto-generated/qapi/qapi-types-ui.h
@@ -311,9 +311,11 @@
 extern const QEnumLookup InputButton_lookup;
 
 typedef enum InputAxis {
-    INPUT_AXIS_X = 0,
-    INPUT_AXIS_Y = 1,
-    INPUT_AXIS__MAX = 2,
+  INPUT_AXIS_X = 0,
+  INPUT_AXIS_Y = 1,
+  INPUT_AXIS_X_WHEEL = 2,
+  INPUT_AXIS_Y_WHEEL = 3,
+  INPUT_AXIS__MAX = 4,
 } InputAxis;
 
 #define InputAxis_str(val) \
diff --git a/ui/console.c b/ui/console.c
index 3726b67..85c9a7a 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2430,6 +2430,14 @@
     qemu_input_event_sync();
 }
 
+void kbd_mouse_wheel_event(int dx, int dy) {
+  assert(active_console && qemu_console_is_graphic(active_console));
+  qemu_input_queue_rel(active_console, INPUT_AXIS_X_WHEEL, dx);
+  qemu_input_queue_rel(active_console, INPUT_AXIS_Y_WHEEL, dy);
+
+  qemu_input_event_sync();
+}
+
 static const TypeInfo qemu_console_info = {
     .name = TYPE_QEMU_CONSOLE,
     .parent = TYPE_OBJECT,