Merge changes Icd076267,I6d5ad6ec

* changes:
  Simplify UI-only sources.
  Simplify core framebuffer management.
diff --git a/Makefile.android b/Makefile.android
index 1e103fd..7ddff81 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -690,7 +690,6 @@
                     module.c \
                     qemu-timer.c \
                     android/boot-properties.c \
-                    android/display.c \
                     android/hw-kmsg.c \
                     android/hw-lcd.c \
                     android/gps.c \
@@ -876,6 +875,7 @@
 VL_SOURCES := android/framebuffer.c \
               user-events-qemu.c \
               android/cmdline-option.c \
+              android/display.c \
               android/looper-qemu.c \
               android/protocol/ui-commands-qemu.c \
               android/protocol/core-commands-qemu.c \
@@ -1209,14 +1209,11 @@
 VL_SOURCES := android/framebuffer.c \
               android/cmdline-option.c \
               android/config.c \
-              android/display.c \
               android/looper-generic.c \
               android/snapshot.c \
               android/main-common.c \
               android/main-ui.c \
-              qemu-timer-ui.c \
               vl-android-ui.c \
-              console-ui.c \
               iolooper-select.c \
               android/protocol/core-connection.c \
               android/protocol/attach-ui-impl.c \
diff --git a/android/console.c b/android/console.c
index d776a5c..d883002 100644
--- a/android/console.c
+++ b/android/console.c
@@ -121,9 +121,6 @@
 /* UI client currently attached to the core. */
 ControlClient attached_ui_client = NULL;
 
-/* Core framebuffer service client. */
-ControlClient framebuffer_client = NULL;
-
 /* User events service client. */
 ControlClient user_events_client = NULL;
 
@@ -245,15 +242,6 @@
         attached_ui_client = NULL;
     }
 
-    if (client == framebuffer_client) {
-        ProxyFramebuffer* core_fb = coredisplay_detach_fb_service();
-        if (core_fb != NULL) {
-            proxyFb_destroy(core_fb);
-            AFREE(core_fb);
-        }
-        framebuffer_client = NULL;
-    }
-
     if (client == user_events_client) {
         userEventsImpl_destroy();
         user_events_client = NULL;
@@ -2525,14 +2513,12 @@
     }
 }
 
-/* Core display instance. */
-extern CoreDisplay core_display;
-
 static int
 do_create_framebuffer_service( ControlClient client, char* args )
 {
     ProxyFramebuffer* core_fb;
     const char* protocol = "-raw";   // Default framebuffer exchange protocol.
+    char reply_buf[64];
 
     // Protocol type is defined by the arguments passed with the stream switch
     // command.
@@ -2555,38 +2541,20 @@
         }
     }
 
-    // Make sure that there are no framebuffer client already existing.
-    if (framebuffer_client != NULL) {
-        control_write( client, "KO: Another framebuffer service is already existing!\r\n" );
-        control_client_destroy(client);
-        return -1;
-    }
-
-    core_fb = proxyFb_create(client->sock, protocol, coredisplay_get_framebuffer());
-    if (!coredisplay_attach_fb_service(core_fb)) {
-        char reply_buf[4096];
-        framebuffer_client = client;
-        // Reply "OK" with the framebuffer's bits per pixel
-        snprintf(reply_buf, sizeof(reply_buf), "OK: -bitsperpixel=%d\r\n",
-                 proxyFb_get_bits_per_pixel(core_fb));
-        control_write( client, reply_buf);
-    } else {
+    core_fb = proxyFb_create(client->sock, protocol);
+    if (core_fb == NULL) {
         control_write( client, "KO\r\n" );
         control_client_destroy(client);
         return -1;
     }
 
+    // Reply "OK" with the framebuffer's bits per pixel
+    snprintf(reply_buf, sizeof(reply_buf), "OK: -bitsperpixel=%d\r\n",
+             proxyFb_get_bits_per_pixel(core_fb));
+    control_write( client, reply_buf);
     return 0;
 }
 
-void
-destroy_control_fb_client(void)
-{
-    if (framebuffer_client != NULL) {
-        control_client_destroy(framebuffer_client);
-    }
-}
-
 static int
 do_create_user_events_service( ControlClient client, char* args )
 {
diff --git a/android/display-core.c b/android/display-core.c
index 6834cd6..80b7665 100644
--- a/android/display-core.c
+++ b/android/display-core.c
@@ -15,120 +15,54 @@
  * by the core to communicate display changes to the attached UI
  */
 
-#include "android/utils/system.h"
 #include "android/display-core.h"
+#include "qemu-common.h"
 
-/* Core display descriptor. */
-struct CoreDisplay {
-    /* Display state for this core display. */
-    DisplayState*       ds;
-
-    /* Framebuffer for this core display. */
-    QFrameBuffer*       fb;
-
-    /* Framebuffer service associated with this core display. */
-    ProxyFramebuffer*   core_fb;
-};
-
-/* One and only one core display instance. */
-CoreDisplay core_display;
-
-/*
- * Framebuffer calls this routine when it detects changes. This routine will
- * initiate a "push" of the framebuffer changes to the UI.
- * See QFrameBufferUpdateFunc in framebuffer.h for more info on this callback.
+/* This callback is call periodically by the GUI timer.
+ * Its purpose is to ensure that hw framebuffer updates are properly
+ * detected. Call the normal QEMU function for this here.
  */
 static void
-coredisplay_fb_update(void* opaque, int x, int y, int w, int h)
+coredisplay_refresh(DisplayState* ds)
 {
-    CoreDisplay* cd = (CoreDisplay*)opaque;
-    if (cd->core_fb) {
-        proxyFb_update(cd->core_fb, cd->fb, x, y, w, h);
-    }
+    (void)ds;
+    vga_hw_update();
 }
 
-/*
- * Framebuffer callback. See QFrameBufferRotateFunc in framebuffer.h for more
- * info on this callback.
+/* Don't do anything here because this callback can't differentiate
+ * between several listeners. This will be handled by a DisplayUpdateListener
+ * instead. See Android-specific changes in console.h
+ *
+ * In the core, the DisplayUpdateListener is registered by the ProxyFramebuffer
+ * object. See android/protocol/fb-updates-proxy.c.
  */
 static void
-coredisplay_fb_rotate(void* opaque, int rotation)
+coredisplay_update(DisplayState* ds, int x, int y, int w, int h)
 {
+    (void)ds;
+    (void)x;
+    (void)y;
+    (void)w;
+    (void)h;
 }
 
-/*
- * Framebuffer callback. See QFrameBufferPollFunc in framebuffer.h for more
- * info on this callback.
+/* This callback is normally used to indicate that the display resolution
+ * was changed by the guest (e.g. when a Windows PC changes the display from
+ * 1024x768 to 800x600. Since this doesn't happen in Android, ignore it.
  */
 static void
-coredisplay_fb_poll(void* opaque)
+coredisplay_resize(DisplayState* ds)
 {
-    // This will eventually call core_display_fb_update.
-    qframebuffer_check_updates();
-}
-
-/*
- * Framebuffer callback. See QFrameBufferDoneFunc in framebuffer.h for more
- * info on this callback.
- */
-static void
-coredisplay_fb_done(void* opaque)
-{
+    (void)ds;
 }
 
 void
 coredisplay_init(DisplayState* ds)
 {
-    int format;
+    static DisplayChangeListener dcl[1];
 
-    core_display.ds = ds;
-    /* Create and initialize framebuffer instance that will be used for core
-     * display.
-     */
-    ANEW0(core_display.fb);
-    core_display.core_fb = NULL;
-
-    /* In the core, there is no skin to parse and the format of ds->surface
-     * is determined by the -android-gui option.
-     */
-    format = QFRAME_BUFFER_RGB565;
-    if (ds->surface->pf.bytes_per_pixel == 4)
-        format = QFRAME_BUFFER_RGBX_8888;
-
-    qframebuffer_init(core_display.fb, ds->surface->width, ds->surface->height,
-                      0, format);
-    qframebuffer_fifo_add(core_display.fb);
-    /* Register core display as the client for the framebuffer, so we can start
-     * receiving framebuffer notifications. Note that until UI connects to the
-     * core all framebuffer callbacks are essentially no-ops.
-     */
-    qframebuffer_add_client(core_display.fb, &core_display,
-                            coredisplay_fb_update, coredisplay_fb_rotate,
-                            coredisplay_fb_poll, coredisplay_fb_done);
-    android_display_init(ds, core_display.fb);
-}
-
-int
-coredisplay_attach_fb_service(ProxyFramebuffer* core_fb)
-{
-    if (core_display.core_fb == NULL) {
-        core_display.core_fb = core_fb;
-        return 0;
-    } else {
-        return -1;
-    }
-}
-
-ProxyFramebuffer*
-coredisplay_detach_fb_service(void)
-{
-    ProxyFramebuffer* ret = core_display.core_fb;
-    core_display.core_fb = NULL;
-    return ret;
-}
-
-QFrameBuffer*
-coredisplay_get_framebuffer(void)
-{
-    return core_display.fb;
+    dcl->dpy_update  = coredisplay_update;
+    dcl->dpy_refresh = coredisplay_refresh;
+    dcl->dpy_resize  = coredisplay_resize;
+    register_displaychangelistener(ds, dcl);
 }
diff --git a/android/display-core.h b/android/display-core.h
index edeccac..e6a1b7d 100644
--- a/android/display-core.h
+++ b/android/display-core.h
@@ -18,42 +18,14 @@
 #ifndef _ANDROID_DISPLAY_CORE_H
 #define _ANDROID_DISPLAY_CORE_H
 
-#include "android/framebuffer.h"
-#include "android/display.h"
-#include "android/protocol/fb-updates-proxy.h"
-
-/* Descriptor for a core display instance */
-typedef struct CoreDisplay CoreDisplay;
+#include "console.h"
 
 /*
  * Initializes one and only one instance of a core display.
- * Param:
+ * Only used to register a dummy display change listener that
+ * will trigger a timer.
  *  ds - Display state to use for the core display.
  */
 extern void coredisplay_init(DisplayState* ds);
 
-/*
- * Attaches framebuffer service to the core display.
- * Param:
- *  core_fb - Framebuffer service descriptor to attach.
- * Return:
- *  0 on success, or -1 on failure.
- */
-extern int coredisplay_attach_fb_service(ProxyFramebuffer* core_fb);
-
-/*
- * Detaches framebuffer service previously attached to the core display.
- * Return:
- *  Framebuffer service descriptor attached to the core display, or NULL if
- *  the core display didn't have framebuffer service attached to it.
- */
-extern ProxyFramebuffer* coredisplay_detach_fb_service(void);
-
-/*
- * Get framebuffer descriptor for core display.
- * Return:
- *  Framebuffer descriptor for core display.
- */
-extern QFrameBuffer* coredisplay_get_framebuffer(void);
-
 #endif /* _ANDROID_DISPLAY_CORE_H */
diff --git a/android/framebuffer.c b/android/framebuffer.c
index 53c6a48..b9b968e 100644
--- a/android/framebuffer.c
+++ b/android/framebuffer.c
@@ -281,6 +281,15 @@
 }
 
 void
+qframebuffer_pulse( void )
+{
+    int  nn;
+    for (nn = 0; nn < framebuffer_fifo_count; nn++) {
+        qframebuffer_poll(framebuffer_fifo[nn]);
+    }
+}
+
+void
 qframebuffer_invalidate_all( void )
 {
     int  nn;
diff --git a/android/framebuffer.h b/android/framebuffer.h
index 9d1f626..faf2f41 100644
--- a/android/framebuffer.h
+++ b/android/framebuffer.h
@@ -172,6 +172,10 @@
 extern void
 qframebuffer_rotate( QFrameBuffer*  qfbuff, int  rotation );
 
+/* this function is used to poll a framebuffer's client for input
+ * events. Should be called either explicitely, or through qframebuffer_pulse()
+ * periodically.
+ */
 extern void
 qframebuffer_poll( QFrameBuffer* qfbuff );
 
@@ -188,6 +192,11 @@
 extern void
 qframebuffer_check_updates( void );
 
+/* call this function periodically to force a poll on all franebuffers
+ */
+extern void
+qframebuffer_pulse( void );
+
 /* this is called by the emulator. for each registered framebuffer, call
  * its producer's Invalidate method, if any
  */
diff --git a/android/looper-generic.c b/android/looper-generic.c
index 6ec0db4..d75fbff 100644
--- a/android/looper-generic.c
+++ b/android/looper-generic.c
@@ -289,7 +289,7 @@
         pnode = &node->activeNext;
     }
     tt->activeNext = *pnode;
-    *pnode         = tt->activeNext;
+    *pnode         = tt;
 }
 
 static void
diff --git a/android/main-common.c b/android/main-common.c
index 23ba5b9..bcae501 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -315,7 +315,9 @@
     }
 
     snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
+#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
     android_display_init(ds, qframebuffer_fifo_get());
+#endif
 }
 
 /* list of skin aliases */
diff --git a/android/main-ui.c b/android/main-ui.c
index 9981b76..daf71cb 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -1507,16 +1507,5 @@
         }
     }
 
-    // Connect to the core's framebuffer service
-    if (implFb_create(attachUiImpl_get_console_socket(), "-raw",
-                      qemulator_get_first_framebuffer(qemulator_get()))) {
-        return -1;
-    }
-
-    // Attach the recepient of UI commands.
-    if (uiCmdImpl_create(attachUiImpl_get_console_socket())) {
-        return -1;
-    }
-
     return qemu_main(n, args);
 }
diff --git a/android/protocol/fb-updates-proxy.c b/android/protocol/fb-updates-proxy.c
index 359c942..ec7414d 100644
--- a/android/protocol/fb-updates-proxy.c
+++ b/android/protocol/fb-updates-proxy.c
@@ -16,7 +16,6 @@
  */
 
 #include "console.h"
-#include "android/framebuffer.h"
 #include "android/looper.h"
 #include "android/display-core.h"
 #include "android/async-utils.h"
@@ -37,8 +36,9 @@
     /* I/O associated with this descriptor. */
     LoopIo                  io;
 
-    /* Framebuffer used for this service. */
-    QFrameBuffer*           fb;
+    /* Display state used for this service */
+    DisplayState*           ds;
+    DisplayUpdateListener*  ds_listener;
 
     /* Looper used to communicate framebuffer updates. */
     Looper* looper;
@@ -80,9 +80,9 @@
  *  Pointer in framebuffer's pixels for the given pixel.
  */
 static const uint8_t*
-_pixel_offset(const QFrameBuffer* fb, int x, int y)
+_pixel_offset(const DisplaySurface* dsu, int x, int y)
 {
-    return (const uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel;
+    return (const uint8_t*)dsu->data + y * dsu->linesize + x * dsu->pf.bytes_per_pixel;
 }
 
 /*
@@ -93,13 +93,13 @@
  *  x, y, w, and h - dimensions of the rectangle to copy.
  */
 static void
-_copy_fb_rect(uint8_t* rect, const QFrameBuffer* fb, int x, int y, int w, int h)
+_copy_fb_rect(uint8_t* rect, const DisplaySurface* dsu, int x, int y, int w, int h)
 {
-    const uint8_t* start = _pixel_offset(fb, x, y);
+    const uint8_t* start = _pixel_offset(dsu, x, y);
     for (; h > 0; h--) {
-        memcpy(rect, start, w * fb->bytes_per_pixel);
-        start += fb->pitch;
-        rect += w * fb->bytes_per_pixel;
+        memcpy(rect, start, w * dsu->pf.bytes_per_pixel);
+        start += dsu->linesize;
+        rect += w * dsu->pf.bytes_per_pixel;
     }
 }
 
@@ -113,10 +113,10 @@
  *  Initialized framebuffer update notification descriptor.
  */
 static FBUpdateNotify*
-fbupdatenotify_create(ProxyFramebuffer* proxy_fb, const QFrameBuffer* fb,
+fbupdatenotify_create(ProxyFramebuffer* proxy_fb,
                       int x, int y, int w, int h)
 {
-    const size_t rect_size = w * h * fb->bytes_per_pixel;
+    const size_t rect_size = w * h * proxy_fb->ds->surface->pf.bytes_per_pixel;
     FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size);
 
     ret->next_fb_update = NULL;
@@ -126,7 +126,7 @@
     ret->message.y = y;
     ret->message.w = w;
     ret->message.h = h;
-    _copy_fb_rect(ret->message.rect, fb, x, y, w, h);
+    _copy_fb_rect(ret->message.rect, proxy_fb->ds->surface, x, y, w, h);
     return ret;
 }
 
@@ -143,9 +143,6 @@
     }
 }
 
-/* Implemented in android/console.c */
-extern void destroy_control_fb_client(void);
-
 /*
  * Asynchronous write I/O callback launched when writing framebuffer
  * notifications to the socket.
@@ -191,6 +188,8 @@
     }
 }
 
+static void proxyFb_update(void* opaque, int x, int y, int w, int h);
+
 /*
  * Asynchronous read I/O callback launched when reading framebuffer requests
  * from the socket.
@@ -201,6 +200,7 @@
 _proxyFb_io_read(ProxyFramebuffer* proxy_fb)
 {
     // Read the request header.
+    DisplaySurface* dsu;
     const AsyncStatus status =
         asyncReader_read(&proxy_fb->fb_req_reader, &proxy_fb->io);
     switch (status) {
@@ -209,9 +209,9 @@
             switch (proxy_fb->fb_req_header.request_type) {
                 case AFB_REQUEST_REFRESH:
                     // Force full screen update to be sent
-                    proxyFb_update(proxy_fb, proxy_fb->fb,
-                                  0, 0, proxy_fb->fb->width,
-                                  proxy_fb->fb->height);
+                    dsu = proxy_fb->ds->surface;
+                    proxyFb_update(proxy_fb,
+                                  0, 0, dsu->width, dsu->height);
                     break;
                 default:
                     derror("Unknown framebuffer request %d\n",
@@ -226,7 +226,7 @@
             loopIo_dontWantRead(&proxy_fb->io);
             if (errno == ECONNRESET) {
                 // UI has exited. We need to destroy framebuffer service.
-                destroy_control_fb_client();
+                proxyFb_destroy(proxy_fb);
             }
             break;
 
@@ -253,14 +253,24 @@
 }
 
 ProxyFramebuffer*
-proxyFb_create(int sock, const char* protocol, QFrameBuffer* fb)
+proxyFb_create(int sock, const char* protocol)
 {
     // At this point we're implementing the -raw protocol only.
     ProxyFramebuffer* ret;
+    DisplayState* ds = get_displaystate();
+    DisplayUpdateListener* dul;
+
     ANEW0(ret);
     ret->sock = sock;
     ret->looper = looper_newCore();
-    ret->fb = fb;
+    ret->ds = ds;
+
+    ANEW0(dul);
+    dul->opaque = ret;
+    dul->dpy_update = proxyFb_update;
+    register_displayupdatelistener(ds, dul);
+    ret->ds_listener = dul;
+
     ret->fb_update_head = NULL;
     ret->fb_update_tail = NULL;
     loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret);
@@ -273,6 +283,7 @@
 proxyFb_destroy(ProxyFramebuffer* proxy_fb)
 {
     if (proxy_fb != NULL) {
+        unregister_displayupdatelistener(proxy_fb->ds, proxy_fb->ds_listener);
         if (proxy_fb->looper != NULL) {
             // Stop all I/O that may still be going on.
             loopIo_done(&proxy_fb->io);
@@ -286,15 +297,16 @@
             looper_free(proxy_fb->looper);
             proxy_fb->looper = NULL;
         }
+        AFREE(proxy_fb);
     }
 }
 
-void
-proxyFb_update(ProxyFramebuffer* proxy_fb,
-              struct QFrameBuffer* fb, int x, int y, int w, int h)
+static void
+proxyFb_update(void* opaque, int x, int y, int w, int h)
 {
+    ProxyFramebuffer* proxy_fb = opaque;
     AsyncStatus status;
-    FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, fb, x, y, w, h);
+    FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, x, y, w, h);
 
     // Lets see if we should list it behind other pending updates.
     if (proxy_fb->fb_update_tail != NULL) {
@@ -327,6 +339,8 @@
 int
 proxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb)
 {
-    return (proxy_fb != NULL && proxy_fb->fb != NULL) ?
-                                            proxy_fb->fb->bits_per_pixel : -1;
+    if (proxy_fb == NULL || proxy_fb->ds == NULL)
+        return -1;
+
+    return proxy_fb->ds->surface->pf.bits_per_pixel;
 }
diff --git a/android/protocol/fb-updates-proxy.h b/android/protocol/fb-updates-proxy.h
index e750f1a..15b1d5b 100644
--- a/android/protocol/fb-updates-proxy.h
+++ b/android/protocol/fb-updates-proxy.h
@@ -29,11 +29,10 @@
  *      supported values ar:
  *      -raw Transfers the updating rectangle buffer over the socket.
  *      -shared Used a shared memory to transfer the updating rectangle buffer.
- *  fb - Framebuffer descriptor for this service.
  * Return:
  *  Framebuffer service descriptor.
  */
-ProxyFramebuffer* proxyFb_create(int sock, const char* protocol, struct QFrameBuffer* fb);
+ProxyFramebuffer* proxyFb_create(int sock, const char* protocol);
 
 /*
  * Destroys framebuffer service created with proxyFb_create.
@@ -43,16 +42,6 @@
 void proxyFb_destroy(ProxyFramebuffer* core_fb);
 
 /*
- * Notifies framebuffer client about changes in framebuffer.
- * Param:
- *  core_fb - Framebuffer service descriptor created with proxyFb_create
- *  fb Framebuffer containing pixels.
- *  x, y, w, and h identify the rectangle that has benn changed.
- */
-void proxyFb_update(ProxyFramebuffer* core_fb, struct QFrameBuffer* fb,
-                   int x, int y, int w, int h);
-
-/*
  * Gets number of bits used to encode a single pixel.
  * Param:
  *  core_fb - Framebuffer service descriptor created with proxyFb_create
diff --git a/android/protocol/ui-commands-impl.c b/android/protocol/ui-commands-impl.c
index f265514..2ca4194 100644
--- a/android/protocol/ui-commands-impl.c
+++ b/android/protocol/ui-commands-impl.c
@@ -124,7 +124,7 @@
         status = read(uicmd->sock, uicmd->reader_buffer + uicmd->reader_offset,
                       uicmd->reader_bytes - uicmd->reader_offset);
         if (status == 0) {
-            /* Disconnection, meaning that the core process got termonated. */
+            /* Disconnection, meaning that the core process got terminated. */
             fprintf(stderr, "core-ui-control service got disconnected\n");
             uiCmdImpl_destroy();
             return;
@@ -201,7 +201,7 @@
         return -1;
     }
 
-    // Initialze UI command reader.
+    // Initialize UI command reader.
     _uiCmdImpl.sock = core_connection_get_socket(_uiCmdImpl.core_connection);
     if (qemu_set_fd_handler(_uiCmdImpl.sock, _uiCmdImpl_io_read, NULL,
                             &_uiCmdImpl)) {
diff --git a/android/qemulator.c b/android/qemulator.c
index 36a9ec8..c90a674 100644
--- a/android/qemulator.c
+++ b/android/qemulator.c
@@ -97,8 +97,10 @@
 {
     QEmulator*  emulator = _emulator;
 
-    if (emulator->window)
-        skin_window_update_display( emulator->window, x, y, w, h );
+    if (!emulator->window) {
+        qemulator_setup( emulator );
+    }
+    skin_window_update_display( emulator->window, x, y, w, h );
 }
 
 static void
diff --git a/console-ui.c b/console-ui.c
deleted file mode 100644
index 42a5cb3..0000000
--- a/console-ui.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * QEMU graphical console
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "console.h"
-#include "qemu-timer.h"
-#include "android/utils/system.h"
-
-//#define DEBUG_CONSOLE
-#define DEFAULT_BACKSCROLL 512
-#define MAX_CONSOLES 12
-
-#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
-
-typedef struct TextAttributes {
-    uint8_t fgcol:4;
-    uint8_t bgcol:4;
-    uint8_t bold:1;
-    uint8_t uline:1;
-    uint8_t blink:1;
-    uint8_t invers:1;
-    uint8_t unvisible:1;
-} TextAttributes;
-
-typedef struct TextCell {
-    uint8_t ch;
-    TextAttributes t_attrib;
-} TextCell;
-
-#define MAX_ESC_PARAMS 3
-
-enum TTYState {
-    TTY_STATE_NORM,
-    TTY_STATE_ESC,
-    TTY_STATE_CSI,
-};
-
-typedef struct QEMUFIFO {
-    uint8_t *buf;
-    int buf_size;
-    int count, wptr, rptr;
-} QEMUFIFO;
-
-typedef enum {
-    GRAPHIC_CONSOLE,
-    TEXT_CONSOLE,
-    TEXT_CONSOLE_FIXED_SIZE
-} console_type_t;
-
-/* ??? This is mis-named.
-   It is used for both text and graphical consoles.  */
-struct TextConsole {
-    console_type_t console_type;
-    DisplayState *ds;
-    /* Graphic console state.  */
-    vga_hw_update_ptr hw_update;
-    vga_hw_invalidate_ptr hw_invalidate;
-    vga_hw_screen_dump_ptr hw_screen_dump;
-    vga_hw_text_update_ptr hw_text_update;
-    void *hw;
-
-    int g_width, g_height;
-    int width;
-    int height;
-    int total_height;
-    int backscroll_height;
-    int x, y;
-    int x_saved, y_saved;
-    int y_displayed;
-    int y_base;
-    TextAttributes t_attrib_default; /* default text attributes */
-    TextAttributes t_attrib; /* currently active text attributes */
-    TextCell *cells;
-    int text_x[2], text_y[2], cursor_invalidate;
-
-    int update_x0;
-    int update_y0;
-    int update_x1;
-    int update_y1;
-
-    enum TTYState state;
-    int esc_params[MAX_ESC_PARAMS];
-    int nb_esc_params;
-
-    /* fifo for key pressed */
-    QEMUFIFO out_fifo;
-    uint8_t out_fifo_buf[16];
-    QEMUTimer *kbd_timer;
-};
-
-static DisplayState *display_state;
-static TextConsole *active_console;
-static TextConsole *consoles[MAX_CONSOLES];
-static int nb_consoles = 0;
-
-#ifdef CONFIG_ANDROID
-/* Graphic console width, height and bits per pixel.
- * These default values can be changed with the "-android-gui" option.
- */
-int android_display_width   = 640;
-int android_display_height  = 480;
-int android_display_bpp     = 32;
-#endif
-
-void vga_hw_update(void)
-{
-    if (active_console && active_console->hw_update)
-        active_console->hw_update(active_console->hw);
-}
-
-void vga_hw_invalidate(void)
-{
-    if (active_console && active_console->hw_invalidate)
-        active_console->hw_invalidate(active_console->hw);
-}
-
-void vga_hw_screen_dump(const char *filename)
-{
-    TextConsole *previous_active_console;
-
-    previous_active_console = active_console;
-    active_console = consoles[0];
-    /* There is currently no way of specifying which screen we want to dump,
-       so always dump the first one.  */
-    if (consoles[0]->hw_screen_dump)
-        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
-    active_console = previous_active_console;
-}
-
-void vga_hw_text_update(console_ch_t *chardata)
-{
-    if (active_console && active_console->hw_text_update)
-        active_console->hw_text_update(active_console->hw, chardata);
-}
-
-/* convert a RGBA color to a color index usable in graphic primitives */
-static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
-{
-    unsigned int r, g, b, color;
-
-    switch(ds_get_bits_per_pixel(ds)) {
-#if 0
-    case 8:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = (rgb_to_index[r] * 6 * 6) +
-            (rgb_to_index[g] * 6) +
-            (rgb_to_index[b]);
-        break;
-#endif
-    case 15:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-        break;
-    case 16:
-        r = (rgba >> 16) & 0xff;
-        g = (rgba >> 8) & 0xff;
-        b = (rgba) & 0xff;
-        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-        break;
-    case 32:
-    default:
-        color = rgba;
-        break;
-    }
-    return color;
-}
-
-/***********************************************************/
-/* basic char display */
-
-#define FONT_HEIGHT 16
-#define FONT_WIDTH 8
-
-#include "vgafont.h"
-
-#define cbswap_32(__x) \
-((uint32_t)( \
-		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
-		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
-		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
-		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) x
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static const uint32_t dmask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
-
-static const uint32_t dmask4[4] = {
-    PAT(0x00000000),
-    PAT(0x0000ffff),
-    PAT(0xffff0000),
-    PAT(0xffffffff),
-};
-
-static uint32_t color_table[2][8];
-
-enum color_names {
-    COLOR_BLACK   = 0,
-    COLOR_RED     = 1,
-    COLOR_GREEN   = 2,
-    COLOR_YELLOW  = 3,
-    COLOR_BLUE    = 4,
-    COLOR_MAGENTA = 5,
-    COLOR_CYAN    = 6,
-    COLOR_WHITE   = 7
-};
-
-static const uint32_t color_table_rgb[2][8] = {
-    {   /* dark */
-        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
-        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
-        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
-        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
-        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
-        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
-        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
-        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
-    },
-    {   /* bright */
-        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
-        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
-        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
-        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
-        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
-        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
-        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
-        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
-    }
-};
-
-static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
-{
-    switch(ds_get_bits_per_pixel(ds)) {
-    case 8:
-        col |= col << 8;
-        col |= col << 16;
-        break;
-    case 15:
-    case 16:
-        col |= col << 16;
-        break;
-    default:
-        break;
-    }
-
-    return col;
-}
-#ifdef DEBUG_CONSOLE
-static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
-{
-    if (t_attrib->bold) {
-        printf("b");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->uline) {
-        printf("u");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->blink) {
-        printf("l");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->invers) {
-        printf("i");
-    } else {
-        printf(" ");
-    }
-    if (t_attrib->unvisible) {
-        printf("n");
-    } else {
-        printf(" ");
-    }
-
-    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
-}
-#endif
-
-void console_select(unsigned int index)
-{
-    TextConsole *s;
-
-    if (index >= MAX_CONSOLES)
-        return;
-    active_console->g_width = ds_get_width(active_console->ds);
-    active_console->g_height = ds_get_height(active_console->ds);
-    s = consoles[index];
-    if (s) {
-        DisplayState *ds = s->ds;
-        active_console = s;
-        if (ds_get_bits_per_pixel(s->ds)) {
-            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
-        } else {
-            s->ds->surface->width = s->width;
-            s->ds->surface->height = s->height;
-        }
-        dpy_resize(s->ds);
-        vga_hw_invalidate();
-    }
-}
-
-static TextConsole *get_graphic_console(DisplayState *ds)
-{
-    int i;
-    TextConsole *s;
-    for (i = 0; i < nb_consoles; i++) {
-        s = consoles[i];
-        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
-            return s;
-    }
-    return NULL;
-}
-
-static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
-{
-    TextConsole *s;
-    int i;
-
-    if (nb_consoles >= MAX_CONSOLES)
-        return NULL;
-    ANEW0(s);
-    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
-        (console_type == GRAPHIC_CONSOLE))) {
-        active_console = s;
-    }
-    s->ds = ds;
-    s->console_type = console_type;
-    if (console_type != GRAPHIC_CONSOLE) {
-        consoles[nb_consoles++] = s;
-    } else {
-        /* HACK: Put graphical consoles before text consoles.  */
-        for (i = nb_consoles; i > 0; i--) {
-            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
-                break;
-            consoles[i] = consoles[i - 1];
-        }
-        consoles[i] = s;
-        nb_consoles++;
-    }
-    return s;
-}
-
-static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
-{
-    DisplaySurface *surface;
-
-    ANEW0(surface);
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-    surface->data = (uint8_t*) android_alloc0(surface->linesize * surface->height);
-
-    return surface;
-}
-
-static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
-                                          int width, int height)
-{
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = width * 4;
-    surface->pf = qemu_default_pixelformat(32);
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        surface->data = (uint8_t*) android_realloc(surface->data, surface->linesize * surface->height);
-    else
-        surface->data = (uint8_t*) android_alloc(surface->linesize * surface->height);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
-    surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-
-    return surface;
-}
-
-DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
-                                              int linesize, uint8_t *data)
-{
-    DisplaySurface *surface;
-
-    ANEW0(surface);
-    surface->width = width;
-    surface->height = height;
-    surface->linesize = linesize;
-    surface->pf = qemu_default_pixelformat(bpp);
-#ifdef HOST_WORDS_BIGENDIAN
-    surface->flags = QEMU_BIG_ENDIAN_FLAG;
-#endif
-    surface->data = data;
-
-    return surface;
-}
-
-static void defaultallocator_free_displaysurface(DisplaySurface *surface)
-{
-    if (surface == NULL)
-        return;
-    if (surface->flags & QEMU_ALLOCATED_FLAG)
-        AFREE(surface->data);
-    AFREE(surface);
-}
-
-static struct DisplayAllocator default_allocator = {
-    defaultallocator_create_displaysurface,
-    defaultallocator_resize_displaysurface,
-    defaultallocator_free_displaysurface
-};
-
-static void dumb_display_init(void)
-{
-    DisplayState *ds;
-    ANEW0(ds);
-    ds->allocator = &default_allocator;
-    ds->surface = qemu_create_displaysurface(ds, 640, 480);
-    register_displaystate(ds);
-}
-
-/***********************************************************/
-/* register display */
-
-void register_displaystate(DisplayState *ds)
-{
-    DisplayState **s;
-    s = &display_state;
-    while (*s != NULL)
-        s = &(*s)->next;
-    ds->next = NULL;
-    *s = ds;
-}
-
-DisplayState *get_displaystate(void)
-{
-    if (!display_state) {
-        dumb_display_init ();
-    }
-    return display_state;
-}
-
-DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
-{
-    if(ds->allocator ==  &default_allocator) {
-        DisplaySurface *surf;
-        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
-        defaultallocator_free_displaysurface(ds->surface);
-        ds->surface = surf;
-        ds->allocator = da;
-    }
-    return ds->allocator;
-}
-
-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)
-{
-    TextConsole *s;
-    DisplayState *ds;
-
-    ANEW0(ds);
-    ds->allocator = &default_allocator;
-#ifdef CONFIG_ANDROID
-    ds->surface = qemu_create_displaysurface(ds, android_display_width, android_display_height);
-#else
-    ds->surface = qemu_create_displaysurface(ds, 640, 480);
-#endif
-
-    s = new_console(ds, GRAPHIC_CONSOLE);
-    if (s == NULL) {
-        qemu_free_displaysurface(ds);
-        AFREE(ds);
-        return NULL;
-    }
-    s->hw_update = update;
-    s->hw_invalidate = invalidate;
-    s->hw_screen_dump = screen_dump;
-    s->hw_text_update = text_update;
-    s->hw = opaque;
-
-    register_displaystate(ds);
-    return ds;
-}
-
-int is_graphic_console(void)
-{
-    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
-}
-
-int is_fixedsize_console(void)
-{
-    return active_console && active_console->console_type != TEXT_CONSOLE;
-}
-
-void console_color_init(DisplayState *ds)
-{
-    int i, j;
-    for (j = 0; j < 2; j++) {
-        for (i = 0; i < 8; i++) {
-            color_table[j][i] = col_expand(ds,
-                   vga_get_color(ds, color_table_rgb[j][i]));
-        }
-    }
-}
-
-void qemu_console_resize(DisplayState *ds, int width, int height)
-{
-    TextConsole *s = get_graphic_console(ds);
-    if (!s) return;
-
-    s->g_width = width;
-    s->g_height = height;
-    if (is_graphic_console()) {
-        ds->surface = qemu_resize_displaysurface(ds, width, height);
-        dpy_resize(ds);
-    }
-}
-
-void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
-                       int dst_x, int dst_y, int w, int h)
-{
-    if (is_graphic_console()) {
-        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
-    }
-}
-
-PixelFormat qemu_different_endianness_pixelformat(int bpp)
-{
-    PixelFormat pf;
-
-    memset(&pf, 0x00, sizeof(PixelFormat));
-
-    pf.bits_per_pixel = bpp;
-    pf.bytes_per_pixel = bpp / 8;
-    pf.depth = bpp == 32 ? 24 : bpp;
-
-    switch (bpp) {
-        case 24:
-            pf.rmask = 0x000000FF;
-            pf.gmask = 0x0000FF00;
-            pf.bmask = 0x00FF0000;
-            pf.rmax = 255;
-            pf.gmax = 255;
-            pf.bmax = 255;
-            pf.rshift = 0;
-            pf.gshift = 8;
-            pf.bshift = 16;
-            pf.rbits = 8;
-            pf.gbits = 8;
-            pf.bbits = 8;
-            break;
-        case 32:
-            pf.rmask = 0x0000FF00;
-            pf.gmask = 0x00FF0000;
-            pf.bmask = 0xFF000000;
-            pf.amask = 0x00000000;
-            pf.amax = 255;
-            pf.rmax = 255;
-            pf.gmax = 255;
-            pf.bmax = 255;
-            pf.ashift = 0;
-            pf.rshift = 8;
-            pf.gshift = 16;
-            pf.bshift = 24;
-            pf.rbits = 8;
-            pf.gbits = 8;
-            pf.bbits = 8;
-            pf.abits = 8;
-            break;
-        default:
-            break;
-    }
-    return pf;
-}
-
-PixelFormat qemu_default_pixelformat(int bpp)
-{
-    PixelFormat pf;
-
-    memset(&pf, 0x00, sizeof(PixelFormat));
-
-    pf.bits_per_pixel = bpp;
-    pf.bytes_per_pixel = bpp / 8;
-    pf.depth = bpp == 32 ? 24 : bpp;
-
-    switch (bpp) {
-        case 15:
-            pf.bits_per_pixel = 16;
-            pf.bytes_per_pixel = 2;
-            pf.rmask = 0x00007c00;
-            pf.gmask = 0x000003E0;
-            pf.bmask = 0x0000001F;
-            pf.rmax = 31;
-            pf.gmax = 31;
-            pf.bmax = 31;
-            pf.rshift = 10;
-            pf.gshift = 5;
-            pf.bshift = 0;
-            pf.rbits = 5;
-            pf.gbits = 5;
-            pf.bbits = 5;
-            break;
-        case 16:
-            pf.rmask = 0x0000F800;
-            pf.gmask = 0x000007E0;
-            pf.bmask = 0x0000001F;
-            pf.rmax = 31;
-            pf.gmax = 63;
-            pf.bmax = 31;
-            pf.rshift = 11;
-            pf.gshift = 5;
-            pf.bshift = 0;
-            pf.rbits = 5;
-            pf.gbits = 6;
-            pf.bbits = 5;
-            break;
-        case 24:
-            pf.rmask = 0x00FF0000;
-            pf.gmask = 0x0000FF00;
-            pf.bmask = 0x000000FF;
-            pf.rmax = 255;
-            pf.gmax = 255;
-            pf.bmax = 255;
-            pf.rshift = 16;
-            pf.gshift = 8;
-            pf.bshift = 0;
-            pf.rbits = 8;
-            pf.gbits = 8;
-            pf.bbits = 8;
-        case 32:
-            pf.rmask = 0x00FF0000;
-            pf.gmask = 0x0000FF00;
-            pf.bmask = 0x000000FF;
-            pf.amax = 255;
-            pf.rmax = 255;
-            pf.gmax = 255;
-            pf.bmax = 255;
-            pf.ashift = 24;
-            pf.rshift = 16;
-            pf.gshift = 8;
-            pf.bshift = 0;
-            pf.rbits = 8;
-            pf.gbits = 8;
-            pf.bbits = 8;
-            pf.abits = 8;
-            break;
-        default:
-            break;
-    }
-    return pf;
-}
-
-#ifdef CONFIG_ANDROID
-void
-android_display_init_from(int width, int height, int rotation, int bpp)
-{
-    DisplayState *ds;
-    ANEW0(ds);
-    ds->allocator = &default_allocator;
-    ds->surface = qemu_create_displaysurface(ds, width, height);
-    register_displaystate(ds);
-}
-#endif
diff --git a/console.c b/console.c
index 5c9a16b..f6694b2 100644
--- a/console.c
+++ b/console.c
@@ -1733,6 +1733,23 @@
 }
 
 #ifdef CONFIG_ANDROID
+
+void
+unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul)
+{
+    DisplayUpdateListener **pnode = &ds->update_listeners;
+    for (;;) {
+        if (*pnode == NULL)
+            break;
+        if (*pnode == dul) {
+            *pnode = dul->next;
+            break;
+        }
+        pnode = &(*pnode)->next;
+    }
+    dul->next = NULL;
+}
+
 void
 android_display_reset(DisplayState* ds, int width, int height, int bitspp)
 {
diff --git a/console.h b/console.h
index bfbc71c..eda9207 100644
--- a/console.h
+++ b/console.h
@@ -169,6 +169,19 @@
     struct DisplayChangeListener *next;
 };
 
+#ifdef CONFIG_ANDROID
+/* The problem with DisplayChangeListener is that the callbacks can't
+ * differentiate between different DisplayChangeListeners. Instead of
+ * modifying the type above, which is going to generate conflicts with
+ * upstream changes, we define our own listener type here.
+ */
+typedef struct DisplayUpdateListener {
+    void* opaque;
+    void (*dpy_update)(void* opaque, int x, int y, int w, int h);
+    struct DisplayUpdateListener *next;
+} DisplayUpdateListener;
+#endif
+
 struct DisplayAllocator {
     DisplaySurface* (*create_displaysurface)(int width, int height);
     DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height);
@@ -182,7 +195,9 @@
 
     struct DisplayAllocator* allocator;
     struct DisplayChangeListener* listeners;
-
+#ifdef CONFIG_ANDROID
+    struct DisplayUpdateListener* update_listeners;
+#endif
     void (*mouse_set)(int x, int y, int on);
     void (*cursor_define)(QEMUCursor *cursor);
 
@@ -233,6 +248,17 @@
     ds->listeners = dcl;
 }
 
+#ifdef CONFIG_ANDROID
+static inline void register_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul)
+{
+    dul->next = ds->update_listeners;
+    ds->update_listeners = dul;
+}
+
+void unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul);
+
+#endif
+
 static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
 {
     struct DisplayChangeListener *dcl = s->listeners;
@@ -240,6 +266,13 @@
         dcl->dpy_update(s, x, y, w, h);
         dcl = dcl->next;
     }
+#ifdef CONFIG_ANDROID
+    DisplayUpdateListener* dul = s->update_listeners;
+    while (dul != NULL) {
+        dul->dpy_update(dul->opaque, x, y, w, h);
+        dul = dul->next;
+    }
+#endif
 }
 
 static inline void dpy_resize(DisplayState *s)
diff --git a/qemu-timer-ui.c b/qemu-timer-ui.c
index ae85509..095036d 100644
--- a/qemu-timer-ui.c
+++ b/qemu-timer-ui.c
@@ -49,6 +49,8 @@
 
 #include "qemu-timer.h"
 
+QEMUClock *rtc_clock;
+
 /***********************************************************/
 /* real time host monotonic timer */
 
diff --git a/vl-android-ui.c b/vl-android-ui.c
index c4a396c..91a7764 100644
--- a/vl-android-ui.c
+++ b/vl-android-ui.c
@@ -27,6 +27,8 @@
 #define _GNU_SOURCE 1
 #endif
 
+#include <sys/wait.h>
+
 #include "qemu-common.h"
 #include "net.h"
 #include "console.h"
@@ -47,217 +49,46 @@
 #include "android/protocol/user-events-proxy.h"
 #include "android/protocol/core-commands-proxy.h"
 #include "android/protocol/ui-commands-impl.h"
+#include "android/qemulator.h"
 
-#ifdef CONFIG_MEMCHECK
-#include "memcheck/memcheck.h"
-#endif  // CONFIG_MEMCHECK
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <zlib.h>
-
-/* Needed early for CONFIG_BSD etc. */
-#include "config-host.h"
-
-#ifndef _WIN32
-#include <libgen.h>
-#include <pwd.h>
-#include <sys/times.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#if defined(__NetBSD__)
-#include <net/if_tap.h>
-#endif
-#ifdef __linux__
-#include <linux/if_tun.h>
-#endif
-#include <arpa/inet.h>
-#include <dirent.h>
-#include <netdb.h>
-#include <sys/select.h>
-#ifdef CONFIG_BSD
-#include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__DragonFly__)
-#include <libutil.h>
-#else
-#include <util.h>
-#endif
-#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
-#include <freebsd/stdlib.h>
-#else
-#ifdef __linux__
-#include <pty.h>
-#include <malloc.h>
-#include <linux/rtc.h>
-
-/* For the benefit of older linux systems which don't supply it,
-   we use a local copy of hpet.h. */
-/* #include <linux/hpet.h> */
-#include "hpet.h"
-
-#include <linux/ppdev.h>
-#include <linux/parport.h>
-#endif
-#ifdef __sun__
-#include <sys/stat.h>
-#include <sys/ethernet.h>
-#include <sys/sockio.h>
-#include <netinet/arp.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h> // must come after ip.h
-#include <netinet/udp.h>
-#include <netinet/tcp.h>
-#include <net/if.h>
-#include <syslog.h>
-#include <stropts.h>
-#endif
-#endif
-#endif
-
-#if defined(__OpenBSD__)
-#include <util.h>
-#endif
-
-#if defined(CONFIG_VDE)
-#include <libvdeplug.h>
-#endif
-
-#ifdef _WIN32
-#include <windows.h>
-#include <malloc.h>
-#include <sys/timeb.h>
-#include <mmsystem.h>
-#define getopt_long_only getopt_long
-#define memalign(align, size) malloc(size)
-#endif
-
-
-#ifdef CONFIG_COCOA
-#undef main
-#define main qemu_main
-#endif /* CONFIG_COCOA */
-
-#include "qemu-timer.h"
-#include "qemu-char.h"
-
-#if defined(CONFIG_SKINS) && !defined(CONFIG_STANDALONE_CORE)
-#undef main
-#define main qemu_main
-#endif
-
-#include "qemu_socket.h"
-
-static const char *data_dir;
-
-static DisplayState *display_state;
-DisplayType display_type = DT_DEFAULT;
-const char* keyboard_layout = NULL;
-int64_t ticks_per_sec;
-int vm_running;
-static int autostart;
-QEMUClock *rtc_clock;
-#ifdef TARGET_SPARC
-int graphic_width = 1024;
-int graphic_height = 768;
-int graphic_depth = 8;
-#else
-int graphic_width = 800;
-int graphic_height = 600;
-int graphic_depth = 15;
-#endif
-static int full_screen = 0;
-#ifdef CONFIG_SDL
-static int no_frame = 0;
-#endif
-int no_quit = 0;
-int smp_cpus = 1;
-const char *vnc_display;
-int acpi_enabled = 1;
-int no_reboot = 0;
-int no_shutdown = 0;
-int cursor_hide = 1;
-int graphic_rotate = 0;
-#ifndef _WIN32
-int daemonize = 0;
-#endif
-#ifdef TARGET_ARM
-int old_param = 0;
-#endif
-const char *qemu_name;
-int alt_grab = 0;
-
-static QEMUTimer *nographic_timer;
-
-uint8_t qemu_uuid[16];
-
-extern int android_display_width;
-extern int android_display_height;
-extern int android_display_bpp;
-
-extern void  dprint( const char* format, ... );
-
-#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
-
-/* compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
-{
-    union {
-        uint64_t ll;
-        struct {
-#ifdef HOST_WORDS_BIGENDIAN
-            uint32_t high, low;
-#else
-            uint32_t low, high;
-#endif
-        } l;
-    } u, res;
-    uint64_t rl, rh;
-
-    u.ll = a;
-    rl = (uint64_t)u.l.low * (uint64_t)b;
-    rh = (uint64_t)u.l.high * (uint64_t)b;
-    rh += (rl >> 32);
-    res.l.high = rh / c;
-    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
-    return res.ll;
-}
+static Looper*  mainLooper;
 
 /***********************************************************/
 /* I/O handling */
 
 typedef struct IOHandlerRecord {
-    int fd;
-    IOCanReadHandler *fd_read_poll;
-    IOHandler *fd_read;
-    IOHandler *fd_write;
-    int deleted;
-    void *opaque;
-    /* temporary data */
-    struct pollfd *ufd;
+    LoopIo  io[1];
+    IOHandler* fd_read;
+    IOHandler* fd_write;
+    int        running;
+    int        deleted;
+    void*      opaque;
     struct IOHandlerRecord *next;
 } IOHandlerRecord;
 
 static IOHandlerRecord *first_io_handler;
 
-/* XXX: fd_read_poll should be suppressed, but an API change is
-   necessary in the character devices to suppress fd_can_read(). */
-int qemu_set_fd_handler2(int fd,
-                         IOCanReadHandler *fd_read_poll,
-                         IOHandler *fd_read,
-                         IOHandler *fd_write,
-                         void *opaque)
+static void ioh_callback(void* opaque, int fd, unsigned events)
+{
+    IOHandlerRecord* ioh = opaque;
+    ioh->running = 1;
+    if ((events & LOOP_IO_READ) != 0) {
+        ioh->fd_read(ioh->opaque);
+    }
+    if (!ioh->deleted && (events & LOOP_IO_WRITE) != 0) {
+        ioh->fd_write(ioh->opaque);
+    }
+    ioh->running = 0;
+    if (ioh->deleted) {
+        loopIo_done(ioh->io);
+        free(ioh);
+    }
+}
+
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque)
 {
     IOHandlerRecord **pioh, *ioh;
 
@@ -266,175 +97,76 @@
         for(;;) {
             ioh = *pioh;
             if (ioh == NULL)
-                break;
-            if (ioh->fd == fd) {
-                ioh->deleted = 1;
+                return 0;
+            if (ioh->io->fd == fd) {
                 break;
             }
             pioh = &ioh->next;
         }
+        if (ioh->running) {
+            ioh->deleted = 1;
+        } else {
+            *pioh = ioh->next;
+            loopIo_done(ioh->io);
+            free(ioh);
+        }
     } else {
         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
-            if (ioh->fd == fd)
+            if (ioh->io->fd == fd)
                 goto found;
         }
         ANEW0(ioh);
         ioh->next = first_io_handler;
         first_io_handler = ioh;
+        loopIo_init(ioh->io, mainLooper, fd, ioh_callback, ioh);
     found:
-        ioh->fd = fd;
-        ioh->fd_read_poll = fd_read_poll;
-        ioh->fd_read = fd_read;
+        ioh->fd_read  = fd_read;
         ioh->fd_write = fd_write;
-        ioh->opaque = opaque;
-        ioh->deleted = 0;
+        ioh->opaque   = opaque;
+
+        if (fd_read != NULL)
+            loopIo_wantRead(ioh->io);
+        else
+            loopIo_dontWantRead(ioh->io);
+
+        if (fd_write != NULL)
+            loopIo_wantWrite(ioh->io);
+        else
+            loopIo_dontWantWrite(ioh->io);
     }
     return 0;
 }
 
-int qemu_set_fd_handler(int fd,
-                        IOHandler *fd_read,
-                        IOHandler *fd_write,
-                        void *opaque)
-{
-    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
-}
-
 /***********************************************************/
 /* main execution loop */
 
+static LoopTimer  gui_timer[1];
+
 static void gui_update(void *opaque)
 {
-    uint64_t interval = GUI_REFRESH_INTERVAL;
-    DisplayState *ds = opaque;
-    DisplayChangeListener *dcl = ds->listeners;
-
-    dpy_refresh(ds);
-
-    while (dcl != NULL) {
-        if (dcl->gui_timer_interval &&
-            dcl->gui_timer_interval < interval)
-            interval = dcl->gui_timer_interval;
-        dcl = dcl->next;
-    }
-    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
+    LoopTimer* timer = opaque;
+    qframebuffer_pulse();
+    loopTimer_startRelative(timer, GUI_REFRESH_INTERVAL);
 }
 
-static void nographic_update(void *opaque)
+static void init_gui_timer(Looper* looper)
 {
-    uint64_t interval = GUI_REFRESH_INTERVAL;
-
-    qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
+    loopTimer_init(gui_timer, looper, gui_update, gui_timer);
+    loopTimer_startRelative(gui_timer, 0);
+    qframebuffer_invalidate_all();
 }
 
-static int shutdown_requested = 0;
-
+/* Called from qemulator.c */
 void qemu_system_shutdown_request(void)
 {
-    shutdown_requested = 1;
-}
-
-
-
-static int qemu_event_init(void)
-{
-    return 0;
-}
-
-static int qemu_init_main_loop(void)
-{
-    return qemu_event_init();
-}
-
-#define qemu_mutex_lock_iothread() do { } while (0)
-#define qemu_mutex_unlock_iothread() do { } while (0)
-
-
-#ifdef _WIN32
-static void host_main_loop_wait(int *timeout)
-{
-}
-#else
-static void host_main_loop_wait(int *timeout)
-{
-}
-#endif
-
-void main_loop_wait(int timeout)
-{
-    IOHandlerRecord *ioh;
-    fd_set rfds, wfds, xfds;
-    int ret, nfds;
-    struct timeval tv;
-
-    host_main_loop_wait(&timeout);
-
-    /* poll any events */
-    /* XXX: separate device handlers from system ones */
-    nfds = -1;
-    FD_ZERO(&rfds);
-    FD_ZERO(&wfds);
-    FD_ZERO(&xfds);
-    for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
-        if (ioh->deleted)
-            continue;
-        if (ioh->fd_read &&
-            (!ioh->fd_read_poll ||
-             ioh->fd_read_poll(ioh->opaque) != 0)) {
-            FD_SET(ioh->fd, &rfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-        if (ioh->fd_write) {
-            FD_SET(ioh->fd, &wfds);
-            if (ioh->fd > nfds)
-                nfds = ioh->fd;
-        }
-    }
-
-    tv.tv_sec = timeout / 1000;
-    tv.tv_usec = (timeout % 1000) * 1000;
-
-    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-    if (ret > 0) {
-        IOHandlerRecord **pioh;
-
-        for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
-            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
-                ioh->fd_read(ioh->opaque);
-            }
-            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
-                ioh->fd_write(ioh->opaque);
-            }
-        }
-
-        /* remove deleted IO handlers */
-        pioh = &first_io_handler;
-        while (*pioh) {
-            ioh = *pioh;
-            if (ioh->deleted) {
-                *pioh = ioh->next;
-                AFREE(ioh);
-            } else
-                pioh = &ioh->next;
-        }
-    }
-
-    qemu_run_all_timers();
-}
-
-static void main_loop(void)
-{
-    while (!shutdown_requested) {
-        main_loop_wait(qemu_calculate_timeout());
-    }
+    looper_forceQuit(mainLooper);
 }
 
 #ifndef _WIN32
 
 static void termsig_handler(int signal)
 {
-    /* qemu_system_shutdown_request(); */
+    qemu_system_shutdown_request();
 }
 
 static void sigchld_handler(int signal)
@@ -459,40 +191,6 @@
 
 #endif
 
-#define QEMU_FILE_TYPE_BIOS   0
-#define QEMU_FILE_TYPE_KEYMAP 1
-
-char *qemu_find_file(int type, const char *name)
-{
-    int len;
-    const char *subdir;
-    char *buf;
-
-    /* If name contains path separators then try it as a straight path.  */
-    if ((strchr(name, '/') || strchr(name, '\\'))
-        && access(name, R_OK) == 0) {
-        return strdup(name);
-    }
-    switch (type) {
-    case QEMU_FILE_TYPE_BIOS:
-        subdir = "";
-        break;
-    case QEMU_FILE_TYPE_KEYMAP:
-        subdir = "keymaps/";
-        break;
-    default:
-        abort();
-    }
-    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
-    buf = android_alloc0(len);
-    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
-    if (access(buf, R_OK)) {
-        AFREE(buf);
-        return NULL;
-    }
-    return buf;
-}
-
 #ifdef _WIN32
 static BOOL WINAPI qemu_ctrl_handler(DWORD type)
 {
@@ -501,13 +199,8 @@
 }
 #endif
 
-int main(int argc, char **argv, char **envp)
+int qemu_main(int argc, char **argv, char **envp)
 {
-    DisplayState *ds;
-    DisplayChangeListener *dcl;
-
-    init_clocks();
-
 #ifndef _WIN32
     {
         struct sigaction act;
@@ -538,18 +231,6 @@
     }
 #endif
 
-    autostart= 1;
-
-    if (qemu_init_main_loop()) {
-        fprintf(stderr, "qemu_init_main_loop failed\n");
-        exit(1);
-    }
-
-    if (init_timer_alarm() < 0) {
-        fprintf(stderr, "could not initialize alarm timer\n");
-        exit(1);
-    }
-
 #ifdef _WIN32
     socket_init();
 #endif
@@ -559,42 +240,23 @@
     sighandler_setup();
 #endif
 
-    /* just use the first displaystate for the moment */
-    ds = display_state = get_displaystate();
+    mainLooper = looper_newGeneric();
 
-    if (display_type == DT_DEFAULT) {
-        display_type = DT_SDL;
+    /* Register a timer to call qframebuffer_pulse periodically */
+    init_gui_timer(mainLooper);
+
+    // Connect to the core's framebuffer service
+    if (implFb_create(attachUiImpl_get_console_socket(), "-raw",
+                      qemulator_get_first_framebuffer(qemulator_get()))) {
+        return -1;
     }
 
-
-    switch (display_type) {
-    case DT_NOGRAPHIC:
-        break;
-    case DT_SDL:
-        sdl_display_init(ds, full_screen, no_frame);
-        break;
-    default:
-        break;
-    }
-    dpy_resize(ds);
-
-    dcl = ds->listeners;
-    while (dcl != NULL) {
-        if (dcl->dpy_refresh != NULL) {
-            ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
-            qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
-        }
-        dcl = dcl->next;
+    // Attach the recepient of UI commands.
+    if (uiCmdImpl_create(attachUiImpl_get_console_socket())) {
+        return -1;
     }
 
-    if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
-        nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
-        qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
-    }
-
-    //qemu_chr_initial_reset();
-
-    main_loop();
+    looper_run(mainLooper);
 
     implFb_destroy();
     userEventsProxy_destroy();
@@ -602,6 +264,5 @@
     uiCmdImpl_destroy();
     attachUiImpl_destroy();
 
-    quit_timers();
     return 0;
 }