Better separation of UI and Core sources for framebuffer emulation.

+ new document under docs/DISPLAY-STATE.TXT to explain what's happening.

Change-Id: Ia0d233377266212da49af932c7528f46f5feb92d
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..48e5916 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -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_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
+        else
+            android_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..3e4fdcc 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,25 @@
 {
     return android_base_port;
 }
+
+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..4ec025f 100644
--- a/android/ui-core-protocol.h
+++ b/android/ui-core-protocol.h
@@ -40,4 +40,11 @@
 /* Returns base port assigned for the emulated system. */
 int android_core_get_base_port(void);
 
+/* 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