diff --git a/Makefile.target b/Makefile.target
index 2f57713c5..21978628c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -357,8 +357,15 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += s5l8900.o iphone2g.o pcf50633.o s5l8900_uart.o s5l8900_spi.o pl192.o
-obj-arm-y += s5l8900_i2c.o usb_synopsys.o #s5l8900_usb_otg.o
-
+obj-arm-y += s5l8900_i2c.o usb_synopsys.o
+
+#ifdef CONFIG_SKINNING
+VPATH+=:$(SRC_PATH)/skin
+CFLAGS+=-I$(SRC_PATH)/skin $(PNG_CFLAGS)
+LIBS+=$(PNG_LIBS) -lexpat
+obj-arm-y += skinning.o skin_config.o skin_image.o skin_button.o
+obj-i386-y += skinning.o skin_config.o skin_image.o skin_button.o
+#endif # CONFIG_SKINNING
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/README.txt b/README.txt
index f53c1f075..8fa0d0d26 100644
--- a/README.txt
+++ b/README.txt
@@ -5,7 +5,7 @@ make
How to run:
-./arm-softmmu/qemu-system-arm -M iphone2g -option-rom iBoot-1.0.2.m68ap.RELEASE -option-rom iphone1-bootrom.bin -pflash nordump.bin -serial stdio
+./arm-softmmu/qemu-system-arm -M iphone2g -option-rom iBoot-1.0.2.m68ap.RELEASE -option-rom iphone1-bootrom.bin -pflash nordump.bin -serial stdio -skin ./skin/devices/iphone2g/skin.xml
How do i contribute:
diff --git a/configure b/configure
index faaed6054..5a1549229 100755
--- a/configure
+++ b/configure
@@ -174,6 +174,7 @@ zero_malloc=""
trace_backend="nop"
trace_file="trace"
spice=""
+skinning="no"
rbd=""
smartcard=""
smartcard_nss=""
@@ -724,6 +725,8 @@ for opt do
;;
--enable-opengl) opengl="yes"
;;
+ --enable-skinning) skinning="yes"
+ ;;
--*dir)
;;
--disable-rbd) rbd="no"
@@ -928,6 +931,7 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
+echo " --enable-skinning Enabled skinning functionality for Qemu"
echo " --enable-trace-backend=B Set trace backend"
echo " Available backends:" $("$source_path"/scripts/tracetool --list-backends)
echo " --with-trace-file=NAME Full PATH,NAME of file to store traces"
@@ -2879,6 +2883,9 @@ fi
if test "$fdatasync" = "yes" ; then
echo "CONFIG_FDATASYNC=y" >> $config_host_mak
fi
+if test "$skinning" = "yes" ; then
+ echo "CONFIG_SKINNING=y" >>$config_host_mak
+fi
if test "$madvise" = "yes" ; then
echo "CONFIG_MADVISE=y" >> $config_host_mak
fi
diff --git a/console.c b/console.c
index 871c1d47b..0570c498a 100644
--- a/console.c
+++ b/console.c
@@ -32,6 +32,21 @@
#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)
+#ifdef CONFIG_SKINNING
+// Skinning overwrites these functions to put the skin in between
+DisplayState *qemu_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);
+#undef graphic_console_init
+#define graphic_console_init qemu_graphic_console_init
+
+void original_qemu_console_resize(DisplayState *ds, int width, int height);
+#undef qemu_console_resize
+#define qemu_console_resize original_qemu_console_resize
+#endif
+
typedef struct TextAttributes {
uint8_t fgcol:4;
uint8_t bgcol:4;
@@ -227,7 +242,7 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
return color;
}
-static void vga_fill_rect (DisplayState *ds,
+void vga_fill_rect (DisplayState *ds,
int posx, int posy, int width, int height, uint32_t color)
{
uint8_t *d, *d1;
diff --git a/console.h b/console.h
index 64d1f090e..4982b62f1 100644
--- a/console.h
+++ b/console.h
@@ -163,7 +163,10 @@ struct DisplayChangeListener {
void (*dpy_fill)(struct DisplayState *s, int x, int y,
int w, int h, uint32_t c);
void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
-
+#ifdef CONFIG_SKINNING
+ void (*dpy_enablezoom)(struct DisplayState *s, int width, int height);
+ void (*dpy_getresolution)(int *width, int *height);
+#endif
struct DisplayChangeListener *next;
};
@@ -298,6 +301,26 @@ static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
}
}
+#ifdef CONFIG_SKINNING
+static inline void dpy_enablezoom(struct DisplayState *s, int width, int height)
+{
+ struct DisplayChangeListener *dcl = s->listeners;
+ while (dcl != NULL) {
+ if (dcl->dpy_enablezoom) dcl->dpy_enablezoom(s, width, height);
+ dcl = dcl->next;
+ }
+}
+
+static inline void dpy_getresolution(struct DisplayState *s, int *width, int *height)
+{
+ struct DisplayChangeListener *dcl = s->listeners;
+ while (dcl != NULL) {
+ if (dcl->dpy_getresolution) dcl->dpy_getresolution(width, height);
+ dcl = dcl->next;
+ }
+}
+#endif
+
static inline int ds_get_linesize(DisplayState *ds)
{
return ds->surface->linesize;
@@ -362,6 +385,9 @@ void qemu_console_resize(DisplayState *ds, int width, int height);
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
int dst_x, int dst_y, int w, int h);
+void vga_fill_rect (DisplayState *ds,
+ int posx, int posy, int width, int height, uint32_t color);
+
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
diff --git a/hw/iphone2g.c b/hw/iphone2g.c
index 1902d077c..ae34e637e 100644
--- a/hw/iphone2g.c
+++ b/hw/iphone2g.c
@@ -100,7 +100,7 @@ static void iphone2g_lcd_update_display(void *opaque)
(void)draw_line_table12; // Unused var.
- if (!lcd || !ds_get_bits_per_pixel(lcd->ds))
+ if (!lcd || !lcd->ds || !ds_get_bits_per_pixel(lcd->ds) || !frame_base)
return;
switch (ds_get_bits_per_pixel(lcd->ds)) {
@@ -236,8 +236,6 @@ static iphone2g_lcd_s * iphone2g_lcd_init(target_phys_addr_t base)
lcd->ds = graphic_console_init(iphone2g_lcd_update_display,
iphone2g_lcd_invalidate_display,
iphone2g_lcd_screen_dump, NULL, lcd);
- qemu_console_resize(lcd->ds, LCD_WIDTH, LCD_HEIGHT);
-
return lcd;
}
diff --git a/input.c b/input.c
index ec05548f7..d1ba66176 100644
--- a/input.c
+++ b/input.c
@@ -28,6 +28,14 @@
#include "console.h"
#include "qjson.h"
+#ifdef CONFIG_SKINNING
+QEMUPutMouseEntry *original_qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+ void *opaque, int absolute,
+ const char *name);
+#undef qemu_add_mouse_event_handler
+#define qemu_add_mouse_event_handler original_qemu_add_mouse_event_handler
+#endif
+
static QEMUPutKBDEvent *qemu_put_kbd_event;
static void *qemu_put_kbd_event_opaque;
static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
diff --git a/qemu-options.hx b/qemu-options.hx
index ef60730e4..76cb4b41f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -769,6 +769,16 @@ STEXI
Rotate graphical output 90 deg left (only PXA LCD).
ETEXI
+DEF("landscape", 0, QEMU_OPTION_landscape,
+ "-landscape rotate graphical output 90 deg right\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -portrait
+@findex -portrait
+Rotate graphical output 90 deg right
+ETEXI
+
+
DEF("vga", HAS_ARG, QEMU_OPTION_vga,
"-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
" select video card type\n", QEMU_ARCH_ALL)
@@ -808,6 +818,24 @@ STEXI
Start in full screen.
ETEXI
+#if defined(CONFIG_SKINNING)
+DEF("skin", HAS_ARG, QEMU_OPTION_skin,
+ "-skin file Skin qemu using provided skin configuration file\n", QEMU_ARCH_ALL)
+STEXI
+@item -skin @var{file}
+Skin qemu using definitions from @var{file}
+ETEXI
+#endif
+
+#if defined(CONFIG_SKINNING)
+DEF("rctport", HAS_ARG, QEMU_OPTION_rctport,
+ "-rctport port Allow remote control of the skin through specified port\n", QEMU_ARCH_ALL)
+STEXI
+@item -rctport @var{d}
+Allow remote control of the skin through port @var{d}
+ETEXI
+#endif
+
DEF("g", 1, QEMU_OPTION_g ,
"-g WxH[xDEPTH] Set the initial graphical resolution and depth\n",
QEMU_ARCH_PPC | QEMU_ARCH_SPARC)
diff --git a/skin/devices/iphone2g/iphone2g-landscape.png b/skin/devices/iphone2g/iphone2g-landscape.png
new file mode 100644
index 000000000..38cff832d
Binary files /dev/null and b/skin/devices/iphone2g/iphone2g-landscape.png differ
diff --git a/skin/devices/iphone2g/iphone2g-portrait.png b/skin/devices/iphone2g/iphone2g-portrait.png
new file mode 100644
index 000000000..0973ae5d2
Binary files /dev/null and b/skin/devices/iphone2g/iphone2g-portrait.png differ
diff --git a/skin/devices/iphone2g/skin.xml b/skin/devices/iphone2g/skin.xml
new file mode 100644
index 000000000..c7be880c4
--- /dev/null
+++ b/skin/devices/iphone2g/skin.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/skin/skin.h b/skin/skin.h
new file mode 100644
index 000000000..70c284d80
--- /dev/null
+++ b/skin/skin.h
@@ -0,0 +1,197 @@
+/*
+ * Qemu skinning header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef SKIN_H__
+#define SKIN_H__
+
+typedef enum SwitchDefaultState {
+ undefined = -1,
+ off = 0,
+ on
+} SwitchDefaultState;
+
+typedef struct SkinImageConfig {
+ char* file;
+ int posx;
+ int posy;
+ struct SkinImageConfig* next;
+} SkinImageConfig;
+
+typedef struct SkinBackgroundColor {
+ int red;
+ int green;
+ int blue;
+} SkinBackgroundColor;
+
+typedef struct SkinButtonConfig {
+ SkinImageConfig image;
+ unsigned int keycode;
+ unsigned int isswitch;
+ SwitchDefaultState defaultstate;
+ char* tooltip;
+ struct SkinButtonConfig* next;
+} SkinButtonConfig;
+
+typedef struct SkinKeyConfig {
+ int posx;
+ int posy;
+ int width;
+ int height;
+ unsigned int keycode;
+ struct SkinKeyConfig* next;
+} SkinKeyConfig;
+
+typedef struct SkinKeyboardConfig {
+ SkinImageConfig* image;
+ int animated;
+ SkinKeyConfig* keys;
+ int switchcode;
+ int screenwidth;
+ int screenheight;
+ int highlight_red;
+ int highlight_green;
+ int highlight_blue;
+ int offset; // Offset to move the skin
+} SkinKeyboardConfig;
+
+typedef struct SkinLayout {
+ int width;
+ int height;
+ int emuscreen_posx;
+ int emuscreen_posy;
+ int emuscreen_width;
+ int emuscreen_height;
+ struct SkinBackgroundColor bgcolor;
+ struct SkinImageConfig* background;
+ struct SkinKeyboardConfig* keyboard;
+ struct SkinButtonConfig* buttons;
+} SkinLayout;
+
+typedef struct SkinConfig {
+ struct SkinLayout* landscape;
+ struct SkinLayout* portrait;
+} SkinConfig;
+
+typedef struct SkinImage {
+ uint16_t posx; // X Position on the skin display
+ uint16_t posy; // Y Position on the skin display
+ uint16_t width; // Width of the image
+ uint16_t height; // Height of the image
+ void* data; // Image data, encoded in PixelFormat
+ int linesize; // Bytes per line
+ struct PixelFormat pf; // Color/Bit information
+} SkinImage;
+
+typedef enum SkinButtonState {
+ ESkinBtn_Idle = 0,
+ ESkinBtn_Highlighted,
+ ESkinBtn_Active,
+ ESkinBtn_ActiveHighlighted,
+ // Button state count
+ ESkinBtn_statecount,
+ ESkinBtn_forceredraw
+} SkinButtonState;
+
+typedef struct SkinKeyEvent {
+ uint8_t mouseover : 1; // Mouse is hovered over the button
+ uint8_t mousedown : 1; // Mouse LSK is clicked on the button currently
+ uint8_t keydown : 1; // The related key is pressed currently
+} SkinKeyEvent;
+
+typedef struct SkinKey { // Has same structure as SkinButton with
+ uint8_t keycode; // posx - height from SkinImage
+ SkinKeyEvent event;
+ uint8_t isswitch : 1;
+ int8_t defaultstate : 3;
+ uint8_t state : 4;
+ uint16_t posx;
+ uint16_t posy;
+ uint16_t width;
+ uint16_t height;
+ struct SkinKey* next;
+} SkinKey;
+
+typedef struct SkinButton { // SkinButton and SkinKey share information
+ struct SkinImage image;
+ struct SkinKey key;
+ char* tooltip;
+ struct SkinButton* next;
+} SkinButton;
+
+typedef struct EmulatedScreen {
+ struct DisplayState* ds; // DisplayState used by client display drivers
+ int posx; // X Position on the skin display
+ int posy; // Y Position on the skin display
+ int width; // Required width of this display
+ int height; // Required height of this display
+} EmulatedScreen;
+
+typedef struct SkinKeyboard {
+ SkinImage* image;
+ int animated;
+ SkinKey* keys;
+ SkinButton* button;
+ int screenwidth;
+ int screenheight;
+ int highlight_red;
+ int highlight_green;
+ int highlight_blue;
+ int offset;
+} SkinKeyboard;
+
+typedef struct SkinFont {
+ struct SkinImage* image; // Font image with characters
+ uint8_t char_width; // Character Width in px
+ uint8_t char_height; // Character Height in px
+} SkinFont;
+
+typedef struct SkinTooltip {
+ uint32_t color; // color for the tooltip background
+ QEMUTimer *timer; // Timeout before the tooltip is shown
+ SkinButton *button; // Button that activated the tooltip
+ SkinImage *image; // Cached image for redrawing
+} SkinTooltip;
+
+typedef struct SkinScreen {
+ int width; // Total width of the display
+ int height; // Total height of the display
+ struct SkinBackgroundColor bgcolor;
+ struct DisplayState* ds; // DisplayState towards qemu
+ struct EmulatedScreen* es; // Emulated display information
+ struct SkinImage* background;
+ struct SkinKeyboard keyboard;
+ struct SkinButton* buttons;
+ struct SkinFont* font;
+ struct SkinTooltip tooltip;
+ int rotation;
+ int rotation_req;
+ int mouse_event;
+ struct SkinConfig* config; // Possible skin configurations to use
+} SkinScreen;
+
+typedef struct SkinArea {
+ int x;
+ int y;
+ int width;
+ int height;
+} SkinArea;
+
+#endif /* SKIN_H__ */
+
diff --git a/skin/skin_button.c b/skin/skin_button.c
new file mode 100644
index 000000000..01bc26896
--- /dev/null
+++ b/skin/skin_button.c
@@ -0,0 +1,250 @@
+/*
+ * Skin button handling
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include
+#include "console.h"
+
+#include "skin_button.h"
+#include "skin_switchstate.h"
+
+typedef struct SkinButtonStateCallback {
+ switchstate_callback *callback;
+ void *opaque;
+ // Next callback
+ struct SkinButtonStateCallback *next;
+} SkinButtonStateCallback;
+
+static SkinButtonStateCallback *switchcb = NULL;
+
+int skin_button_handle_mouse(SkinKey* button, int mousebtn)
+{
+ button->event.mouseover = 1;
+ if(button->isswitch) {
+ int newstate = button->state;
+ if(!mousebtn && button->event.mousedown) {
+ // Trigger the switch
+ if(newstate == ESkinBtn_Highlighted)
+ newstate = ESkinBtn_ActiveHighlighted;
+ else
+ newstate = ESkinBtn_Highlighted;
+ if (button->keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(button->keycode);
+ }
+ else {
+ kbd_put_keycode(button->keycode | 0x80);
+ }
+ }
+
+ if(newstate == ESkinBtn_Idle) newstate = ESkinBtn_Highlighted;
+ if(newstate == ESkinBtn_Active) newstate = ESkinBtn_ActiveHighlighted;
+
+ button->event.mousedown = mousebtn != 0;
+ return newstate;
+ } else {
+ if(mousebtn && !button->event.mousedown) {
+ if (button->keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(button->keycode & 0x7F);
+ }
+ else {
+ kbd_put_keycode(button->keycode);
+ }
+ }
+ if(!mousebtn && button->event.mousedown) {
+ if (button->keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(button->keycode);
+ }
+ else {
+ kbd_put_keycode(button->keycode | 0x80);
+ }
+ }
+ button->event.mousedown = mousebtn != 0;
+ return ESkinBtn_Highlighted;
+ }
+}
+
+int skin_button_handle_mouseleave(SkinKey* button)
+{
+ if(button->isswitch) {
+ int newstate = button->event.keydown == 0 ? ESkinBtn_Idle : ESkinBtn_Highlighted;
+ button->event.mousedown = 0;
+ button->event.mouseover = 0;
+ if(button->state == ESkinBtn_Active ||
+ button->state == ESkinBtn_ActiveHighlighted ) {
+ if(!button->event.keydown) newstate = ESkinBtn_Active;
+ else newstate = ESkinBtn_ActiveHighlighted;
+ }
+ return newstate;
+ } else {
+ if(button->event.mousedown) {
+ if (button->keycode & 0x80) {
+ kbd_put_keycode(0xe0);
+ kbd_put_keycode(button->keycode);
+ }
+ else {
+ kbd_put_keycode(button->keycode | 0x80);
+ }
+ }
+ button->event.mousedown = 0;
+ button->event.mouseover = 0;
+ if(button->event.keydown) return ESkinBtn_Highlighted;
+ return ESkinBtn_Idle;
+ }
+}
+
+int skin_button_handle_key(SkinKey* button, int keypressed)
+{
+ int newstate = button->state;
+ if(keypressed) {
+ button->event.keydown = 1;
+ switch(button->state) {
+ case ESkinBtn_Idle:
+ newstate = ESkinBtn_Highlighted;
+ break;
+ case ESkinBtn_Active:
+ newstate = ESkinBtn_ActiveHighlighted;
+ break;
+ case ESkinBtn_Highlighted:
+ case ESkinBtn_ActiveHighlighted:
+ break;
+ default:
+ fprintf(stderr, "skin_key_handler, wrong state for switch having key: %d\n", button->keycode);
+ break;
+ }
+ } else {
+ button->event.keydown = 0;
+ switch(button->state) {
+ case ESkinBtn_Idle:
+ case ESkinBtn_Active:
+ break;
+ case ESkinBtn_Highlighted:
+ if(!button->event.mouseover) newstate = ESkinBtn_Idle;
+ break;
+ case ESkinBtn_ActiveHighlighted:
+ if(!button->event.mouseover) newstate = ESkinBtn_Active;
+ break;
+ default:
+ fprintf(stderr, "skin_key_handler, wrong state for switch having key: %d\n", button->keycode);
+ break;
+ }
+ }
+
+ if(!keypressed && button->isswitch) {
+ switch(newstate) {
+ case ESkinBtn_Idle:
+ case ESkinBtn_Highlighted:
+ if(!button->event.mouseover) newstate = ESkinBtn_Active;
+ else newstate = ESkinBtn_ActiveHighlighted;
+ break;
+ case ESkinBtn_Active:
+ case ESkinBtn_ActiveHighlighted:
+ if(!button->event.mouseover) newstate = ESkinBtn_Idle;
+ else newstate = ESkinBtn_Highlighted;
+ break;
+ default:
+ fprintf(stderr, "skin_key_handler, wrong state for switch having key: %d\n", button->keycode);
+ break;
+ }
+ }
+ return newstate;
+}
+
+void skin_button_checkswitch(SkinScreen* skin, SkinButton* button)
+{
+ //printf(">> skin_button_checkswitch\n");
+ if (button->key.isswitch) {
+ int hwstate = unknown;
+ SkinButtonStateCallback *cb = switchcb;
+ while (cb && hwstate == unknown) {
+ hwstate = cb->callback(cb->opaque, button->key.keycode);
+ if (cb->next) cb = cb->next;
+ else break;
+ }
+
+ if (button->key.defaultstate == on) {
+ // If default switch state is on, it overrides the hardware state.
+ // Make sure the hardware state is in sync also.
+ //printf("skin_button_checkswitch, button=%d, defaultstate=on\n", button->key.keycode);
+ if (hwstate == inactive) {
+ //printf("hwstate=inactive, defaultstate alreadyset for button %d\n", button->key.keycode);
+ button->key.defaultstate = undefined;
+ kbd_put_keycode(button->key.keycode | 0x80);
+ hwstate = cb->callback(cb->opaque, button->key.keycode);
+ //printf("defaultstate=on, hwstate=%d\n", hwstate);
+ }
+ }
+
+ if (button->key.defaultstate == off) {
+ // If default switch state is off, it overrides the hardware state.
+ // Make sure the hardware state is in sync also.
+ //printf("skin_button_checkswitch, button=%d, defaultstate=off\n", button->key.keycode);
+ if (hwstate == active) {
+ //printf("hwstate=active, defaultstate alreadyset for button %d\n", button->key.keycode);
+ button->key.defaultstate = undefined;
+ kbd_put_keycode(button->key.keycode | 0x80);
+ hwstate = cb->callback(cb->opaque, button->key.keycode);
+ //printf("defaultstate=%d, hwstate=%d for button %d\n", button->key.defaultstate, hwstate, button->key.keycode);
+ }
+ }
+
+ // If we retrieved a valid state, update the button accordingly
+ if (hwstate == inactive) {
+ if (button->key.state == ESkinBtn_Active) button->key.state = ESkinBtn_Idle;
+ if (button->key.state == ESkinBtn_ActiveHighlighted) button->key.state = ESkinBtn_Highlighted;
+ }
+ if (hwstate == active) {
+ if (button->key.state == ESkinBtn_Idle) button->key.state = ESkinBtn_Active;
+ if (button->key.state == ESkinBtn_Highlighted) button->key.state = ESkinBtn_ActiveHighlighted;
+ }
+
+ // If the hardware state is not yet retrieved, go with the defaultstate
+ if (hwstate == unknown && button->key.defaultstate == off) {
+ button->key.state = ESkinBtn_Idle;
+ }
+ //printf("keycode: %d, hwstate: %d\n", button->key.keycode, hwstate);
+ }
+ //printf("skin_button_checkswitch >>\n");
+}
+
+void qemu_skin_add_switchstate_callback(switchstate_callback *callback,
+ void *opaque)
+{
+ SkinButtonStateCallback *cb = switchcb;
+ if (!switchcb) {
+ switchcb = (SkinButtonStateCallback*)qemu_mallocz(sizeof(SkinButtonStateCallback));
+ cb = switchcb;
+ }
+ else {
+ while (cb) cb = cb->next;
+ cb = (SkinButtonStateCallback*)qemu_mallocz(sizeof(SkinButtonStateCallback));
+ }
+
+ if (cb) {
+ // Store the parameters for later use
+ cb->callback = callback;
+ cb->opaque = opaque;
+
+ /* if (cb->callback(opaque, 59) == active) {
+ printf("qemu_skin_add_switchstate_callback() registered keyboard: %d\n", cb->callback(opaque, 59));
+ }*/
+ }
+}
+
diff --git a/skin/skin_button.h b/skin/skin_button.h
new file mode 100644
index 000000000..42625b1cc
--- /dev/null
+++ b/skin/skin_button.h
@@ -0,0 +1,39 @@
+/*
+ * Skin button handling header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "skin.h"
+
+#ifndef SKIN_BUTTON_H__
+#define SKIN_BUTTON_H__
+
+static inline int skin_button_mouse_over(SkinKey* button, int x, int y ) {
+ return (x > button->posx &&
+ y > button->posy &&
+ x < button->posx+button->width &&
+ y < button->posy+button->height);
+}
+
+int skin_button_handle_mouse(SkinKey* button, int mousebtn);
+int skin_button_handle_mouseleave(SkinKey* button);
+int skin_button_handle_key(SkinKey* button, int keypressed);
+
+void skin_button_checkswitch(SkinScreen* skin, SkinButton* button);
+
+#endif /* SKIN_BUTTON_H__ */
diff --git a/skin/skin_config.c b/skin/skin_config.c
new file mode 100644
index 000000000..5e940ced0
--- /dev/null
+++ b/skin/skin_config.c
@@ -0,0 +1,636 @@
+/*
+ * Skin configuration reading
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include
+#include "expat.h"
+#include "console.h"
+
+#include "skin_config.h"
+#include "skin_image.h"
+
+const int BUFFER_SIZE = 512;
+
+typedef struct SkinParser {
+ SkinScreen* skin;
+ SkinLayout* layout;
+ char* filepath;
+} SkinParser;
+
+static inline int value_is(const char *attr, const char *name)
+{
+ return (strcmp(attr, name) == 0);
+}
+
+static int skin_load_images(SkinScreen* skin, SkinLayout* layout)
+{
+ //printf("skin_config.c: skin_load_images, background file='%s'\n",
+ // layout->background->file);
+ if (layout->background && layout->background->file != NULL) {
+ skin->background = skin_load_image((char*)layout->background->file);
+ skin->background->posx = layout->background->posx;
+ skin->background->posy = layout->background->posy;
+ }
+
+ if (layout->keyboard && layout->keyboard->image->file != NULL) {
+ skin->keyboard.image = skin_load_image((char*)layout->keyboard->image->file);
+ skin->keyboard.image->posx = layout->keyboard->image->posx;
+ skin->keyboard.image->posy = layout->keyboard->image->posy;
+ if (layout->keyboard->animated) {
+ // If keyboard image is animated, it consists of 5 pictures
+ skin->keyboard.image->height /= 5;
+ skin->keyboard.animated = 1;
+ }
+ else skin->keyboard.animated = 0;
+
+ skin->keyboard.screenwidth = layout->keyboard->screenwidth;
+ skin->keyboard.screenheight = layout->keyboard->screenheight;
+ skin->keyboard.highlight_red = layout->keyboard->highlight_red;
+ skin->keyboard.highlight_green = layout->keyboard->highlight_green;
+ skin->keyboard.highlight_blue = layout->keyboard->highlight_blue;
+ skin->keyboard.offset = layout->keyboard->offset;
+ }
+
+ SkinButtonConfig *latestButton = layout->buttons;
+ if(latestButton) {
+ skin->buttons = (SkinButton*)qemu_mallocz(sizeof(SkinButton));
+ }
+
+ SkinButton* button = skin->buttons;
+ while (latestButton) {
+ if (latestButton->image.file) {
+ //printf("load button: %s, posx=%d, posy=%d\n",latestButton->image.file,
+ // latestButton->image.posx, latestButton->image.posy);
+ skin_load_image_data(&button->image, latestButton->image.file);
+ button->key.posx = button->image.posx = latestButton->image.posx;
+ button->key.posy = button->image.posy = latestButton->image.posy;
+ button->key.keycode = latestButton->keycode;
+ button->key.isswitch = latestButton->isswitch;
+ button->key.defaultstate = latestButton->defaultstate;
+ button->image.height /= 2;
+ button->tooltip = latestButton->tooltip;
+ // Switches have 4 pictures
+ if (button->key.isswitch)
+ button->image.height /= 2;
+ button->key.width = button->image.width;
+ button->key.height = button->image.height;
+ if (layout->keyboard && layout->keyboard->switchcode != 0 &&
+ layout->keyboard->switchcode == button->key.keycode) {
+ int state = button->key.state;
+ if (skin->keyboard.button) state = skin->keyboard.button->key.state;
+ skin->keyboard.button = button;
+ skin->keyboard.button->key.state = state;
+ }
+ }
+
+ latestButton = latestButton->next;
+ if(latestButton) {
+ button->next = (SkinButton*)qemu_mallocz(sizeof(SkinButton));
+ button = button->next;
+ }
+ }
+ return 0;
+}
+
+static void skin_free_image(SkinImage** image)
+{
+ if (!(*image)) return;
+ if ((*image)->data) {
+ qemu_free((*image)->data);
+ (*image)->data = NULL;
+ }
+ qemu_free(*image);
+ *image = NULL;
+}
+
+static void skin_free_keys(SkinKey** keys)
+{
+ SkinKey* key = *keys;
+ while(key) {
+ *keys = key->next;
+ qemu_free(key);
+ key = *keys;
+ *keys = NULL;
+ }
+}
+
+static void skin_free_buttons(SkinButton** buttons)
+{
+ SkinButton* button = *buttons;
+ while(button) {
+ *buttons = button->next;
+ if (button->image.data) {
+ qemu_free(button->image.data);
+ button->image.data = NULL;
+ }
+ qemu_free(button);
+ button = *buttons;
+ *buttons = NULL;
+ }
+}
+
+int skin_activate_layout(SkinScreen* skin, int rotation)
+{
+ int result = -1;
+ if (!skin->config->landscape && !skin->config->portrait) {
+ //printf("skin_config.c: skin_activate_layout, no landscape or portrait\n");
+ return result;
+ }
+ printf("skin_config.c: skin_activate_layout, rotation=%d\n", rotation);
+ SkinLayout* layout = skin->config->landscape;
+ if (!skin->config->landscape) {
+ layout = skin->config->portrait;
+ // Only portrait possible
+ skin->rotation_req = skin->rotation = on;
+ }
+ if (rotation == on) {
+ if (skin->config->portrait) {
+ layout = skin->config->portrait;
+ skin->rotation_req = skin->rotation = off;
+ }
+ // Only landscape possible
+ else skin->rotation_req = skin->rotation = on;
+ } else {
+ skin->rotation_req = skin->rotation = on;
+ }
+ if (layout->width == 0 || layout->height == 0) {
+ // No value given in XML, use some default
+ //printf("Default layout values\n");
+ layout->width = 1200;
+ layout->height = 650;
+ }
+ if (layout->emuscreen_width == 0 || layout->emuscreen_height == 0) {
+ // No default value given, make it 800x480 then
+ layout->emuscreen_width = 320;
+ layout->emuscreen_height = 480;
+ }
+ skin->width = layout->width;
+ skin->height = layout->height;
+ memcpy(&skin->bgcolor, &layout->bgcolor, sizeof(SkinBackgroundColor));
+ if (layout->keyboard)
+ skin->keyboard.animated = layout->keyboard->animated;
+
+ skin->es->posx = layout->emuscreen_posx;
+ skin->es->posy = layout->emuscreen_posy;
+ skin->es->width = layout->emuscreen_width;
+ skin->es->height = layout->emuscreen_width;
+
+ // Store pointers to obsolete data
+ SkinImage* curr_background = skin->background;
+ SkinButton* curr_buttons = skin->buttons;
+ SkinImage* curr_keyboard = skin->keyboard.image;
+ SkinKey* curr_keys = skin->keyboard.keys;
+
+ // Copy all the keys
+ if (layout->keyboard) {
+ if (layout->keyboard->keys)
+ skin->keyboard.keys = (SkinKey*)qemu_mallocz(sizeof(SkinKey));
+ SkinKey *key = skin->keyboard.keys;
+ SkinKeyConfig* keyc = layout->keyboard->keys;
+ while(keyc) {
+ key->posx = keyc->posx;
+ key->posy = keyc->posy;
+ key->width = keyc->width;
+ key->height = keyc->height;
+ key->keycode = keyc->keycode;
+ keyc = keyc->next;
+ if (keyc) {
+ key->next = (SkinKey*)qemu_mallocz(sizeof(SkinKey));
+ key = key->next;
+ }
+ }
+ }
+ result = skin_load_images(skin, layout);
+
+ // Free obsolete data
+ skin_free_image(&curr_background);
+ skin_free_buttons(&curr_buttons);
+ skin_free_image(&curr_keyboard);
+ skin_free_keys(&curr_keys);
+
+ return result;
+}
+
+static void parser_start_hndl(void *data, const char *element, const char **attr)
+{
+ //printf("parser_start_hndl, element=%s\n", element);
+ SkinParser *parserconfig = (SkinParser*)data;
+ SkinLayout *layout = NULL;
+ SkinButtonConfig *latestButton = NULL;
+ SkinKeyConfig *latestKey = NULL;
+ int i = 0;
+ unsigned int hex;
+ // Print XML file content for testing
+ /*for (i = 0; attr[i]; i += 2) {
+ printf("attr %s='%s'\n", attr[i], attr[i + 1]);
+ }*/
+
+ if (value_is(element, "root")) {
+ // Initialize the pointers
+ layout = NULL;
+ latestButton = NULL;
+ latestKey = NULL;
+ return;
+ }
+
+ if (value_is(element, "landscape")) {
+ if(parserconfig->layout != NULL) {
+ fprintf(stderr, "XML Parsing failure unexpected nesting of %s\n", element);
+ exit(1);
+ }
+ parserconfig->skin->config->landscape =
+ (SkinLayout*) qemu_mallocz(sizeof(SkinLayout));
+ parserconfig->layout = parserconfig->skin->config->landscape;
+ }
+
+ if (value_is(element, "portrait")) {
+ if(parserconfig->layout != NULL) {
+ fprintf(stderr, "XML Parsing failure unexpected nesting of %s\n", element);
+ exit(1);
+ }
+ parserconfig->skin->config->portrait =
+ (SkinLayout*) qemu_mallocz(sizeof(SkinLayout));
+ parserconfig->layout = parserconfig->skin->config->portrait;
+ }
+
+ if (parserconfig) layout = parserconfig->layout;
+
+ if (value_is(element, "tooltip")) {
+ parserconfig->skin->tooltip.color |= 0xFF000000; // Full alpha channel
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "red")) {
+ parserconfig->skin->tooltip.color |= atoi(attr[i + 1]) << 16;
+ }
+ if (value_is(attr[i], "green")) {
+ parserconfig->skin->tooltip.color |= atoi(attr[i + 1]) << 8;
+ }
+ if (value_is(attr[i], "blue")) {
+ parserconfig->skin->tooltip.color |= atoi(attr[i + 1]);
+ }
+ }
+ }
+
+ if (value_is(element, "font")) {
+ // We have a font, allocate it
+ SkinFont* font = parserconfig->skin->font = (SkinFont*)qemu_mallocz(sizeof(SkinFont));
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "width")) {
+ font->char_width = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "height")) {
+ font->char_height = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "image")) {
+ // We load the font image directly, first construct the path
+ char* filepath = (char*)qemu_malloc(
+ strlen(parserconfig->filepath) +
+ strlen(attr[i + 1]) + 1);
+ strcpy(filepath, parserconfig->filepath);
+ strcat(filepath, attr[i + 1]);
+ font->image = skin_load_image(filepath);
+ qemu_free(filepath);
+ }
+ }
+ // If we don't have an image, then no font
+ if (!font->image || font->char_width == 0 || font->char_height == 0) {
+ parserconfig->skin->font = NULL;
+ qemu_free(font);
+ }
+ }
+
+ if (value_is(element, "skin")) {
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "width")) {
+ layout->width = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "height")) {
+ layout->height = atoi(attr[i + 1]);
+ }
+ }
+ }
+
+ if (value_is(element, "bgcolor")) {
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "red")) {
+ layout->bgcolor.red = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "green")) {
+ layout->bgcolor.green = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "blue")) {
+ layout->bgcolor.blue = atoi(attr[i + 1]);
+ }
+ }
+ }
+ if (value_is(element, "background")) {
+ if (!layout->background) {
+ layout->background =
+ (SkinImageConfig*) qemu_mallocz(sizeof(SkinImageConfig));
+ layout->background->file = NULL;
+ }
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "image")) {
+ layout->background->file = qemu_mallocz(strlen(parserconfig->filepath) +
+ strlen(attr[i + 1]) + 1);
+ strcpy(layout->background->file, parserconfig->filepath);
+ strcat(layout->background->file, attr[i + 1]);
+ //printf("layout->background->file='%s'\n",layout->background->file);
+ }
+ if (value_is(attr[i], "posx")) {
+ layout->background->posx = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "posy")) {
+ layout->background->posy = atoi(attr[i + 1]);
+ }
+ }
+ }
+ if (value_is(element, "screen")) {
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "posx")) {
+ layout->emuscreen_posx = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "posy")) {
+ layout->emuscreen_posy = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "width")) {
+ layout->emuscreen_width = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "height")) {
+ layout->emuscreen_height = atoi(attr[i + 1]);
+ }
+ }
+ //layout->emuscreen_posx, layout->emuscreen_posy,layout->emuscreen_width, layout->emuscreen_height);
+ }
+
+ if (value_is(element, "keyboard")) {
+ if (!layout->keyboard) {
+ layout->keyboard =
+ (SkinKeyboardConfig*)qemu_mallocz(sizeof(SkinKeyboardConfig));
+ layout->keyboard->image =
+ (SkinImageConfig*) qemu_mallocz(sizeof(SkinImageConfig));
+ layout->keyboard->image->file = NULL;
+ }
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "image")) {
+ layout->keyboard->image->file = qemu_mallocz(strlen(parserconfig->filepath) +
+ strlen(attr[i + 1]) + 1);
+ strcpy(layout->keyboard->image->file, parserconfig->filepath);
+ strcat(layout->keyboard->image->file, attr[i + 1]);
+ }
+ if (value_is(attr[i], "animated")) {
+ if (value_is(attr[i + 1], "yes"))
+ layout->keyboard->animated = 1;
+ }
+ if (value_is(attr[i], "posx")) {
+ layout->keyboard->image->posx = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "posy")) {
+ layout->keyboard->image->posy = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "switchkey")) {
+ layout->keyboard->switchcode = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "screenwidth")) {
+ layout->keyboard->screenwidth = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "screenheight")) {
+ layout->keyboard->screenheight = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "red")) {
+ layout->keyboard->highlight_red = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "green")) {
+ layout->keyboard->highlight_green = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "blue")) {
+ layout->keyboard->highlight_blue = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "offset")) {
+ layout->keyboard->offset = atoi(attr[i + 1]);
+ }
+ }
+ }
+ if (value_is(element, "key")) {
+ if (!layout->keyboard->keys) {
+ //printf("first key\n");
+ layout->keyboard->keys = (SkinKeyConfig*) qemu_mallocz(sizeof(SkinKeyConfig));
+ latestKey = layout->keyboard->keys;
+ }
+ else {
+ //printf("not the first key\n");
+ latestKey = layout->keyboard->keys;
+ while (latestKey->next) latestKey = latestKey->next;
+ latestKey->next = (SkinKeyConfig*) qemu_mallocz(sizeof(SkinKeyConfig));
+ latestKey = latestKey->next;
+ }
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "posx")) {
+ latestKey->posx = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "posy")) {
+ latestKey->posy = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "width")) {
+ latestKey->width = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "height")) {
+ latestKey->height = atoi(attr[i + 1]);
+ }
+ if (value_is(attr[i], "keycode")) {
+ sscanf(attr[i + 1], "%X", &hex);
+ latestKey->keycode = hex;
+ }
+ }
+ }
+ if (value_is(element, "button")) {
+ if (!layout->buttons) {
+ //printf("first button\n");
+ layout->buttons = (SkinButtonConfig*)qemu_mallocz(sizeof(SkinButtonConfig));
+ latestButton = layout->buttons;
+ }
+ else {
+ //printf("not the first button\n");
+ latestButton = layout->buttons;
+ while( latestButton->next ) latestButton = latestButton->next;
+ latestButton->next = (SkinButtonConfig*)qemu_mallocz(sizeof(SkinButtonConfig));
+ latestButton = latestButton->next;
+ }
+ //printf("not the first button 2\n");
+ for (i = 0; attr[i]; i += 2) {
+ if (value_is(attr[i], "image")) {
+ latestButton->image.file = (char*)qemu_malloc(strlen(attr[i + 1])
+ + strlen(parserconfig->filepath) + 1);
+ strcpy(latestButton->image.file, parserconfig->filepath);
+ strcat(latestButton->image.file, attr[i + 1]);
+ //printf("button file='%s'\n", latestButton->image.file);
+ }
+ if (value_is(attr[i], "posx")) {
+ latestButton->image.posx = atoi(attr[i + 1]);
+ //printf("posx=%d\n", latestButton->image.posx);
+ }
+ if (value_is(attr[i], "posy")) {
+ latestButton->image.posy = atoi(attr[i + 1]);
+ //printf("posy=%d\n", latestButton->image.posy);
+ }
+ if (value_is(attr[i], "keycode")) {
+ latestButton->keycode = atoi(attr[i + 1]);
+ //printf("keycode=0x%x\n",latestButton->keycode);
+ }
+ if (value_is(attr[i], "switch")) {
+ if (value_is(attr[i + 1], "yes")) {
+ latestButton->isswitch = 1;
+ latestButton->defaultstate = undefined;
+ }
+ //printf("switch=%s\n", latestButton->isswitch ? "yes":"no");
+ }
+ if (value_is(attr[i], "defaultstate")) {
+ if (value_is(attr[i + 1], "on")) latestButton->defaultstate = on;
+ if (value_is(attr[i + 1], "off")) latestButton->defaultstate = off;
+ //printf("defaultstate=%d\n", latestButton->defaultstate);
+ }
+ if (value_is(attr[i], "action")) {
+ latestButton->tooltip = (char*)qemu_malloc(strlen(attr[i + 1]) + 1);
+ strcpy(latestButton->tooltip, attr[i + 1]);
+ }
+ }
+ }
+}
+
+
+static void parser_end_hndl(void *data, const char *element)
+{
+ //printf("parser_end_hndl, element=%s\n", element);
+ SkinParser *parserconfig = (SkinParser*)data;
+ if (value_is(element, "landscape")) {
+ if(parserconfig->layout != parserconfig->skin->config->landscape) {
+ fprintf(stderr, "Unexpected ending of %s in XML file\n", element);
+ exit(1);
+ }
+ parserconfig->layout = NULL;
+ }
+
+ if (value_is(element, "portrait")) {
+ if(parserconfig->layout != parserconfig->skin->config->portrait) {
+ fprintf(stderr, "Unexpected ending of %s in XML file\n", element);
+ exit(1);
+ }
+ parserconfig->layout = NULL;
+ }
+}
+
+
+static int skin_load_file(SkinScreen* skin, char *file)
+{
+ FILE* skin_xml;
+ char buffer[BUFFER_SIZE];
+ int done;
+ XML_Parser parser = XML_ParserCreate(NULL);
+ if (parser) {
+ SkinParser parserconfig;
+ parserconfig.skin = skin;
+ parserconfig.layout = NULL;
+
+ XML_SetUserData( parser, (void*)&parserconfig );
+ XML_SetElementHandler(parser, parser_start_hndl, parser_end_hndl);
+
+ skin_xml = fopen(file, "r");
+ //printf("skin_config_c: skin_load_file = '%s'\n", file);
+ if (!skin_xml) {
+ fprintf(stderr, "Error opening skin file '%s'\n", file);
+ XML_ParserFree(parser);
+ return -1;
+ }
+ // Extract the path of the given XML file to be used as a default path
+ char *p = strrchr(file, '/');
+ if (p) {
+ int index = p - file + 1;
+ p = qemu_mallocz(index + 1);
+ strncpy(p, file, index);
+ // last character already zeroed at malloc
+ } else {
+ p = qemu_mallocz(3);
+ p[0] = '.';
+ p[1] = '/';
+ // last character already zeroed at malloc
+ }
+
+ parserconfig.filepath = p;
+ XML_SetUserData(parser, (void*)&parserconfig);
+ XML_SetElementHandler(parser, parser_start_hndl, parser_end_hndl);
+ do {
+ if (fgets(buffer, sizeof(buffer), skin_xml) == NULL)
+ done = 1;
+ else {
+ done = feof(skin_xml);
+ if (!XML_Parse(parser, buffer, strlen(buffer), done)) {
+ fprintf(stderr, "Parse error at line %d: %s\n",
+ XML_GetCurrentLineNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+ // Continue anyway
+ }
+ }
+ } while (!done);
+
+ if (done && !feof(skin_xml)) {
+ fprintf(stderr, "Parse error, unexpected EOF\n");
+ // Continue anyway
+ }
+
+ XML_ParserFree(parser);
+ qemu_free(parserconfig.filepath);
+
+ // Create a buffer to store the information
+ fclose(skin_xml);
+ return skin_activate_layout(skin, skin->rotation);
+ }
+ return -1;
+}
+
+SkinScreen* skin_load_configuration(char* file, int portrait)
+{
+ //printf("skin_config.c: >> skin_load_configuration\n");
+ SkinScreen *skin = (SkinScreen*) qemu_mallocz(sizeof(SkinScreen));
+ if(!skin) return NULL;
+ skin->es = (EmulatedScreen*) qemu_mallocz(sizeof(EmulatedScreen));
+ //printf("skin_load_configuration 1\n");
+ if(!skin->es) {
+ qemu_free(skin);
+ return NULL;
+ }
+ skin->config = (SkinConfig*) qemu_mallocz(sizeof(SkinConfig));
+ //printf("skin_load_configuration 2\n");
+ if (!skin->config) {
+ qemu_free(skin->es);
+ qemu_free(skin);
+ return NULL;
+ }
+ if (portrait) {
+ skin->rotation_req = skin->rotation = on;
+ }
+ if(skin_load_file(skin, file)) {
+ //printf("skin_config.c: skin_load_configuration, skin loaded '%s'\n", file);
+ qemu_free(skin->config);
+ qemu_free(skin->es);
+ qemu_free(skin);
+ skin = NULL;
+ }
+ if (skin && skin->keyboard.button)
+ skin->keyboard.button->key.state = ESkinBtn_Active;
+
+ return skin;
+}
diff --git a/skin/skin_config.h b/skin/skin_config.h
new file mode 100644
index 000000000..7b0d693f4
--- /dev/null
+++ b/skin/skin_config.h
@@ -0,0 +1,29 @@
+/*
+ * Skin configuration reading header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "skin.h"
+
+#ifndef SKIN_CONFIG_H__
+#define SKIN_CONFIG_H__
+
+SkinScreen *skin_load_configuration(char* file, int portrait);
+int skin_activate_layout(SkinScreen* skin, int rotation);
+
+#endif /* SKIN_CONFIG_H__ */
diff --git a/skin/skin_image.c b/skin/skin_image.c
new file mode 100644
index 000000000..6b116c799
--- /dev/null
+++ b/skin/skin_image.c
@@ -0,0 +1,490 @@
+/*
+ * Skin image drawing
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "qemu-common.h"
+#ifndef CONFIG_COCOA
+#define PNG_SKIP_SETJMP_CHECK
+#include
+#endif
+
+#include "console.h"
+
+#include "skin_image.h"
+
+#define PIXEL_DST 2
+#include "skin_image_template.h"
+#undef PIXEL_DST
+#define PIXEL_DST 4
+#include "skin_image_template.h"
+#undef PIXEL_DST
+
+// Font defines, ascii table font from ' ' to '~' characters supported
+#define CHAR_BASE ' ' // base number (first character in table)
+#define CHAR_LAST '~' // character in the font picture
+
+#define TOOLTIP_SPAC_W 3 // Spacing of the tooltip on each side
+#define TOOLTIP_SPAC_H 1 // Spacing of the tooltip on each side
+
+static void skin_merge_image( SkinImage *dst, SkinImage *src,
+ int xd, int yd, // Destination
+ int xs, int ys, int w, int h) // Source
+{
+ int line;
+ // This will fit, now copy line by line
+ uint32_t r, g, b, a, px;
+ uint32_t *srcpx, *dstpx;
+ for( line = 0; line < h; line++) {
+ dstpx = (uint32_t*)(dst->data + // base destination
+ ((yd + line) * dst->linesize) + // pixel row
+ (xd * dst->pf.bytes_per_pixel)); // pixel column start
+ srcpx = (uint32_t*)(src->data + // base source
+ src->linesize * (ys + line) + // pixel row
+ xs * dst->pf.bytes_per_pixel); // pixel column start
+ for (px = 0; px < w; px++) {
+ // Extract color values and alpha channel
+ r = ((srcpx[px]) & src->pf.rmask) >> (src->pf.rshift);
+ g = ((srcpx[px]) & src->pf.gmask) >> (src->pf.gshift);
+ b = ((srcpx[px]) & src->pf.bmask) >> (src->pf.bshift);
+ a = ((srcpx[px]) & src->pf.amask) >> (src->pf.ashift);
+
+ // Apply alpha blend factor
+ r = r * a / src->pf.amax;
+ g = g * a / src->pf.gmax;
+ b = b * a / src->pf.bmax;
+ // Convert to destination depth
+ r = r >> (8 - dst->pf.rbits);
+ g = g >> (8 - dst->pf.gbits);
+ b = b >> (8 - dst->pf.bbits);
+ // Merge the colors
+ r |= ((dstpx[px] & dst->pf.rmask) >> dst->pf.rshift) *
+ (dst->pf.rmax - (a >> (8 - dst->pf.rbits))) / dst->pf.rmax;
+ g |= ((dstpx[px] & dst->pf.gmask) >> dst->pf.gshift) *
+ (dst->pf.gmax - (a >> (8 - dst->pf.gbits))) / dst->pf.gmax;
+ b |= ((dstpx[px] & dst->pf.bmask) >> dst->pf.bshift) *
+ (dst->pf.bmax - (a >> (8 - dst->pf.bbits))) / dst->pf.bmax;
+ a = a >> (8 - dst->pf.abits);
+ a = a + ((dstpx[px] & dst->pf.amask) >> dst->pf.ashift) *
+ (dst->pf.amax - (a >> (8 - dst->pf.abits))) / dst->pf.amax;
+
+ // Put the color as destination pixel
+ dstpx[px] = ((r << dst->pf.rshift) & dst->pf.rmask) |
+ ((g << dst->pf.gshift) & dst->pf.gmask) |
+ ((b << dst->pf.bshift) & dst->pf.bmask) |
+ ((a << dst->pf.ashift) & dst->pf.amask);
+
+ }
+ }
+}
+
+SkinImage* skin_image_createtext(SkinScreen* skin, char* text)
+{
+ if (skin->font && skin->font->char_width != 0) {
+ int cur, line;
+ int len = strlen(text);
+ if (len <= 0) return NULL;
+ struct SkinImage* image = (SkinImage*)qemu_malloc(sizeof(SkinImage));
+ if (image) {
+ memcpy(image, skin->font->image, sizeof(SkinImage));
+ // Create width with spacing on each side
+ image->width = skin->font->char_width * len + TOOLTIP_SPAC_W * 2;
+ image->height += TOOLTIP_SPAC_H * 2;
+ image->linesize = image->width * 4; // bytes/pixel
+ image->data = qemu_malloc(image->width * image->height * 4);
+ uint32_t *cleardst;
+ // Full background is always black (gives us a border)
+ for (line = 0; line < image->height; line++)
+ for (cur = 0; cur < image->width; cur++) {
+ cleardst = (uint32_t*)(image->data +
+ (line * image->linesize) + (cur * 4));
+ *cleardst = 0xFF000000; // Black
+ }
+ // Next fill the background color if given (defaults to transparent)
+ for (line = 1; line < image->height-1; line++)
+ for (cur = 1; cur < image->width-1; cur++) {
+ cleardst = (uint32_t*)(image->data +
+ (line * image->linesize) + (cur * 4));
+ *cleardst = skin->tooltip.color;
+ }
+
+ // Copy the characters in place, one at a time
+ for (cur = 0; cur < len; cur++) {
+ skin_merge_image(image, skin->font->image,
+ cur * skin->font->char_width + TOOLTIP_SPAC_W, TOOLTIP_SPAC_H,
+ (text[cur]-CHAR_BASE) * skin->font->char_width, 0,
+ skin->font->char_width, skin->font->char_height);
+ }
+ }
+ return image;
+ }
+ return NULL;
+}
+
+void skin_rotate_buffer(SkinScreen* skin, DisplayState* ds, int x, int y, int w, int h)
+{
+ switch (ds_get_bytes_per_pixel(ds)) {
+ case 2:
+ skin_rotate_buffer_bytes_2(skin, ds, x, y, w, h);
+ break;
+ case 4:
+ skin_rotate_buffer_bytes_4(skin, ds, x, y, w, h);
+ break;
+ default:
+ printf("Wrong destination buffer\n");
+ break;
+ }
+}
+
+void skin_fill_color( SkinScreen* skin, SkinArea* area, int r, int g, int b)
+{
+ uint32_t color = 0;
+ PixelFormat* pf = &skin->ds->surface->pf;
+ color = (((r << (pf->rshift)) >> (8 - pf->rbits)) & pf->rmask) |
+ (((g << (pf->gshift)) >> (8 - pf->gbits)) & pf->gmask) |
+ (((b << (pf->bshift)) >> (8 - pf->bbits)) & pf->bmask);
+ vga_fill_rect(skin->ds, area->x, area->y, area->width, area->height, color);
+}
+
+void skin_fill_background(SkinScreen* skin, SkinArea* area)
+{
+ int r = skin->bgcolor.red;
+ int g = skin->bgcolor.green;
+ int b = skin->bgcolor.blue;
+ skin_fill_color(skin, area, r, g, b);
+}
+
+int skin_draw_button(SkinScreen* skin, SkinButton* button, int state)
+{
+ //printf("skin_draw_button( state: %d ) %d\n", state, button->key.state);
+ if(state == button->key.state) return 0;
+ if(state != ESkinBtn_forceredraw) button->key.state = state;
+ struct SkinImage image;
+ memcpy(&image, &button->image, sizeof(SkinImage));
+ // Correct the data pointer
+ image.data += (image.linesize * image.height * button->key.state);
+ struct SkinArea clip = { image.posx, image.posy, image.width, image.height };
+ skin_fill_background(skin, &clip);
+ if (skin->background != NULL) {
+ (void)skin_draw_image(skin, skin->background, &clip);
+ }
+ return skin_draw_image(skin, &image, &clip);
+}
+
+int skin_draw_animated_keyboard(SkinScreen* skin, SkinImage* image, int phase)
+{
+ //printf("skin_draw_animated_keyboard, phase=%d\n", phase);
+ struct SkinImage keyboardpart;
+ memcpy(&keyboardpart, image, sizeof(SkinImage));
+ // Correct the data pointer to draw only part of the picture
+ keyboardpart.data += (keyboardpart.linesize * keyboardpart.height * phase);
+ struct SkinArea clip = { keyboardpart.posx, keyboardpart.posy,
+ keyboardpart.width, keyboardpart.height };
+ if (skin->background != NULL) {
+ (void)skin_draw_image(skin, skin->background, &clip);
+ }
+ return skin_draw_image(skin, &keyboardpart, &clip);
+
+}
+
+int skin_highlight_key(SkinScreen* skin, SkinKey* key, int state)
+{
+ if (state == key->state) return 0;
+ key->state = state;
+ // Do we draw the actual key image or do we highlight that area
+ if (state != ESkinBtn_Idle) {
+ uint8_t *d, *d1;
+ int x, y, bpp, r, g, b, a, rd, gd, bd;
+ bpp = (ds_get_bits_per_pixel(skin->ds) + 7) >> 3;
+ d1 = ds_get_data(skin->ds) +
+ ds_get_linesize(skin->ds) * key->posy + bpp * key->posx;
+
+ PixelFormat* dpf = &skin->ds->surface->pf;
+ // Apply alpha blend factor
+ a = 128;
+ r = skin->keyboard.highlight_red * a / 255;
+ g = skin->keyboard.highlight_green * a / 255;
+ b = skin->keyboard.highlight_blue * a / 255;
+ // Convert to destination depth
+ r = r >> (8 - dpf->rbits);
+ g = g >> (8 - dpf->gbits);
+ b = b >> (8 - dpf->bbits);
+ // Apply color overlay
+ for (y = 0; y < key->height; y++) {
+ d = d1;
+ switch(bpp) {
+ case 1:
+ break;
+ case 2:
+ for (x = 0; x < key->width; x++) {
+ // Merge the colors
+ rd = r | (((*((uint16_t *)d)) & dpf->rmask) >> dpf->rshift) *
+ (dpf->rmax - (a >> (8 - dpf->rbits))) / dpf->rmax;
+ gd = g | ((*((uint16_t *)d) & dpf->gmask) >> dpf->gshift) *
+ (dpf->gmax - (a >> (8 - dpf->gbits))) / dpf->gmax;
+ bd = b | ((*((uint16_t *)d) & dpf->bmask) >> dpf->bshift) *
+ (dpf->bmax - (a >> (8 - dpf->bbits))) / dpf->bmax;
+ // Put the color as destination pixel
+ *((uint16_t *)d) = ((rd << dpf->rshift) & dpf->rmask) |
+ ((gd << dpf->gshift) & dpf->gmask) | ((bd << dpf->bshift) & dpf->bmask);
+ d += 2;
+ }
+ break;
+ case 4:
+ for (x = 0; x < key->width; x++) {
+ // Merge the colors
+ rd = r | ((*((uint32_t *)d) & dpf->rmask) >> dpf->rshift) *
+ (dpf->rmax - (a >> (8 - dpf->rbits))) / dpf->rmax;
+ gd = g | ((*((uint32_t *)d) & dpf->gmask) >> dpf->gshift) *
+ (dpf->gmax - (a >> (8 - dpf->gbits))) / dpf->gmax;
+ bd = b | ((*((uint32_t *)d) & dpf->bmask) >> dpf->bshift) *
+ (dpf->bmax - (a >> (8 - dpf->bbits))) / dpf->bmax;
+ // Put the color as destination pixel
+ *((uint32_t *)d) = ((rd << dpf->rshift) & dpf->rmask) |
+ ((gd << dpf->gshift) & dpf->gmask) | ((bd << dpf->bshift) & dpf->bmask);
+ d += 4;
+ }
+ break;
+ }
+ d1 += ds_get_linesize(skin->ds);
+ }
+ }
+ else {
+ SkinArea area = { key->posx, key->posy, key->width, key->height };
+ skin_fill_background(skin, &area);
+ skin_draw_image( skin, skin->keyboard.image, &area);
+ }
+ return 1;
+}
+
+SkinArea skin_cliparea(SkinImage* image, SkinArea* area)
+{
+ SkinArea clip;
+ clip.x = area->x;
+ clip.y = area->y;
+ clip.width = area->width;
+ clip.height = area->height;
+
+ int imagex = image->posx + image->width;
+ int imagey = image->posy + image->height;
+ int areax = area->x + area->width;
+ int areay = area->y + area->height;
+
+ if (image->posx > area->x) {
+ clip.x = image->posx;
+ clip.width -= image->posx - area->x;
+ }
+ if (image->posy > area->y) {
+ clip.y = image->posy;
+ clip.height -= image->posy - area->y;
+ }
+ if (areax > imagex) clip.width = imagex - clip.x;
+ if (areay > imagey) clip.height = imagey - clip.y;
+// printf("%d, %d, %d, %d\n", clip.x, clip.y, clip.width, clip.height);
+ return clip;
+}
+
+int skin_draw_image(SkinScreen* skin, SkinImage* image, SkinArea* area)
+{
+ //printf("skin_draw_image(area: %d, %d, %d %d)\nimage: %d, %d, %d, %d\nimage->data: 0x%X\n",
+ // area->x, area->y, area->width, area->height,
+ // image->posx, image->posy, image->width, image->height), (unsigned int)image->data);
+ // Get the clipping area we need to update
+ SkinArea clip = skin_cliparea(image, area);
+ // Determine the correct destination buffer
+ switch (ds_get_bytes_per_pixel(skin->ds)) {
+ case 2:
+ return skin_draw_image_from_a24_to_2(skin, image, &clip);
+ case 4:
+ return skin_draw_image_from_a24_to_4(skin, image, &clip);
+ default:
+ printf("Wrong destination buffer\n");
+ return 0;
+ }
+}
+
+// Load / Read png files
+#ifndef CONFIG_COCOA
+void *skin_loadpng(const char *fn, unsigned *_width, unsigned *_height)
+{
+ FILE *fp = 0;
+ unsigned char header[8];
+ unsigned char *data = 0;
+ unsigned char **rowptrs = 0;
+ png_structp p = 0;
+ png_infop pi = 0;
+
+ png_uint_32 width, height;
+ int bitdepth, colortype, imethod, cmethod, fmethod, i;
+
+ p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if(p == 0) {
+ printf("%s: failed to allocate png read struct\n", fn);
+ return 0;
+ }
+
+ pi = png_create_info_struct(p);
+ if(pi == 0) {
+ printf("%s: failed to allocate png info struct\n", fn);
+ goto oops;
+ }
+
+ fp = fopen(fn, "rb");
+ if(fp == 0) {
+ printf("%s: failed to open file\n", fn);
+ return 0;
+ }
+
+ if(fread(header, 8, 1, fp) != 1) {
+ printf("%s: failed to read header\n", fn);
+ goto oops;
+ }
+
+ if(png_sig_cmp(header, 0, 8)) {
+ printf("%s: header is not a PNG header\n", fn);
+ goto oops;
+ }
+
+ if(setjmp(png_jmpbuf(p))) {
+ printf("%s: png library error\n", fn);
+ oops:
+ png_destroy_read_struct(&p, &pi, 0);
+ if(fp != 0) fclose(fp);
+ if(data != 0) free(data);
+ if(rowptrs != 0) free(rowptrs);
+ return 0;
+ }
+
+ png_init_io(p, fp);
+ png_set_sig_bytes(p, 8);
+
+ png_read_info(p, pi);
+
+ png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype,
+ &imethod, &cmethod, &fmethod);
+// printf("PNG: %d x %d (d=%d, c=%d)\n",
+// width, height, bitdepth, colortype);
+
+ switch(colortype){
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(p);
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ if(png_get_valid(p, pi, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(p);
+ } else {
+ png_set_filler(p, 0xFF, PNG_FILLER_AFTER);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ printf("\n");
+ if(bitdepth < 8) {
+ png_set_gray_1_2_4_to_8(p);
+ }
+
+ default:
+ printf("%d: unsupported (grayscale?) color type\n", colortype);
+ goto oops;
+ }
+
+ png_set_bgr(p);
+
+ if(bitdepth == 16) {
+ png_set_strip_16(p);
+ }
+
+ data = (unsigned char*) malloc((width * 4) * height);
+ rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height);
+
+ if((data == 0) || (rowptrs == 0)){
+ printf("could not allocate data buffer\n");
+ goto oops;
+ }
+
+ for(i = 0; i < height; i++) {
+ rowptrs[i] = data + ((width * 4) * i);
+ }
+
+ png_read_image(p, rowptrs);
+
+ png_destroy_read_struct(&p, &pi, 0);
+ fclose(fp);
+ if(rowptrs != 0) free(rowptrs);
+
+ *_width = width;
+ *_height = height;
+
+ return (void*) data;
+}
+#endif
+
+static void skin_png_defaultpixelformat(SkinImage* image)
+{
+ image->pf.bits_per_pixel = 32;
+ image->pf.bytes_per_pixel = 4;
+ image->pf.depth = 32;
+ image->pf.rmask = 0x00FF0000;
+ image->pf.gmask = 0x0000FF00;
+ image->pf.bmask = 0x000000FF;
+ image->pf.amask = 0xFF000000;
+ image->pf.rshift = 16;
+ image->pf.gshift = 8;
+ image->pf.bshift = 0;
+ image->pf.ashift = 24;
+ image->pf.rmax = 255;
+ image->pf.gmax = 255;
+ image->pf.bmax = 255;
+ image->pf.amax = 255;
+ image->pf.rbits = 8;
+ image->pf.gbits = 8;
+ image->pf.bbits = 8;
+ image->pf.abits = 8;
+ image->linesize = image->pf.bytes_per_pixel * image->width;
+}
+
+int skin_load_image_data(SkinImage* image, char* file)
+{
+ unsigned width, height;
+ image->data = skin_loadpng(file, &width, &height);
+ if (image->data == NULL) {
+ fprintf(stderr, "failed to load image '%s'\n", file );
+ return 1;
+ }
+ image->width = (int)width;
+ image->height = (int)height;
+ skin_png_defaultpixelformat(image);
+
+// printf("image loaded '%s', width=%d, height=%d\n", file, width, height);
+ return 0;
+}
+
+SkinImage* skin_load_image(char* file)
+{
+ SkinImage* image = (SkinImage*)qemu_mallocz(sizeof(SkinImage));
+ if(!image) return NULL;
+ if(skin_load_image_data(image, file)) {
+ qemu_free(image);
+ return NULL;
+ }
+ return image;
+}
+
diff --git a/skin/skin_image.h b/skin/skin_image.h
new file mode 100644
index 000000000..74a15d558
--- /dev/null
+++ b/skin/skin_image.h
@@ -0,0 +1,44 @@
+/*
+ * Skin image drawing header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "skin.h"
+
+#ifndef SKIN_IMAGE_H__
+#define SKIN_IMAGE_H__
+
+SkinImage* skin_image_createtext( SkinScreen* skin, char* text);
+
+void skin_rotate_buffer(SkinScreen* skin, DisplayState* ds, int x, int y, int w, int h);
+
+void skin_fill_color( SkinScreen* skin, SkinArea* area, int r, int g, int b);
+void skin_fill_background(SkinScreen* skin, SkinArea* area);
+int skin_draw_button(SkinScreen* skin, SkinButton* button, int state);
+int skin_highlight_key(SkinScreen* skin, SkinKey* key, int state);
+int skin_draw_image(SkinScreen* skin, SkinImage* image, SkinArea* area);
+int skin_draw_animated_keyboard(SkinScreen* skin, SkinImage* image, int state);
+
+SkinArea skin_cliparea(SkinImage* image, SkinArea* area);
+
+int skin_load_image_data(SkinImage* image, char* file);
+SkinImage* skin_load_image(char* file);
+
+void *skin_loadpng(const char *fn, unsigned *w, unsigned *h);
+
+#endif /* SKIN_IMAGE_H__ */
diff --git a/skin/skin_image_template.h b/skin/skin_image_template.h
new file mode 100644
index 000000000..28fa3484b
--- /dev/null
+++ b/skin/skin_image_template.h
@@ -0,0 +1,113 @@
+/*
+ * Skin image conversion template header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if PIXEL_DST == 2
+ #define DST_TYPE uint16_t
+#endif
+#if PIXEL_DST == 4
+ #define DST_TYPE uint32_t
+#endif
+
+/* Function declaration depending on the bytes per pixel
+ either 2 bytes or 4 bytes types are used */
+static inline void glue(skin_rotate_buffer_bytes_,PIXEL_DST)
+ (SkinScreen* skin, DisplayState* ds, int x, int y, int w, int h)
+{
+ DST_TYPE *srcpixel, *dstpixel;
+ int px, py;
+ // Loop through all the pixels to rotate them 90 degr clockwise
+ for (py = 0; py < h; py++) {
+ for (px = 0; px < w; px++) {
+ // Source pixel (landscape orientation)
+ srcpixel = (DST_TYPE*)(ds_get_data(ds) +
+ ((y + py) * ds_get_linesize(ds)) +
+ ((x + px) * ds_get_bytes_per_pixel(ds)));
+ // Destination pixel (portrait orientation)
+ dstpixel = (DST_TYPE*)(ds_get_data(skin->ds) +
+ (skin->es->posy + x + px) * ds_get_linesize(skin->ds) +
+ (skin->es->posx + skin->es->height - (y+py)) *
+ ds_get_bytes_per_pixel(skin->ds));
+ // Copy the pixel data
+ *dstpixel = *srcpixel;
+ }
+ }
+}
+
+static inline int glue(skin_draw_image_from_a24_to_,PIXEL_DST)
+ (SkinScreen* skin, SkinImage* image, SkinArea* clip)
+{
+ int line;
+ // Calculate source row and column start
+ int colst = (clip->x - image->posx) * image->pf.bytes_per_pixel;
+ int rowst = (clip->y - image->posy);
+ // Determine number of bytes to copy
+ if (image && skin->ds &&
+ ds_get_width(skin->ds) >= clip->x + clip->width &&
+ ds_get_height(skin->ds) >= clip->y + clip->height ) {
+ // This will fit, now copy line by line
+ uint32_t r, g, b, a, px;
+ uint32_t* srcpx;
+ DST_TYPE* dstpx;
+ PixelFormat* dpf = &skin->ds->surface->pf;
+ for( line = 0; line < clip->height; line++) {
+ dstpx = (DST_TYPE*)(ds_get_data(skin->ds) + // base destination
+ ((clip->y + line) * ds_get_linesize(skin->ds)) + // pixel row
+ (clip->x * ds_get_bytes_per_pixel(skin->ds))); // pixel column start
+ srcpx = (uint32_t*)(image->data + // base source
+ image->linesize * (rowst + line) + // pixel row
+ colst); // pixel column start
+ for (px = 0; px < clip->width; px++) {
+ // Extra color values and alpha channel
+ r = ((srcpx[px]) & image->pf.rmask) >> (image->pf.rshift);
+ g = ((srcpx[px]) & image->pf.gmask) >> (image->pf.gshift);
+ b = ((srcpx[px]) & image->pf.bmask) >> (image->pf.bshift);
+ a = ((srcpx[px]) & image->pf.amask) >> (image->pf.ashift);
+ // Apply alpha blend factor
+ r = r * a / image->pf.amax;
+ g = g * a / image->pf.gmax;
+ b = b * a / image->pf.bmax;
+ // Convert to destination depth
+ r = r >> (8 - dpf->rbits);
+ g = g >> (8 - dpf->gbits);
+ b = b >> (8 - dpf->bbits);
+ // Merge the colors
+ r |= ((dstpx[px] & dpf->rmask) >> dpf->rshift) *
+ (dpf->rmax - (a >> (8 - dpf->rbits))) / dpf->rmax;
+ g |= ((dstpx[px] & dpf->gmask) >> dpf->gshift) *
+ (dpf->gmax - (a >> (8 - dpf->gbits))) / dpf->gmax;
+ b |= ((dstpx[px] & dpf->bmask) >> dpf->bshift) *
+ (dpf->bmax - (a >> (8 - dpf->bbits))) / dpf->bmax;
+ // Put the color as destination pixel
+ dstpx[px] = ((r << dpf->rshift) & dpf->rmask) |
+ ((g << dpf->gshift) & dpf->gmask) |
+ ((b << dpf->bshift) & dpf->bmask);
+ }
+ }
+ return 1;
+ }
+ else {
+ printf("That wouldn't fit!\n");
+ }
+ return 0;
+}
+
+#undef SRC_TYPE
+#undef DST_TYPE
+
diff --git a/skin/skin_switchstate.h b/skin/skin_switchstate.h
new file mode 100644
index 000000000..0a0a04960
--- /dev/null
+++ b/skin/skin_switchstate.h
@@ -0,0 +1,35 @@
+/*
+ * Skin button slider switchstate handling header
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+ #ifndef SKIN_SWITCHSTATE_H
+ #define SKIN_SWITCHSTATE_H
+
+ typedef enum SkinSwitchState {
+ unknown = -1,
+ inactive = 0,
+ active
+ } SkinSwitchState;
+
+typedef int switchstate_callback(void *opaque, const int keycode);
+
+ void qemu_skin_add_switchstate_callback(switchstate_callback *callback,
+ void *opaque);
+
+#endif
diff --git a/skin/skinning.c b/skin/skinning.c
new file mode 100755
index 000000000..a9e34b79b
--- /dev/null
+++ b/skin/skinning.c
@@ -0,0 +1,1056 @@
+/*
+ * Qemu main skinning
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include
+#include
+
+#include "skin.h"
+#include "skin_config.h"
+#include "skin_image.h"
+#include "skin_button.h"
+#include "qemu-timer.h"
+#include "qemu_socket.h"
+#include "console.h"
+#include
+
+struct SkinScreen *skin = NULL;
+// Timer for animated keyboard
+static QEMUTimer *keyboard_timer = NULL;
+static int keyboard_animation_phase = 0;
+#define ANIM_NOT_USED 13 // Defined instead of const int because of case-usage
+static int no_keyboard_anim = 0;
+const int ZOOM_STEP = 10;
+const int ZOOM_INDICATOR_POS = 26;
+const int ZOOM_MIN_FACTOR = 50;
+const int ZOOM_MAX_FACTOR = 130;
+static int zoom_factor = 100;
+static int first_keyboard_check = 1;
+static int startup = 1;
+static int rct_sock = -1;
+
+// #jun:hacking
+DisplayState *es_ds = NULL;
+int es_posx, es_posy;
+
+// Local prototypes
+static void setup_keyboard_animation_timer(void);
+static void skin_update_keyboard(void *opaque);
+static void skin_draw_skin(SkinArea* area);
+static void skin_cleartooltip(void *opaque);
+static void skin_handle_zooming(void);
+static void skin_position_items(int move);
+static void skin_rct_serve(void *opaque);
+static int skin_rct_initialize(int rctport);
+
+// Local prototypes used externally
+int skinning_init(char* skin_file, int portrait, int rctport);
+void skin_toggle_full_screen(DisplayState *ds);
+// Overruled functions from console.c
+DisplayState *qemu_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);
+
+void original_qemu_console_resize(DisplayState *ds, int width, int height);
+
+static void skin_handle_rotation(void)
+{
+ if (skin->rotation != skin->rotation_req) {
+ skin_cleartooltip(NULL);
+ skin->rotation = skin->rotation_req;
+ skin_activate_layout(skin, skin->rotation);
+ SkinButton* b = skin->buttons;
+ while (b) {
+ b->key.defaultstate = undefined;
+ b = b->next;
+ }
+ no_keyboard_anim = 1;
+ // Update keyboard if needed
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ // Check if the skin offset should be applied
+ if (skin->rotation == on && skin->keyboard.offset != 0) {
+ skin_position_items(1);
+ }
+ // Resizing screen and updating keyboard without animation
+ if (keyboard_timer) qemu_del_timer(keyboard_timer);
+ original_qemu_console_resize(skin->ds, skin->keyboard.screenwidth,
+ skin->keyboard.screenheight);
+ skin_update_keyboard(NULL);
+ skin_handle_zooming();
+ }
+ else {
+ // No keyboard needs to be drawn
+ if (keyboard_timer) qemu_del_timer(keyboard_timer);
+ original_qemu_console_resize(skin->ds, skin->width, skin->height);
+ skin_handle_zooming();
+ }
+ if (skin->rotation) {
+ kbd_put_keycode(0x4f); // x -= axis_max
+ kbd_put_keycode(0x4c); // y += axis_max
+ kbd_put_keycode(0x4f | 0x80);
+ kbd_put_keycode(0x4c | 0x80);
+ } else {
+ kbd_put_keycode(0x50); // x += axis_max
+ kbd_put_keycode(0x4b); // y -= axis_max
+ kbd_put_keycode(0x50 | 0x80);
+ kbd_put_keycode(0x4b | 0x80);
+ }
+ }
+}
+
+static int skin_overlaps(SkinImage* image, SkinArea* area)
+{
+ if (image->posx + image->width < area->x) return 0;
+ if (image->posy + image->height < area->y) return 0;
+ if (area->x + area->width < image->posx) return 0;
+ if (area->y + area->height < image->posy) return 0;
+ return 1;
+}
+
+static void calculate_tooltip_position( SkinButton* button,
+ SkinImage* tooltip )
+{
+ // Determine the tooltip position
+ // Best would be in the center below the button
+ int x = 0, y = 0;
+ x = button->image.posx + button->image.width / 2 - tooltip->width / 2;
+ y = button->image.posy + button->image.height;
+ // If it moves out top or left, move it to the edge
+ if (x < 0) x = 2;
+ if (y < 0) y = 2;
+ // If it moves out bottom or right, move it to the edge
+ if (x + tooltip->width > ds_get_width(skin->ds))
+ x = ds_get_width(skin->ds) - (tooltip->width + 2);
+ if (y + tooltip->height > ds_get_height(skin->ds))
+ y = ds_get_height(skin->ds) - (tooltip->height + 2);
+ // Put the tooltip position to the tooltip image
+ tooltip->posx = x;
+ tooltip->posy = y;
+}
+
+static void skin_draw_tooltip(SkinArea *clip)
+{
+ if (skin->tooltip.image &&
+ skin_overlaps(skin->tooltip.image, clip) ) {
+ skin_draw_image(skin, skin->tooltip.image, clip);
+ }
+}
+
+static void skin_cleartooltip(void *opaque)
+{
+ // Clear the timer and tooltip
+ if (skin->tooltip.timer) {
+ qemu_del_timer(skin->tooltip.timer);
+ }
+ skin->tooltip.button = NULL;
+ if (skin->tooltip.image) {
+ SkinArea clip = { skin->tooltip.image->posx,
+ skin->tooltip.image->posy,
+ skin->tooltip.image->width,
+ skin->tooltip.image->height };
+ if (skin->tooltip.image->data) qemu_free(skin->tooltip.image->data);
+ qemu_free(skin->tooltip.image);
+ skin->tooltip.image = NULL;
+ // Redraw the skin
+ skin_draw_skin(&clip);
+ // Make sure the emulated screen is redrawn if needed
+ if (skin->es) {
+ vga_hw_invalidate();
+ vga_hw_update();
+ }
+ dpy_update(skin->ds, clip.x, clip.y, clip.width, clip.height);
+ }
+}
+
+static void skin_handle_tooltip_timeout(void *opaque)
+{
+ // Time to show the tooltip
+ SkinTooltip* tooltip = (SkinTooltip*)opaque;
+ if (tooltip->button) {
+ // Create the correct text image for the button
+ SkinImage *image =
+ skin_image_createtext(skin, tooltip->button->tooltip);
+ if (image) {
+ // Find the correct location to draw the tooltip
+ calculate_tooltip_position(tooltip->button, image);
+ // Everything set, store the image and have it drawn
+ tooltip->image = image;
+ struct SkinArea clip = { image->posx, image->posy,
+ image->width, image->height };
+ skin_draw_tooltip(&clip);
+ dpy_update(skin->ds, image->posx, image->posy,
+ image->width, image->height);
+ }
+ }
+}
+
+static void skin_mouse_event(void *opaque,
+ int x, int y, int z, int buttons_state)
+{
+ if (!is_graphic_console()) return;
+
+ static int in_screen = 0;
+
+ skin->mouse_event = on;
+ // Mouse position mx/my in range 0-32767, equals pixel 0 to width/height-1
+ // actual mouse x and y on the application
+ int mx = x;
+ int my = y;
+ x = (mx - skin->es->posx) * 0x7FFF / ds_get_width(skin->es->ds);
+ y = (my - skin->es->posy) * 0x7FFF / ds_get_height(skin->es->ds);
+
+// printf("skin_mouse_event: %d, %d btn: %d (w:%d, h:%d)\n", x, y, buttons_state,
+// ds_get_width(skin->ds), ds_get_height(skin->ds));
+ QEMUPutMouseEntry *child = (QEMUPutMouseEntry *)opaque;
+// printf("skin_mouse_event: mx:%d, my:%d, posx:%d, posy:%d, relw: %d, relh: %d, w:%d, h:%d\n", mx, my, skin->es->posx, skin->es->posy, ds_get_width(skin->es->ds), ds_get_height(skin->es->ds), skin->es->width, skin->es->height);
+ if (skin->rotation == off) {
+ if (mx > skin->es->posx &&
+ mx < skin->es->posx + ds_get_width(skin->es->ds) /*skin->es->width*/ &&
+ my > skin->es->posy &&
+ my < skin->es->posy + ds_get_height(skin->es->ds) /*skin->es->height*/ ) {
+// printf("skin_mouse_event: report x: %d, y: %d\n", mx - skin->es->posx, my - skin->es->posy);
+
+ if (!in_screen) {
+ in_screen = 1;
+ SDL_ShowCursor(0);
+ }
+
+ child->qemu_put_mouse_event( child->qemu_put_mouse_event_opaque,
+ (mx - skin->es->posx) * 0x7FFF / ds_get_width(skin->es->ds),
+ (my - skin->es->posy) * 0x7FFF / ds_get_height(skin->es->ds),
+ z, buttons_state);
+ } else {
+ if (in_screen) {
+ in_screen = 0;
+ SDL_ShowCursor(1);
+ }
+
+ }
+ }
+ else {
+ // We have to change the coordinates, since we draw rotated
+ if (mx > skin->es->posx &&
+ mx < skin->es->posx + skin->es->height &&
+ my > skin->es->posy &&
+ my < skin->es->posy + skin->es->width ) {
+
+ child->qemu_put_mouse_event( child->qemu_put_mouse_event_opaque,
+ y, -x, z, buttons_state);
+ SDL_ShowCursor(0);
+ } else {
+ SDL_ShowCursor(1);
+ }
+ }
+
+ // Check if we pressed any button
+ SkinButton* button = skin->buttons;
+ while (button) {
+ if (skin_button_mouse_over(&button->key, mx, my)) {
+ // Check if we handle start tooltip handling
+ if (button->tooltip &&
+ skin->tooltip.button != button) {
+ skin_cleartooltip(NULL);
+ skin->tooltip.button = button;
+ if (!skin->tooltip.timer) {
+ skin->tooltip.timer = qemu_new_timer_ns(rt_clock,
+ skin_handle_tooltip_timeout,
+ &skin->tooltip);
+ }
+ // Set expiration time to be 1 second
+ qemu_mod_timer(skin->tooltip.timer, qemu_get_clock_ns(rt_clock) + 1000);
+ }
+ int state = skin_button_handle_mouse(&button->key, buttons_state & MOUSE_EVENT_LBUTTON );
+ if (skin_draw_button(skin, button, state)) {
+ dpy_update(skin->ds, button->image.posx, button->image.posy,
+ button->image.width, button->image.height);
+ }
+ }
+ else {
+ if (button == skin->tooltip.button) {
+ skin_cleartooltip(NULL);
+ }
+ int state = skin_button_handle_mouseleave(&button->key);
+ if (skin_draw_button(skin, button, state)) {
+ dpy_update(skin->ds, button->image.posx, button->image.posy,
+ button->image.width, button->image.height);
+ }
+ }
+ button = button->next;
+ }
+ // Check if we pressed any key from the keyboard
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ SkinKey* key = skin->keyboard.keys;
+ while (key) {
+ if (skin_button_mouse_over(key, mx, my)) {
+ int state = skin_button_handle_mouse(key, buttons_state & MOUSE_EVENT_LBUTTON);
+ if (skin_highlight_key(skin, key, state)) {
+ dpy_update(skin->ds, key->posx, key->posy,
+ key->width, key->height);
+ }
+ }
+ else {
+ int state = skin_button_handle_mouseleave(key);
+ if (skin_highlight_key(skin, key, state)) {
+ dpy_update(skin->ds, key->posx, key->posy,
+ key->width, key->height);
+ }
+ }
+ key = key->next;
+ }
+ }
+
+ skin_handle_rotation();
+ skin->mouse_event = off;
+}
+
+static void skin_position_items(int move)
+{
+ if (skin->keyboard.offset) {
+ if (skin->background != NULL) {
+ skin->background->posx += move * skin->keyboard.offset;
+ }
+ skin->es->posx += move * skin->keyboard.offset;
+
+ SkinButton* button = skin->buttons;
+ while (button) {
+ button->image.posx += move * skin->keyboard.offset;
+ button->key.posx += move * skin->keyboard.offset;
+ button = button->next;
+ }
+ }
+}
+
+static void skin_animate_keyboard(int phase)
+{
+ //printf(">> skin_animate_keyboard, phase=%d\n", phase);
+ if (skin->keyboard.button) {
+ switch (skin->keyboard.button->key.state) {
+ // Keyboard opening
+ case ESkinBtn_Active:
+ case ESkinBtn_ActiveHighlighted:
+ {
+ if (phase == ANIM_NOT_USED) {
+ // No animation, just draw the full keyboard
+ //printf("skin_animate_keyboard, no animation, draw keyboard\n");
+ SkinArea area = { skin->keyboard.image->posx,
+ skin->keyboard.image->posy,
+ skin->keyboard.image->width,
+ skin->keyboard.image->height };
+ skin_draw_image(skin,
+ skin->keyboard.image,
+ &area);
+ }
+ if (phase == 0) {
+ // Resize the screen to fit keyboard
+ //printf("skin_animate_keyboard, expand screen\n");
+ keyboard_animation_phase++;
+ skin_cleartooltip(NULL);
+ skin_position_items(1);
+ original_qemu_console_resize(skin->ds, skin->keyboard.screenwidth,
+ skin->keyboard.screenheight);
+ skin_handle_zooming();
+ break;
+ }
+
+ if (phase > 2 && phase < 7) {
+ // Draw actual animation phases
+ //printf("skin_animate_keyboard, opening, phase=%d\n", phase);
+ skin_draw_animated_keyboard(skin, skin->keyboard.image, 7-phase);
+ dpy_update(skin->ds, skin->keyboard.image->posx,
+ skin->keyboard.image->posy,
+ skin->keyboard.image->width,
+ skin->keyboard.image->height);
+ }
+ else if (phase == 7) {
+ // Draw fully open keyboard
+ //printf("skin_animate_keyboard, open\n");
+ keyboard_animation_phase = 8;
+ skin_draw_animated_keyboard(skin, skin->keyboard.image, 0);
+ dpy_update(skin->ds, skin->keyboard.image->posx,
+ skin->keyboard.image->posy,
+ skin->keyboard.image->width,
+ skin->keyboard.image->height);
+ }
+ }
+ break;
+ // Keyboard closing
+ case ESkinBtn_Idle:
+ case ESkinBtn_Highlighted:
+ {
+ // Draw actual animation phases
+ if (phase > 2 && phase < 7) {
+ skin_draw_animated_keyboard(skin, skin->keyboard.image, phase-2);
+ dpy_update(skin->ds, skin->keyboard.image->posx,
+ skin->keyboard.image->posy,
+ skin->keyboard.image->width,
+ skin->keyboard.image->height);
+ }
+ else if (phase == 7) {
+ // Shrink the screen, no keyboard
+ //printf("skin_animate_keyboard, shrink screen\n");
+ keyboard_animation_phase = 8;
+ skin_cleartooltip(NULL);
+ skin_position_items(-1);
+ original_qemu_console_resize(skin->ds, skin->width, skin->height);
+ skin_handle_zooming();
+ }
+ }
+ default:
+ // Do nothing
+ break;
+ }
+ }
+ //printf("skin_animate_keyboard >>\n");
+}
+
+static void skin_update_keyboard(void *opaque)
+{
+ if (!skin->keyboard.animated || no_keyboard_anim) {
+ // Animated keyboard is not used
+ keyboard_animation_phase = ANIM_NOT_USED;
+ no_keyboard_anim = 0;
+ }
+
+ //printf("skin_update_keyboard, phase=%d\n", keyboard_animation_phase);
+ switch (keyboard_animation_phase) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ //printf("skin_update_keyboard, executing anim...\n");
+ skin_animate_keyboard(keyboard_animation_phase);
+ keyboard_animation_phase++;
+ setup_keyboard_animation_timer();
+ break;
+ case 9:
+ //printf("skin_update_keyboard, end...\n");
+ keyboard_animation_phase = ANIM_NOT_USED;
+ break;
+ case ANIM_NOT_USED:
+ skin_animate_keyboard(keyboard_animation_phase);
+ break;
+ default:
+ // Do nothing
+ break;
+ }
+}
+
+static void setup_keyboard_animation_timer(void)
+{
+ // Set up timer for keyboard animation
+ //printf("setup_keyboard_timer\n");
+ if (keyboard_timer) qemu_del_timer(keyboard_timer);
+ // Create new timer and call skin_update_keyboard when it expires
+ keyboard_timer = qemu_new_timer_ns(rt_clock, skin_update_keyboard, NULL);
+ // Set expiration time to be 0.1 seconds
+ qemu_mod_timer(keyboard_timer, qemu_get_clock_ns(rt_clock) + 100);
+
+}
+
+static void skin_draw_skin(SkinArea* area)
+{
+ // Skinning draws in various layers, from bottom to top:
+ // background color - background image - keyboard - buttons
+
+ // Set the background color
+ skin_fill_background(skin, area);
+ // Draw the background image
+ if (skin->background &&
+ skin_overlaps(skin->background, area)) {
+ skin_draw_image(skin, skin->background, area);
+ }
+ // Draw the keyboard
+ if (skin->keyboard.image && skin->keyboard.keys && !first_keyboard_check) {
+ skin_update_keyboard(NULL);
+ }
+ // Draw the buttons
+ SkinButton* button = skin->buttons;
+ while (button) {
+ if (skin_overlaps(&button->image, area)) {
+ // Check the switch state when redrawing the skin. Check the
+ // keyboard switch only once, because it messes up the animated
+ // keyboard if pressed it open from computer keyboard.
+ if (button == skin->keyboard.button && first_keyboard_check) {
+ skin_button_checkswitch(skin, button);
+ first_keyboard_check = 0;
+ no_keyboard_anim = 1;
+ skin_update_keyboard(NULL);
+ }
+ else if (button != skin->keyboard.button) {
+ skin_button_checkswitch(skin, button);
+ }
+ skin_draw_button(skin, button, ESkinBtn_forceredraw);
+ }
+ button = button->next;
+ }
+}
+
+#define RCT_BUFSIZE 256
+static void skin_rct_serve(void *opaque)
+{
+ struct sockaddr_in addr;
+ int i;
+ socklen_t addrlen = sizeof(addr);
+ int csock = qemu_accept(rct_sock, (struct sockaddr *)&addr, &addrlen);
+ if (csock >= 0) {
+ char req[RCT_BUFSIZE];
+ char rep[RCT_BUFSIZE] = "ERROR:unidentified request";
+ int rlen;
+
+ // read and handle incoming RCT request
+ if ( (rlen = recv(csock, (void *)req, RCT_BUFSIZE, 0)) > 0) {
+ for(i=0;irotation ? "on" : "off");
+ } else if (strncmp(req, "setzoom", 7) == 0) {
+ char *endp;
+ int arg, newzoom, ok = 0;
+
+ printf("char 8 %c\n", req[7]);
+ if (req[7] == '\n') {
+ sprintf(rep, "ERROR:missing setzoom argument");
+ } else if (req[7] == '=') {
+ arg = strtol(req + 8, &endp, 10);
+ newzoom = arg;
+ ok = 1;
+ } else if ((req[7] == '+' || req[7] == '-') && req[8] == '=') {
+ // set relative to old value
+ arg = strtol(req + 9, &endp, 10);
+ if (!*endp && req[7] == '-') {
+ arg = -arg;
+ }
+ newzoom = zoom_factor + arg;
+ ok = 1;
+ }
+
+ if (ok) {
+ if (*endp) {
+ sprintf(rep, "ERROR:invalid setzoom argument:%s",
+ req + ((req[7] == '=') ? 8 : 9));
+ } else if (newzoom < ZOOM_MIN_FACTOR ||
+ newzoom > ZOOM_MAX_FACTOR) {
+ sprintf(rep, "ERROR:new zoom factor out of range:%d",
+ newzoom);
+ } else {
+ zoom_factor = newzoom;
+ skin_handle_zooming();
+ sprintf(rep, "OK:%d", zoom_factor);
+ }
+ } // otherwise the default error message applies
+ } else if (strncmp(req, "setrotation", 11) == 0) {
+ if (req[11] == '\n') {
+ // toggle current state if no argument
+ skin->rotation_req = (skin->rotation == off) ? on : off;
+ skin_handle_rotation();
+ sprintf(rep, "OK:%s",
+ (skin->rotation == on) ? "on" : "off");
+ } else if (strncmp(req + 11, "=on", 3) == 0) {
+ skin->rotation_req = on;
+ skin_handle_rotation();
+ sprintf(rep, "OK:on");
+ } else if (strncmp(req + 11, "=off", 4) == 0) {
+ skin->rotation_req = off;
+ skin_handle_rotation();
+ sprintf(rep, "OK:off");
+ } else if (req[11] == '=') {
+ sprintf(rep, "ERROR:invalid setrotation argument\n");
+ } // otherwise the default error message applies
+ }
+
+ if (send(csock, (const void *)rep, strlen(rep) + 1, 0) < 0) {
+ fprintf(stderr, "%s: send(): %s\n",
+ __FUNCTION__, strerror(socket_error()));
+ }
+ }
+
+ closesocket(csock);
+ } else {
+ fprintf(stderr, "%s: qemu_accept(): %s\n",
+ __FUNCTION__, strerror(socket_error()));
+ }
+}
+
+static int skin_rct_initialize(int rctport)
+{
+ struct sockaddr_in addr;
+
+ if ( (rct_sock = qemu_socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "%s: qemu_socket(): %s\n",
+ __FUNCTION__, strerror(socket_error()));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(rctport);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(rct_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "%s: bind(): %s\n", __FUNCTION__, strerror(socket_error()));
+ return -1;
+ }
+
+ if (listen(rct_sock, 1) < 0) {
+ fprintf(stderr, "%s: listen(): %s\n", __FUNCTION__, strerror(socket_error()));
+ return -1;
+ }
+
+ return qemu_set_fd_handler(rct_sock, skin_rct_serve, NULL, NULL);
+}
+
+int skinning_init(char* skin_file, int portrait, int rctport)
+{
+ skin = skin_load_configuration(skin_file, portrait);
+
+ if (skin) {
+ if (skin->rotation == on && skin->keyboard.image &&
+ skin->keyboard.keys &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ skin_position_items(1);
+ }
+ if (rctport) {
+ skin_rct_initialize(rctport);
+ }
+ }
+ return (skin == NULL);
+}
+
+static void skin_host_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ //printf("skin_host_update()\n");
+ // We probably initiated this
+}
+
+static void skin_host_setdata(DisplayState *ds)
+{
+ //printf("skin_host_setdata\n");
+}
+
+static void skin_host_resize(DisplayState *ds)
+{
+ if (!is_graphic_console()) return;
+ if (startup) {
+ int width = 0, height = 0;
+ dpy_getresolution(ds, &width, &height);
+ //printf("%s, dpy_getresolution: width=%d, height=%d, skin->width=%d, skin->height=%d\n", __FUNCTION__, width, height, skin->width, skin->height);
+ if (width != 0 && height != 0) {
+ startup = 0;
+#if 0
+ if (skin->width >= width ||
+ skin->height >= height ) {
+ // Determine zoom level
+ while( (skin->width * zoom_factor / 100 >= width ||
+ skin->height * zoom_factor / 100 >= height) &&
+ zoom_factor > ZOOM_MIN_FACTOR)
+ zoom_factor -= ZOOM_STEP;
+ skin_handle_zooming();
+ }
+#endif
+ }
+ }
+ SkinArea area = { 0, 0, ds_get_width(skin->ds), ds_get_height(skin->ds) };
+ skin_draw_skin(&area);
+ // Likely we got a new buffer, update the emulated display buffer
+ if (skin->es && skin->es->ds) {
+ skin->es->ds->surface = qemu_resize_displaysurface(skin->es->ds,
+ skin->es->width, skin->es->height);
+ }
+ // Redraw the emulated screen on top
+ vga_hw_invalidate();
+ vga_hw_update();
+
+ dpy_update(skin->ds, 0, 0, ds_get_width(skin->ds), ds_get_height(skin->ds));
+}
+
+static void skin_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ // Updates done by emulated screen need to be converted to our display
+ int xd = x, yd = y, wd = w, hd = h;
+ if (skin->rotation == off) {
+ // Check if the drawing will fit the screen
+ if (ds_get_width(skin->ds) >= (w + (x + skin->es->posx)) &&
+ ds_get_height(skin->ds) >= (h + (y + skin->es->posy)) ) {
+ xd += skin->es->posx;
+ yd += skin->es->posy;
+ }
+ }
+ else {
+ skin_rotate_buffer(skin, ds, x, y, w, h);
+ xd = skin->es->posx + skin->es->height - (y + h - 1);
+ yd = skin->es->posy + x;
+ wd = h;
+ hd = w;
+ }
+ // Check if we have an overlapping tooltip
+ if (skin->tooltip.image) {
+ struct SkinArea clip = { xd, yd, wd, hd };
+ if (skin_overlaps(skin->tooltip.image, &clip)) {
+ SkinArea drawclip = skin_cliparea(skin->tooltip.image, &clip);
+ skin_draw_tooltip(&drawclip);
+ }
+ }
+ // Update the correct part
+ dpy_update(skin->ds, xd, yd, wd, hd);
+}
+
+static void skin_setdata(DisplayState *ds)
+{
+ //printf("skin_setdata()\n");
+ //if (skin->es && skin->es->ds)
+ // dpy_setdata(skin->es->ds);
+ if (!es_ds) es_ds = ds;
+ dpy_setdata(skin->ds);
+}
+
+static void skin_resize(DisplayState *ds)
+{
+ // Emulated display has resized
+ //printf("skin_resize()\n");
+ // Resize our display also then...
+ //qemu_console_resize(skin->ds, skin->width, skin->height);
+ skin_setdata(ds);
+}
+
+static void skin_refresh(DisplayState *ds)
+{
+ //printf("skin_refresh()\n");
+}
+
+static DisplaySurface* skin_create_displaysurface(int width, int height)
+{
+ //printf(">> skin_create_displaysurface(%d,%d)\n", width, height);
+ // We need a host surface to do this
+ if (!skin) return NULL;
+ DisplaySurface *surface =
+ (DisplaySurface*)qemu_mallocz(sizeof(DisplaySurface));
+ surface->width = width;
+ surface->height = height;
+ surface->linesize = ds_get_linesize(skin->ds);
+ surface->pf = skin->ds->surface->pf;
+ if (skin->rotation == off) {
+ // No rotation, draw directly to display buffer
+ surface->data = ds_get_data(skin->ds) +
+ skin->es->posy * ds_get_linesize(skin->ds) +
+ skin->es->posx * ds_get_bytes_per_pixel(skin->ds);
+ }
+ else {
+ surface->linesize = ds_get_bytes_per_pixel(skin->ds) * surface->width;
+ // Rotation is done in skinning source with skin_rotate_buffer
+ surface->data = qemu_malloc(height * surface->linesize);
+ // Mark data is allocated here
+ surface->flags |= QEMU_ALLOCATED_FLAG;
+ }
+ return surface;
+}
+
+static void skin_free_displaysurface(DisplaySurface *surface)
+{
+ //printf("skin_free_displaysurface\n");
+ if (surface == NULL)
+ return;
+
+ if (surface->flags & QEMU_ALLOCATED_FLAG)
+ qemu_free(surface->data);
+ qemu_free(surface);
+}
+
+static DisplaySurface* skin_resize_displaysurface(DisplaySurface *surface, int width, int height)
+{
+ //printf("skin_resize_displaysurface, width=%d, height=%d\n", width, height);
+ skin_free_displaysurface(surface);
+ return skin_create_displaysurface(width, height);
+}
+
+int is_skin_available(void);
+int is_skin_available(void)
+{
+ return (skin != NULL);
+}
+
+static void skin_handle_zooming(void)
+{
+ //printf("skin_handle_zooming, zoom_factor=%d%%\n", zoom_factor);
+
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ dpy_enablezoom(skin->ds, skin->keyboard.screenwidth * zoom_factor / 100,
+ skin->keyboard.screenheight * zoom_factor / 100);
+ }
+ else {
+ // No keyboard needs to be drawn
+ dpy_enablezoom(skin->ds, skin->width * zoom_factor / 100,
+ skin->height * zoom_factor / 100);
+ }
+}
+
+static void skin_show_zooming_level(int zoom_level, int posx)
+{
+ // Create the correct text for the zooming level
+ SkinTooltip* tooltip = &skin->tooltip;
+ char text[20];
+ sprintf(text, "Zooming to %d%%", zoom_level);
+ SkinImage *image = skin_image_createtext(skin, text);
+ if (image) {
+ // Everything set, store the image and have it drawn
+ tooltip->image = image;
+ image->posx = posx - image->width - ZOOM_INDICATOR_POS;
+ image->posy = ZOOM_INDICATOR_POS;
+ struct SkinArea clip = { image->posx, image->posy,
+ image->width, image->height };
+ // Make a "dummy" timer
+ if (!skin->tooltip.timer) {
+ skin->tooltip.timer = qemu_new_timer_ns(rt_clock,
+ skin_cleartooltip,
+ NULL);
+ }
+ // Prevent zoom button's own tooltip appearing. Set long expiration time.
+ qemu_mod_timer(skin->tooltip.timer, qemu_get_clock_ns(rt_clock) + 600000000); // 1000 min
+ // Draw the zooming level indicator
+ skin_draw_tooltip(&clip);
+ dpy_update(skin->ds, image->posx, image->posy,
+ image->width, image->height);
+ }
+}
+
+static void skin_key_handler(void *opaque, int keycode)
+{
+ // Check if someone triggered one of our buttons
+ int keyvalue = keycode & 0x7F;
+ int released = keycode & 0x80;
+ SkinButton* button = skin->buttons;
+ while (button) {
+ if ((button->key.keycode & 0x7F) == keyvalue) {
+ int state = skin_button_handle_key(&button->key, !released);
+ if (skin_draw_button(skin, button, state)) {
+ dpy_update(skin->ds, button->image.posx, button->image.posy,
+ button->image.width, button->image.height);
+ }
+ // Check if the keyboard needs to be udpated
+ if (button == skin->keyboard.button && released) {
+ if (skin->keyboard.animated) {
+ keyboard_animation_phase = 0;
+ skin_update_keyboard(NULL);
+ }
+ else {
+ // Changing the size, automatically triggers a redraw
+ if (button->key.state == ESkinBtn_Active ||
+ button->key.state == ESkinBtn_ActiveHighlighted) {
+ original_qemu_console_resize(skin->ds, skin->keyboard.screenwidth,
+ skin->keyboard.screenheight);
+ SkinArea area = { skin->keyboard.image->posx,
+ skin->keyboard.image->posy,
+ skin->keyboard.image->width,
+ skin->keyboard.image->height };
+ skin_handle_zooming();
+ skin_draw_image(skin,
+ skin->keyboard.image,
+ &area);
+ }
+ else {
+ original_qemu_console_resize(skin->ds, skin->width, skin->height);
+ skin_handle_zooming();
+ }
+ }
+ }
+ // Check if rotation button is pressed (test-code)
+ if (button->key.keycode == 67 && released) {
+ if (skin->rotation_req == on) skin->rotation_req = off;
+ else skin->rotation_req = on;
+ }
+
+ // Zoom buttons
+ if (button->key.keycode == 87 && released) { // F11
+ // Zooming in, zoom_factor in %
+ if (zoom_factor < ZOOM_MAX_FACTOR) {
+ zoom_factor += ZOOM_STEP;
+ no_keyboard_anim = 1;
+ skin_handle_zooming();
+ skin_show_zooming_level(zoom_factor, button->image.posx);
+ }
+ }
+ if (button->key.keycode == 88 && released) { // F12
+ // Zooming out, zoom_factor in %
+ if (zoom_factor > ZOOM_MIN_FACTOR) {
+ zoom_factor -= ZOOM_STEP;
+ no_keyboard_anim = 1;
+ skin_handle_zooming();
+ skin_show_zooming_level(zoom_factor, button->image.posx);
+ }
+ }
+ }
+ button = button->next;
+ }
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ SkinKey* key = skin->keyboard.keys;
+ while (key) {
+ if ((key->keycode & 0x7F) == keyvalue) {
+ int state = skin_button_handle_key(key, !released);
+ if (skin_highlight_key(skin, key, state)) {
+ dpy_update(skin->ds, key->posx, key->posy,
+ key->width, key->height);
+ }
+ }
+ key = key->next;
+ }
+ }
+
+ if (skin->mouse_event == off) skin_handle_rotation();
+}
+
+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)
+{
+ DisplayState *ds;
+ //printf(">> graphic_console_init\n");
+ // Host display for skin, register it to the qemu system
+ ds = qemu_graphic_console_init(update, invalidate, screen_dump, text_update, opaque);
+
+ // If skinning is enabled, we create a host display, otherwise return ds
+ if (is_skin_available() && ds) {
+ // We need to know when we are resized
+ DisplayChangeListener *dcl;
+ dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+ dcl->dpy_update = skin_host_update;
+ dcl->dpy_setdata = skin_host_setdata;
+ dcl->dpy_resize = skin_host_resize;
+ dcl->dpy_refresh = NULL;
+ register_displaychangelistener(ds, dcl);
+ // Store the DisplayState to the SkinScreen information
+ skin->ds = ds;
+ // Resize the display to our own size
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.defaultstate == on ||
+ skin->keyboard.button->key.defaultstate == undefined)) {
+ original_qemu_console_resize(skin->ds, skin->keyboard.screenwidth,
+ skin->keyboard.screenheight);
+ } else {
+ //printf("skin->ds=%x, skin->width=%d, skin->height=%d\n", skin->ds, skin->width, skin->height);
+ original_qemu_console_resize(skin->ds, skin->width, skin->height);
+ }
+
+ // Create a new DisplayState, this is the emulated display, we keep it to ourselves
+ ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
+ // Also we want control over the emulated display ourselves
+ DisplayAllocator *da = qemu_mallocz(sizeof(DisplayAllocator));
+ da->create_displaysurface = skin_create_displaysurface;
+ da->resize_displaysurface = skin_resize_displaysurface;
+ da->free_displaysurface = skin_free_displaysurface;
+ ds->allocator = da;
+ //printf("%s, es->width=%d, es->height=%d\n", __FUNCTION__, skin->es->width, skin->es->height);
+ ds->surface = skin_create_displaysurface(skin->es->width, skin->es->height);
+ // Client DisplayState, which is the actual screen we are emulating
+ skin->es->ds = ds;
+
+ //Reserve es posx & posy for SDL blit
+ es_posx = skin->es->posx;
+ es_posy = skin->es->posy;
+ // We want all events on our emulated screen
+ DisplayChangeListener *skindcl = qemu_mallocz(sizeof(DisplayChangeListener));
+ skindcl->dpy_update = skin_update;
+ skindcl->dpy_setdata = skin_setdata;
+ skindcl->dpy_resize = skin_resize;
+ skindcl->dpy_refresh = skin_refresh;
+ register_displaychangelistener(ds, skindcl);
+
+ // We are also interested in keyboard events to match possible switches
+ qemu_add_kbd_event_handler(skin_key_handler, NULL);
+ //printf("graphic_console_init >>\n");
+ }
+ return ds;
+}
+
+void skin_toggle_full_screen(DisplayState *ds)
+{
+ skin_update_keyboard(NULL);
+ skin_handle_zooming();
+}
+
+void qemu_console_resize(DisplayState *ds, int width, int height)
+{
+ //printf(">> skinning: qemu_console_resize, width=%d, height=%d\n", width, height);
+ if (is_skin_available() && skin->ds && skin->es && skin->es->ds == ds) {
+ int neww = skin->width;
+ int newh = skin->height;
+ if (skin->keyboard.button &&
+ (skin->keyboard.button->key.state == ESkinBtn_Active ||
+ skin->keyboard.button->key.state == ESkinBtn_ActiveHighlighted)) {
+ neww = skin->keyboard.screenwidth;
+ newh = skin->keyboard.screenheight;
+ }
+ // Record the required width / height
+ skin->es->width = width;
+ skin->es->height = height;
+ if (ds_get_width(skin->ds) == neww &&
+ ds_get_height(skin->ds) == newh ) {
+ // Just change the emulated screen size
+ skin->es->ds->surface = qemu_resize_displaysurface(skin->es->ds,
+ skin->es->width, skin->es->height);
+ }
+ else {
+ original_qemu_console_resize(skin->ds, neww, newh);
+ skin_handle_zooming();
+ }
+ }
+ else
+ original_qemu_console_resize(ds, width, height);
+ //printf("skinning: qemu_console_resize >>\n");
+}
+
+
+QEMUPutMouseEntry *original_qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+ void *opaque, int absolute,
+ const char *name);
+
+QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+ void *opaque, int absolute,
+ const char *name)
+{
+ if (skin) {
+ // If a skin is applied, keep reference to the calling one
+ // but don't register that to qemu
+ QEMUPutMouseEntry *other = qemu_mallocz(sizeof(*other));
+ other->qemu_put_mouse_event = func;
+ other->qemu_put_mouse_event_opaque = opaque;
+ other->qemu_put_mouse_event_absolute = absolute;
+ other->qemu_put_mouse_event_name = qemu_strdup(name);
+ original_qemu_add_mouse_event_handler(skin_mouse_event, other, 1, "Skin mouse handling");
+ return other;
+ }
+ return original_qemu_add_mouse_event_handler(func, opaque, absolute, name);
+}
diff --git a/ui/sdl.c b/ui/sdl.c
index dc5c3a1bc..09634b044 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -63,10 +63,32 @@ static SDL_PixelFormat host_format;
static int scaling_active = 0;
static Notifier mouse_mode_notifier;
+#ifdef CONFIG_SKINNING
+void skin_toggle_full_screen(DisplayState *ds);
+static int host_display_width;
+static int host_display_height;
+extern DisplayState *es_ds;
+extern int es_posx;
+extern int es_posy;
+#endif
+
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
{
// printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
- SDL_Rect rec;
+ SDL_Rect rec, rec_src;
+
+#ifdef CONFIG_SKINNING
+ rec_src.x = x - es_posx;
+ rec_src.y = y - es_posy;
+ rec_src.w = w;
+ rec_src.h = h;
+#else
+ rec_src.x = x;
+ rec_src.y = y;
+ rec_src.w = w;
+ rec_src.h = h;
+#endif
+
rec.x = x;
rec.y = y;
rec.w = w;
@@ -87,6 +109,12 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
static void sdl_setdata(DisplayState *ds)
{
+
+#ifdef CONFIG_SKINNING
+ if (es_ds)
+ ds = es_ds;
+#endif
+
if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
@@ -133,6 +161,32 @@ static void sdl_resize(DisplayState *ds)
}
}
+#ifdef CONFIG_SKINNING
+static void sdl_scale_window(DisplayState *ds, int width, int height)
+{
+ // Alter window size by zooming skin images in or out
+ if (real_screen) {
+ int bpp = real_screen->format->BitsPerPixel;
+ if (bpp != 16 && bpp != 32)
+ bpp = 32;
+ do_sdl_resize(width, height, bpp);
+ scaling_active = 1;
+ if (!is_buffer_shared(ds->surface)) {
+ ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
+ dpy_resize(ds);
+ }
+ vga_hw_invalidate();
+ vga_hw_update();
+ }
+}
+
+static void sdl_getresolution(int *width, int *height)
+{
+ if (width) *width = host_display_width;
+ if (height) *height = host_display_height;
+}
+#endif
+
static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
{
PixelFormat qemu_pf;
@@ -541,6 +595,9 @@ static void toggle_full_screen(DisplayState *ds)
}
vga_hw_invalidate();
vga_hw_update();
+#ifdef CONFIG_SKINNING
+ skin_toggle_full_screen(ds);
+#endif
}
static void sdl_refresh(DisplayState *ds)
@@ -845,6 +902,11 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
vi = SDL_GetVideoInfo();
host_format = *(vi->vfmt);
+#ifdef CONFIG_SKINNING
+ host_display_width = vi->current_w;
+ host_display_height = vi->current_h;
+#endif
+
/* Load a 32x32x4 image. White pixels are transparent. */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
if (filename) {
@@ -863,6 +925,10 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
dcl->dpy_refresh = sdl_refresh;
dcl->dpy_setdata = sdl_setdata;
dcl->dpy_fill = sdl_fill;
+#ifdef CONFIG_SKINNING
+ dcl->dpy_enablezoom = sdl_scale_window;
+ dcl->dpy_getresolution = sdl_getresolution;
+#endif
ds->mouse_set = sdl_mouse_warp;
ds->cursor_define = sdl_mouse_define;
register_displaychangelistener(ds, dcl);
diff --git a/vl.c b/vl.c
index de232b75e..eeab066b0 100644
--- a/vl.c
+++ b/vl.c
@@ -215,7 +215,7 @@ int fd_bootchk = 1;
int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
-int graphic_rotate = 0;
+int graphic_rotate = 1;
uint8_t irq0override = 1;
const char *watchdog;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
@@ -251,6 +251,12 @@ uint8_t qemu_uuid[16];
static QEMUBootSetHandler *boot_set_handler;
static void *boot_set_opaque;
+#ifdef CONFIG_SKINNING
+int skinning_init(char* skin_file, int portrait, int rctport);
+const char *skin_file = NULL;
+int rctport = 0;
+#endif /* CONFIG_SKINNING */
+
static NotifierList exit_notifiers =
NOTIFIER_LIST_INITIALIZER(exit_notifiers);
@@ -2197,6 +2203,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_portrait:
graphic_rotate = 1;
break;
+ case QEMU_OPTION_landscape:
+ graphic_rotate = 0;
+ break;
case QEMU_OPTION_kernel:
kernel_filename = optarg;
break;
@@ -2551,6 +2560,21 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_full_screen:
full_screen = 1;
break;
+#ifdef CONFIG_SKINNING
+ case QEMU_OPTION_skin:
+ skin_file = optarg;
+ printf("skin_file: %s\n", skin_file);
+ break;
+ case QEMU_OPTION_rctport:
+ {
+ const char *p;
+ p = optarg;
+ rctport = strtol(p, (char **)&p, 10);
+ if (p == optarg)
+ printf("Bad argument to rctport\n");
+ break;
+ }
+#endif
#ifdef CONFIG_SDL
case QEMU_OPTION_no_frame:
no_frame = 1;
@@ -2817,6 +2841,13 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "warning: unable to initialize simple trace backend\n");
}
+#ifdef CONFIG_SKINNING
+ if( skin_file && skinning_init((char*)skin_file, graphic_rotate, rctport) ) {
+ fprintf( stderr, "Skin could not be initialised\n");
+ exit(1);
+ }
+#endif
+
/* If no data_dir is specified then try to find it relative to the
executable path. */
if (!data_dir) {