Merge "Make the GSM simulator more realistic"
diff --git a/Makefile.android b/Makefile.android
index 2eb39c4..5d0d6e8 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -564,6 +564,25 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 ##############################################################################
+# Common CFLAGS for UI and Core builds
+
+# add the build ID to the default macro definitions
+UI_AND_CORE_CFLAGS = -DANDROID_BUILD_ID="$(strip $(BUILD_ID))-$(strip $(BUILD_NUMBER))"
+
+# For non-standalone builds, extract the major version number from the Android SDK
+# tools revision number.
+ifneq ($(BUILD_STANDALONE_EMULATOR),true)
+    ANDROID_SDK_TOOLS_REVISION := $(shell awk -F= '/Pkg.Revision/ { print $$2; }' sdk/files/tools_source.properties)
+endif
+
+ANDROID_SDK_TOOLS_REVISION := $(strip $(ANDROID_SDK_TOOLS_REVISION))
+ifdef ANDROID_SDK_TOOLS_REVISION
+    UI_AND_CORE_CFLAGS += -DANDROID_SDK_TOOLS_REVISION=$(ANDROID_SDK_TOOLS_REVISION)
+endif
+
+UI_AND_CORE_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+##############################################################################
 # lists of source files used to build the emulator core
 #
 
@@ -632,6 +651,7 @@
                     bt-vhci.c \
                     module.c \
                     android/boot-properties.c \
+                    android/display.c \
                     android/hw-kmsg.c \
                     android/hw-lcd.c \
                     android/gps.c \
@@ -641,6 +661,7 @@
                     android/avd/hw-config.c \
                     android/avd/info.c \
                     android/utils/ini.c \
+                    android/hw-sensors.c \
 
 ifeq ($(HOST_ARCH),x86)
     CORE_MISC_SOURCES += i386-dis.c
@@ -717,9 +738,42 @@
                       android/utils/timezone.c \
                       android/utils/mapfile.c \
 
+# include the Zlib sources
+#
+UI_AND_CORE_SOURCES += $(ZLIB_SOURCES)
+UI_AND_CORE_CFLAGS  += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
+
+# include the Libpng sources
+#
+UI_AND_CORE_SOURCES += $(LIBPNG_SOURCES)
+UI_AND_CORE_CFLAGS  += $(LIBPNG_CFLAGS) -I$(LOCAL_PATH)/$(LIBPNG_DIR)
+
 # temp files used to collect UI->Core exchange protocol.
 UI_AND_CORE_SOURCES += android/ui-core-protocol.c android/core-ui-protocol.c
 
+# The common libraries
+#
+QEMU_SYSTEM_LDLIBS := -lm
+ifeq ($(HOST_OS),windows)
+  QEMU_SYSTEM_LDLIBS += -mno-cygwin -mwindows -mconsole
+endif
+
+ifeq ($(HOST_OS),freebsd)
+    QEMU_SYSTEM_LDLIBS += -L/usr/local/lib -lpthread -lX11 -lutil
+endif
+
+ifeq ($(HOST_OS),linux)
+  QEMU_SYSTEM_LDLIBS += -lutil -lrt
+endif
+
+ifeq ($(HOST_OS),windows)
+  QEMU_SYSTEM_LDLIBS += -lwinmm -lws2_32 -liphlpapi
+else
+  QEMU_SYSTEM_LDLIBS += -lpthread
+endif
+
+
+
 ##############################################################################
 # now build the emulator itself
 #
@@ -737,28 +791,7 @@
 LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS) $(EMULATOR_UI_CFLAGS)
 
 # add the build ID to the default macro definitions
-LOCAL_CFLAGS += -DANDROID_BUILD_ID="$(strip $(BUILD_ID))-$(strip $(BUILD_NUMBER))"
-
-# For non-standalone builds, extract the major version number from the Android SDK
-# tools revision number.
-ifneq ($(BUILD_STANDALONE_EMULATOR),true)
-    ANDROID_SDK_TOOLS_REVISION := $(shell awk -F= '/Pkg.Revision/ { print $$2; }' sdk/files/tools_source.properties)
-endif
-
-ANDROID_SDK_TOOLS_REVISION := $(strip $(ANDROID_SDK_TOOLS_REVISION))
-ifdef ANDROID_SDK_TOOLS_REVISION
-    LOCAL_CFLAGS += -DANDROID_SDK_TOOLS_REVISION=$(ANDROID_SDK_TOOLS_REVISION)
-endif
-
-# include the Zlib sources
-#
-LOCAL_SRC_FILES += $(ZLIB_SOURCES)
-LOCAL_CFLAGS    += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
-
-# include the Libpng sources
-#
-LOCAL_SRC_FILES += $(LIBPNG_SOURCES)
-LOCAL_CFLAGS    += $(LIBPNG_CFLAGS) -I$(LOCAL_PATH)/$(LIBPNG_DIR)
+LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS)
 
 # include sound support source files. we first try to see if we have a prebuilt audio
 # library. if not, we build things the "hard" way.
@@ -792,23 +825,14 @@
               user-events-qemu.c \
               android/cmdline-option.c \
               android/config.c \
-              android/hw-sensors.c \
               android/main.c \
 
-ifeq ($(HOST_OS),windows)
-  LOCAL_LDLIBS += -mno-cygwin -mwindows -mconsole
-endif
-
-ifeq ($(HOST_OS),freebsd)
-    LOCAL_LDLIBS += -L/usr/local/lib -lpthread -lX11 -lutil
-endif
+# Add common system libraries
+#
+LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)
 
 LOCAL_SRC_FILES += $(VL_SOURCES) $(CORE_SOURCES) $(UI_SOURCES) $(UI_AND_CORE_SOURCES)
 
-ifeq ($(HOST_OS),linux)
-  LOCAL_LDLIBS += -lutil -lrt
-endif
-
 # add SDL-specific flags
 #
 LOCAL_CFLAGS += $(SDL_CFLAGS)
@@ -917,18 +941,6 @@
   LOCAL_CFLAGS += -I$(intermediates)
 endif
 
-
-
-# other flags
-LOCAL_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-LOCAL_LDLIBS += -lm
-
-ifeq ($(HOST_OS),windows)
-    LOCAL_LDLIBS += -lwinmm -lws2_32 -liphlpapi
-else
-    LOCAL_LDLIBS += -lpthread
-endif
-
 LOCAL_LDLIBS += $(QEMU_AUDIO_LIB)
 
 # Generate a completely static executable if needed.
@@ -946,4 +958,174 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
+##############################################################################
+# Build standalone emulator core.
+#
+include $(CLEAR_VARS)
+
+LOCAL_GENERATED_SOURCES :=
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC                        := $(MY_CC)
+LOCAL_MODULE                    := qemu-android
+LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-arm emulator-tcg
+LOCAL_STATIC_LIBRARIES          += emulator-elff
+LOCAL_STATIC_LIBRARIES          += emulator-core
+LOCAL_LDLIBS                    := $(MY_LDLIBS)
+
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS)
+LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS) -DCONFIG_STANDALONE_CORE
+
+# include sound support source files. we first try to see if we have a prebuilt audio
+# library. if not, we build things the "hard" way.
+#
+# note that to generate the prebuilt audio library, you should do the following:
+#
+#   cd tools/qemu
+#   ./android-rebuild.sh
+#   distrib/update-audio.sh
+#
+ifeq ($(QEMU_AUDIO_LIB),)
+  LOCAL_SRC_FILES += $(AUDIO_SOURCES)
+endif  # !QEMU_AUDIO_LIB
+
+LOCAL_CFLAGS  += $(AUDIO_CFLAGS)
+LOCAL_LDLIBS  += $(AUDIO_LDLIBS)
+
+# the linux-user sources, I doubt we really need these
+#
+#LINUX_SOURCES := main.c elfload.c mmap.c signal.c path.c syscall.c
+#LOCAL_SRC_FILES += $(LINUX_SOURCES:%=linux-user/%)
+
+# include other sources
+#
+VL_SOURCES := framebuffer.c \
+              user-events-qemu.c \
+
+# Add common system libraries
+#
+LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)
+
+LOCAL_SRC_FILES += $(VL_SOURCES) $(CORE_SOURCES) $(UI_AND_CORE_SOURCES)
+
+# add ELFF-specific flags
+#
+LOCAL_LDLIBS += $(ELFF_LDLIBS)
+
+# on Windows, link the icon file as well into the executable
+# unfortunately, our build system doesn't help us much, so we need
+# to use some weird pathnames to make this work...
+#
+ifeq ($(HOST_OS),windows)
+
+# Locate windres executable
+WINDRES := windres
+ifneq ($(USE_MINGW),)
+  # When building the Windows emulator under Linux, use the MinGW one
+  WINDRES := i586-mingw32msvc-windres
+endif
+
+INTERMEDIATE     := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+ANDROID_ICON_OBJ := android_icon.o
+ANDROID_ICON_PATH := $(LOCAL_PATH)/images
+$(ANDROID_ICON_PATH)/$(ANDROID_ICON_OBJ): $(ANDROID_ICON_PATH)/android_icon.rc
+	$(WINDRES) $< -I $(ANDROID_ICON_PATH) -o $@
+
+# seems to be the only way to add an object file that was not generated from
+# a C/C++/Java source file to our build system. and very unfortunately,
+# $(TOPDIR)/$(LOCALPATH) will always be prepended to this value, which forces
+# us to put the object file in the source directory...
+#
+LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
+endif
+
+# qemu-options.h is generated from qemu-options.hx with the "hxtool" shell script
+#
+intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+
+QEMU_OPTIONS_H := $(intermediates)/qemu-options.h
+$(QEMU_OPTIONS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_OPTIONS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
+$(QEMU_OPTIONS_H): $(LOCAL_PATH)/qemu-options.hx $(LOCAL_PATH)/hxtool
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_OPTIONS_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_OPTIONS_H)
+
+# qemu-monitor.h is generated from qemu-monitor.hx with the "hxtool" shell script
+#
+intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+
+QEMU_MONITOR_H := $(intermediates)/qemu-monitor.h
+$(QEMU_MONITOR_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_MONITOR_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
+$(QEMU_MONITOR_H): $(LOCAL_PATH)/qemu-monitor.hx $(LOCAL_PATH)/hxtool
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_MONITOR_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_MONITOR_H)
+
+
+# gdbstub-xml.c contains C-compilable arrays corresponding to the content
+# of $(LOCAL_PATH)/gdb-xml/, and is generated with the 'feature_to_c.sh' script.
+#
+ifeq ($(QEMU_TARGET_XML_SOURCES),)
+    QEMU_TARGET_XML_SOURCES := arm-core arm-neon arm-vfp arm-vfp3
+    QEMU_TARGET_XML_SOURCES := $(QEMU_TARGET_XML_SOURCES:%=$(LOCAL_PATH)/gdb-xml/%.xml)
+endif
+
+QEMU_GDBSTUB_XML_C := $(intermediates)/gdbstub-xml.c
+$(QEMU_GDBSTUB_XML_C): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_SOURCES := $(TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/feature_to_c.sh $@ $(QEMU_TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): $(QEMU_TARGET_XML_SOURCES) $(LOCAL_PATH)/feature_to_c.sh
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_GDBSTUB_XML_C)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_GDBSTUB_XML_C)
+
+# hw-config-defs.h is generated from android/avd/hardware-properties.ini
+#
+QEMU_HARDWARE_PROPERTIES_INI := $(LOCAL_PATH)/android/avd/hardware-properties.ini
+QEMU_HW_CONFIG_DEFS_H := $(LOCAL_PATH)/android/avd/hw-config-defs.h
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_SOURCES := $(QEMU_HARDWARE_PROPERTIES_INI)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/android/tools/gen-hw-config.py $(QEMU_HARDWARE_PROPERTIES_INI) $@
+$(QEMU_HW_CONFIG_DEFS_H): $(QEMU_HARDWARE_PROPERTIES_INI) $(LOCAL_PATH)/android/tools/gen-hw-config.py
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+$(LOCAL_PATH)/android/avd/hw-config.h: $(QEMU_HW_CONFIG_DEFS_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_HW_CONFIG_DEFS_H)
+
+# this is already done by the Android build system, but is done for the
+# benefit of the stand-alone one.
+#
+ifeq ($(BUILD_STANDALONE_EMULATOR),true)
+  LOCAL_CFLAGS += -I$(intermediates)
+endif
+
+# other flags
+ifneq ($(HOST_OS),windows)
+    LOCAL_LDLIBS += -ldl
+endif
+
+LOCAL_LDLIBS += $(QEMU_AUDIO_LIB)
+
+# Generate a completely static executable if needed.
+# Note that this means no sound and graphics on Linux.
+#
+ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
+    LOCAL_SRC_FILES += dynlink-static.c
+    LOCAL_LDLIBS    += -static
+endif
+
+LOCAL_MODULE := qemu-android
+
+include $(BUILD_HOST_EXECUTABLE)
+
 endif  # TARGET_ARCH == arm
diff --git a/aio-android.c b/aio-android.c
index 53f7a6d..2b67579 100644
--- a/aio-android.c
+++ b/aio-android.c
@@ -151,6 +151,11 @@
 
         walking_handlers = 0;
 
+        /* No AIO operations? Get us out of here */
+        if (!iolooper_has_operations(looper)) {
+            break;
+        }
+
         /* wait until next event */
         ret = iolooper_wait(looper, -1);
 
diff --git a/android/display.c b/android/display.c
new file mode 100644
index 0000000..0cfd98d
--- /dev/null
+++ b/android/display.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/* Initialization of the Android-specific DisplayState.
+ * Read docs/DISPLAY-STATE.TXT to understand what this
+ * is supposed to do.
+ */
+#include "android/display.h"
+
+/*
+
+TECHNICAL NOTE:
+
+DisplayState <--> QFrameBuffer <--> QEmulator/SDL
+
+*/
+
+/* QFrameBuffer producer callbacks */
+
+/* this is called periodically by the GUI timer to check for updates
+ * and poll user events. Use vga_hw_update().
+ */
+static void
+android_display_producer_check(void *opaque)
+{
+    /* core: call vga_hw_update(). this will eventually
+     * lead to calls to android_display_update()
+     */
+    (void)opaque;
+    vga_hw_update();
+}
+
+static void
+android_display_producer_invalidate(void *opaque)
+{
+    (void)opaque;
+    vga_hw_invalidate();
+}
+
+/* QFrameBuffer client callbacks */
+
+/* this is called from dpy_update() each time a hardware framebuffer
+ * rectangular update was detected. Send this to the QFrameBuffer.
+ */
+static void
+android_display_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    QFrameBuffer* qfbuff = ds->opaque;
+    qframebuffer_update(qfbuff, x, y, w, h);
+}
+
+static void
+android_display_resize(DisplayState *ds)
+{
+    QFrameBuffer* qfbuff = ds->opaque;
+    qframebuffer_rotate(qfbuff, 0);
+}
+
+static void
+android_display_refresh(DisplayState *ds)
+{
+    QFrameBuffer* qfbuff = ds->opaque;
+    qframebuffer_poll(qfbuff);
+}
+
+
+void android_display_init(DisplayState* ds, QFrameBuffer* qf)
+{
+    DisplayChangeListener* dcl;
+
+    qframebuffer_set_producer(qf, ds,
+                              android_display_producer_check,
+                              android_display_producer_invalidate,
+                              NULL); // detach
+
+    /* Replace the display surface with one with the right dimensions */
+    qemu_free_displaysurface(ds);
+    ds->opaque    = qf;
+    ds->surface   = qemu_create_displaysurface_from(qf->width,
+                                                    qf->height,
+                                                    16,
+                                                    qf->pitch,
+                                                    qf->pixels);
+
+    /* Register a change listener for it */
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update      = android_display_update;
+    dcl->dpy_resize      = android_display_resize;
+    dcl->dpy_refresh     = android_display_refresh;
+    dcl->dpy_text_cursor = NULL;
+
+    register_displaychangelistener(ds, dcl);
+}
diff --git a/android/display.h b/android/display.h
new file mode 100644
index 0000000..111979c
--- /dev/null
+++ b/android/display.h
@@ -0,0 +1,20 @@
+/* Copyright (C) 2010 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_DISPLAY_H
+#define _ANDROID_DISPLAY_H
+
+#include "console.h"
+#include "framebuffer.h"
+
+extern void android_display_init(DisplayState* ds, QFrameBuffer* qfbuff);
+
+#endif /* _ANDROID_DISPLAY_H */
diff --git a/android/main.c b/android/main.c
index 88ce36b..99720f5 100644
--- a/android/main.c
+++ b/android/main.c
@@ -70,11 +70,13 @@
 #include "tcpdump.h"
 
 #include "android/qemulator.h"
+#include "android/display.h"
 
 /* in vl.c */
 extern void  qemu_help(int  code);
 
 #include "framebuffer.h"
+
 AndroidRotation  android_framebuffer_rotation;
 
 #define  STRINGIFY(x)   _STRINGIFY(x)
@@ -103,8 +105,6 @@
 static int  opts->flashkeys;      /* forward */
 #endif
 
-static void  handle_key_command( void*  opaque, SkinKeyCommand  command, int  param );
-
 #ifdef CONFIG_TRACE
 extern void  start_tracing(void);
 extern void  stop_tracing(void);
@@ -247,298 +247,6 @@
 /*****                                                             *****/
 /***********************************************************************/
 /***********************************************************************/
-
-/* called by the emulated framebuffer device each time the content of the
- * framebuffer has changed. the rectangle is the bounding box of all changes
- */
-static void
-sdl_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    /* this function is being called from the console code that is currently inactive
-    ** simple totally ignore it...
-    */
-    (void)ds;
-    (void)x;
-    (void)y;
-    (void)w;
-    (void)h;
-}
-
-
-
-
-/* called by the emulated framebuffer device each time the framebuffer
- * is resized or rotated */
-static void
-sdl_resize(DisplayState *ds)
-{
-    //fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
-    //exit(1);
-}
-
-
-/* called periodically to poll for user input events */
-static void sdl_refresh(DisplayState *ds)
-{
-    QEmulator*     emulator = ds->opaque;
-    SDL_Event      ev;
-    SkinWindow*    window   = emulator->window;
-    SkinKeyboard*  keyboard = emulator->keyboard;
-
-   /* this will eventually call sdl_update if the content of the VGA framebuffer
-    * has changed */
-    qframebuffer_check_updates();
-
-    if (window == NULL)
-        return;
-
-    while(SDL_PollEvent(&ev)){
-        switch(ev.type){
-        case SDL_VIDEOEXPOSE:
-            skin_window_redraw( window, NULL );
-            break;
-
-        case SDL_KEYDOWN:
-#ifdef _WIN32
-            /* special code to deal with Alt-F4 properly */
-            if (ev.key.keysym.sym == SDLK_F4 &&
-                ev.key.keysym.mod & KMOD_ALT) {
-              goto CleanExit;
-            }
-#endif
-#ifdef __APPLE__
-            /* special code to deal with Command-Q properly */
-            if (ev.key.keysym.sym == SDLK_q &&
-                ev.key.keysym.mod & KMOD_META) {
-              goto CleanExit;
-            }
-#endif
-            skin_keyboard_process_event( keyboard, &ev, 1 );
-            break;
-
-        case SDL_KEYUP:
-            skin_keyboard_process_event( keyboard, &ev, 0 );
-            break;
-
-        case SDL_MOUSEMOTION:
-            skin_window_process_event( window, &ev );
-            break;
-
-        case SDL_MOUSEBUTTONDOWN:
-        case SDL_MOUSEBUTTONUP:
-            {
-                int  down = (ev.type == SDL_MOUSEBUTTONDOWN);
-                if (ev.button.button == 4)
-                {
-                    /* scroll-wheel simulates DPad up */
-                    AndroidKeyCode  kcode;
-
-                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
-                        android_keycode_rotate(kKeyCodeDpadUp,
-                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
-                    user_event_key( kcode, down );
-                }
-                else if (ev.button.button == 5)
-                {
-                    /* scroll-wheel simulates DPad down */
-                    AndroidKeyCode  kcode;
-
-                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
-                        android_keycode_rotate(kKeyCodeDpadDown,
-                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
-                    user_event_key( kcode, down );
-                }
-                else if (ev.button.button == SDL_BUTTON_LEFT) {
-                    skin_window_process_event( window, &ev );
-                }
-#if 0
-                else {
-                fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
-                                down ? "down" : "up  ",
-                                ev.button.button, ev.button.state, ev.button.x, ev.button.y);
-                }
-#endif
-            }
-            break;
-
-        case SDL_QUIT:
-#if defined _WIN32 || defined __APPLE__
-        CleanExit:
-#endif
-            /* only save emulator config through clean exit */
-            qemulator_done(qemulator_get());
-            qemu_system_shutdown_request();
-            return;
-        }
-    }
-
-    skin_keyboard_flush( keyboard );
-}
-
-
-/* used to respond to a given keyboard command shortcut
- */
-static void
-handle_key_command( void*  opaque, SkinKeyCommand  command, int  down )
-{
-    static const struct { SkinKeyCommand  cmd; AndroidKeyCode  kcode; }  keycodes[] =
-    {
-        { SKIN_KEY_COMMAND_BUTTON_CALL,   kKeyCodeCall },
-        { SKIN_KEY_COMMAND_BUTTON_HOME,   kKeyCodeHome },
-        { SKIN_KEY_COMMAND_BUTTON_BACK,   kKeyCodeBack },
-        { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
-        { SKIN_KEY_COMMAND_BUTTON_POWER,  kKeyCodePower },
-        { SKIN_KEY_COMMAND_BUTTON_SEARCH,      kKeyCodeSearch },
-        { SKIN_KEY_COMMAND_BUTTON_MENU,        kKeyCodeMenu },
-        { SKIN_KEY_COMMAND_BUTTON_DPAD_UP,     kKeyCodeDpadUp },
-        { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT,   kKeyCodeDpadLeft },
-        { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT,  kKeyCodeDpadRight },
-        { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN,   kKeyCodeDpadDown },
-        { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
-        { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP,   kKeyCodeVolumeUp },
-        { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
-        { SKIN_KEY_COMMAND_BUTTON_CAMERA,      kKeyCodeCamera },
-        { SKIN_KEY_COMMAND_NONE, 0 }
-    };
-    int          nn;
-#ifdef CONFIG_TRACE
-    static int   tracing = 0;
-#endif
-    QEmulator*   emulator = opaque;
-
-
-    for (nn = 0; keycodes[nn].kcode != 0; nn++) {
-        if (command == keycodes[nn].cmd) {
-            unsigned  code = keycodes[nn].kcode;
-            if (down)
-                code |= 0x200;
-            kbd_put_keycode( code );
-            return;
-        }
-    }
-
-    // for the show-trackball command, handle down events to enable, and
-    // up events to disable
-    if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
-        emulator->show_trackball = (down != 0);
-        skin_window_show_trackball( emulator->window, emulator->show_trackball );
-        //qemulator_set_title( emulator );
-        return;
-    }
-
-    // only handle down events for the rest
-    if (down == 0)
-        return;
-
-    switch (command)
-    {
-    case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
-        {
-            qemu_net_disable = !qemu_net_disable;
-            if (android_modem) {
-                amodem_set_data_registration(
-                        android_modem,
-                qemu_net_disable ? A_REGISTRATION_UNREGISTERED
-                    : A_REGISTRATION_HOME);
-            }
-            D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
-        }
-        break;
-
-    case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
-        if (emulator->window) {
-            skin_window_toggle_fullscreen(emulator->window);
-        }
-        break;
-
-    case SKIN_KEY_COMMAND_TOGGLE_TRACING:
-        {
-#ifdef CONFIG_TRACE
-            tracing = !tracing;
-            if (tracing)
-                start_tracing();
-            else
-                stop_tracing();
-#endif
-        }
-        break;
-
-    case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
-        emulator->show_trackball = !emulator->show_trackball;
-        skin_window_show_trackball( emulator->window, emulator->show_trackball );
-        qemulator_set_title(emulator);
-        break;
-
-    case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
-    case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
-        if (emulator->onion)
-        {
-            int  alpha = emulator->onion_alpha;
-
-            if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
-                alpha += 16;
-            else
-                alpha -= 16;
-
-            if (alpha > 256)
-                alpha = 256;
-            else if (alpha < 0)
-                alpha = 0;
-
-            emulator->onion_alpha = alpha;
-            skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
-            skin_window_redraw( emulator->window, NULL );
-            //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
-        }
-        break;
-
-    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
-    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
-        {
-            SkinLayout*  layout = NULL;
-
-            if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
-                layout = emulator->layout->next;
-                if (layout == NULL)
-                    layout = emulator->layout_file->layouts;
-            }
-            else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
-                layout = emulator->layout_file->layouts;
-                while (layout->next && layout->next != emulator->layout)
-                    layout = layout->next;
-            }
-            if (layout != NULL) {
-                SkinRotation  rotation;
-
-                emulator->layout = layout;
-                skin_window_reset( emulator->window, layout );
-
-                rotation = skin_layout_get_dpad_rotation( layout );
-
-                if (emulator->keyboard)
-                    skin_keyboard_set_rotation( emulator->keyboard, rotation );
-
-                if (emulator->trackball) {
-                    skin_trackball_set_rotation( emulator->trackball, rotation );
-                    skin_window_set_trackball( emulator->window, emulator->trackball );
-                    skin_window_show_trackball( emulator->window, emulator->show_trackball );
-                }
-
-                skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
-
-                qframebuffer_invalidate_all();
-                qframebuffer_check_updates();
-            }
-        }
-        break;
-
-    default:
-        /* XXX: TODO ? */
-        ;
-    }
-}
-
-
 static void sdl_at_exit(void)
 {
     emulator_config_done();
@@ -551,8 +259,8 @@
 {
     QEmulator*    emulator = qemulator_get();
     SkinDisplay*  disp     = skin_layout_get_display(emulator->layout);
-    DisplayChangeListener*  dcl;
     int           width, height;
+    char          buf[128];
 
     if (disp->rotation & 1) {
         width  = disp->rect.size.h;
@@ -562,22 +270,8 @@
         height = disp->rect.size.h;
     }
 
-    /* Register a display state object for the emulated framebuffer */
-    ds->allocator = &default_allocator;
-    ds->opaque    = emulator;
-    ds->surface   = qemu_create_displaysurface(ds, width, height);
-    register_displaystate(ds);
-
-    /* Register a change listener for it */
-    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
-    dcl->dpy_update      = sdl_update;
-    dcl->dpy_resize      = sdl_resize;
-    dcl->dpy_refresh     = sdl_refresh;
-    dcl->dpy_text_cursor = NULL;
-    register_displaychangelistener(ds, dcl);
-
-    skin_keyboard_enable( emulator->keyboard, 1 );
-    skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+    snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
+    android_display_init(ds, qframebuffer_fifo_get());
 }
 
 
diff --git a/android/qemulator.c b/android/qemulator.c
index 7d2d2e8..f6dc550 100644
--- a/android/qemulator.c
+++ b/android/qemulator.c
@@ -15,6 +15,7 @@
 #include "android/globals.h"
 #include "android/qemulator.h"
 #include "android/ui-core-protocol.h"
+#include "user-events.h"
 
 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
 static double get_default_scale( AndroidOptions*  opts );
@@ -22,6 +23,9 @@
 /* QEmulator structure instance. */
 static QEmulator   qemulator[1];
 
+static void handle_key_command( void*  opaque, SkinKeyCommand  command, int  param );
+static void qemulator_refresh(QEmulator* emulator);
+
 static void
 qemulator_light_brightness( void* opaque, const char*  light, int  value )
 {
@@ -98,11 +102,18 @@
 static void
 qemulator_fb_rotate( void*  _emulator, int  rotation )
 {
-    QEmulator*     emulator = _emulator;
+    QEmulator*  emulator = _emulator;
 
     qemulator_setup( emulator );
 }
 
+static void
+qemulator_fb_poll( void* _emulator )
+{
+    QEmulator* emulator = _emulator;
+    qemulator_refresh(emulator);
+}
+
 QEmulator*
 qemulator_get(void)
 {
@@ -141,12 +152,17 @@
         SkinDisplay*  disp = part->display;
         if (disp->valid) {
             qframebuffer_add_client( disp->qfbuff,
-                                        emulator,
-                                        qemulator_fb_update,
-                                        qemulator_fb_rotate,
-                                        NULL );
+                                     emulator,
+                                     qemulator_fb_update,
+                                     qemulator_fb_rotate,
+                                     qemulator_fb_poll,
+                                     NULL );
         }
     SKIN_FILE_LOOP_END_PARTS
+
+    skin_keyboard_enable( emulator->keyboard, 1 );
+    skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+
     return 0;
 }
 
@@ -301,6 +317,260 @@
     return scale;
 }
 
+/* used to respond to a given keyboard command shortcut
+ */
+static void
+handle_key_command( void*  opaque, SkinKeyCommand  command, int  down )
+{
+    static const struct { SkinKeyCommand  cmd; AndroidKeyCode  kcode; }  keycodes[] =
+    {
+        { SKIN_KEY_COMMAND_BUTTON_CALL,   kKeyCodeCall },
+        { SKIN_KEY_COMMAND_BUTTON_HOME,   kKeyCodeHome },
+        { SKIN_KEY_COMMAND_BUTTON_BACK,   kKeyCodeBack },
+        { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
+        { SKIN_KEY_COMMAND_BUTTON_POWER,  kKeyCodePower },
+        { SKIN_KEY_COMMAND_BUTTON_SEARCH,      kKeyCodeSearch },
+        { SKIN_KEY_COMMAND_BUTTON_MENU,        kKeyCodeMenu },
+        { SKIN_KEY_COMMAND_BUTTON_DPAD_UP,     kKeyCodeDpadUp },
+        { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT,   kKeyCodeDpadLeft },
+        { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT,  kKeyCodeDpadRight },
+        { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN,   kKeyCodeDpadDown },
+        { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
+        { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP,   kKeyCodeVolumeUp },
+        { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
+        { SKIN_KEY_COMMAND_BUTTON_CAMERA,      kKeyCodeCamera },
+        { SKIN_KEY_COMMAND_NONE, 0 }
+    };
+    int          nn;
+#ifdef CONFIG_TRACE
+    static int   tracing = 0;
+#endif
+    QEmulator*   emulator = opaque;
+
+
+    for (nn = 0; keycodes[nn].kcode != 0; nn++) {
+        if (command == keycodes[nn].cmd) {
+            unsigned  code = keycodes[nn].kcode;
+            if (down)
+                code |= 0x200;
+            user_event_keycode( code );
+            return;
+        }
+    }
+
+    // for the show-trackball command, handle down events to enable, and
+    // up events to disable
+    if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
+        emulator->show_trackball = (down != 0);
+        skin_window_show_trackball( emulator->window, emulator->show_trackball );
+        //qemulator_set_title( emulator );
+        return;
+    }
+
+    // only handle down events for the rest
+    if (down == 0)
+        return;
+
+    switch (command)
+    {
+    case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
+        {
+            qemu_net_disable = !qemu_net_disable;
+            android_core_set_network_enabled(!qemu_net_disable);
+            D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
+        }
+        break;
+
+    case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
+        if (emulator->window) {
+            skin_window_toggle_fullscreen(emulator->window);
+        }
+        break;
+
+    case SKIN_KEY_COMMAND_TOGGLE_TRACING:
+        {
+#ifdef CONFIG_TRACE
+            tracing = !tracing;
+            if (tracing)
+                android_core_tracing_start();
+            else
+                android_core_tracing_stop();
+#endif
+        }
+        break;
+
+    case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
+        emulator->show_trackball = !emulator->show_trackball;
+        skin_window_show_trackball( emulator->window, emulator->show_trackball );
+        qemulator_set_title(emulator);
+        break;
+
+    case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
+    case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
+        if (emulator->onion)
+        {
+            int  alpha = emulator->onion_alpha;
+
+            if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
+                alpha += 16;
+            else
+                alpha -= 16;
+
+            if (alpha > 256)
+                alpha = 256;
+            else if (alpha < 0)
+                alpha = 0;
+
+            emulator->onion_alpha = alpha;
+            skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
+            skin_window_redraw( emulator->window, NULL );
+            //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
+        }
+        break;
+
+    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
+    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
+        {
+            SkinLayout*  layout = NULL;
+
+            if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
+                layout = emulator->layout->next;
+                if (layout == NULL)
+                    layout = emulator->layout_file->layouts;
+            }
+            else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
+                layout = emulator->layout_file->layouts;
+                while (layout->next && layout->next != emulator->layout)
+                    layout = layout->next;
+            }
+            if (layout != NULL) {
+                SkinRotation  rotation;
+
+                emulator->layout = layout;
+                skin_window_reset( emulator->window, layout );
+
+                rotation = skin_layout_get_dpad_rotation( layout );
+
+                if (emulator->keyboard)
+                    skin_keyboard_set_rotation( emulator->keyboard, rotation );
+
+                if (emulator->trackball) {
+                    skin_trackball_set_rotation( emulator->trackball, rotation );
+                    skin_window_set_trackball( emulator->window, emulator->trackball );
+                    skin_window_show_trackball( emulator->window, emulator->show_trackball );
+                }
+
+                skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
+
+                qframebuffer_invalidate_all();
+                qframebuffer_check_updates();
+            }
+        }
+        break;
+
+    default:
+        /* XXX: TODO ? */
+        ;
+    }
+}
+
+/* called periodically to poll for user input events */
+static void qemulator_refresh(QEmulator* emulator)
+{
+    SDL_Event      ev;
+    SkinWindow*    window   = emulator->window;
+    SkinKeyboard*  keyboard = emulator->keyboard;
+
+   /* this will eventually call sdl_update if the content of the VGA framebuffer
+    * has changed */
+    qframebuffer_check_updates();
+
+    if (window == NULL)
+        return;
+
+    while(SDL_PollEvent(&ev)){
+        switch(ev.type){
+        case SDL_VIDEOEXPOSE:
+            skin_window_redraw( window, NULL );
+            break;
+
+        case SDL_KEYDOWN:
+#ifdef _WIN32
+            /* special code to deal with Alt-F4 properly */
+            if (ev.key.keysym.sym == SDLK_F4 &&
+                ev.key.keysym.mod & KMOD_ALT) {
+              goto CleanExit;
+            }
+#endif
+#ifdef __APPLE__
+            /* special code to deal with Command-Q properly */
+            if (ev.key.keysym.sym == SDLK_q &&
+                ev.key.keysym.mod & KMOD_META) {
+              goto CleanExit;
+            }
+#endif
+            skin_keyboard_process_event( keyboard, &ev, 1 );
+            break;
+
+        case SDL_KEYUP:
+            skin_keyboard_process_event( keyboard, &ev, 0 );
+            break;
+
+        case SDL_MOUSEMOTION:
+            skin_window_process_event( window, &ev );
+            break;
+
+        case SDL_MOUSEBUTTONDOWN:
+        case SDL_MOUSEBUTTONUP:
+            {
+                int  down = (ev.type == SDL_MOUSEBUTTONDOWN);
+                if (ev.button.button == 4)
+                {
+                    /* scroll-wheel simulates DPad up */
+                    AndroidKeyCode  kcode;
+
+                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
+                        android_keycode_rotate(kKeyCodeDpadUp,
+                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
+                    user_event_key( kcode, down );
+                }
+                else if (ev.button.button == 5)
+                {
+                    /* scroll-wheel simulates DPad down */
+                    AndroidKeyCode  kcode;
+
+                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
+                        android_keycode_rotate(kKeyCodeDpadDown,
+                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
+                    user_event_key( kcode, down );
+                }
+                else if (ev.button.button == SDL_BUTTON_LEFT) {
+                    skin_window_process_event( window, &ev );
+                }
+#if 0
+                else {
+                fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
+                                down ? "down" : "up  ",
+                                ev.button.button, ev.button.state, ev.button.x, ev.button.y);
+                }
+#endif
+            }
+            break;
+
+        case SDL_QUIT:
+#if defined _WIN32 || defined __APPLE__
+        CleanExit:
+#endif
+            /* only save emulator config through clean exit */
+            qemulator_done(qemulator_get());
+            qemu_system_shutdown_request();
+            return;
+        }
+    }
+
+    skin_keyboard_flush( keyboard );
+}
+
 /*
  * android/console.c helper routines.
  */
diff --git a/android/skin/window.c b/android/skin/window.c
index 4765bba..9aa7ec9 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -15,7 +15,7 @@
 #include "android/charmap.h"
 #include "android/utils/debug.h"
 #include "android/utils/system.h"
-#include "android/hw-sensors.h"
+#include "android/ui-core-protocol.h"
 #include <SDL_syswm.h>
 #include "user-events.h"
 #include <math.h>
@@ -1220,15 +1220,6 @@
 
     skin_window_redraw( window, NULL );
 
-    if (slayout->event_type != 0) {
-        user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value );
-        /* XXX: hack, replace by better code here */
-        if (slayout->event_value != 0)
-            android_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
-        else
-            android_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE );
-    }
-
     return 0;
 }
 
@@ -1238,7 +1229,18 @@
     if (!window->fullscreen) {
         SDL_WM_GetPos(&window->x_pos, &window->y_pos);
     }
-    return skin_window_reset_internal( window, slayout );
+    if (skin_window_reset_internal( window, slayout ) < 0)
+        return -1;
+
+    if (slayout->event_type != 0) {
+        user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value );
+        /* XXX: hack, replace by better code here */
+        if (slayout->event_value != 0)
+            android_core_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
+        else
+            android_core_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE );
+    }
+    return 0;
 }
 
 void
diff --git a/android/ui-core-protocol.c b/android/ui-core-protocol.c
index c62f09e..a5caba0 100644
--- a/android/ui-core-protocol.c
+++ b/android/ui-core-protocol.c
@@ -23,6 +23,8 @@
 #include "android/globals.h"
 #include "android/hw-control.h"
 #include "android/ui-core-protocol.h"
+#include "telephony/modem_driver.h"
+#include "trace.h"
 
 int
 android_core_get_hw_lcd_density(void)
@@ -45,3 +47,30 @@
 {
     return android_base_port;
 }
+
+void
+android_core_sensors_set_coarse_orientation( AndroidCoarseOrientation  orient )
+{
+    android_sensors_set_coarse_orientation(orient);
+}
+
+void
+android_core_set_network_enabled(int enabled)
+{
+    if (android_modem) {
+        amodem_set_data_registration(
+                android_modem,
+        qemu_net_disable ? A_REGISTRATION_UNREGISTERED
+            : A_REGISTRATION_HOME);
+    }
+}
+
+void android_core_tracing_start(void)
+{
+    start_tracing();
+}
+
+void android_core_tracing_stop(void)
+{
+    stop_tracing();
+}
diff --git a/android/ui-core-protocol.h b/android/ui-core-protocol.h
index 7b12f24..f461d21 100644
--- a/android/ui-core-protocol.h
+++ b/android/ui-core-protocol.h
@@ -21,6 +21,8 @@
 #ifndef QEMU_ANDROID_UI_CORE_PROTOCOL_H
 #define QEMU_ANDROID_UI_CORE_PROTOCOL_H
 
+#include "android/hw-sensors.h"
+
 /* Gets LCD density property from the core properties. */
 int android_core_get_hw_lcd_density(void);
 
@@ -40,4 +42,14 @@
 /* Returns base port assigned for the emulated system. */
 int android_core_get_base_port(void);
 
+/* change the coarse orientation value */
+void  android_core_sensors_set_coarse_orientation( AndroidCoarseOrientation  orient );
+
+/* Sets/toggles the network state */
+void android_core_set_network_enabled(int enabled);
+
+/* Start/stop tracing in the guest system */
+void android_core_tracing_start(void);
+void android_core_tracing_stop(void);
+
 #endif  // QEMU_ANDROID_UI_CORE_PROTOCOL_H
diff --git a/console.h b/console.h
index 3d0c4f4..fd283ba 100644
--- a/console.h
+++ b/console.h
@@ -330,4 +330,9 @@
 /* curses.c */
 void curses_display_init(DisplayState *ds, int full_screen);
 
+#if defined(CONFIG_ANDROID)
+/* android-display.c */
+void android_display_init(DisplayState *ds);
+#endif
+
 #endif
diff --git a/docs/DISPLAY-STATE.TXT b/docs/DISPLAY-STATE.TXT
new file mode 100644
index 0000000..b76376f
--- /dev/null
+++ b/docs/DISPLAY-STATE.TXT
@@ -0,0 +1,263 @@
+This tries to document the mess that is DisplayState in QEMU.
+See "console.h" for the main definitions, and below for some
+explanations:
+
+
+DISPLAY STATE OBJECTS:
+======================
+
+A DisplayState holds state for stuff to be displayed on QEMU. More
+precisely:
+
+ - A DisplayState owns a 'DisplaySurface' which is nothing more than a
+   pixel buffer with specific dimensions, pitch and format plus bytes
+   to carry its content.
+
+ - A DisplayState also holds a 'DisplayAllocator' which allows it to
+   allocate its surface through a proper API. For example, this is
+   used in the upstream sdl UI backend to allocate the surface pixels
+   through SDL_SetVideoMode(). The default allocator simply uses
+   'malloc' to do the allocation (with 32-bits/pixel).
+
+ - A DisplayState also holds a list of DisplayChangeListener object.
+   Each listener contains a small set of callbacks that will be called
+   whenever an "event" happens on the display state. Events examples
+   are:
+
+      dpy_update:  a rectangular portion of the surface has been updated.
+      dpy_resize:  the hardware decided to resize the framebuffer.
+      dpy_refresh: called periodically by the GUI timer.
+      dpy_copy:    the hardware performed a rectangular copy operation.
+      dpy_fill:    the hardware performed a rectangular fill operation.
+      dpy_setdata: the hardware decided to change the framebuffer address.
+      dpy_text_cursor: the hardware placed the text cursor at a given (x,y).
+
+   NOTE: dpy_setdata is essentially the same than dpy_resize except that
+         there is a guarantee that the size didn't change.
+
+   More on DisplayChangeListeners below.
+
+ - The file "console.h" provides many helper functions to call all listeners
+   registered for a given DisplayState. For example, dpy_update(ds,x,y,w,h)
+   will call the 'dpy_update' callback of all listeners for the display
+   state 'ds'.
+
+
+CONSOLES:
+=========
+
+A "console" is something that can write pixels into a DisplayState.
+There are two kinds of consoles, and they're fairly different in usage.
+
+  GRAPHICAL CONSOLE:
+  ------------------
+
+  A "Graphical console" creates and owns a DisplayState. It is used when one
+  needs to write directly to the DisplaySurface pixel buffer. A typical
+  hardware framebuffer emulator (e.g. hw/vga-pic.c) will call the
+  function graphic_console_init() to create the DisplayState. Note that
+  this functions accepts several callbacks and is defined as:
+
+        typedef void (*vga_hw_update_ptr)(void *);
+        typedef void (*vga_hw_invalidate_ptr)(void *);
+        typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
+        typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
+
+        DisplayState *graphic_console_init(vga_hw_update_ptr update,
+                                        vga_hw_invalidate_ptr invalidate,
+                                        vga_hw_screen_dump_ptr screen_dump,
+                                        vga_hw_text_update_ptr text_update,
+                                        void *opaque);
+
+  The update/invalidate/screen_dump/text_update functions must be provided
+  by the hardware framebuffer emulation, and will be called under various
+  circumstances:
+
+      'update' is called periodically to check for any hw framebuffer
+      updates (and then copy them to the DisplayState, to finally send
+      them through dpy_update() to the listeners).
+
+      'invalidate' is called to indicate that the next call to 'update'
+      should send the content of _all_ the framebuffer, instead of only
+      the smallest possible update.
+
+      'screen_dump' is called to force a screen dump (i.e. print the
+      content of the framebuffer to a ppm file, which name is passed as
+      a parameter).
+
+      'text_update' is called to display one single character. XXX: Code is
+      not very clear, but probably related to text console.
+
+
+  TEXT CONSOLES:
+  --------------
+
+  A "Text console" attaches to an existing DisplayState, and is able to
+  take over its rendering in order to display a text *terminal*. It's not
+  sure whether this emulates VT101 or something else (see the code inside
+  the console_putchar() for all the gory details), but the main idea is
+  that you create a console with a call to:
+
+        CharDriverState*  text_console_init(const char* p);
+
+  The function returns a CharDriverState* (see docs/CHAR-DEVICES.TXT) that
+  will be connected to a host device identified by the string in 'p'. This
+  allows you, for example, to connect the console to stdio.
+
+  The text console code is capable of producing a bitmap each time you update
+  its content (i.e. it includes code to manage fixed-size font rendering,
+  scrolling, escape sequences, color, blinking cursor, etc...).
+
+  - By default, the graphics console writes to its DisplayState, but you can
+    use console_select() to change that at runtime. This function can be used
+    to force switching between virtual terminals and the graphics display.
+    There can be several text consoles associated to a single DisplayState
+    object.
+
+
+DISPLAY CHANGE LISTENERES:
+==========================
+
+There QEMU sources provide the implementation for various
+DisplayChangeListeners, most notables are the following:
+
+ - In sdl.c: This one uses the SDL library to display the content of a
+   DisplaySurface through a SDL_Window. The implementation also supports
+   zooming the output to an arbitrary size (using SDL functions).
+
+ - In vnc.c: This listener implements a VNC Server that can be used to
+   display the DisplaySurface remotely through the RDP protocol.
+
+ - In curses.c: This listener is used to display text consoles through the
+   "curses" library on Unix systems. It cannot be used to display any
+   graphics though.
+
+NOTE: The initialization sequence in vl.c only allows for a single listener
+on the main display state, but the rest of the code deals with several
+listeners per DisplayState just fine.
+
+Each DisplayChangeListener can specify a refresh period (e.g. every 1/60th
+of second). QEMU will then create a timer that will be programmed to called
+the listener's 'dpy_refresh' callback periodically. The point of this
+callback is to perform the following:
+
+- poll for new user input events from the underlying UI (e.g. from the SDL
+  event loop, or from the network for VNC). These should be translated into
+  guest event codes with functions like 'kbd_put_keycode' or 'kbd_mouse_event'.
+
+- call the global vga_hw_update() function. It will, if the graphics console
+  is being displayed, call the 'update' callback that was passed to
+  graphic_console_init(). If a text console is being displayed, the does
+  nothing.
+
+- eventually call the global vga_hw_invalidate() to indicate that the whole
+  framebuffer content should be resent as an update. This can happen when a
+  UI window was minimized and is made visible again, for example.
+
+
+INITIALIZATION AND RUNTIME EXECUTION:
+=====================================
+
+Initialization happens in the qemu main() function in the vl.c source file.
+
+First, the hardware machine is initialized. The hardware fraembuffer emulation
+shall call graphic_console_init() to create a new DisplayState. Note that the
+object returned by this function has a default DisplaySurface of 640x480 pixels
+allocated through malloc(). In other words, the hardware emulation does not
+set the size of the display state by default!
+
+After that, the listener's initialization function (e.g. sdl_display_init)
+is called. It is passed the DisplayState object and can replace the
+corresponding DisplaySurface with another one with proper dimensions, and
+eventually created with a different DisplayAllocator. It also registers a
+DisplayChangeListener to receive later state changes.
+
+Note that the VNC listener doesn't change the dimension of the DisplayState
+surface it is initialized with. However, it will react to dpy_resize events
+accordingly.
+
+NOTE: dpy_resize()s are currently only generated when switching between
+consoles, or when the framebuffer's size is modified by the guest kernel.
+
+
+The GUI timer, corresponding to the first listener than has one refresh
+period, drives the whole update process (if no listener provides a refresh
+period, a default 'no_graphic' timer is setup with a default refresh period
+of 30 frame/s).
+
+Things happen in this order:
+
+ - the GUI timer kicks in, and calls the 'dpy_refresh()' callback of
+   the listener (each listener has its own timer, btw).
+
+ - the listener callback polls for user events, and calls vga_hw_update()
+   to see if there are hardware framebuffer updates.
+
+ - vga_hw_update() checks that the graphics console is displayed (otherwise
+   it exits)
+
+ - it then calls the graphics console's 'update' callback
+
+ - the callback, implemented by the framebuffer hw emulation, checks for
+   dirty pages in order to detect what changed since it was invoked.
+
+   For every rectangle of the hw framebuffer that was modified, it copies
+   the pixels from VRAM into the DisplayState's surface buffer (eventually
+   performing format conversion at the same time).
+
+   After that, it calls dpy_update() to send the update to all registered
+   listeners for the DisplayState.
+
+ - The listener's 'dpy_update' callback is called and receives a pointer
+   to the DisplayState, and the rectangle corresponding to the update. Its
+   implementation can then update the content of the screen (or the internal
+   VNC framebuffer).
+
+Eventually, hardware emulation can also trigger other dpy_xxxx events (e.g.
+dpy_resize, dpy_copy, dpy_fill....)
+
+Here's a simplified diagram of what happens in the typical case:
+
+            _____________
+            |             |
+            |  hardware   |
+            | framebuffer |-------+
+            |             |       |
+            |_____________|       |
+               ^                  |
+               |                  |
+               | 3/ ds.update()   | 4/ dpy_update(ds,x,y,w,h)
+               |                  |
+               |                  |
+            _____________         |
+            |             |       |
+            |  Display    | <-----+
+            |   State     |
+            |             | ----------+
+            |_____________|           |
+                ^                     |
+                |                     |
+                | 2/ vga_hw_update()  |
+                |                     |
+                |                     |
+                |                     |
+                |     +---------------+
+                |     |               |
+                |     | 5/listener.dpy_update(ds,x,y,w,h)
+                |     |               |
+                |     |               | 6/listener.dpy_update(...)
+                |     |               |
+                |     v               v
+             _____________     _____________
+            |             |   |             |
+            |  SDL        |   |  VNC        |
+            |   Listener  |   |   Listener  |
+            |             |   |             |
+            |_____________|   |_____________|
+                ^
+                |
+                | 1/ listener.dpy_refresh()
+                |
+
+               GUI timer
+
diff --git a/framebuffer.c b/framebuffer.c
index d0f9b40..adbebb3 100644
--- a/framebuffer.c
+++ b/framebuffer.c
@@ -19,6 +19,7 @@
     void*                        fb_opaque;
     QFrameBufferUpdateFunc       fb_update;
     QFrameBufferRotateFunc       fb_rotate;
+    QFrameBufferPollFunc         fb_poll;
     QFrameBufferDoneFunc         fb_done;
 
     void*                        pr_opaque;
@@ -122,6 +123,7 @@
                          void*                   fb_opaque,
                          QFrameBufferUpdateFunc  fb_update,
                          QFrameBufferRotateFunc  fb_rotate,
+                         QFrameBufferPollFunc    fb_poll,
                          QFrameBufferDoneFunc    fb_done )
 {
     QFrameBufferExtra*  extra = qfbuff->extra;
@@ -129,6 +131,7 @@
     extra->fb_opaque = fb_opaque;
     extra->fb_update = fb_update;
     extra->fb_rotate = fb_rotate;
+    extra->fb_poll   = fb_poll;
     extra->fb_done   = fb_done;
 }
 
@@ -170,6 +173,15 @@
         extra->fb_rotate( extra->fb_opaque, rotation );
 }
 
+void
+qframebuffer_poll( QFrameBuffer* qfbuff )
+{
+    QFrameBufferExtra*  extra = qfbuff->extra;
+
+    if (extra->fb_poll)
+        extra->fb_poll( extra->fb_opaque );
+}
+
 
 extern void
 qframebuffer_done( QFrameBuffer*   qfbuff )
diff --git a/framebuffer.h b/framebuffer.h
index 1dce0d9..9e99d26 100644
--- a/framebuffer.h
+++ b/framebuffer.h
@@ -106,6 +106,13 @@
  */
 typedef void (*QFrameBufferRotateFunc)( void*  opaque, int  rotation );
 
+/* the Client::Poll method is called periodically to poll for input
+ * events and act on them. Putting this here is not 100% pure but
+ * make things simpler due to QEMU's weird architecture where the
+ * GUI timer drivers event polling.
+ */
+typedef void (*QFrameBufferPollFunc)( void* opaque );
+
 /* the Client::Done func tells a client that a framebuffer object was freed.
  * no more reference to its pixels should be done.
  */
@@ -121,6 +128,7 @@
                          void*                   fb_opaque,
                          QFrameBufferUpdateFunc  fb_update,
                          QFrameBufferRotateFunc  fb_rotate,
+                         QFrameBufferPollFunc    fb_poll,
                          QFrameBufferDoneFunc    fb_done );
 
 /* Producer::CheckUpdate is called to let the producer check the
@@ -161,6 +169,9 @@
 extern void
 qframebuffer_rotate( QFrameBuffer*  qfbuff, int  rotation );
 
+extern void
+qframebuffer_poll( QFrameBuffer* qfbuff );
+
 /* finalize a framebuffer, release its pixel buffer. Should be called
  * from the framebuffer object's owner
  */
diff --git a/hw/android_arm.c b/hw/android_arm.c
index f5df7f2..d805b0e 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -70,7 +70,6 @@
     int i;
     struct arm_boot_info  info;
     ram_addr_t ram_offset;
-    DisplayState*  ds = get_displaystate();
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -116,7 +115,7 @@
         }
     }
 
-    goldfish_fb_init(ds, 0);
+    goldfish_fb_init(0);
 #ifdef HAS_AUDIO
     goldfish_audio_init(0xff004000, 0, audio_input_source);
 #endif
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index d04a166..19f4b32 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -41,7 +41,7 @@
 qemu_irq *goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq);
 void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq);
 int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq);
-void goldfish_fb_init(DisplayState *ds, int id);
+void goldfish_fb_init(int id);
 void goldfish_audio_init(uint32_t base, int id, const char* input_source);
 void goldfish_battery_init();
 void goldfish_battery_set_prop(int ac, int property, int value);
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
index 9e98dac..3f5bf0b 100644
--- a/hw/goldfish_events_device.c
+++ b/hw/goldfish_events_device.c
@@ -102,7 +102,7 @@
         return;
     }
 
-    if(s->first == s->last){
+    if(s->first == s->last) {
         qemu_irq_raise(s->irq);
     }
 
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
index d092fe4..8300e7c 100644
--- a/hw/goldfish_fb.c
+++ b/hw/goldfish_fb.c
@@ -12,7 +12,7 @@
 #include "qemu_file.h"
 #include "android/android.h"
 #include "goldfish_device.h"
-#include "framebuffer.h"
+#include "console.h"
 
 enum {
     FB_GET_WIDTH        = 0x00,
@@ -31,7 +31,7 @@
 
 struct goldfish_fb_state {
     struct goldfish_device dev;
-    QFrameBuffer*  qfbuff;
+    DisplayState*  ds;
     uint32_t fb_base;
     uint32_t base_valid : 1;
     uint32_t need_update : 1;
@@ -41,20 +41,21 @@
     uint32_t int_status;
     uint32_t int_enable;
     int      rotation;   /* 0, 1, 2 or 3 */
+    int      dpi;
 };
 
-#define  GOLDFISH_FB_SAVE_VERSION  1
+#define  GOLDFISH_FB_SAVE_VERSION  2
 
 static void goldfish_fb_save(QEMUFile*  f, void*  opaque)
 {
     struct goldfish_fb_state*  s = opaque;
 
-    QFrameBuffer*  q = s->qfbuff;
+    DisplayState*  ds = s->ds;
 
-    qemu_put_be32(f, q->width);
-    qemu_put_be32(f, q->height);
-    qemu_put_be32(f, q->pitch);
-    qemu_put_byte(f, q->rotation);
+    qemu_put_be32(f, ds->surface->width);
+    qemu_put_be32(f, ds->surface->height);
+    qemu_put_be32(f, ds->surface->linesize);
+    qemu_put_byte(f, 0);
 
     qemu_put_be32(f, s->fb_base);
     qemu_put_byte(f, s->base_valid);
@@ -65,13 +66,12 @@
     qemu_put_be32(f, s->int_status);
     qemu_put_be32(f, s->int_enable);
     qemu_put_be32(f, s->rotation);
+    qemu_put_be32(f, s->dpi);
 }
 
 static int  goldfish_fb_load(QEMUFile*  f, void*  opaque, int  version_id)
 {
     struct goldfish_fb_state*  s   = opaque;
-
-    QFrameBuffer*              q   = s->qfbuff;
     int                        ret = -1;
     int                        ds_w, ds_h, ds_pitch, ds_rot;
 
@@ -83,10 +83,12 @@
     ds_pitch = qemu_get_be32(f);
     ds_rot   = qemu_get_byte(f);
 
-    if (q->width != ds_w      ||
-        q->height != ds_h     ||
-        q->pitch != ds_pitch  ||
-        q->rotation != ds_rot )
+    DisplayState*  ds = s->ds;
+
+    if (ds->surface->width != ds_w ||
+        ds->surface->height != ds_h ||
+        ds->surface->linesize != ds_pitch ||
+        ds_rot != 0)
     {
         /* XXX: We should be able to force a resize/rotation from here ? */
         fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__);
@@ -102,6 +104,7 @@
     s->int_status   = qemu_get_be32(f);
     s->int_enable   = qemu_get_be32(f);
     s->rotation     = qemu_get_be32(f);
+    s->dpi          = qemu_get_be32(f);
 
     /* force a refresh */
     s->need_update = 1;
@@ -111,6 +114,17 @@
     return ret;
 }
 
+static int
+pixels_to_mm(int  pixels, int dpi)
+{
+    /* dpi = dots / inch
+    ** inch = dots / dpi
+    ** mm / 25.4 = dots / dpi
+    ** mm = (dots * 25.4)/dpi
+    */
+    return (int)(0.5 + 25.4 * pixels  / dpi);
+}
+
 
 #define  STATS  0
 
@@ -156,10 +170,11 @@
     }
 
     src_line  = qemu_get_ram_ptr( base );
-    dst_line  = s->qfbuff->pixels;
-    pitch     = s->qfbuff->pitch;
-    width     = s->qfbuff->width;
-    height    = s->qfbuff->height;
+
+    dst_line  = s->ds->surface->data;
+    pitch     = s->ds->surface->linesize;
+    width     = s->ds->surface->width;
+    height    = s->ds->surface->height;
 
 #if STATS
     if (full_update)
@@ -272,7 +287,7 @@
                                     base + y_last * width * 2,
                                     VGA_DIRTY_FLAG);
 
-    qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first );
+    dpy_update(s->ds, 0, y_first, width, y_last-y_first);
 }
 
 static void goldfish_fb_invalidate_display(void * opaque)
@@ -282,12 +297,6 @@
     s->need_update = 1;
 }
 
-static void  goldfish_fb_detach_display(void*  opaque)
-{
-    struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
-    s->qfbuff = NULL;
-}
-
 static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
 {
     uint32_t ret;
@@ -295,12 +304,12 @@
 
     switch(offset) {
         case FB_GET_WIDTH:
-            ret = s->qfbuff->width;
+            ret = ds_get_width(s->ds);
             //printf("FB_GET_WIDTH => %d\n", ret);
             return ret;
 
         case FB_GET_HEIGHT:
-            ret = s->qfbuff->height;
+            ret = ds_get_height(s->ds);
             //printf( "FB_GET_HEIGHT = %d\n", ret);
             return ret;
 
@@ -313,12 +322,12 @@
             return ret;
 
         case FB_GET_PHYS_WIDTH:
-            ret = s->qfbuff->phys_width_mm;
+            ret = pixels_to_mm( ds_get_width(s->ds), s->dpi );
             //printf( "FB_GET_PHYS_WIDTH => %d\n", ret );
             return ret;
 
         case FB_GET_PHYS_HEIGHT:
-            ret = s->qfbuff->phys_height_mm;
+            ret = pixels_to_mm( ds_get_height(s->ds), s->dpi );
             //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret );
             return ret;
 
@@ -353,7 +362,7 @@
             goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
             if (need_resize) {
                 //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation );
-                qframebuffer_rotate( s->qfbuff, s->rotation );
+                dpy_resize(s->ds);
             }
             } break;
         case FB_SET_ROTATION:
@@ -381,7 +390,7 @@
    goldfish_fb_write
 };
 
-void goldfish_fb_init(DisplayState *ds, int id)
+void goldfish_fb_init(int id)
 {
     struct goldfish_fb_state *s;
 
@@ -391,15 +400,16 @@
     s->dev.size = 0x1000;
     s->dev.irq_count = 1;
 
-    s->qfbuff = qframebuffer_fifo_get();
-    qframebuffer_set_producer( s->qfbuff, s,
-                               goldfish_fb_update_display,
-                               goldfish_fb_invalidate_display,
-                               goldfish_fb_detach_display );
+    s->ds = graphic_console_init(goldfish_fb_update_display,
+                                 goldfish_fb_invalidate_display,
+                                 NULL,
+                                 NULL,
+                                 s);
+
+    s->dpi = 165;  /* XXX: Find better way to get actual value ! */
 
     goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
 
     register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
                      goldfish_fb_save, goldfish_fb_load, s);
 }
-
diff --git a/iolooper-select.c b/iolooper-select.c
index 74a5a3a..bf7ae8f 100644
--- a/iolooper-select.c
+++ b/iolooper-select.c
@@ -174,3 +174,9 @@
 {
     return FD_ISSET(fd, iol->writes_result);
 }
+
+int
+iolooper_has_operations( IoLooper* iol )
+{
+    return iolooper_fd_count(iol) > 0;
+}
diff --git a/iolooper.h b/iolooper.h
index ead3583..2822f71 100644
--- a/iolooper.h
+++ b/iolooper.h
@@ -21,5 +21,7 @@
 
 int        iolooper_is_read( IoLooper*  iol, int  fd );
 int        iolooper_is_write( IoLooper*  iol, int  fd );
+/* Returns 1 if this IoLooper has one or more file descriptor to interact with */
+int        iolooper_has_operations( IoLooper*  iol );
 
 #endif /* IOLOOPER_H */