From: Anthony Liguori <anthony@codemonkey.ws>
To: "Daniel P. Berrange" <berrange@redhat.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] opengl rendering in the sdl window
Date: Sun, 07 Sep 2008 19:12:34 -0500 [thread overview]
Message-ID: <48C46DF2.2050007@codemonkey.ws> (raw)
In-Reply-To: <20080907163123.GD31773@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1139 bytes --]
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
>
[-- Attachment #2: gtk.patch --]
[-- Type: text/x-patch, Size: 26161 bytes --]
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 <aliguori@us.ibm.com>
+ *
+ * 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)
next prev parent reply other threads:[~2008-09-08 0:13 UTC|newest]
Thread overview: 75+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-29 15:22 [Qemu-devel] [PATCH] opengl rendering in the sdl window Stefano Stabellini
2008-09-02 16:53 ` Ian Jackson
2008-09-04 3:00 ` Anthony Liguori
2008-09-04 7:41 ` Gerd Hoffmann
2008-09-04 9:42 ` Daniel P. Berrange
2008-09-04 10:06 ` Andreas Färber
2008-09-04 10:20 ` Daniel P. Berrange
2008-09-05 16:42 ` Andreas Färber
2008-09-07 7:51 ` Avi Kivity
2008-09-07 3:07 ` Anthony Liguori
2008-09-07 16:31 ` Daniel P. Berrange
2008-09-08 0:12 ` Anthony Liguori [this message]
2008-09-04 10:06 ` Stefano Stabellini
2008-09-05 12:02 ` Jamie Lokier
2008-09-05 12:11 ` Samuel Thibault
2008-09-06 23:27 ` Jamie Lokier
2008-09-07 14:22 ` Samuel Thibault
2008-09-07 14:36 ` Paul Brook
2008-09-07 14:42 ` Samuel Thibault
2008-09-07 15:03 ` Paul Brook
2008-09-07 15:12 ` Samuel Thibault
2008-09-07 15:35 ` Paul Brook
2008-09-07 15:41 ` Samuel Thibault
2008-09-07 15:57 ` Paul Brook
2008-09-08 0:08 ` Anthony Liguori
2008-09-08 0:21 ` Samuel Thibault
2008-09-08 1:18 ` Jamie Lokier
2008-09-08 10:38 ` Stefano Stabellini
2008-09-08 13:21 ` Jamie Lokier
2008-09-05 16:44 ` Stefano Stabellini
2008-09-05 16:55 ` Daniel P. Berrange
2008-09-05 17:13 ` Stefano Stabellini
2008-09-07 3:21 ` Anthony Liguori
2008-09-08 10:48 ` Stefano Stabellini
2008-09-08 13:16 ` Jamie Lokier
2008-09-08 13:51 ` Stefano Stabellini
2008-09-08 13:41 ` Jamie Lokier
2008-09-08 13:48 ` Daniel P. Berrange
2008-09-08 14:56 ` Gerd Hoffmann
2008-09-08 15:08 ` Jamie Lokier
2008-09-08 15:35 ` Gerd Hoffmann
2008-09-08 15:39 ` Jamie Lokier
2008-09-08 16:23 ` Gerd Hoffmann
2008-09-08 16:47 ` Anthony Liguori
2008-09-08 19:15 ` Gerd Hoffmann
2008-09-08 19:43 ` Jamie Lokier
2008-09-08 15:47 ` Daniel P. Berrange
2008-09-08 16:05 ` Anthony Liguori
2008-09-08 17:08 ` Mike Kronenberg
2008-09-08 19:21 ` Gerd Hoffmann
2008-09-08 21:06 ` Mike Kronenberg
2008-09-08 19:32 ` Jamie Lokier
2008-09-08 19:48 ` Jamie Lokier
2008-09-08 19:57 ` Anthony Liguori
2008-09-08 20:11 ` Jamie Lokier
2008-09-08 23:18 ` Daniel P. Berrange
2008-09-09 0:10 ` Jamie Lokier
2008-09-09 2:45 ` Anthony Liguori
2008-09-09 4:17 ` Jamie Lokier
2008-09-08 14:22 ` Anthony Liguori
2008-09-07 7:48 ` Avi Kivity
2008-09-07 11:57 ` Daniel P. Berrange
2008-09-07 13:12 ` Avi Kivity
2008-09-08 10:30 ` Stefano Stabellini
2008-09-08 10:35 ` Daniel P. Berrange
2008-09-08 10:53 ` Stefano Stabellini
2008-09-08 11:00 ` Daniel P. Berrange
2008-09-08 12:38 ` François Revol
2008-09-08 13:05 ` Jamie Lokier
2008-09-08 13:08 ` Anthony Liguori
2008-09-08 13:44 ` François Revol
2008-09-05 18:11 ` malc
2008-09-04 10:14 ` Stefano Stabellini
2008-09-07 3:09 ` Anthony Liguori
2008-09-04 10:21 ` Andreas Färber
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48C46DF2.2050007@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=berrange@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).