qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] opengl rendering in the sdl window


From: Anthony Liguori
Subject: Re: [Qemu-devel] [PATCH] opengl rendering in the sdl window
Date: Sun, 07 Sep 2008 19:12:34 -0500
User-agent: Thunderbird 2.0.0.16 (X11/20080723)

Daniel P. Berrange wrote:
On Sat, Sep 06, 2008 at 10:07:10PM -0500, Anthony Liguori wrote:
Daniel P. Berrange wrote:
On Wed, Sep 03, 2008 at 10:00:31PM -0500, Anthony Liguori wrote:
Actually I'm not so sure this was a good idea in the end. I'm seriously
considering re-writing the GTK-VNC stuff to use Cairo, which in turn
can use 2-d hardware acceleration primitives - it really doesn't need
the full 3-d acceleration stack just for scaling.
I tried to originally write the GTK-VNC scaling stuff in Cairo. Could not get it to perform well at all. I'd be really interested if you had better luck with it.

I've just posted patches to the GTK-VNC devel list demonstrating use of
Cairo for all rendering. I can't notice any serious drop in performance
when enabling scaling with Cairo. If you confirm my tests, it'd be worth
evaluating Cairo as an alternative to OpenGL in QEMU too.

Here's the beginning of a GTK front-end in case someone wants to try adapting the Cairo patches to QEMU.

Regards,

Anthony Liguori

Regards,
Daniel

diff --git a/Makefile b/Makefile
index 0472e16..3927c40 100644
--- a/Makefile
+++ b/Makefile
@@ -124,6 +124,9 @@ ifdef CONFIG_CURSES
 OBJS+=curses.o
 endif
 OBJS+=vnc.o d3des.o
+ifdef CONFIG_GTK
+OBJS+=gtk.o
+endif
 
 ifdef CONFIG_COCOA
 OBJS+=cocoa.o
@@ -145,6 +148,9 @@ cocoa.o: cocoa.m
 sdl.o: sdl.c keymaps.c sdl_keysym.h
        $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $<
 
+gtk.o: gtk.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(GTK_CFLAGS) -c -o $@ $<
+
 vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
        $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $<
 
diff --git a/Makefile.target b/Makefile.target
index 42162c3..572b44b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -515,6 +515,10 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
 LIBS += $(CONFIG_VNC_TLS_LIBS)
 endif
 
+ifdef CONFIG_GTK
+LIBS += $(GTK_LIBS)
+endif
+
 # SCSI layer
 OBJS+= lsi53c895a.o esp.o
 
diff --git a/configure b/configure
index 0a3b7c9..d0e63fa 100755
--- a/configure
+++ b/configure
@@ -90,6 +90,7 @@ EXESUF=""
 gdbstub="yes"
 slirp="yes"
 vde="yes"
+gtk="yes"
 fmod_lib=""
 fmod_inc=""
 vnc_tls="yes"
@@ -283,6 +284,8 @@ for opt do
   ;;
   --disable-vde) vde="no"
   ;;
+  --disable-gtk) gtk="no"
+  ;;
   --disable-kqemu) kqemu="no"
   ;;
   --disable-brlapi) brlapi="no"
@@ -436,6 +439,7 @@ echo "  --fmod-inc               path to FMOD includes"
 echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
 echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7, v8, 
v8plus, v8plusa, v9"
 echo "  --disable-vde            disable support for vde network"
+echo "  --disable-gtk            disable support for GTK"
 echo ""
 echo "NOTE: The object files are built at the place where configure is 
launched"
 exit 1
@@ -758,6 +762,20 @@ EOF
     fi
 fi
 
+if test "$gtk" = "yes" ; then
+    cat > $TMPC <<EOF
+#include <gtk/gtk.h>
+int main(int argc, char **argv) { gtk_init(&argc, &argv); return 0; }
+EOF
+    gtk_cflags=`pkg-config --cflags gtk+-2.0`
+    gtk_libs=`pkg-config --libs gtk+-2.0`
+    if $cc $ARCH_CFLAGS -o $TMPE $TMPC $gtk_cflags $gtk_libs ; then
+       :
+    else
+       gtk="no"
+    fi
+fi
+
 ##########################################
 # Sound support libraries probe
 
@@ -923,6 +941,7 @@ echo "Documentation     $build_docs"
 echo "uname -r          $uname_release"
 echo "NPTL support      $nptl"
 echo "vde support       $vde"
+echo "gtk support       $gtk"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1097,6 +1116,12 @@ if test "$vde" = "yes" ; then
   echo "#define CONFIG_VDE 1" >> $config_h
   echo "VDE_LIBS=-lvdeplug" >> $config_mak
 fi
+if test "$gtk" = "yes" ; then
+  echo "CONFIG_GTK=yes" >> $config_mak
+  echo "#define CONFIG_GTK 1" >> $config_h
+  echo "GTK_CFLAGS=$gtk_cflags" >> $config_mak
+  echo "GTK_LIBS=$gtk_libs" >> $config_mak
+fi
 for card in $audio_card_list; do
     def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
     echo "$def=yes" >> $config_mak
diff --git a/console.h b/console.h
index e852dd1..92de255 100644
--- a/console.h
+++ b/console.h
@@ -140,6 +140,11 @@ void qemu_console_resize(QEMUConsole *console, int width, 
int height);
 /* sdl.c */
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 
+/* gtk.c */
+void gtk_display_init(DisplayState *ds, int *argc, char ***argv);
+
+void gtk_display_main_loop(DisplayState *ds, int (*func)(void));
+
 /* cocoa.m */
 void cocoa_display_init(DisplayState *ds, int full_screen);
 
diff --git a/gdk_keysym.h b/gdk_keysym.h
new file mode 100644
index 0000000..2dce2ad
--- /dev/null
+++ b/gdk_keysym.h
@@ -0,0 +1,280 @@
+typedef struct {
+       const char* name;
+       int keysym;
+} name2keysym_t;
+static name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                GDK_space},
+    { "exclam",               GDK_exclam},
+    { "quotedbl",             GDK_quotedbl},
+    { "numbersign",           GDK_numbersign},
+    { "dollar",               GDK_dollar},
+    { "percent",              GDK_percent},
+    { "ampersand",            GDK_ampersand},
+    { "apostrophe",           GDK_apostrophe},
+    { "parenleft",            GDK_parenleft},
+    { "parenright",           GDK_parenright},
+    { "asterisk",             GDK_asterisk},
+    { "plus",                 GDK_plus},
+    { "comma",                GDK_comma},
+    { "minus",                GDK_minus},
+    { "period",               GDK_period},
+    { "slash",                GDK_slash},
+    { "0",                    GDK_0},
+    { "1",                    GDK_1},
+    { "2",                    GDK_2},
+    { "3",                    GDK_3},
+    { "4",                    GDK_4},
+    { "5",                    GDK_5},
+    { "6",                    GDK_6},
+    { "7",                    GDK_7},
+    { "8",                    GDK_8},
+    { "9",                    GDK_9},
+    { "colon",                GDK_colon},
+    { "semicolon",            GDK_semicolon},
+    { "less",                 GDK_less},
+    { "equal",                GDK_equal},
+    { "greater",              GDK_greater},
+    { "question",             GDK_question},
+    { "at",                   GDK_at},
+    { "A",                    GDK_A},
+    { "B",                    GDK_B},
+    { "C",                    GDK_C},
+    { "D",                    GDK_D},
+    { "E",                    GDK_E},
+    { "F",                    GDK_F},
+    { "G",                    GDK_G},
+    { "H",                    GDK_H},
+    { "I",                    GDK_I},
+    { "J",                    GDK_J},
+    { "K",                    GDK_K},
+    { "L",                    GDK_L},
+    { "M",                    GDK_M},
+    { "N",                    GDK_N},
+    { "O",                    GDK_O},
+    { "P",                    GDK_P},
+    { "Q",                    GDK_Q},
+    { "R",                    GDK_R},
+    { "S",                    GDK_S},
+    { "T",                    GDK_T},
+    { "U",                    GDK_U},
+    { "V",                    GDK_V},
+    { "W",                    GDK_W},
+    { "X",                    GDK_X},
+    { "Y",                    GDK_Y},
+    { "Z",                    GDK_Z},
+    { "bracketleft",          GDK_bracketleft},
+    { "backslash",            GDK_backslash},
+    { "bracketright",         GDK_bracketright},
+    { "asciicircum",          GDK_asciicircum},
+    { "underscore",           GDK_underscore},
+    { "grave",                GDK_grave},
+    { "a",                    GDK_a},
+    { "b",                    GDK_b},
+    { "c",                    GDK_c},
+    { "d",                    GDK_d},
+    { "e",                    GDK_e},
+    { "f",                    GDK_f},
+    { "g",                    GDK_g},
+    { "h",                    GDK_h},
+    { "i",                    GDK_i},
+    { "j",                    GDK_j},
+    { "k",                    GDK_k},
+    { "l",                    GDK_l},
+    { "m",                    GDK_m},
+    { "n",                    GDK_n},
+    { "o",                    GDK_o},
+    { "p",                    GDK_p},
+    { "q",                    GDK_q},
+    { "r",                    GDK_r},
+    { "s",                    GDK_s},
+    { "t",                    GDK_t},
+    { "u",                    GDK_u},
+    { "v",                    GDK_v},
+    { "w",                    GDK_w},
+    { "x",                    GDK_x},
+    { "y",                    GDK_y},
+    { "z",                    GDK_z},
+    { "braceleft",            GDK_braceleft},
+    { "bar",                  GDK_bar},
+    { "braceright",           GDK_braceright},
+    { "asciitilde",           GDK_asciitilde},
+
+/* latin 1 extensions */
+{ "nobreakspace",         GDK_nobreakspace},
+{ "exclamdown",           GDK_exclamdown},
+{ "cent",                GDK_cent},
+{ "sterling",             GDK_sterling},
+{ "currency",             GDK_currency},
+{ "yen",                  GDK_yen},
+{ "brokenbar",            GDK_brokenbar},
+{ "section",              GDK_section},
+{ "diaeresis",            GDK_diaeresis},
+{ "copyright",            GDK_copyright},
+{ "ordfeminine",          GDK_ordfeminine},
+{ "guillemotleft",        GDK_guillemotleft},
+{ "notsign",              GDK_notsign},
+{ "hyphen",               GDK_hyphen},
+{ "registered",           GDK_registered},
+{ "macron",               GDK_macron},
+{ "degree",               GDK_degree},
+{ "plusminus",            GDK_plusminus},
+{ "twosuperior",          GDK_twosuperior},
+{ "threesuperior",        GDK_threesuperior},
+{ "acute",                GDK_acute},
+{ "mu",                   GDK_mu},
+{ "paragraph",            GDK_paragraph},
+{ "periodcentered",       GDK_periodcentered},
+{ "cedilla",              GDK_cedilla},
+{ "onesuperior",          GDK_onesuperior},
+{ "masculine",            GDK_masculine},
+{ "guillemotright",       GDK_guillemotright},
+{ "onequarter",           GDK_onequarter},
+{ "onehalf",              GDK_onehalf},
+{ "threequarters",        GDK_threequarters},
+{ "questiondown",         GDK_questiondown},
+{ "Agrave",               GDK_Agrave},
+{ "Aacute",               GDK_Aacute},
+{ "Acircumflex",          GDK_Acircumflex},
+{ "Atilde",               GDK_Atilde},
+{ "Adiaeresis",           GDK_Adiaeresis},
+{ "Aring",                GDK_Aring},
+{ "AE",                   GDK_AE},
+{ "Ccedilla",             GDK_Ccedilla},
+{ "Egrave",               GDK_Egrave},
+{ "Eacute",               GDK_Eacute},
+{ "Ecircumflex",          GDK_Ecircumflex},
+{ "Ediaeresis",           GDK_Ediaeresis},
+{ "Igrave",               GDK_Igrave},
+{ "Iacute",               GDK_Iacute},
+{ "Icircumflex",          GDK_Icircumflex},
+{ "Idiaeresis",           GDK_Idiaeresis},
+{ "ETH",                  GDK_ETH},
+{ "Eth",                  GDK_Eth},
+{ "Ntilde",               GDK_Ntilde},
+{ "Ograve",               GDK_Ograve},
+{ "Oacute",               GDK_Oacute},
+{ "Ocircumflex",          GDK_Ocircumflex},
+{ "Otilde",               GDK_Otilde},
+{ "Odiaeresis",           GDK_Odiaeresis},
+{ "multiply",             GDK_multiply},
+{ "Ooblique",             GDK_Ooblique},
+{ "Oslash",               GDK_Oslash},
+{ "Ugrave",               GDK_Ugrave},
+{ "Uacute",               GDK_Uacute},
+{ "Ucircumflex",          GDK_Ucircumflex},
+{ "Udiaeresis",           GDK_Udiaeresis},
+{ "Yacute",               GDK_Yacute},
+{ "THORN",                GDK_THORN},
+{ "Thorn",                GDK_Thorn},
+{ "ssharp",               GDK_ssharp},
+{ "agrave",               GDK_agrave},
+{ "aacute",               GDK_aacute},
+{ "acircumflex",          GDK_acircumflex},
+{ "atilde",               GDK_atilde},
+{ "adiaeresis",           GDK_adiaeresis},
+{ "aring",                GDK_aring},
+{ "ae",                   GDK_ae},
+{ "ccedilla",             GDK_ccedilla},
+{ "egrave",               GDK_egrave},
+{ "eacute",               GDK_eacute},
+{ "ecircumflex",          GDK_ecircumflex},
+{ "ediaeresis",           GDK_ediaeresis},
+{ "igrave",               GDK_igrave},
+{ "iacute",               GDK_iacute},
+{ "icircumflex",          GDK_icircumflex},
+{ "idiaeresis",           GDK_idiaeresis},
+{ "eth",                  GDK_eth},
+{ "ntilde",               GDK_ntilde},
+{ "ograve",               GDK_ograve},
+{ "oacute",               GDK_oacute},
+{ "ocircumflex",          GDK_ocircumflex},
+{ "otilde",               GDK_otilde},
+{ "odiaeresis",           GDK_odiaeresis},
+{ "division",             GDK_division},
+{ "oslash",               GDK_oslash},
+{ "ooblique",             GDK_ooblique},
+{ "ugrave",               GDK_ugrave},
+{ "uacute",               GDK_uacute},
+{ "ucircumflex",          GDK_ucircumflex},
+{ "udiaeresis",           GDK_udiaeresis},
+{ "yacute",               GDK_yacute},
+{ "thorn",                GDK_thorn},
+{ "ydiaeresis",           GDK_ydiaeresis},
+{"EuroSign", GDK_EuroSign},
+
+    /* modifiers */
+{"Control_L", GDK_Control_L},
+{"Control_R", GDK_Control_R},
+{"Alt_L", GDK_Alt_L},
+{"Alt_R", GDK_Alt_R},
+{"Caps_Lock", GDK_Caps_Lock},
+{"Meta_L", GDK_Meta_L},
+{"Meta_R", GDK_Meta_R},
+{"Shift_L", GDK_Shift_L},
+{"Shift_R", GDK_Shift_R},
+{"Super_L", GDK_Super_L},
+{"Super_R", GDK_Super_R},
+
+    /* special keys */
+{"BackSpace", GDK_BackSpace},
+{"Tab", GDK_Tab},
+{"Return", GDK_Return},
+{"Right", GDK_Right},
+{"Left", GDK_Left},
+{"Up", GDK_Up},
+{"Down", GDK_Down},
+{"Page_Down", GDK_Page_Down},
+{"Page_Up", GDK_Page_Up},
+{"Insert", GDK_Insert},
+{"Delete", GDK_Delete},
+{"Home", GDK_Home},
+{"End", GDK_End},
+{"Scroll_Lock", GDK_Scroll_Lock},
+{"F1", GDK_F1},
+{"F2", GDK_F2},
+{"F3", GDK_F3},
+{"F4", GDK_F4},
+{"F5", GDK_F5},
+{"F6", GDK_F6},
+{"F7", GDK_F7},
+{"F8", GDK_F8},
+{"F9", GDK_F9},
+{"F10", GDK_F10},
+{"F11", GDK_F11},
+{"F12", GDK_F12},
+{"F13", GDK_F13},
+{"F14", GDK_F14},
+{"F15", GDK_F15},
+{"Sys_Req", GDK_Sys_Req},
+{"KP_0", GDK_KP_0},
+{"KP_1", GDK_KP_1},
+{"KP_2", GDK_KP_2},
+{"KP_3", GDK_KP_3},
+{"KP_4", GDK_KP_4},
+{"KP_5", GDK_KP_5},
+{"KP_6", GDK_KP_6},
+{"KP_7", GDK_KP_7},
+{"KP_8", GDK_KP_8},
+{"KP_9", GDK_KP_9},
+{"KP_Add", GDK_KP_Add},
+{"KP_Decimal", GDK_KP_Decimal},
+{"KP_Divide", GDK_KP_Divide},
+{"KP_Enter", GDK_KP_Enter},
+{"KP_Equal", GDK_KP_Equal},
+{"KP_Multiply", GDK_KP_Multiply},
+{"KP_Subtract", GDK_KP_Subtract},
+{"help", GDK_Help},
+{"Menu", GDK_Menu},
+#if 0
+{"Power", GDK_Power},
+#endif
+{"Print", GDK_Print},
+{"Mode_switch", GDK_Mode_switch},
+{"Multi_Key", GDK_Multi_key},
+{"Num_Lock", GDK_Num_Lock},
+{"Pause", GDK_Pause},
+{"Escape", GDK_Escape},
+
+{0,0},
+};
diff --git a/gtk.c b/gtk.c
new file mode 100644
index 0000000..9d45bef
--- /dev/null
+++ b/gtk.c
@@ -0,0 +1,356 @@
+/*
+ * GTK Front-end support for QEMU
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+typedef struct GtkDisplayState
+{
+    DisplayState *ds;
+    GtkWidget *window;
+    GtkWidget *widget;
+    GdkImage *image;
+    GdkGC *gc;
+    gint mouse_x, mouse_y;
+    gint mouse_buttons;
+} GtkDisplayState;
+
+static void gtk_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    GtkDisplayState *s = ds->opaque;
+
+    /* Queuing the drawing area will cause an expose event to occur which is
+     * where we really draw the screen */
+    gtk_widget_queue_draw_area(s->widget, x, y, w, h);
+}
+
+static void gtk_dpy_resize(DisplayState *ds, int w, int h)
+{
+    GtkDisplayState *s = ds->opaque;
+    GdkVisual *visual;
+
+    /* Free old buffer if we have to */
+    if (s->image) {
+        g_object_unref(s->image);
+        s->image = NULL;
+    }
+    ds->data = NULL;
+
+    /* Initialize new buffer */
+    ds->width = w;
+    ds->height = h;
+
+    /* FIXME valid all DisplayState assumptions */
+    visual = gtk_widget_get_visual(s->widget);
+    s->image = gdk_image_new(GDK_IMAGE_FASTEST, visual, ds->width, ds->height);
+    ds->depth = s->image->bpp * 8;
+    ds->linesize = s->image->bpl;
+    if (s->image->byte_order == GDK_MSB_FIRST)
+        ds->bgr = 1;
+    else
+        ds->bgr = 0;
+    ds->data = s->image->mem;
+
+    /* Set the size of the widget being used to display the VGA screen. */
+    gtk_widget_set_size_request(s->widget, ds->width, ds->height);
+}
+
+static void update_caption(GtkDisplayState *s)
+{
+    char buf[1024];
+    const char *status = "";
+
+    if (!vm_running)
+        status = " [Stopped]";
+#if 0
+    else if (gui_grab)
+        status = " - Press Ctrl-Alt to exit grab";
+#endif
+
+    if (qemu_name)
+        snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
+    else
+        snprintf(buf, sizeof(buf), "QEMU%s", status);
+
+    gtk_window_set_title(GTK_WINDOW(s->window), buf);
+}
+
+static void gtk_dpy_refresh(DisplayState *ds)
+{
+    GtkDisplayState *s = ds->opaque;
+    static int last_vm_running = -1;
+
+    if (last_vm_running != vm_running) {
+        last_vm_running = vm_running;
+        update_caption(s);
+    }
+
+    vga_hw_update();
+
+    while (gtk_events_pending()) {
+        if (gtk_main_iteration()) {
+            /* GTK main loop has been exited */
+            qemu_system_shutdown_request();
+            vm_start();
+            break;
+        }
+    }
+}
+
+static gboolean gtk_dpy_expose(GtkWidget *widget, GdkEventExpose *expose,
+                               gpointer opaque)
+{
+    GtkDisplayState *s = opaque;
+    gint x, y, w, h;
+
+    /* The widget may be exposed before we are ready to go.  Be defensive */
+    if (widget->window == NULL || s->image == NULL)
+        return FALSE;
+
+    /* Create a graphics context if we need to */
+    if (s->gc == NULL)
+        s->gc = gdk_gc_new(widget->window);
+
+    /* Clip expose area to DisplayState */
+    x = MIN(expose->area.x, s->ds->width);
+    y = MIN(expose->area.y, s->ds->height);
+    w = MIN(expose->area.x + expose->area.width, s->ds->width);
+    h = MIN(expose->area.y + expose->area.height, s->ds->height);
+    w -= x;
+    h -= y;
+
+    /* Draw screen */
+    gdk_draw_image(widget->window, s->gc, s->image, x, y, x, y, w, h);
+
+    return TRUE;
+}
+
+#include "gdk_keysym.h"
+#include "keymaps.c"
+
+static kbd_layout_t *kbd_layout;
+
+static uint8_t gtk_keyevent_to_keycode_generic(GdkEventKey *key)
+{
+    return keysym2scancode(kbd_layout, key->keyval);
+}
+
+static uint8_t gtk_keyevent_to_keycode(GdkEventKey *key)
+{
+    int keycode;
+
+    keycode = key->hardware_keycode;
+
+    if (keycode < 9) {
+        keycode = 0;
+    } else if (keycode < 97) {
+        keycode -= 8;
+    } else if (keycode < 212) {
+        keycode = _translate_keycode(keycode - 97);
+    } else {
+        keycode = 0;
+    }
+
+    return keycode;
+}
+
+static gboolean gtk_dpy_key(GtkWidget *widget, GdkEventKey *key,
+                            gpointer opaque)
+{
+    int keycode, v;
+
+    if (key->keyval == GDK_Pause) {
+        v = 0;
+        if (key->type == GDK_KEY_PRESS)
+            v |= 0x80;
+        kbd_put_keycode(0xe1);
+        kbd_put_keycode(0x1d | v);
+        kbd_put_keycode(0x45 | v);
+        return TRUE;
+    }
+
+    if (kbd_layout)
+        keycode = gtk_keyevent_to_keycode_generic(key);
+    else
+        keycode = gtk_keyevent_to_keycode(key);
+
+    if (keycode & 0x80)
+        kbd_put_keycode(0xe0);
+    if (key->type == GDK_KEY_RELEASE)
+        kbd_put_keycode(keycode | 0x80);
+    else
+        kbd_put_keycode(keycode & 0x7f);
+
+    return TRUE;
+}
+
+static gboolean gtk_dpy_motion(GtkWidget *widget, GdkEventMotion *motion,
+                               gpointer opaque)
+{
+    GtkDisplayState *s = opaque;
+    int dx, dy;
+
+    if (kbd_mouse_is_absolute()) {
+        dx = (gint)motion->x * 0x7FFF / (s->ds->width - 1);
+        dy = (gint)motion->y * 0x7FFF / (s->ds->height - 1);
+    } else {
+        dx = (gint)motion->x - s->mouse_x;
+        dy = (gint)motion->y - s->mouse_y;
+    }
+
+    s->mouse_x = (gint)motion->x;
+    s->mouse_y = (gint)motion->y;
+
+    kbd_mouse_event(dx, dy, 0, s->mouse_buttons);
+
+    return TRUE;
+}
+
+static gboolean gtk_dpy_button(GtkWidget *widget, GdkEventButton *button,
+                               gpointer opaque)
+{
+    GtkDisplayState *s = opaque;
+    gint mask;
+
+    mask = 0;
+    if (button->button == 1)
+        mask |= MOUSE_EVENT_LBUTTON;
+    else if (button->button == 2)
+        mask |= MOUSE_EVENT_MBUTTON;
+    else if (button->button == 3)
+        mask |= MOUSE_EVENT_RBUTTON;
+
+    /* make sure to ignore double and triple clicks */
+    if (button->type == GDK_BUTTON_PRESS)
+        s->mouse_buttons |= mask;
+    else if (button->type == GDK_BUTTON_RELEASE)
+        s->mouse_buttons &= ~mask;
+
+    if (kbd_mouse_is_absolute())
+        kbd_mouse_event(s->mouse_x, s->mouse_y, 0, s->mouse_buttons);
+    else
+        kbd_mouse_event(0, 0, 0, s->mouse_buttons);
+
+    return TRUE;
+}
+
+static gboolean gtk_dpy_scroll(GtkWidget *widget, GdkEventScroll *scroll,
+                               gpointer opaque)
+{
+    GtkDisplayState *s = opaque;
+    gint dz = 0;
+
+    if (scroll->direction == GDK_SCROLL_UP)
+        dz = -1;
+    else if (scroll->direction == GDK_SCROLL_DOWN)
+        dz = 1;
+
+    if (kbd_mouse_is_absolute())
+        kbd_mouse_event(s->mouse_x, s->mouse_y, dz, s->mouse_buttons);
+    else
+        kbd_mouse_event(0, 0, dz, s->mouse_buttons);
+
+    return TRUE;
+}
+
+void gtk_display_init(DisplayState *ds, int *argc, char ***argv)
+{
+    GtkDisplayState *s;
+
+    gtk_init(argc, argv);
+
+    if (keyboard_layout) {
+        kbd_layout = init_keyboard_layout(keyboard_layout);
+        if (!kbd_layout)
+            exit(1);
+    }
+
+    s = qemu_mallocz(sizeof(*s));
+    if (s == NULL) {
+        fprintf(stderr, "failed to allocate GtkDisplayState\n");
+        exit(1);
+    }
+
+    s->ds = ds;
+    s->widget = gtk_drawing_area_new();
+    s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE);
+    gtk_container_add(GTK_CONTAINER(s->window), s->widget);
+    gtk_widget_show_all(s->window);
+
+    gtk_signal_connect(GTK_OBJECT(s->widget), "key-press-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_key), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "key-release-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_key), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "motion-notify-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_motion), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "button-press-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_button), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "button-release-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_button), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "scroll-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_scroll), s);
+    gtk_signal_connect(GTK_OBJECT(s->widget), "expose-event",
+                       GTK_SIGNAL_FUNC(gtk_dpy_expose), s);
+    gtk_signal_connect(GTK_OBJECT(s->window), "delete-event",
+                       GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+
+    GTK_WIDGET_SET_FLAGS(s->widget, GTK_CAN_FOCUS);
+
+    gtk_widget_add_events(s->widget,
+                          GDK_POINTER_MOTION_MASK |
+                          GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_BUTTON_MOTION_MASK |
+                          GDK_SCROLL_MASK |
+                          GDK_KEY_PRESS_MASK |
+                          GDK_KEY_RELEASE_MASK);
+
+    gtk_widget_set_double_buffered(s->widget, FALSE);
+    gtk_widget_grab_focus(s->widget);
+
+    ds->dpy_update = gtk_dpy_update;
+    ds->dpy_resize = gtk_dpy_resize;
+    ds->dpy_refresh = gtk_dpy_refresh;
+    ds->opaque = s;
+
+    gtk_dpy_resize(ds, 640, 480);
+    update_caption(s);
+}
+
+/* GTK has it's own main loop and while it provides a mechanism to
+ * asynchronously iterate the main loop, assumes that these methods are being
+ * called from something invoked by the main loop.  To work around this, we
+ * register an idle callback that runs the QEMU main loop, and then we use the
+ * asynchronous iteration functions from the refresh callback.  This makes GTK
+ * happy while allowing QEMU to control the main loop. */
+static gboolean run_main_loop(gpointer opaque)
+{
+    void (*func)(void);
+
+    func = opaque;
+    func();
+    return FALSE;
+}
+
+/* @func is the QEMU main loop.  We pass in as a function pointer to avoid
+ * exporting the function from vl.c */
+void gtk_display_main_loop(DisplayState *ds, int (*func)(void))
+{
+    g_idle_add(run_main_loop, func);
+    gtk_main();
+}
diff --git a/hw/ps2.c b/hw/ps2.c
index 054b92f..daccc93 100644
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -284,6 +284,8 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
     unsigned int b;
     int dx1, dy1, dz1;
 
+    printf("sending packet\n");
+
     dx1 = s->mouse_dx;
     dy1 = s->mouse_dy;
     dz1 = s->mouse_dz;
@@ -332,6 +334,8 @@ static void ps2_mouse_event(void *opaque,
 {
     PS2MouseState *s = opaque;
 
+    printf("status - %d\n", (s->mouse_status & MOUSE_STATUS_ENABLED));
+
     /* check if deltas are recorded when disabled */
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
         return;
@@ -345,6 +349,9 @@ static void ps2_mouse_event(void *opaque,
        return;
     s->mouse_buttons = buttons_state;
 
+    printf("remote: %d\n", !(s->mouse_status & MOUSE_STATUS_REMOTE));
+    printf("queue count %d\n", s->common.queue.count);
+
     if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
         (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
         for(;;) {
@@ -392,6 +399,7 @@ void ps2_write_mouse(void *opaque, int val)
             ps2_queue(&s->common, AUX_ACK);
             break;
         case AUX_SET_STREAM:
+            printf("stream\n");
             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
             ps2_queue(&s->common, AUX_ACK);
             break;
@@ -400,6 +408,7 @@ void ps2_write_mouse(void *opaque, int val)
             ps2_queue(&s->common, AUX_ACK);
             break;
         case AUX_SET_REMOTE:
+            printf("remote\n");
             s->mouse_status |= MOUSE_STATUS_REMOTE;
             ps2_queue(&s->common, AUX_ACK);
             break;
diff --git a/vl.c b/vl.c
index 03cd386..0410bff 100644
--- a/vl.c
+++ b/vl.c
@@ -9012,7 +9012,9 @@ int main(int argc, char **argv)
     } else
 #endif
     {
-#if defined(CONFIG_SDL)
+#if defined(CONFIG_GTK)
+        gtk_display_init(ds, &argc, &argv);
+#elif defined(CONFIG_SDL)
         sdl_display_init(ds, full_screen, no_frame);
 #elif defined(CONFIG_COCOA)
         cocoa_display_init(ds, full_screen);
@@ -9146,7 +9148,11 @@ int main(int argc, char **argv)
        close(fd);
     }
 
+#if defined(CONFIG_GTK)
+    gtk_display_main_loop(ds, main_loop);
+#else
     main_loop();
+#endif
     quit_timers();
 
 #if !defined(_WIN32)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]